图形用户界面之---窗口:
主函数一般是:
/*************************************************************************
* WinMain
* 功能:程序入口点,调用InitApplication,InitInstance,进行消息循环
* 参数:hinstance---应用程序本次运行实例
* hPrevInstance---应用程序之前的实例,始终为NULL
* lpCmdLine---命令行参数
* nCmdShow---窗口显示方式,如SW_SHOW
* 返回值:失败返回FALSE
************************************************************************/
int WINAPI WinMain(HINSTANCE hinstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
BOOL fGotMessage;
if(!InitApplication(hinstance)) //注册窗口类
{
return FALSE;
}
if(!InitInstance(hinstance, nCmdShow)) //创建窗口和控件子窗口
{
return FALSE;
}
//消息循环
while((fGotMessage=GetMessage(&msg, (HWND)NULL, 0, 0)) != 0
&& fGotMessage != -1)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
UNREFERENCED_PARAMETER(lpCmdLine);
}
1)注册窗口类
任何一个窗口都必须属于一个窗口类,同一个类的窗口具有同样的窗口消息处理过程。Windows API函数RegisterClass和RegisterClassEx可以完成窗口类的注册:
ATOM WINAPI RegisterClass(
__in const WNDCLASS *lpWndClass
);
ATOM WINAPI RegisterClassEx(
__in const WNDCLASSEX *lpwcx
);
这两个函数分别使用了WNDCLASS和WNDCLASSEX结构作为参数,其中WNDCLASS定义如下:
typedef struct tagWNDCLASS {
UINT style; //窗口样式,通过系统预先定义的一些常量来设置窗口的样子
WNDPROC lpfnWndProc; //消息处理函数
int cbClsExtra; //附加窗口类内存
int cbWndExtra; //附加窗口内存
HINSTANCE hInstance; //赋值为应用程序的实例
HICON hIcon; //窗口的图标样式
HCURSOR hCursor; //窗口的鼠标样式
HBRUSH hbrBackground; //窗口的背景画刷,如COLOR_BACKGROUND、COLOR_WINDOW.
LPCTSTR lpszMenuName; //菜单名
LPCTSTR lpszClassName; //新建类的类名,在创建窗口时需要指定窗口所属类的类名
} WNDCLASS, *PWNDCLASS;
WNDCLASSEX结构定义如下:
typedef struct tagWNDCLASSEX {
UINT cbSize; //WNDCLASSEX结构的大小
UINT style; //窗口样式
WNDPROC lpfnWndProc; //窗口消息处理函数
int cbClsExtra; //附加窗口类内存
int cbWndExtra; //附加窗口内存
HINSTANCE hInstance; //应用程序实例
HICON hIcon; //窗口图标
HCURSOR hCursor; //窗口鼠标
HBRUSH hbrBackground; //背景画刷
LPCTSTR lpszMenuName; //菜单资源
LPCTSTR lpszClassName; //窗口类名
HICON hIconSm; //小图标
} WNDCLASSEX, *PWNDCLASSEX;
实例代码中InitApplication函数注册了窗口类:
/*************************************************************
* BOOL InitApplication(HINSTANCE hinstance)
* 功能:注册主窗口类
* 参数:hinstance,应用程序本次运行实例
* 返回值:是否成功
*************************************************************/
BOOL InitApplication(HINSTANCE hinstance)
{
//使用RegisterClassEx
WNDCLASSEX wcx;
//填充结构
wcx.cbSize = sizeof(wcx); //WNDCLASSEX结构的大小
wcx.style = CS_HREDRAW | CS_VREDRAW; //如果大小改变了将重绘窗口
wcx.lpfnWndProc = MainWndProc; //窗口消息处理函数
wcx.cbClsExtra = 0; //无附加窗口类内存
wcx.cbWndExtra = 0; //无附加窗口内存
wcx.hInstance = hinstance; //应用程序实例
wcx.hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_ICON_MAIN)); //图标º
wcx.hCursor = LoadCursor(NULL, IDC_ARROW); //鼠标指针
wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //背景画刷
wcx.lpszMenuName = MAKEINTRESOURCE(IDR_MENU_MAIN); //菜单资源
wcx.lpszClassName = "ASCEClass"; //窗口类名
wcx.hIconSm = (HICON)LoadImage(hinstance, //小图标
MAKEINTRESOURCE(IDI_ICON_MAIN),
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
LR_DEFAULTCOLOR);
//注册窗口类,并返回
return RegisterClassEx(&wcx);
}
2)创建窗口
WinMain主函数调用InitInstance函数实现了程序主窗口的创建,CreateWindow和CreateWindowEx是用于创建窗口的API函数。
CreateWindow函数的功能是创建一个窗口,在创建窗口前,需先注册窗口类。如果创建的窗口是系统控件,那么系统控制的类已经由系统注册好,所以不再需要注册:
HWND WINAPI CreateWindow(
__in_opt LPCTSTR lpClassName, //窗口所需窗口类的类名
__in_opt LPCTSTR lpWindowName, //窗口名,窗口有标题栏的话,将显示在上面
__in DWORD dwStyle, //窗口样式,窗口是否具有标题栏,是否可改变大小,
//边框的样式等都通过这个参数设置
__in int x, //创建创建后的初始位置,可设为CW_USEDEFAULT,由系统来设置
__in int y,
__in int nWidth, //窗口的宽和高,以像素点为单位,同样可指定为CW_USEDEFAULT
__in int nHeight,
__in_opt HWND hWndParent, //父窗口的句柄,当窗口样式设有WS_CHILD时需设置该项
__in_opt HMENU hMenu, //
__in_opt HINSTANCE hInstance, //应用程序实例,设置为WinMain的hInstance参数
__in_opt LPVOID lpParam //指定相关参数,指向CREATESTRUCT结构的变量,可以为NULL
);
最常见的窗口样式:
WS_BORDER //具有边框
WS_CAPTION //具有标题栏
WS_CHILD //是子窗口
WS_CHILDWINDOW //同上
WS_HSCROLL //具有水平滚动条
WS_MAXIMIZE //创建最大化窗口
WS_MINIMIZE //创建最小化窗口
WS_POPUP //顶层窗口(无父窗口,不能和WS_CHILD同时使用)
WS_SIZEBOX //具有拖拉窗口边框,窗口可改变大小
WS_SYSMENU //窗口具有菜单(窗口必须同时具有标题栏)
WS_TILED //具有标题栏和边框
WS_VISIBLE //窗口可见
WS_VSCROLL //具有竖直滚动条
CreateWindow和CreateWindowEx返回值都是HWND类型。HWND是窗口句柄数据类型。在Windows系统中每个窗口都有一个句柄,所有窗口句柄都是HWND数据类型的。
WinMain函数调用InitInstance函数实现了窗口的创建:
/*************************************************************
* BOOL InitInstance(HINSTANCE hinstance, int nCmdShow)
* 功能;创建主窗口和控件
* 参数:hinstance,应用程序本次运行实例
* nCmdShow,如何显示
* 返回值:是否成功
*************************************************************/
BOOL InitInstance(HINSTANCE hinstance, int nCmdShow)
{
HWND hwnd;
RECT rect;
//保存应用程序实例句柄
hinst = hinstance;
hwnd = CreateWindow(
"ASCEClass", //窗口类名,使用之前注册的主窗口类
"This’s ASCE’s Windows", //窗口名,显示在窗口标题栏上的字符串
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
WS_POPUPWINDOW, //窗口样式
CW_USEDEFAULT, //水平位置(默认)
CW_USEDEFAULT, //垂直位置(默认)
800, //宽
600, //高
(HWND)NULL, //无父窗口
(HMENU)LoadMenu(hinst, MAKEINTRESOURCE(IDR_MENU_COMMAND)), //菜单
hinstance, //应用程序实例
(LPVOID)NULL //无窗口创建数据
);
//窗口创建是否成功
if(!hwnd)
return FALSE;
//保留窗口句柄
hwndMain = hwnd;
//保证通用控件动态链接库已经加载
InitCommonControls();
//创建三种控件、子窗口
hwndTreeView = CreateTreeView(hwndMain, "files");
hwndListView = CreateListView(hwndMain, "processing");
hwndEdit = CreateEdit(hwndMain, "textarea");
//获取本窗口客户区的RECT(矩形方框的4个边界点)
GetClientRect(hwndMain, &rect);
//设置子窗口客户区的大小和位置
SetWindows(&rect);
//在EDIT控件中显示文本
ShowTextOnEdit(lpszLatin);
//显示、刷新窗口,使用WinMain函数设置的窗口显示方式
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
return TRUE;
}
3)窗口消息处理函数:
消息处理函数是一个回调函数,是注册窗口类时指定,在有消息需要处理时由系统调用。
消息处理函数具有固定的接口形式:
LRESULT CALLBACK WindowProc( //函数名任意
__in HWND hwnd, //操作的窗口
__in UINT uMsg, //消息标识符,窗口处理函数中需根据这个函数判断消息的类型做出不同的处理
__in WPARAM wParam, //消息的两个参数,根据消息类型的不同而有不同的意义
__in LPARAM lParam
);
窗口处理消息实例:
/****************************************************
* MainWndProc
* 窗口消息处理函数
****************************************************/
LRESULT CALLBACK MainWndProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch(uMsg)
{
case WM_CREATE: //窗口被创建时收到此消息
break;
case WM_PAINT: //窗口被绘制时收到此消息
break;
case WM_SIZE: //窗口大小改变时收到此消息
OnWindowResize();
break;
case WM_NOTIFY: //通常由控件发送给其父窗口,说明控件正在进行某项窗口操作
OnChildWindowsNotify((PVOID)lParam);
break;
case WM_DESTROY: //窗口销毁,单击右上角的关闭按钮会触发此消息
PostQuitMessage(0);
break;
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
//在“帮助”菜单中选择“关于”
case ID_HELP_ABOUT:
{
DialogBox(hinst, (LPCTSTR)IDD_DIALOG_ABOUT, hwnd, (DLGPROC)About);
return 0;
}
}
}
//可以在这里处理其他消息
default:
break;
}
//有很多消息未做处理,需要由默认窗口消息处理函数来处理
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
常见的窗口消息:
WM_CLOSE //收到此消息时窗口应关闭
WM_CREATE //窗口被创建时
WM_DESTROY//当窗口从界面上销毁时(用户单击窗口右上角关闭按钮)
WM_MOVING //窗口被移动时
WM_SIZE //窗口大小改变时
WM_NOTIFY //窗口所包含的子窗口被操作时,窗口会收到此消息
WM_COMMAND //当菜单、按钮被操作时,窗口会收到此消息
WM_NCLBUTTONDOWN //当用户在窗口中单击左键时,窗口会收到此小溪
WM_MOUSEHOVER //当鼠标在窗口客户区徘徊一段时间后窗口会收到此消息
重要消息:
1)WM_NOTIFY:
当一个窗口的子窗口被操作时,该子窗口会向父窗口发送WM_NOTIFY通知。WM_NOTIFY的lParam参数是一个指向NMHDR结构的指针:
typedef struct tagNMHDR {
HWND hwndFrom; //向主窗口发送此消息的子窗口的句柄
UINT_PTR idFrom; //子窗口的标识符
UINT code; //表示进行哪种操作
} NMHDR;
比如上面提到的OnChildWindowNotify函数所有到了NM_RCLICK表示右键单击;此外,还有NM_SETFOCUS(获得焦点)、NM_KEYDOWN(键盘按键)等,OnChildWindowNotify函数具体代码如下:
/*****************************************************************
* 功能:处理控制子窗口向父窗口发送的WM_NOTIFY消息
* 参数:pParam---WM_NOTIFY的消息参数
* 返回值:是否是Tree View发送的
******************************************************************/
BOOL OnChildWindowNotify(PVOID pParam)
{
LPNMHDR phdr = (LPNMHDR)pParam;
//只处理Tree View发送的Notify,其他的不予处理
if(phdr->hwndFrom != hwndTreeView)
{
return FALSE;
}
switch((LPNMHDR)pParam->code)
{
//如果是右键单击,则调用OnRclickTree函数,弹出右键菜单
case NM_RCLICK:
OnRclickTree((LPNMHDR)pParam);
break;
default:
break;
}
return TRUE;
}
2)WM_DESTROY:
收到WM_DESTROY消息表示用户单击窗口的关闭按钮。因此在MainWndProc函数收到WM_DESTROY消息后,调用PostQuitMessage函数退出程序运行。当然,要退出一个进程的运行,也可以调用ExitProcess函数。
3)WM_COMMAND:
收到WM_COMMAND一般是因为用户通过菜单、按钮等向程序输入命令。WM_COMMAND消息的wParam的低位WORD是表示用户单击的控件或菜单项的ID。
窗口会收到很多消息,但这些消息不一定需要处理,有些消息可能直接由系统来处理。DefWindowProc
的作用就是处理窗口处理函数没有处理完、或者不需要处理的函数。如果在消息处理函数中不把消息交给DefWindowProc处理,那么对窗口的动作几乎不会有响应,包括移动窗口、关闭窗口等,甚至有很多窗口样式不能显示。
设置窗口位置和大小:
上面的InitInstance函数除了完成父窗口的创建外,还创建了3个子窗口。在创建子窗口完成后,调用了SetWindows函数,代码如下:
/*************************************************************************
* 功能:本函数设置子窗口的位置和大小
* 参数:指向表示父窗口客户区的RECT
*************************************************************************/
DWORD SetWindows(LPRECT lpRect)
{
//Tree View
SetWindowPos(hwndTreeView, HWND_TOP,
lpRect->left, lpRect->top,
lpRect->right * 0.3, lpRect->bottom,
SWP_SHOWWINDOW);
//List View
SetWindowPos(hwndListView, HWND_TOP,
lpRect->right * 0.3, lpRect->bottom * 0.7,
lpRect->right * 0.7, lpRect->bottom * 0.3,
SWP_SHOWWINDOW);
//Edit
SetWindowPos(hwndEdit, HWND_TOP,
lpRect->right * 0.3, lpRect->top,
lpRect->right * 0.7, lpRect->bottom * 0.7,
SWP_SHOWWINDOW);
return 0;
}
上面用到的API函数是SetWindowPos:
BOOL WINAPI SetWindowPos(
__in HWND hWnd, //需设置的窗口句柄
__in_opt HWND hWndInsertAfter, //说明窗口的层次顺序,HWND_TOP表示显示在最上方
__in int X, //窗口的左上角所在位置和窗口的宽、高
__in int Y,
__in int cx,
__in int cy,
__in UINT uFlags //窗口大小和位置标志,SWP_SHOWWINDOW表示窗口正常显示
);
不仅窗口的位置和大小可以设置,窗口几乎所有属性都可以设置,包括窗口样式、消息处理函数等。
SetWindowLong函数可实现窗口多种属性设置:
LONG WINAPI SetWindowLong(
__in HWND hWnd, //指明需要设置属性的窗口
__in int nIndex, //指明需要设置哪种属性
__in LONG dwNewLong //新属性值
);
nIndex常见的值有:
GWL_STYLE //窗口样式
GWL_WNDPROC //窗口的消息处理函数
GWL_HINSTANCE //应用程序实例
窗口显示方式:
创建好的窗口可以在屏幕上显示,也可以不在屏幕上显示,通过ShowWindow函数进行设置:
BOOL WINAPI ShowWindow(
__in HWND hWnd, //窗口句柄
__in int nCmdShow //显示的方式,如SW_HIDE、SW_SHOW,SW_MAXIMIZE等
);
线程消息处理和消息循环:
GetMessage函数是从其所在的线程的消息队列中得到一条消息:
BOOL WINAPI GetMessage(
__out LPMSG lpMsg, //指向MSG结构的指针,该结构由于存储获取的消息
__in_opt HWND hWnd, //指定从哪个窗口获取消息,1)为NULL时,表示处理属于当前线程的
//所有窗口消息,以及线程消息队列中hwnd为NULL的窗口消息;
//2)为-1时,表示只处理线程消息队列中hwnd为NULL的窗口消息
__in UINT wMsgFilterMin, //获取消息的ID编号最小值,小于这个值就不获取
__in UINT wMsgFilterMax //获取消息的ID编号最大值,大于这个值就不获取
);
TranslateMessage函数用来把虚拟键消息转换成字符消息。因为Windows对所有键盘编码都采用虚拟键的定义,当按键按下时,并不得到字符消息,需要该函数来进行转换。转换后字符消息被传递到调用线程的消息队列中,当下一次调用GetMessage或PeekMessage时被取出:
BOOL WINAPI TranslateMessage(
__in const MSG *lpMsg
);
DispatchMessage函数把消息发送到窗口的消息处理函数处:
LRESULT WINAPI DispatchMessage(
__in const MSG *lpmsg
);
Windows系统为每个线程创建消息队列,从消息队列中获取消息使用GetMessage函数。也可以调用API函数将消息添加到消息队列中。PostMessage和SendMessage函数不同的是:PostMessage函数只是把消息放置在线程的消息队列之后就立即返回;而SendMessage函数是直接交给窗口消息处理函数:
BOOL WINAPI PostMessage(
__in_opt HWND hWnd,
__in UINT Msg,
__in WPARAM wParam,
__in LPARAM lParam
);
LRESULT WINAPI SendMessage(
__in HWND hWnd,
__in UINT Msg,
__in WPARAM wParam,
__in LPARAM lParam
);
PostQuitMessage函数将WM_QUIT消息消息放置在消息队列中,GetMessage函数在获得了WM_QUIT消息后,会返回0,退出消息循环。
注意,GetMessage函数只是获取了其所在的线程的消息队列中的消息,因此,在开发多线程的图形用户界面程序时,一般将所有窗口的创建放置在同一个线程,子窗口的创建最好在主窗口的消息处理函数中,这样能保证消息都集中中同一个线程中。如果在其他线程中需要操作界面,可以直接使用PostThreadMessage、SendMessage等函数向窗口发送自定义的消息,然后再在窗口消息处理函数中处理这些自定义窗口消息时进行窗口操作。
BOOL WINAPI PostThreadMessage(
__in DWORD idThread,
__in UINT Msg,
__in WPARAM wParam,
__in LPARAM lParam
);
相关推荐
6. **图形用户界面(GUI)编程**:构建Windows GUI应用程序,包括窗口样式、控件、消息循环和消息处理,以及绘图和事件处理。 7. **网络编程**:Windows API提供了套接字(Socket)接口,用于实现网络通信。书中...
通过学习《Windows图形编程》,开发者不仅可以掌握Windows平台上的图形开发技能,还能了解到如何设计和实现功能丰富的用户界面,提升软件的交互性和美观性。结合书中的源代码实践,将有助于深化理论知识,增强实际...
GUI 图形用户界面编程 本章节将介绍 GUI 图形用户界面编程的基本概念和实现方法。GUI 编程是指使用图形用户界面来与用户交互的编程技术。 Python 提供了多种 GUI 库,包括 Tkinter、wxPython 和 PyQT 等,本章节将...
这是GUI(图形用户界面)程序的常见工作方式。 7. **资源管理**:在UI开发中,图标、图像、字体等资源的管理也很重要。源代码可能包括了如何加载和使用这些资源的部分。 8. **跨平台考虑**:尽管XP界面主要针对...
在本节中,我们将深入探讨Java语言中的图形用户界面(GUI)编程,这是Java应用程序与用户交互的关键部分。第十一章“图形用户界面”主要涵盖了Java AWT(Abstract Window Toolkit)和Swing库,这两个库提供了创建...
在Windows Presentation Foundation (WPF) 中,开发人员可以利用丰富的UI功能来构建具有高级图形和交互性的应用程序。本文将深入探讨如何实现一个主窗口中嵌入子界面的效果,类似于C#中的TabControl控件,但无需实际...
MFC是C++类库,它封装了Windows API,使得编写复杂的用户界面和系统功能变得更加容易。这个"Windows高级编程-MFC"教程深入探讨了MFC的各种关键概念和技术,通过图文并茂的方式帮助学习者理解并应用。 1. **GDI编程*...
)设计<br>5.1GUIDE简介<br>5.1.1启动GUIDE””<br>5.1.2输出编辑器<br>...窗口<br>9.3.2Figure对象用做GUI<br>9.3.3Root对象——Figure对象的父对象<br>9.4核心图形对象<br>9.4.1核心图形对象简介<br>9.4.2创建核心...
在Windows图形编程中,核心概念是Windows图形设备接口(GDI)和GDI+。GDI是Windows API的一部分,提供了丰富的功能来绘制文本、图形和图像。它允许程序员控制屏幕上的像素,从而创建出复杂的用户界面和动态效果。GDI...
Windows图形编程主要涉及如何利用Microsoft Windows操作系统提供的API(应用程序接口)和其他工具来创建、管理和交互图形用户界面(GUI)。本资源"Windows图形编程.rar"包含了一个名为"Windows图形编程.pdf"的文档,...
《Windows核心编程》第五版是一本深入探讨Windows操作系统编程的经典之作。随书源码集包含了大量的实例代码,这些代码旨在帮助读者理解并掌握Windows API、MFC(Microsoft Foundation Classes)框架以及其他关键的...
袁枫和英宇工作室的"Windows图形编程"提供了深入的理论和实践指导,帮助开发者掌握如何创建美观、高效的图形用户界面。源码下载提供了书中实例的实现,使学习者能够更直观地理解编程概念。 在Windows图形编程中,...
根据提供的文件信息,“Windows图形编程.pdf”是一份详细介绍Windows环境下图形编程的专业资料。这份文档被标榜为“最权威的GDI编程的作品”,这表明它深入探讨了Windows平台下的图形设备接口(GDI)编程技术,并且...
在IT领域,Windows窗口编程是开发桌面应用软件的基础,它涉及到如何在Microsoft Windows操作系统上创建、管理和交互用户界面。这个主题通常涵盖Windows API(应用程序接口)的使用,其中包括消息循环、窗口过程、...
C++作为一门强大且高效的编程语言,是进行Windows核心编程的首选工具之一。 在Windows平台上,使用C++进行编程涉及的知识点广泛而深入,主要包括以下几个方面: 1. **Windows API**:Windows API是微软提供的用于...
它深入探讨了在Windows操作系统上创建图形用户界面(GUI)和进行2D、3D图形渲染的技术。书中不仅介绍了基本概念,还涵盖了高级主题,旨在帮助初学者和有经验的程序员提升技能,实现更复杂、更高效的图形应用。 在...
- Win32 API是微软为Windows操作系统提供的核心编程接口,它包含了大量用于创建图形用户界面(GUI)和处理系统级任务的函数。 - 在图形编程中,Win32 API提供了创建窗口、处理消息、绘制基本形状和文本等基本功能...
Java作为一种广泛使用的编程语言,提供了强大的图形用户界面功能,帮助开发者轻松构建功能完善且用户友好的应用程序。 #### Java图形用户界面的关键概念 Java支持GUI开发主要依赖于两个核心包:`java.awt`和`javax...
【Qt图形用户界面编程技术入门】是一篇针对初学者的指南,主要讲解如何利用Qt框架进行GUI应用开发。Qt是一个跨平台的C++库,它提供了丰富的API和工具,使得开发者能够创建桌面系统和嵌入式设备上的应用程序,无需...
- **定义**:Windows是一种基于图形用户界面的多任务操作系统,由微软公司开发。 - **特点**: - 图形用户界面:统一的外观和命令结构,使用户更容易学习和使用应用程序。 - 大量内建函数支持:如弹出菜单、滚动条...