程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> Win32開發入門(3) 窗口的重繪

Win32開發入門(3) 窗口的重繪

編輯:關於C++

我們今天來吹一下關於窗口重繪的事情,在開始吹牛之前,我們先用上一篇博文中說到的方法寫一 個簡單的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會被自動釋放。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved