2409wtl,切换视图

原文

介绍

我从一个基于SDI(单文档接口)WTL向导的应用开始,添加了一些从控件继承窗口一些对话框窗口(表单视图),然后才发现我必须,使SDI框架动态加载和卸载子窗口.

本文演示了两个可用来完成的技术:在SDI应用中的视图动态切换.这是我使用的两个.

技术

1技术:第一个方法涉及按需析构和重建视图实例.这更简单,且在不介意析构和重建窗口对象时效果很好.

2:按需创建视图,然后用Win32函数SetWindowLongPtr直接更改内部标识,在后续选择保留这些视图.
现已弃用SetWindowLong.

背景

回到SDI,在叫m_hWndClient的公共变量中,主框架存储子视图的(HWND)句柄.

不要

一开始可能会想重新赋值新的子窗口给框架的m_hWndClient然后更新布局来解决问题.

//在你的`框架`类中的某个位置
this->m_hWndClient = m_hWndNewView; //
//不管用!!`m_hWndNewView`是我想切换到的视图的句柄
UpdateLayout();

可惜,这不管用,主要是因为框架不知道提供句柄的窗口.

“把戏”

解决的技巧,是了解窗口隐式引用框架窗口中的第一个不是控制栏但恰好是子视图"面板".

MFC中,此面板标识为AFX_IDW_PANE_FIRST.如果你在ATL(atlres.h)查看,有一个名字相似的定义,叫ATL_IDW_PANE_FIRST.但两者有相同"0xE900"值.

如前,可析构当前的子"视图",创建新视图,然后再赋值新视图的句柄(隐式设置第一个面板ID)–技术#1;

或,可显式更改两个视图的ID,这样ATL_IDW_PANE_FIRST不再是当前视图ID,然后用一些直接的窗口调用给新视图赋值此ID.

有趣的是,技术#1不需要切换ID,所以我猜测,当你创建第二个视图时,它肯定有不同内部ID,框架或窗口会重新给ID赋值"0xE900".

如果不切换ID,而只按其父窗柄该框架创建第二个视图,则只要它存在,该框架就会继续按其子视图引用第一个视图.

技巧#1:析构并重建视图

BitmapView示例中查找名为TogglePrintPreview()的函数.

使用不同版本,这样示例代码演示和源码匹配.我还扩展它,这样可支持多个视图.步骤大致为:
1,创建新视图
2,给框架的m_hWndClient赋值新视图窗柄
3,显示新视图
4,析构旧视图
5,更新窗口
6,可选:更新框架的预翻译消息方法以包含新视图的覆盖.

 //`视图`只是一个枚举,这使得更加方便定位`视图`.对想切换到的`每个视图/对话框类`,都有个定义的`视图`枚举.
//可用简单的整数,成员窗口句柄或区分请求视图和当前视图.enum VIEW {BASIC, DIALOG, EDIT, NONE};
//成员视图,,
CBasicView m_view; //向导继承的基本视图
CEditView m_edit; //向导继承的基本对话框,
CBasicDialog m_dlg; //向导继承的基本编辑控件视图
...
void SwitchView(VIEW view)
{//旧视图和新视图的指针CWindow *pOldView, *pNewView;//取当前窗口/视图,在下面定义pOldView = GetCurrentView(); ////取/创建请求的视图pNewView = GetNewView(view); //在下面定义//检查请求的视图是当前视图还是默认视图if(!pOldView || !pNewView || (pOldView == pNewView))return; //闲着显示/隐藏隐藏旧窗口//显示新窗口删除旧视图pOldView->ShowWindow(SW_HIDE); //pNewView->ShowWindow(SW_SHOW); //pOldView->DestroyWindow();//要求`框架`更新客户UpdateLayout();
}

GetCurrentView()是一个比较m_hWndClient每个视图的句柄,然后返回匹配的视图,并转换为CWindow的助手函数.这样:

//取当前视图的助手方法~不可用`MFC`的`GetActiveView()`!
CWindow* GetCurrentView()
{if(!m_hWndClient)return NULL;if(m_hWndClient == m_view.m_hWnd)return (CWindow*)&m_view;else if(m_hWndClient == m_dlg.m_hWnd)return (CWindow*)&m_dlg;else if(m_hWndClient == m_edit.m_hWnd)return (CWindow*)&m_edit;elsereturn NULL;
}

