《PicSi的实现细节》 第2节 窗口类CAboutDlg的定义
来源:互联网 发布:淘宝号登录 编辑:程序博客网 时间:2024/06/05 15:29
为了把重点集中在窗口类的定义方法上,本节以较为简单的AboutDlg为例,阐述如何定义窗口类。
在第一节中,我们已经在Resource View(资源视图)中添加了所需的窗口。在这里简单总结一下:向主窗口中添加Tab控制,用作菜单选项卡;添加IDD_DLG_CREATOR子窗口,作为Main子窗口;向IDD_ABOUTBOX子窗口添加了一个Edit控制,用来显示PicSi的使用说明,作为About子窗口。
切换到Solution Explorer视图,我们可以看到Application Wizard自动生成的源文件AboutDlg.h,双击它进入编辑窗口。AboutDlg.h比较简短,全部代码如下:
// aboutdlg.h : interface of the CAboutDlg class///////////////////////////////////////////////////////////////////////////////#pragma onceclass CAboutDlg : public CDialogImpl<CAboutDlg>{public: enum { IDD = IDD_ABOUTBOX };private: CEdit m_editAbout;public: BEGIN_MSG_MAP(CAboutDlg) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) COMMAND_ID_HANDLER(IDOK, OnCloseCmd) COMMAND_ID_HANDLER(IDCANCEL, OnCloseCmd) END_MSG_MAP()// Handler prototypes (uncomment arguments if needed):// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { m_editAbout.Attach(GetDlgItem(IDC_EDIT_ABOUT)); display_information(); return TRUE; } LRESULT OnCloseCmd(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { //EndDialog(wID); return 0; }private: // display information void display_information() throw() { WTL::CString strReadme; if(!PS_GetInstallationDirectory(strReadme)) return; if(!PS_PathAppendBackslash(strReadme)) return; strReadme += _T("readme.txt"); ATL::CComPtr<IStream> spStream; HRESULT hr = ::SHCreateStreamOnFile(strReadme, STGM_READ | STGM_SHARE_DENY_WRITE, &spStream); if(FAILED(hr)) return; ULONG nCount; WTL::CString strInfo; TCHAR szInfo[1025]; while(true) { ZeroMemory(szInfo, 1025 * sizeof(TCHAR)); hr = spStream->Read(szInfo, 1024, &nCount); if(FAILED(hr)) return; else { strInfo += szInfo; if(nCount < 1024) break; } } // end while m_editAbout.SetWindowText(strInfo); }};pragma once表示AboutDlg.h头文件只被Project包含进一次,从而避免重复定义。
第10行指定About窗口类对应的资源ID,当调用Create方法创建About子窗口时,程序将根据ID号加载所需的资源。
第13行定义了成员变量m_editAbout,它对应于About子窗口上的文本框,用来显示PicSi的说明文档。
第17到21行是CAboutDlg的消息映射,之所以它具有处理消息的能力,是因为它继承自CDialogImpl类。CDialogImpl类是一个mix-in class,这是WTL中模板的典型用法,它提供了一种trunk机制,将窗口过程函数的HWND参数替换成this指针,使CAboutDlg也能捕获并处理消息。
从消息映射可以看出,About子窗口只需处理三条消息WM_INITDIALOG/IDOK/IDCANCEL,其中较为复杂的是WM_INITDIALOG消息。它在窗口创建的时候抛出,定义OnInitDialog对它进行响应。在Application Wizard自动生成的代码中,OnInitDialog的第一行代码是CenterWindow(),对于非模态(modaless)的窗口是没有意义的,可以将它删除。我们首先调用CEdit::Attach方法,将变量m_editAbout与控制IDC_EDIT_ABOUT关联起来,这样我们就可通过m_editAbout来控制Edit控制的行为。比如更改文本框的显示内容,就可调用m_editAbout.SetWindowText方法来实现。随后我们调用了一个私有方法display_information,它定义在第43到70行。
OnCloseCmd方法响应了IDOK和IDCANCEL消息,这里需将EndDialog(wID)注释掉。原因在于About子窗口现在是modaless的,只有在父窗口销毁时才被销毁,自身不能提前清理。如果不注释EndDialog(wID),当用户敲击Enter键时可能会触发IDOK消息,这样会使程序运行时出错。
现在重点说明私有方法display_information的实现。顾名思义,此方法用来显示相关信息(实际上就即PicSi使用说明文档)。思路分为4步:(1)获得readme.txt文件的全路径;(2)为readme.txt文件创建IStream接口指针;(3)从readme.txt文件中读取文本信息;(4)将读到的文本显示到文本框控制中。
为了获得readme.txt的全路径,我们调用了公共函数PS_GetInstallationDirectory,它定义在private/Fcommon.h头文件中,代码为:
// PS_GetInstallationDirectoryinlineBOOL PS_GetInstallationDirectory(WTL::CString& strPath) throw(){ TCHAR szPath[MAX_PATH]; if(!GetModuleFileName(NULL, szPath, MAX_PATH)) return FALSE; strPath = szPath; int nPos = strPath.ReverseFind(_T('\\')); strPath = strPath.Mid(0, nPos); return TRUE;}
这段代码很好理解,你只需查一查GetModuleFileName这个API函数的作用就明白了。
为readme.txt文件创建ISteam接口指针调用了API函数 SHCreateStreamOnFile ,传入标签参数STGM_READ | STGM_SHARE_DENY_WRITE表示以读方式打开readme.txt,而且不允许其它进程对它进行Write操作。
接着进入一个while循环,一次读取1024个字符,直至读到文本的末尾。值得注意的是,每次读之前都要调用ZeroMemory函数对szInfo进行清零操作,否则会出现乱码。判断是否读完readme.txt的方法很简单,只要将每次实际读取的字符数与1024进行比较即可,若实际读取的字符数比1024小,则说明已经读到了readme.txt的末尾。每次成功读取到的字符串szInfo都附加到WTL::CString变量strInfo的尾部。
最后将strInfo显示到About子窗口的文本框控制中,调用m_editAbout.SetWindowText方法即可实现。
可能你已发现上述每个函数/方法体最后都有一句throw(),它表示本函数/方法不会抛出异常。这是一种强烈的信号,警惕程序员必须在函数/方法内部将所有可能的异常处理掉。
CAboutDlg的定义就讲到这里,在下一节中,博主将详细介绍CPicsiCreatorDlg窗口类的定义。CPicsiCreatorDlg比CAboutDlg要复杂得多,它是PicSi的核心部分。
- 《PicSi的实现细节》 第2节 窗口类CAboutDlg的定义
- 《PicSi的实现细节》 第3节 窗口类CPicSiCreatorDlg的定义
- 《PicSi的实现细节》 第4节 主窗口CMainDlg的定义及杂项
- 《PicSi的实现细节》 第1节 界面的布局
- 《PicSi的实现细节》 第0节 下载方式及使用说明
- C++类的构造函数 后单冒号加基类 例如:CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
- C++中类定义的细节
- 分层窗口实现细节,UpdateLayeredWindow的使用问题
- 通过CSS的细节处理实现窗口适应
- CAboutDlg
- CAboutDlg
- 宏定义的细节问题
- 无法解析的外部符号 "public: void __thiscall CAboutDlg
- 委托实现了首次定义类时无法确定的一些细节,是通过协议实现的
- VC中,CAboutDlg,CDrawApp,CDrawDoc,CDrawView和CMainFrame五个类的关系是怎样的?它们各有什么作用?
- const的实现细节
- Spider的实现细节
- 线程的实现细节
- 表格的操作包括:标记行、移动行、删除行、插入行
- c#的udp通讯代码
- 21天学通JAVA——学习笔记
- jdk时区相差8小时 .
- 虚拟机下系统键盘无法使用
- 《PicSi的实现细节》 第2节 窗口类CAboutDlg的定义
- jquery_easyui_中文解析
- 采样率和比特率和位数
- jdk时区相差8小时
- Windows程序自启动原理
- Android开发环境搭建详细指南
- OpenGL ES之glNormalPointer函数
- jdk时区相差8小时 .
- hdu 1013