分享
 
 
 

在C++类中实现Windows窗口的创建

王朝c/c++·作者佚名  2006-11-16
窄屏简体版  字體: |||超大  

//========================================================================

//TITLE:

// 在C++类中实现Windows窗口的创建

//AUTHOR:

// norains

//DATE:

// Thursday 9-November-2006

//========================================================================

在面向过程的方法中实现窗口的创建很简单,但有个非常明显的缺点,就是封装不好。如果是自写自用,倒不是一个很大的问题,但如果是写给用户的,可能用户在包含头文件之后,看到那一大堆函数以及变量声明就已经晕掉。最好的方法当然是使用类,只给使用者留出应该使用的接口。但这会有个问题,就是消息处理函数必须为static的CALLBACK,否则编译会出错;但如果消息处理函数为static,其就归属于类,就根本无法调用对象的成员函数,而这个在经典的《windows 程序设计》中也没有涉及到。

难道我们就只能束手无策,只能采用面向过程的方法了么?那倒未必,毕竟在MFC框架中已经做到,那么相信我们也可以做到。经过一番摸索,终于找到在类中创建窗口的方法,在此不敢独享,放出代码和大家探讨。

为便于理解,代码的作用很简单,仅仅是完成了类的声明和对话框的创建,唯一多余的是在接收到WM_INITDIALOG消息时弹出一个消息框,以证明private函数能够正常调用。

代码首先是声明一个CMainDlg类:

///////////////////////////

//MainDlg.h

///////////////////////////

class CMainDlg

{

//--------------------------------------------------------------------------------------------

public:

//静态的回调函数

static BOOL CALLBACK CMainDlg::MainDlgProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam);

//-------------------------------------------------------------------------------------------

//Function

public:

//构造函数

CMainDlg(HINSTANCE hInst);

//析构函数

virtual ~CMainDlg();

//创建对话框

BOOL CreateMainDlg();

//消息调用函数,具体意义请参见函数的实现

BOOL CallDlgProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam);

private:

//临时测试调用函数,仅作为调试用

void TempTestFuncion(){MessageBox(NULL,L"test",L"",NULL);};

//---------------------------------------------------------------------------------------------

//数据成员

private:

HINSTANCE m_hInst;

HWND m_hDlg;

};

然后是MainDlg类的实现:

/////////////////////////////////

//MainDlg.cpp

////////////////////////////////

#include "stdafx.h"

#include "MainDlg.h"

#include "resource.h"

//全局指针,用来指向所创建的对象,即this的指向对象

CMainDlg *g_pDlg = NULL;

//消息的回调函数的实现

BOOL CALLBACK CMainDlg::MainDlgProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)

{

if(g_pDlg != NULL)

{

//如果this指针不为空,则调用CallDlgProc函数

return g_pDlg->CallDlgProc(hWnd,wMsg,wParam,lParam);

}

return FALSE;

}

//构造函数

CMainDlg::CMainDlg(HINSTANCE hInst)

{

g_pDlg = this; //存储this对象到全局变量中

m_hInst = hInst;

}

//析构函数

CMainDlg::~CMainDlg()

{

}

//创建对话框

BOOL CMainDlg::CreateMainDlg()

{

m_hDlg = CreateDialog(m_hInst,MAKEINTRESOURCE(IDD_MAIN_DLG),NULL,MainDlgProc);

if(m_hDlg == NULL)

{

return FALSE;

}

ShowWindow(m_hDlg,TRUE);//显示窗口

return TRUE;

}

//真正的消息处理函数,在这里可以任意调用对象的成员函数

BOOL CMainDlg::CallDlgProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)

{

switch(wMsg)

{

case WM_INITDIALOG:

TempTestFuncion(); //norains:测试的私有函数

break;

}

return FALSE;

}

这是在主程序中对类的的调用:

//////////////////

//MainApp.cpp

//////////////////

#include "stdafx.h"

#include "MainDlg.h"

int WINAPI WinMain( HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPTSTR lpCmdLine,

int nCmdShow)

{

//声明一个对象

CMainDlg mainDlg(hInstance);

//创建并显示窗口

if(mainDlg.CreateMainDlg() == FALSE)

{

return 0x05;

}

//消息循环

MSG msg;

while(GetMessage(&msg,NULL,0,0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return 0;

}

这段代码的关键点在于MainDlgProc声明为类的static函数,以及使用g_pDlg来存储this对象指针,并在MainDlgProc中调用。只要注意到这两点,在类中创建一个窗口就不是一件非常困难的事情。

对于CallDlgProc()函数,可能有不少人觉得是鸡肋,因为相同的功能完全可以在MainDlgProc()中实现,比如这程序的代码完全可以撇开CallDlgProc()写成这样:

BOOL CALLBACK CMainDlg::MainDlgProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)

{

if(g_pDlg != NULL)

{

switch(wMsg)

{

case WM_INITDIALOG:

g_pDlg->TempTestFuncion();

break;

}

}

return FALSE;

}

所完成的功能和之前的代码相同。不过如果要更改之后的代码正常工作的话,还需要把TempTestFuncion()函数声明为public。也许有的读者已经发现问题之所在:如果对消息相应的处理函数不多,这样倒是可以;但如果很多的话,那么那些消息相应函数都需要声明为public,并且这些消息响应函数都是用户不可能用到的!用户看到如此之多用不到的public函数,即使没头晕,也需要好一阵子才能回神过来。

所以呢,CallDlgProc()函数只是起到一个缓冲作用,不必要把所有的消息相应函数都暴露给用户。虽然这样做也暴露了CallDlgProc()函数,但毕竟相对于上十个甚至上百个消息响应函数而言,仅仅只是暴露一个没什么作用的CallDlgProc()函数函数,应该能让用户减轻不少负担才是。

在网上看到有一个方法不是采用全局变量,而是直接设置窗口数据,然后再获取。这方法比较有意思,在此将更改的代码贴出:

BOOL CMainDlg::CreateMainDlg()

{

m_hDlg = CreateDialog(m_hInst,MAKEINTRESOURCE(IDD_MAIN_DLG),NULL,MainDlgProc);

if(m_hDlg == NULL)

{

return FALSE;

}

ShowWindow(m_hDlg,TRUE);//显示窗口

SetWindowLong(m_hDlg,GWL_USERDATA,(LONG)this); //将this指针传递给窗口

return TRUE;

}

BOOL CALLBACK CMainDlg::MainDlgProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)

{

static CMainDlg * pDlg = NULL;

if(pDlg == NULL)

{

pDlg = (CMainDlg *)GetWindowLong(hWnd,GWL_USERDATA);

}

if(pDlg != NULL)

{

switch(wMsg)

{

case WM_INITDIALOG:

pDlg->TempTestFuncion();

break;

}

}

return FALSE;

}

这段代码关键就只在于两个函数:SetWindowLong()和GetWindowLong().很巧妙地让窗口通过这两个函数来传输this对象,的确是一个很好的方法.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有