当前位置:首页 >> 编程开发 >> Visual C++ >> 内容

Win32开发入门(3) 窗口的重绘

时间:2015/5/19 21:32:39 作者:平凡之路 来源:xuhantao.com 浏览:

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

#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)     
{     
    WCHAR* cln = L"MyApp";     
    //设计窗口类     
    WNDCLASS wc = {};     
    wc.hInstance = hInstance;     
    wc.lpszClassName = cln;     
    wc.lpfnWndProc = MyWindowProc;     
    //注册窗口类     
    RegisterClass(&wc);     
    // 创建窗口     
    HWND hMainwind = CreateWindow(     
        cln,     
        L"绘制窗口",     
        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);     
    }     
}

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

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

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

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

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消息,我们可以响应它来完成绘制。

// 窗口消息处理程序   

  
LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)     
{     
    switch(msg)     
    {     
    case WM_PAINT:     
        {     
            PAINTSTRUCT ps;     
            BeginPaint(hwnd, &ps);     
            DrawText(ps.hdc, L"朋友,你好。",wcslen(L"朋友,你好。"), &(ps.rcPaint), 

DT_CENTER);     
            EndPaint(hwnd, &ps);     
        }     
        return 0;     
...................

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

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

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

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

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

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

wc.style = 

CS_HREDRAW | CS_VREDRAW;

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

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

case WM_PAINT:     
    {     
        PAINTSTRUCT ps;     
        BeginPaint(hwnd, &ps);     
        SetTextColor(ps.hdc, RGB(10, 0, 255));//设置文本颜色     
        DrawText(ps.hdc, L"朋友,你好。",-1, &(ps.rcPaint), DT_CENTER);     
        EndPaint(hwnd, &ps);     
    }     
    return 0;

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

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

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

// 填充图形     
// 创建画刷     
HBRUSH hb = CreateSolidBrush(RGB(0,255,0));     
// 画刷选择到当前DC中     
HBRUSH orgBrs = (HBRUSH)SelectObject(ps.hdc, hb);     
// 填充图形     
Ellipse(ps.hdc,135,35,202,170);     
// 选回原先的画刷     
SelectObject(ps.hdc, orgBrs);                                
sp;                          DeleteObject(hb); //清理对象

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

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

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

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

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

相关文章
  • 没有相关文章
  • 徐汉涛(www.xuhantao.com) © 2024 版权所有 All Rights Reserved.
  • 部分内容来自网络,如有侵权请联系站长尽快处理 站长QQ:965898558(广告及站内业务受理) 网站备案号:蒙ICP备15000590号-1