2409wtl,切换视图

2024-09-08 04:36
文章标签 切换 视图 2409wtl

本文主要是介绍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.

这篇关于2409wtl,切换视图的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1147131

相关文章

数据视图(AngularJS)

<!DOCTYPE html><html ng-app="home.controller"><head><meta charset="utf-8"><title>数据视图</title><link href="page/common/css/bootstrap.min.css" rel="stylesheet"><script src="page/common/js/angular.js"></

2409wtl,网浏包装

原文 介绍 本教程帮助你用IE引擎构建一个基于WTL,并使用我编写的处理IWebBrowser2接口包装类的迷你浏览器. 因为知道代码可能很难读,因此本教程帮助你逐步开发一个迷你浏览器. 背景 大部分项都与互联网浏览有关.我常用超文本视图使用SDI. 有时,我要用真正的浏览器函数,因此我为IWebBrowser2编写了一个包装器. 此包装类可处理在IE中嵌入的窗口.它还可非常简单的处

MyBatis 切换不同的类型数据库方案

下属案例例当前结合SpringBoot 配置进行讲解。 背景: 实现一个工程里面在部署阶段支持切换不同类型数据库支持。 方案一 数据源配置 关键代码(是什么数据库,该怎么配就怎么配) spring:datasource:name: test# 使用druid数据源type: com.alibaba.druid.pool.DruidDataSource# @需要修改 数据库连接及驱动u

解决Office Word不能切换中文输入

我们在使用WORD的时可能会经常碰到WORD中无法输入中文的情况。因为,虽然我们安装了搜狗输入法,但是到我们在WORD中使用搜狗的输入法的切换中英文的按键的时候会发现根本没有效果,无法将输入法切换成中文的。下面我就介绍一下如何在WORD中把搜狗输入法切换到中文。

15 组件的切换和对组件的data的使用

划重点 a 标签的使用事件修饰符组件的定义组件的切换:登录 / 注册 泡椒鱼头 :微辣 <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-

12C 新特性,MOVE DATAFILE 在线移动 包括system, 附带改名 NID ,cdb_data_files视图坏了

ALTER DATABASE MOVE DATAFILE  可以改名 可以move file,全部一个命令。 resue 可以重用,keep好像不生效!!! system照移动不误-------- SQL> select file_name, status, online_status from dba_data_files where tablespace_name='SYSTEM'

71-java 导致线程上下文切换的原因

Java中导致线程上下文切换的原因通常包括: 线程时间片用完:当前线程的时间片用完,操作系统将其暂停,并切换到另一个线程。 线程被优先级更高的线程抢占:操作系统根据线程优先级决定运行哪个线程。 线程进入等待状态:如线程执行了sleep(),wait(),join()等操作,使线程进入等待状态或阻塞状态,释放CPU。 线程占用CPU时间过长:如果线程执行了大量的I/O操作,而不是CPU计算

[轻笔记]ubuntu shell脚本切换conda环境

source /home/yourhostname/anaconda3/etc/profile.d/conda.sh # 关键!!!conda activate env_name

ViewPager+fragment实现切换页面(一)

如今的很多应用中都是下面有一排按钮,点击可以切换页面,滑动也可以切换页面。下面就来简单的实现这个功能。 思路 首先肯定是会用到viewpager这个控件,为了能够向下兼容,最好用v4包下的viewpager,Activity要继承FragmentActivity 其次用一个集合来存储所有的fragment页面在设置viewpager的适配器时,把存储fragment页面的list集合传入ada

『功能项目』武器的切换实例【34】

本章项目成果展示 我们打开上一篇33战士的A键连击的项目, 本章要做的事情是按键盘E键切换职业时切换手中的武器 首先在资源商店下载免费的武器模型 创建一个空物体 命名为WeaponPos 将武器预制体拖拽至WeaponPos (注意调整空物体位置就可以后续文章会更换武器) 隐藏两把武器 运行项目 隐藏装备 在资源商店