Windows 图形界面笔记(1) - 窗口的显示

Windows 消息驱动
  • 当Windows 向程序发送消息时,它调用程序中的一个函数,这个函数的参数精确地描述了Windows 发送的消息。在程序中称这个函数为窗口函数(Window Procedure)或消息处理函数。它是一个自定义的回调函数,原形如下。
    • LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
      • CALLBACK 宏是__stdcall 的意思,
      • hWnd 参数标识了消息到达的窗口;
      • uMsg 参数是一个被命名的常量(消息ID 号)
      • wParam 和lParam 是消息的两个参数,其值取决于uMsg
在桌面上显示一个窗口的具体步骤,这就是主程序的结构流程。
  • (1)注册窗口类(RegisterClassEx)
  • (2)创建窗口(CreateWindowEx)
  • (3)在桌面显示窗口(ShowWindow)
  • (4)更新窗口客户区(UpdateWindow)
  • (5)进入无限的消息获取和处理的循环。首先是获取消息(GetMessage),如果有消息到达,则将消息分派到回调函数处理(DispatchMessage),如果消息是WM_QUIT,则 GetMessage 函数返回 FALSE,整个消息循环结束。消息具体的处理过程是在 MainWndProc 函数中进行的。
一个 Windows 基本窗口的实现
// 窗口函数的函数原形
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	char szClassName[] = "MainWClass";	
	WNDCLASSEX wndclass;
	
	// 用描述主窗口的参数填充WNDCLASSEX结构
	wndclass.cbSize = sizeof(wndclass);	// 结构的大小
	wndclass.style = CS_HREDRAW|CS_VREDRAW;	// 指定如果大小改变就重画
	wndclass.lpfnWndProc = MainWndProc;	// 窗口函数指针
	wndclass.cbClsExtra = 0;		// 没有额外的类内存
	wndclass.cbWndExtra = 0;		// 没有额外的窗口内存
	wndclass.hInstance = hInstance;		// 实例句柄 
	wndclass.hIcon = ::LoadIcon(NULL, 
			IDI_APPLICATION);	// 使用预定义图标
	wndclass.hCursor = ::LoadCursor(NULL,
			IDC_ARROW);		// 使用预定义的光标
	wndclass.hbrBackground = (HBRUSH)
		::GetStockObject(WHITE_BRUSH);	// 使用白色背景画刷
	wndclass.lpszMenuName = NULL;		// 不指定菜单
	wndclass.lpszClassName = szClassName ;	// 窗口类的名称	
	wndclass.hIconSm = NULL;		// 没有类的小图标
	
	// 注册这个窗口类
	::RegisterClassEx(&wndclass); 
	
	// 创建主窗口
	HWND hwnd = ::CreateWindowEx( 
		0,			// dwExStyle,扩展样式	
		szClassName,		// lpClassName,类名			
		"My first Window!",	// lpWindowName,标题		
		WS_OVERLAPPEDWINDOW,	// dwStyle,窗口风格	
		CW_USEDEFAULT,		// X,初始 X 坐标		
		CW_USEDEFAULT,		// Y,初始 Y 坐标		
		CW_USEDEFAULT,		// nWidth,宽度			
		CW_USEDEFAULT,		// nHeight,高度			
		NULL,			// hWndParent,父窗口句柄			
		NULL,			// hMenu,菜单句柄		
		hInstance,		// hlnstance,程序实例句柄		
		NULL) ;			// lpParam,用户数据			

	if(hwnd == NULL)
	{
		::MessageBox(NULL, "创建窗口出错!", "error", MB_OK);
		return -1;
	}

	// 显示窗口,刷新窗口客户区
	::ShowWindow(hwnd, nCmdShow);
	::UpdateWindow(hwnd);
	
	// 从消息堆中取出消息
	MSG msg;	
	while(::GetMessage(&msg, NULL, 0, 0))
	{
		// 转化键盘消息
		::TranslateMessage(&msg);
		// 将消息发送到相应的窗口函数
		::DispatchMessage(&msg);
	}

	// 当GetMessage返回0时程序结束
	return msg.wParam;
}

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	char szText[] = "最简单的窗口程序!";
	switch (message)
	{	 	
	case WM_PAINT: // 窗口客户区需要重画
		{
			HDC hdc;
			PAINTSTRUCT ps;

			// 使无效的客户区变的有效,并取得设备环境句柄
			hdc = ::BeginPaint (hwnd, &ps) ;	
			// 显示文字
			::TextOut(hdc, 10, 10, szText, strlen(szText));
			::EndPaint(hwnd, &ps);
			return 0;
		}	
	case WM_DESTROY: // 正在销毁窗口

		// 向消息队列投递一个WM_QUIT消息,促使GetMessage函数返回0,结束消息循环
		::PostQuitMessage(0) ;
		return 0 ;
	}

	// 将我们不处理的消息交给系统做默认处理
	return ::DefWindowProc(hwnd, message, wParam, lParam);
}
详细说明:
  • 注册窗口类
  • 注册窗口类的API 函数是RegisterClassEx,最后的“Ex”是扩展的意思,因为它是Win16 的RegisterClass 函数的扩展。一个窗口类定义了窗口的一些主要属性,如:图标、光标、背景色和负责处理消息的窗口函数等。这些属性定义在WNDCLASSEX 结构中。
  • typedef struct _WNDCLASSEX {UINT cbSize; // WNDCLASSEX 结构的大小
    • UINT style; // 从这个窗口类派生的窗口具有的风格
    • WNDPROC lpfnWndProc;// 即 window procedure, 窗口消息处理函数指针
    • int cbClsExtra; // 指定紧跟在窗口类结构后的附加字节数
    • int cbWndExtra; // 指定紧跟在窗口事例后的附加字节数
    • HANDLE hInstance; // 本模块的实例句柄
    • HICON hIcon; // 窗口左上角图标的句柄
    • HCURSOR hCursor; // 光标的句柄
    • HBRUSH hbrBackground;// 背景画刷的句柄
    • LPCTSTR lpszMenuName;// 菜单名
    • LPCTSTR lpszClassName;// 该窗口类的名称
    • HICON hIconSm; // 小图标句柄
  • } WNDCLASSEX;
  • wndclass.lpfnWndProc = MainWndProc; // 窗口函数指针
    • lpfnWndProc 指定了基于此类的窗口的窗口函数,当窗口收到消息时Windows 即自动调用这个函数通知应用程序。
  • hIcon 和hCursor 为要装载的图标和光标的句柄。
  • wndclass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH); // 使用白色背景画刷
    • WHITE_BRUSH 是一个Windows 预定义的画刷对象类型,也可以自定义
  • ::RegisterClassEx(&wndclass);  // 注册窗口类,失败返回0
  • 创建窗口
    • 用注册的窗口类的类名调用 CreateWindowEx 函数即可,失败返回NULL
    • 第四个参数dwStyle 的值是 WS_OVERLAPPEDWINDOW,即重叠式窗口(Overlapped Window)。其他类型:
      • WS_BORDER 创建一个单边框的窗口
      • WS_CAPTION 创建一个有标题框的窗口(包括WS_BODER 风格)
      • WS_CHIlD 创建一个子窗口。这个风格不能与WS_POPVP 风格合用
      • WS_DISABLED 创建一个初始状态为禁止的子窗口。一个禁止状态的窗日不能接受来自用户的输人信息
      • WS_DLGFRAME 创建一个带对话框边框风格的窗口。这种风格的窗口不能带标题条
      • WS_HSCROLL 创建一个有水平滚动条的窗口
      • WS_VSCROLL 创建一个有垂直滚动条的窗口
      • WS_ICONIC 创建一个初始状态为最小化状态的窗口。与WS_MINIMIZE 风格相同
      • WS_MAXIMIZE 创建一个具有最大化按钮的窗口。该风格不能和WS_EX_CONTEXTHELP 风格同时出现,同时必须指定WS_SYSMENU 风格
      • WS_OVERLAPPED 产生一个层叠的窗口。一个层叠的窗口有一个标题条和一个边框。与WS_TILED风格相同
        WS_OVERLAPPEDWINDOW 创建一个具有 WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU ,WS_THICKFRAME,WS_MINIMIZEBOX,WS_MAXMIZEBOX风格的层叠窗口
      • WS_POPUP 创建一个弹出式窗口。该风格不能与WS_CHLD 风格同时使用
      • WS_POPUPWINDOW 创建一个具有WS_BORDER,WS_POPUP,WS_SYSMENU 风格的窗口,WS_CAPTION 和WS_POPUPWINDOW 必须同时设定才能使窗口某单可见
      • WS_SIZEBOX 创建一个可调边框的窗口,与WS_THICKFRAME 风格相同
      • WS_SYSMENU 创建一个在标题条上带有窗口菜单的窗口,必须同时设定 WS_CAPTION 风格
      • WS_THICKFRAME 创建一个具有可调边框的窗口,与WS_SIZEBOX 风格相同
      • WS_VISIBLE 创建一个初始状态为可见的窗口
  • 在桌面显示窗口
    • ::ShowWindow(hwnd, nCmdShow);
  • 更新窗口客户区
    • ::UpdateWindow(hwnd);
      • 如果指定窗口的更新区域不为空的话,UpdateWindow 函数通过向这个窗口发送一个 WM_PAINT 消息更新它的客户区。当窗口显示在屏幕上时,窗口的客户区被在 WNDCLASSEX 中指定的刷子擦去了,调用 UpdateWindow 函数将促使客户区重画,以显示其内容。
  • 进入无限的消息循环
    • 在调用UpdateWindow 函数之后,整个窗口已经显示在桌面上,程序必须准备从用户接收键盘和鼠标输入了。Windows 为每个线程维护了一个消息队列,每当有一个输入发生,Windows 就把用户的输入翻译成消息放在消息队列中。利用 GetMessage 函数可以从调用线程的消息队列中取出一个消息来填充MSG 结构。如果消息队列中没有消息(即没有用户输入),这个函数会一直等待下去,直到有消息进入到消息队列为止。
    • ::GetMessage(&msg, NULL, 0, 0);
      • GetMessage 函数从消息队列中取得的消息如果不是WM_QUIT,则返回非零值。一个 WM_QUIT 消息会促使GetMessage 函数返回 0,从而结束消息循环。
    • MSG 结构类型
      • typedef struct tagMSG {
        • HWND hwnd;    // 消息要发向的窗口句柄
        • UINT message;  // 消息标识符,以WM_ 开头的预定义值(意为Window Message)
        • WPARAM wParam; // 消息的参数之一
        • LPARAM lParam;    // 消息的参数之二
        • DWORD time;         // 消息放入消息队列的时间
        • POINT pt;                // 这是一个POINT 数据结构,表示消息放入消息队列时的鼠标位置
      • } MSG, *PMSG ;
    • DispatchMessage 函数分发一个消息到对应窗口的窗口函数。在上面的例子中,窗口函数是MainWndProc。MainWndProc 处理消息后把控制权交给Windows,此时 DispatchMessage 函数仍然在继续工作,当它返回时,消息循环从调用GetMessage 函数开始进入下一轮循环。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值