GetNewView(VIEWview)是一个返回请求视图,并转换为CWindow助手函数.
在此过程中,它会按需创建视图对象,并给框架的m_hWndClient赋值其句柄.这样:

//取/创建新视图的助手方法
CWindow* GetNewView(VIEW view)
{CWindow* newView = NULL;//现在设置请求的视图switch(view){case BASIC://如果不存在,则创建它,并按`框架`的`m_hWndClient`设置`引用`if(m_view.m_hWnd == NULL)m_view.Create(m_hWnd);m_hWndClient = m_view.m_hWnd;newView = (CWindow*)&m_view;break;case DIALOG:if(m_dlg.m_hWnd == NULL)m_dlg.Create(m_hWnd);m_hWndClient = m_dlg.m_hWnd;newView = (CWindow*)&m_dlg;break;case EDIT:if(m_edit.m_hWnd == NULL)m_edit.Create(m_hWnd);m_hWndClient = m_edit.m_hWnd;newView = (CWindow*)&m_edit;break;}return newView;
}

1,上面函数是直接的.SwitchView(VIEWview)首先调用GetCurrentView()以取当前视图的引用.
2,然后,它调用GetNewView(VIEWview)来取请求视图的引用,并在必要创建该视图.它还给框架的m_hWndClient赋值新视图的句柄.

3,如果新视图或旧视图无效彼此相等(即用户已按自身更改当前视图),则它不会操作.

4,然后SwitchView(VIEWview)隐藏旧视图,并显示新视图.

5,最后,它析构了旧的视图.最后一步隐式按ATL_IDW_PANE_FIRST更改新视图的内部ID.

如上,还应该考虑更新框架预翻译消息覆盖,以确保视图可处理消息自己的预翻译消息.

预翻译消息实质上允许框架和/或视图预览消息,并在翻译和分发消息前处理它们.返回以避免翻译和分发消息.

大多数应用不会覆盖预翻译消息,除非需要特殊处理消息,如子类化许多控件时.

也即,WTL向导自动在CWindowImplCDialogImpl视图中生成预翻译消息函数,且还会添加从主机的预翻译消息消息路由它们期望代码,这是必须确保从主机路由消息视图另一个原因.

以下是我修改框架预翻译消息以使视图查看消息的方法:

