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,一经查实,立即删除!

相关文章

三维最小球覆盖(模拟退火)

地址&#xff1a;https://codeforces.com/gym/101981/attachments 代码: #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <cstring> #include <cmath> #include <ctime> #include <algorithm> #inclu…

[物理专题]经典浮力题目的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账号 …

Ubuntu创建一个虚拟摄像头

假如你目前没有摄像头&#xff0c;想在ubuntu下创建一个虚拟的摄像头&#xff0c;不妨参考以下方法&#xff1a; 安装 v4l2loopback sudo apt install v4l2loopback-dkms # 安装 v4l2loopback sudo modprobe v4l2loopback # 加载 v4l2loopback 模块 创建虚拟摄…

flutter开发多端平台应用的探索 下 (跨模块、跨语言通信之平台通道)

前文 Flutter 是一个跨平台的开发框架&#xff0c;它允许开发者使用相同的代码库来构建 iOS、Android、Web 和桌面应用程序。 上文flutter开发多端平台应用的探索 上&#xff08;基本操作&#xff09;-CSDN博客列举了一些特定平台的case&#xff08;桌面端菜单&#xff0c;鼠…

【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;依…

装修找人做“私活”有哪些风险?

装修过程中&#xff0c;有的业主为了节省开支&#xff0c;绕开装修公司与装修人员个人订立合同做“私活”&#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…

python批量替换sql语句中的id

python批量替换sql语句中的id 1、解决问题 把sql文本中的id替换成新表中最新的id,然后把表记录添加到新表中。 比如有以下sql: INSERT INTO `book` VALUES (1, 智慧七柱, 10719, TE劳伦斯, book_cover/10719.jpg, 66.66, 2023-05-21 18:16:00.000000); INSERT INTO `book…

面对养老困局我心安若素

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

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

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

mysql基础知识-锁机制

文章目录 锁类型1. 共享锁&#xff08;Shared Locks, S锁&#xff09;2. 排他锁&#xff08;Exclusive Locks, X锁&#xff09;3. 意向锁&#xff08;Intention Locks&#xff09;4. 记录锁&#xff08;Record Locks&#xff09;5. 间隙锁&#xff08;Gap Locks&#xff09;6. …

3.比 HTTP 更安全的 HTTPS(工作原理理解、非对称加密理解、证书理解)

所谓的协议 协议只是一种规则&#xff0c;你不按规则来就无法和目标方进行你的工作 协议说白了只是人定的规则&#xff0c;任何人都可以定协议 我们不需要太了解细节&#xff0c;这些制定和完善协议的人去做的&#xff0c;我们只需要知道协议的一个大概 HTTPS 协议 1、概述…

国产脑机全面超越马斯克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;原因…

数据传输安全——混合加解密

使用Hutool实现AES与RSA混合加密解密——构建安全的数据传输通道 在当今数字化社会中&#xff0c;信息安全已经成为企业和个人不可忽视的重要议题。加密技术作为保障数据安全的重要手段&#xff0c;其作用愈发突出。本文将深入探讨如何利用Hutool库实现AES与RSA混合加密解密方…