• 跟我一起玩Win32开发(3):窗口的重绘






    c可以编译
    #include <Windows.h> //先声明一下消息处理函数 LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); // 入口点 int CALLBACK WinMain( HINSTANCE hInstance, HINSTANCE hPrvInstance, LPSTR lpCommandLine, int cmdShow) { CHAR* cln = "MyApp"; //设计窗口类 WNDCLASS wc = {}; wc.hInstance = hInstance; wc.lpszClassName = cln; wc.lpfnWndProc = MyWindowProc; //注册窗口类 RegisterClass(&wc); // 创建窗口 HWND hMainwind = CreateWindow( cln, "绘制窗口", WS_OVERLAPPEDWINDOW, 20, 12, 450, 300, NULL, NULL, hInstance, NULL); // 显示窗口 if(hMainwind == NULL) return 0; ShowWindow(hMainwind,SW_NORMAL); // 消息循环 MSG msg; while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } // 窗口消息处理程序 LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_PAINT: break; case WM_DESTROY: PostQuitMessage(0);//退出程序 return 0; default: return DefWindowProc(hwnd,msg,wParam,lParam); } }   

    上面这段是修改了char不兼容,蓝色地方 宽字符

    c/c++都可以编译
    
    #include <Windows.h>  
    #include<iostream>
    //先声明一下消息处理函数  
    LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
    
    // 入口点  
    int CALLBACK WinMain(
    	HINSTANCE hInstance,
    	HINSTANCE hPrvInstance,
    	LPSTR lpCommandLine,
    	int cmdShow)
    {
    	//PCWSTR cln = 0;
    	//设计窗口类  
    	WNDCLASS wc = { 0 };
    	wc.hInstance = hInstance;
    	wc.lpszClassName = "ewfewew";
    	wc.lpfnWndProc = MyWindowProc;
    	//注册窗口类  
    	RegisterClass(&wc);
    	// 创建窗口  
    	HWND hMainwind = CreateWindow(
    		"ewfewew",
    		"qwer",
    		WS_OVERLAPPEDWINDOW,
    		20,
    		12,
    		450,
    		300,
    		NULL,
    		NULL,
    		hInstance,
    		NULL);
    	// 显示窗口  
    	if (hMainwind == NULL)
    		return 0;
    	ShowWindow(hMainwind, SW_NORMAL);
    	// 消息循环  
    	MSG msg;
    	while (GetMessage(&msg, NULL, 0, 0))
    	{
    		TranslateMessage(&msg);
    		DispatchMessage(&msg);
    	}
    	return 0;
    }
    
    // 窗口消息处理程序  
    LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    	switch (msg)
    	{
    	case WM_PAINT:
    		break;
    	case WM_DESTROY:
    		PostQuitMessage(0);//退出程序  
    		return 0;
    	default:
    		return DefWindowProc(hwnd, msg, wParam, lParam);
    	}
    	
    }
    

      

    我们今天来吹一下关于窗口重绘的事情,在开始吹牛之前,我们先用上一篇博文中说到的方法写一个简单的Win32应用程序。代码如下:

    [cpp] view plain copy
     
    1. #include <Windows.h>  
    2.   
    3. //先声明一下消息处理函数  
    4. LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);  
    5.   
    6. // 入口点  
    7. int CALLBACK WinMain(  
    8.     HINSTANCE hInstance,  
    9.     HINSTANCE hPrvInstance,  
    10.     LPSTR lpCommandLine,  
    11.     int cmdShow)  
    12. {  
    13.     WCHAR* cln = L"MyApp";  
    14.     //设计窗口类  
    15.     WNDCLASS wc = {};  
    16.     wc.hInstance = hInstance;  
    17.     wc.lpszClassName = cln;  
    18.     wc.lpfnWndProc = MyWindowProc;  
    19.     //注册窗口类  
    20.     RegisterClass(&wc);  
    21.     // 创建窗口  
    22.     HWND hMainwind = CreateWindow(  
    23.         cln,  
    24.         L"绘制窗口",  
    25.         WS_OVERLAPPEDWINDOW,  
    26.         20,  
    27.         12,  
    28.         450,  
    29.         300,  
    30.         NULL,  
    31.         NULL,  
    32.         hInstance,  
    33.         NULL);  
    34.     // 显示窗口  
    35.     if(hMainwind == NULL)  
    36.         return 0;  
    37.     ShowWindow(hMainwind,SW_NORMAL);  
    38.     // 消息循环  
    39.     MSG msg;  
    40.     while(GetMessage(&msg,NULL,0,0))  
    41.     {  
    42.         TranslateMessage(&msg);  
    43.         DispatchMessage(&msg);  
    44.     }  
    45.     return 0;  
    46. }  
    47.   
    48. // 窗口消息处理程序  
    49. LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
    50. {  
    51.     switch(msg)  
    52.     {  
    53.     case WM_PAINT:  
    54.         break;  
    55.     case WM_DESTROY:  
    56.         PostQuitMessage(0);//退出程序  
    57.         return 0;  
    58.     default:  
    59.         return DefWindowProc(hwnd,msg,wParam,lParam);  
    60.     }  
    61. }  


    这个程序是可以正常运行的,我们先来运行一下,看看有什么效果,当然没什么效果,因为只是一个空白窗口。

    窗口是正常出现了,但是,现在你试一下改变它的大小时,你人发现有问题了。

    这时候我们看到,窗口中有一部分内容变成黑色了,也就是说它没有被重新绘制。当我们的窗口被另一个窗口挡住,然后另一个窗口被移开,我们的程序窗口重新显示时,会发生重绘;但我们改变窗口的大小后,窗口也会发生重绘;当我们把窗口隐藏(如最小化)后再显示,它也会发生重绘。我们的窗口就像一堵墙,在运行期间会不断地被重新粉刷

    要让窗口自动重绘,有一种简单的方法,就是在注册窗口类的时候,设置一个背景色。

    [cpp] view plain copy
     
    1. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);  

    现在你运行的时候,改变窗口的大小,就看不到黑色区域了,因为有了背景色。而上面的代码中,有朋友可能会问,COLOR_WINDOW + 1是什么东西,背景色为什么加1?

    我们不妨看看COLOR_WINDOW 的定义。

    其实这些都是数值来的,我们看到COLOR_WINDOW是5,那么 5 + 1 就是6吧,你看看6是谁?是不是COLOR_WINDOWFRAME的值?所以,你现在懂了吗,它只是选择COLOR_WINDOW作为参考点,因此,你可以推算到 COLOR_WINDOW - 2是哪个颜色值了。

    当窗口需要重新粉刷时,我们的程序都会收到一条WM_PAINT消息,我们可以响应它来完成绘制。

    [cpp] view plain copy
     
    1. // 窗口消息处理程序  
    2. LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  
    3. {  
    4.     switch(msg)  
    5.     {  
    6.     case WM_PAINT:  
    7.         {  
    8.             PAINTSTRUCT ps;  
    9.             BeginPaint(hwnd, &ps);  
    10.             DrawText(ps.hdc, L"朋友,你好。",wcslen(L"朋友,你好。"), &(ps.rcPaint), DT_CENTER);  
    11.             EndPaint(hwnd, &ps);  
    12.         }  
    13.         return 0;  
    14. ...................  

    我们也许在其他书上看到过,绘制图形要先GetDC来获得一个HDC,然后画图,画完之后再ReleaseDC,为什么我们这里不需要这样做?从代码中我们看到,绘图代码放在BeginPaint和EndPaint之间,这是专门用在处理WM_PAINT消息用的,注意在其他地方不能这样用。

    我们用DrawText函数在窗口上绘制了一行文本,但是,在你运行程序后,如果你调整了窗口的大小,你会发现又有新问题出现了。



    现在,我们还是来想一想,为啥会出现这种情况呢?

    那是因为窗口不是把整个客户区域完全重画,而是判断哪一部分应该重画,就重画,先前因为我们用的都同一种颜色的画刷来填充背景,所以我们看不出问题所在,然现在我们在窗口上绘制了文本,问题就显现出来了。由于每次重画时的矩形范围都是不同的,而且在重画之前没有清除前面的内容,使得新画的东西覆盖在原来的上面,就好像我们拿油漆在墙壁上涂鸦一样。

    窗口的客户区域就是你看到的白色的那块矩形,除了标题栏和边框,剩下的那些都可以归为客户区域。

    要解决上面问题的最简单方法,就是在设计窗口类的时候,把类样式同时设为水平重画(CS_HREDRAW)和垂直重画(CS_VREDRAW).

    [cpp] view plain copy
     
    1. wc.style = CS_HREDRAW | CS_VREDRAW;  

    现在再运行一下,哈哈,没问题了。

    上面的文本是使用默认颜色的绘制的,我想改一下文本的颜色,可以使用SetTextColor函数,第一参数接受一个hdc,第二个参数是COLORREF,通过RGB宏可以创建。如下面的例子:

    [cpp] view plain copy
     
    1. case WM_PAINT:  
    2.     {  
    3.         PAINTSTRUCT ps;  
    4.         BeginPaint(hwnd, &ps);  
    5.         SetTextColor(ps.hdc, RGB(10, 0, 255));//设置文本颜色  
    6.         DrawText(ps.hdc, L"朋友,你好。",-1, &(ps.rcPaint), DT_CENTER);  
    7.         EndPaint(hwnd, &ps);  
    8.     }  
    9.     return 0;  


    如果想一次性绘制多个字符串,可以调用PolyTextOut函数,但这个函数在绘制出来的字符上好像有点问题。

    [cpp] view plain copy
     
    1. case WM_PAINT:  
    2.     {  
    3.         PAINTSTRUCT ps;  
    4.         BeginPaint(hwnd, &ps);  
    5.         SetTextColor(ps.hdc, RGB(10, 0, 255));//设置文本颜色  
    6.         DrawText(ps.hdc, L"朋友,你好。",-1, &(ps.rcPaint), DT_CENTER);  
    7.         // 用于设置每个字符间隔的数组  
    8.         int arr1[2]= {45,0};  
    9.         int arr2[3] = { 35, 40, 0 };  
    10.         int arr3[2] = { 32, 0 };  
    11.         POLYTEXT polys[] =  { {2,2,3,L"大家",ETO_CLIPPED,ps.rcPaint,&arr1[0]},  
    12.             {2,25,3,L"新年好",ETO_CLIPPED,ps.rcPaint,&arr2[0]},  
    13.             {30,60,3,L"快乐",ETO_CLIPPED,ps.rcPaint,&arr3[0]}  
    14.         };  
    15.         PolyTextOut(ps.hdc, &polys[0],3);  
    16.         EndPaint(hwnd, &ps);  
    17.     }  
    18.     return 0;  


    当然也可以填充一些图形区域。

    [cpp] view plain copy
     
    1. // 填充图形  
    2. // 创建画刷  
    3. HBRUSH hb = CreateSolidBrush(RGB(0,255,0));  
    4. // 画刷选择到当前DC中  
    5. HBRUSH orgBrs = (HBRUSH)SelectObject(ps.hdc, hb);  
    6. // 填充图形  
    7. Ellipse(ps.hdc,135,35,202,170);  
    8. // 选回原先的画刷  
    9. SelectObject(ps.hdc, orgBrs);                             
    10. sp;                          DeleteObject(hb); //清理对象  


    这样我们就在窗口上画了一个椭圆了。

    响应WM_PAINT消息进行绘图,应按照以下步骤:

    1、声明一个PAINTSTRUCT结构体的变量,用于被填充与绘图相关的信息。

    2、BeginPaint,函数调用后开始画图。

    3、画完之后调用EndPaint函数,HDC会被自动释放。

  • 相关阅读:
    表管理和索引,外键作用
    小场景 shell 应用
    高并发Linux系统及kernel参数优化
    H3C F100-M-G 配置2条数字专线
    yun update更新后 vm-workstation 找不到kernel
    布局页面
    第八节课
    第七堂课
    第六堂课 框架和样式表的基础
    第五节课 表单元素
  • 原文地址:https://www.cnblogs.com/weekbo/p/8681883.html
Copyright © 2020-2023  润新知