一起来搭建像Qt一样的win32图形框架
来源:互联网 发布:淘宝充值平台进价表 编辑:程序博客网 时间:2024/04/27 03:08
哎,就文章标题就纠结的很。其实就是觉得Qt的图形框架很爽,但有时候想写一个工具,用Qt带的dll就一堆,有点不爽。又不想用MFC,所以就有了这篇文章。
大家都知道在Qt中的main函数超级简单
int main(){ QApplication app; MainWindow w; w.show(); return app.exec();}
大家是不是觉得Qt做得很棒呢!如果我们的win32可以这样,那不是也好爽。下面我们就一步一步来搭建这个框架。
首先用VS建立一个win32工程。为了说明,我调整了代码并删除了一些不必要的代码。
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){switch (message){case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}return 0;}int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow){WNDCLASSEX wcex;wcex.cbSize = sizeof(WNDCLASSEX);wcex.style = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc = WndProc;wcex.cbClsExtra = 0;wcex.cbWndExtra = 0;wcex.hInstance = hInstance;wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32PROJECT7));wcex.hCursor = LoadCursor(NULL, IDC_ARROW);wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32PROJECT7);wcex.lpszClassName = L"123";wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));RegisterClassEx(&wcex);HWND hWnd = CreateWindow(L"123", L"title", WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);HACCEL hAccelTable = 0;MSGmsg;// 主消息循环: while (GetMessage(&msg, NULL, 0, 0)){if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)){TranslateMessage(&msg);DispatchMessage(&msg);}}return (int) msg.wParam;}
从上面的代码需要关注几个关键点:
1 调用RegisterClassEx注册窗口类。只需要调用一次。
2 调用CreateWindow创建窗口。
3 使用GetMessage进行消息循环。
4 实现窗口的回调函数WndProc。
如果要实现像Qt那样的架构。RegisterClassEx当然要放到Application中,CreateWindow当然要放到MainWindow中,因为可以创建多个窗口,GetMessage也只能放到Application中。准确地说是放到Application的exec中。至于WndProc放到哪,现在先不管。
千言万语,不如代码来得实在。下面我们来时Application类类似Qt的QApplication类。修改后的代码如下:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){switch (message){case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);}return 0;}class Application{public:Application(){WNDCLASSEX wcex;wcex.cbSize = sizeof(WNDCLASSEX);wcex.style = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc = WndProc;wcex.cbClsExtra = 0;wcex.cbWndExtra = 0;wcex.hInstance = NULL;wcex.hIcon = NULL;wcex.hCursor = LoadCursor(NULL, IDC_ARROW);wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32PROJECT7);wcex.lpszClassName = L"123";wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));RegisterClassEx(&wcex);}int exec(){HACCEL hAccelTable = 0;MSGmsg;while (GetMessage(&msg, NULL, 0, 0)){if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)){TranslateMessage(&msg);DispatchMessage(&msg);}}return (int)msg.wParam;}};int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow){Application app;HWND hWnd = CreateWindow(L"123", L"title", WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);return app.exec();}
哈哈,是不是发现main函数一下子简单了好多,并且有点像Qt的框架了!别着急,我们继续。
CreateWindow放到一个窗口类中这可以搞定,但如何把回调函数也放到里面呢?怎么办?怎么办?嘿,我想到一个好办法,在Application实现一个static函数作为全局的回调函数,然后CreateWindow时记录所有窗口的句柄,然后Application的Proc不是就可以分发消息到不同的窗口类了嘛!呵呵,说干就干。
#include <cassert>
#include <unordered_map>
class Wnd;
class Application{
public:
Application(){
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = Application::proc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = NULL;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32PROJECT7);
wcex.lpszClassName = L"123";
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassEx(&wcex);
}
int exec(){
HACCEL hAccelTable = 0;
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
static void registerWnd(Wnd* wnd);
static void unregisterWnd(Wnd* wnd);
static Wnd* wnd(HWND hWnd);
static HRESULT CALLBACK proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
private:
static std::unordered_map<HWND, Wnd*> s_wnds;
};
std::unordered_map<HWND, Wnd*> Application::s_wnds;
class Wnd{
public:
Wnd() :_hWnd(NULL){}
virtual ~Wnd(){
Application::unregisterWnd(this);
DestroyWindow(_hWnd);
}
void createWindow(LPCWSTR className, LPCWSTR windowName, DWORD style, int x, int y, int w, int h, HWND hParent, HMENU hMenu){
_hWnd = CreateWindow(className, windowName, style, x, y, w, h, hParent, hMenu,
GetModuleHandle(NULL), 0);
Application::registerWnd(this);
}
HWND hWnd()const{ return _hWnd; }
void show(){ ShowWindow(_hWnd, SW_SHOW); }
virtual HRESULT proc(UINT message, WPARAM wParam, LPARAM lParam){ return 0; }
protected:
HWND _hWnd;
};
void Application::registerWnd(Wnd* wnd){
assert(wnd);
s_wnds[wnd->hWnd()] = wnd;
}
void Application::unregisterWnd(Wnd* wnd){
auto itr = s_wnds.find(wnd->hWnd());
if (itr != s_wnds.end()){
s_wnds.erase(itr);
}
}
Wnd* Application::wnd(HWND hWnd){
auto itr = s_wnds.find(hWnd);
if (itr != s_wnds.end())
return itr->second;
return nullptr;
}
HRESULT CALLBACK Application::proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
auto wnd = Application::wnd(hWnd);
if (wnd){
return wnd->proc(message, wParam, lParam);
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
class MainWindow :public Wnd{
public:
MainWindow(){
createWindow(L"123", L"title", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL);
}
HRESULT proc(UINT message, WPARAM wParam, LPARAM lParam){
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(_hWnd, message, wParam, lParam);
}
return 0;
}
};
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
Application app;
MainWindow w;
w.show();
return app.exec();
}
看,现在基本上像Qt了,注意注册类时的回调函数已经变了哈!现在集成MainWindow然后实现proc处理函数就好了,当然还有更好的方法!好了,其实接下来还有好多工作,比如按钮等控件的布局,类似QLayout,按钮等事件如mouseClickEvent等。我要回家了,改天在写吧!
- 一起来搭建像Qt一样的win32图形框架
- 一起来搭建像Qt一样的win32图形框架(2)
- Qt-像丝一样滑
- 结合struts实现像html一样的fram框架
- Win32图形设计框架基础知识
- Qt教程10--像丝一样滑
- QT图形视图框架
- QT图形视图框架
- Qt图形视图框架
- QT 图形视图框架
- QT图形视图框架
- QT图形框架
- 一起来搭建我们的世界
- 一起来搭建我们的世界
- 像猪一样的周末
- 像yahoo一样的logo
- 像流星一样的名字
- 像树一样的成长
- POSIX标准和XSI扩展
- void *memmove(void *dest, const void *src, size_t n) 的实现
- 补番推荐
- memcache 的内存管理介绍和 php实现memcache一致性哈希分布式算法
- 王朝 第五周
- 一起来搭建像Qt一样的win32图形框架
- 洛谷 P1021 邮票面值设计
- java拾遗-泛型总结
- git add用法详解
- (4)Deep Learning模型之:CNN卷积神经网络(2)模型训练
- 错排&&递归问题
- 可重入内核
- 文章标题
- springmvc 下拉框联动