//在`CMainFrame`中实现
virtual BOOL PreTranslateMessage(MSG* pMsg)
{if(CFrameWindowImpl<CMainFrame>::PreTranslateMessage(pMsg))return TRUE;if(m_hWndClient != NULL){//为当前视图调用`预翻译消息`取当前视图(转换为`CWindow*`)~函数,如上所示CWindow* pCurrentView = GetCurrentView(); //if(m_view.m_hWnd == pCurrentView->m_hWnd)return m_view.PreTranslateMessage(pMsg);else if(m_dlg.m_hWnd == pCurrentView->m_hWnd)return m_dlg.PreTranslateMessage(pMsg);else if(m_edit.m_hWnd == pCurrentView->m_hWnd)return m_edit.PreTranslateMessage(pMsg);}return FALSE;
}

在此,我首先确保该框架有效的子句柄,然后调用GetCurrentView()函数来返回CWindow*.然后,我用每个视图比较该CWindow*窗柄成员.

这样用视图来调用视图自己的预翻译消息.我不能CWindow来调用它,因为它没有实现预翻译消息.

你不需要路由消息到未实现预翻译消息视图.

即,预翻译消息CMessageFilter接口中的唯一方法,也是主框架实现的方法.但是,它不在CWindowImplCDialogImpl继承层次中.

即它不是隐式可用的,也不一定都需要.

技巧#2:析构并重建视图

此时,只需简单的更改SwitchView方法,即可在切换持久保存视图,而不是析构它们.

//删除旧视图
pOldView->DestroyWindow();
//用如下替换:
C++
//更改当前视图的`ID`,使它不是框架中的第一个子项pOldView->SetWindowLongPtr(GWL_ID, 0);
//按框架的第一个/子项,设置`面板新视图`
pNewView->SetWindowLongPtr(GWL_ID, ATL_IDW_PANE_FIRST);

就是这样!如上,框架使用第一个面板ID更新其客户视图,因此需要按ATL_IDW_PANE_FIRST以外的其他内容更改当前视图GWL_ID,然后按ATL_IDW_PANE_FIRST更改新视图的GWL_ID.

使用代码

可在任意地方调用SwitchView,只需使用与要求视图对应的视图枚举调用它即可.如SwitchView(BASIC)SwitchView(EDIT).

如果想使用实现,需要:
1,更新enum VIEW{}以包含每个视图的标识.
2,在每个视图的主框架中,添加成员变量.如CMyView m_myView.

3,更新GetNewView(VIEW)中的语句,以包含每个视图枚举和视图成员的例子.

4,更新GetCurrentView()以返回每个视图成员CWindow*引用.

5,(可选)更新框架的预翻译消息方法,以调用视图自己的预翻译消息方法.

实际上,一般想使用一个方法或另一个方法,但这为你提供了在同一个应用中同时使用这两个方法的选项.有效更改包括:

void SwitchView(VIEW view, BOOL bPreserve = FALSE) //默认析构
{...if(bPreserve){//使用技巧`#2`}else{//使用技巧`#1`}
}

结束语

见,SDIMultiView_src.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/878904.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[物理专题]经典浮力题目的Fh图像绘制

这段代码用于绘制物体在液体中受到的浮力变化的图像&#xff0c;它有多个好处&#xff1a; 直观展示数据&#xff1a;通过图形化展示&#xff0c;可以直观地看到物体在液体中浸入深度与受到的浮力之间的关系。 教育和学习工具&#xff1a;这种类型的图像常用于教育目的&#x…

基于canal的Redis缓存双写

canal地址&#xff1a;alibaba/canal: 阿里巴巴 MySQL binlog 增量订阅&消费组件 (github.com)https://github.com/alibaba/canal 1. 准备 1.1 MySQL 查看主机二进制日志 show master status 查看binlog是否开启 show variables like log_bin 授权canal连接MySQL账号 …

【OpenCV3】图像的翻转、图像的旋转、仿射变换之图像平移、仿射变换之获取变换矩阵、透视变换

1 图像的放大与缩小 2 图像的翻转 3 图像的旋转 4 仿射变换之图像平移 5 仿射变换之获取变换矩阵 6 透视变换 1 图像的放大与缩小 resize(src, dsize[, dst[, fx[, fy[, interpolation]]]]) src: 要缩放的图片dsize: 缩放之后的图片大小, 元组和列表表示均可.dst: 可选参数, 缩…

【无标题】XSS安全防护:responseBody (输入流可重复读) 配置

接上文:配置XSS过滤器 XXS 安全防护:拦截器+注解实现校验-CSDN博客XSS(跨站脚本)攻击是一种网络安全威胁,允许攻击者注入恶意脚本到看似安全的网站。当用户浏览这些被注入恶意代码的网页时,恶意脚本会在用户的浏览器环境中执行,这可能导致多种安全问题,如窃取敏感数据、…

将添加功能的抽屉剥离,在父组件调用思路

一、新建组件 新建AddRoleEditerDrawer.vue<template><div><el-drawer v-model"dialog" title"添加角色" :before-close"handleClose" direction"rtl" colse"cancelForm"class"demo-drawer" moda…

「数学::质数」试除法 / Luogu P5736(C++)

概述 在质数的第一节我们来讲解试除法。 质数是指在大于1的自然数中只能被1和它自己整除的数。 我们可以利用这一除法性质对质数进行判定。 Luogu P5736&#xff1a; 输入 n 个不大于 10^5 的正整数。要求全部储存在数组中&#xff0c;去除掉不是质数的数字&#xff0c;依…

LLM Attention and Rotary Position Embedding(旋转位置编码)

旋转位置编码&#xff08;Rotary Position Embedding&#xff0c;RoPE&#xff09;是一种能够将相对位置信息依赖集成Attention计算里的方法。就是在做词表映射的时候不是单一的进行一个embedding计算&#xff0c;还考虑位置信息。 一些资料 [1] https://arxiv.org/pdf/2104.0…

面对养老困局我心安若素

“2025年&#xff0c;我们需要注意什么&#xff1f;是复杂的国际环境么&#xff1f;明年对于我国70岁以上的老年人来说这可不是主要关心的问题。反而有这两件事情需要他们来关注&#xff0c;如果70岁老人不提前做好准备&#xff0c;可能会有非常严重的后果......”这是昨天发表…

鸿蒙轻内核M核源码分析系列十五 CPU使用率CPUP

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 轻内核M核源码分析系列一 数据结构-双向循环链表 轻内核M核源码分析系列二 数据结构-任务就绪队列 鸿蒙轻内核M核源码分析系列三 数据结构-任务排序链表 轻…

国产脑机全面超越马斯克Nearlink

&#x1f4a5;&#x1f4a5;&#x1f4a5;刚刚&#xff0c;世界首富马斯克同学已经是完全懵逼了&#xff0c;心态都崩了&#xff01;因为今天爆出来了一个轰动了全世界科技界的大新闻&#xff0c;国产脑机在多个维度上全面超越了马斯克的Nearlink&#xff01; &#x1f4a5;&am…

SpringBoot2:请求处理原理分析-RESTFUL风格接口

一、RESTFUL简介 Rest风格支持&#xff08;使用HTTP请求方式&#xff0c;动词来表示对资源的操作&#xff09; 以前&#xff1a;/getUser 获取用户 /deleteUser 删除用户 /editUser 修改用户 /saveUser 保存用户 现在&#xff1a; /user GET-获取用户 DELETE-删除用户 PUT-修改…

数据仓库技术选型方案文档

关联博客&#xff1a; 数据仓库技术选型方案文档 Flink CDC MySQL数据同步到Doris表同步配置生成工具类 新版报表系统&#xff08;明细报表、看板、数据大屏&#xff09;方案&介绍 文章目录 数据仓库技术选型背景现状现状架构目标架构业务反馈&痛点问题&#xff1a;原因…

随手记:小程序体积超出2M包大小如何优化

小程序的包体积限制是2M&#xff0c;超出包大小如何优化 先简单列出&#xff0c;最近比较忙&#xff0c;后续优化明细&#xff0c;有着急的先留言踢我 1.分包 留几个主要的页面体积小的&#xff0c;剩下的在page.json中拆到subpackages中&#xff0c;简单举个例子 "page…

多维动态规划-面试高频!-最长公共子序列和最长公共子串、回文串-c++实现和详解

1143. 最长公共子序列 中等 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删…

力扣1049-最后一块石头的重量II(Java详细题解)

题目链接&#xff1a;1049. 最后一块石头的重量 II - 力扣&#xff08;LeetCode&#xff09; 前情提要&#xff1a; 因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。 最近刚学完01背包&#xff0c;所以现在的题解都是以01背包问题为基础再来写的。 如果大家不懂…

FPGA实现串口升级及MultiBoot(二)FPGA启动流程

这个系列开篇肯定要先了解FPGA的启动流程&#xff0c;试想一下&#xff1a;我想实现MultiBoot&#xff0c;那么我应该在什么时候开始升级&#xff0c;升级失败后FPGA进行了哪些操作&#xff0c;以及怎么回到Golden区&#xff1f; 还有一个问题&#xff0c;就是我硬件打板回来&a…

Selenium 实现图片验证码识别

前言 在测试过程中&#xff0c;有的时候登录需要输入图片验证码。这时候使用Selenium进行自动化测试&#xff0c;怎么做图片验证码识别&#xff1f;本篇内容主要介绍使用Selenium、BufferedImage、Tesseract进行图片 验证码识别。 环境准备 jdk&#xff1a;1.8 tessdata&…

深度学习--对抗生成网络(GAN, Generative Adversarial Network)

对抗生成网络&#xff08;GAN, Generative Adversarial Network&#xff09;是一种深度学习模型&#xff0c;由Ian Goodfellow等人在2014年提出。GAN主要用于生成数据&#xff0c;通过两个神经网络相互对抗&#xff0c;来生成以假乱真的新数据。以下是对GAN的详细阐述&#xff…

如果电脑一直提示微软账号登录……

前言 今天小白接了个电脑故障问题&#xff1a;电脑提示微软账号登录&#xff0c;然后经过各种操作…… 电脑重启之后就变成了这样&#xff1a; 按理说&#xff0c;登录了微软账号之后&#xff0c;Windows系统要进入到桌面就必须有一个输入密码验证的过程&#xff0c;但这个界…

Harmony OS DevEco Studio 如何导入第三方库(以lottie为例)?-- HarmonyOS自学2

在做鸿蒙开发时&#xff0c;离不开第三方库的引入 一.有哪些支持的Harmony OS的 第三方库&#xff1f; 第三方库下载地址&#xff1a; 1 tpc_resource: 三方组件资源汇总 2 OpenHarmony三方库中心仓 二. 如何加入到DevEco Studio工程 以 lottie为例 OpenHarmony-TPC/lot…