[翻譯]-WinCE 程序設計 (3rd 版)--2.4 線條和形狀

線條和形狀
同Windows其它版本相比,Windows CE提供相當少的功能的領域之一就是基本線條繪製和形狀繪製功能。用來創建複雜環形的Chord, Arc, 和Pie函數被去掉了。大部分使用"當前點[current point]"概念的函數也被去掉了。除了MoveToEx, LineTo和GetCurrentPositionEx外,處理當前點的其它GDI函數都不被Windows CE支持。因此想用 ArcTo、PolyBezierTo等函數來繪製一系列連接的直線和曲線是不可能了。不過即使在缺少很多圖形函數的情況下,Windows CE依然提供了繪製直線和形狀所需要的基本函數。

線條
簡單調用Polyline就可以繪製一個或者多個線條了。函數原型如下:

BOOL Polyline (HDC hdc, const POINT *lppt, int cPoints);
第2個參數是指向POINT結構數組的指針,該結構定義如下:
typedef struct tagPOINT {
    LONG x;
    LONG y;
} POINT

每個X、Y結合起來描述一個從屏幕左上角開始的像素。第三個參數是數組裏的point結構的數量。因此繪製一個從(0,0)到(50,100)的直線,代碼看起來如下:
POINTS pts[2];
  
pts[0].x = 0;
pts[0].y = 0;
pts[1].x = 50;
pts[1].y = 100;
PolyLine (hdc, &pts, 2);

繪製該直線的另外一個方法是使用MoveToEx和LineTo函數。它們的原型如下:
BOOL WINAPI MoveToEx (HDC hdc, int X, int Y, LPPOINT lpPoint);
BOOL WINAPI LineTo (HDC hdc, int X, int Y);

要使用這兩個函數繪製線條,首先要調用MoveToEx將當前點移動到線條的起始座標處,接下來用終點座標調用LineTo。調用代碼如下:
MoveToEx (hdc, 0, 0, NULL);
LineTo (hdc, 50, 100);

要查詢當前點,可調用函數GetCurrentPositionEx,原型如下:
WINGDIAPI BOOL WINAPI GetCurrentPositionEx (HDC hdc, LPPOINT pPoint);

和前面繪製文本的例子一樣,這些代碼片段對設備描述表的狀態做了大量假設。例如,繪製的(0, 0)和(50, 100)之間的線條是什麼樣子?寬度和顏色是什麼以及是實心線條嗎?所有版本的Windows,包括Windows CE在內,都允許指定這些參數。

畫筆
畫筆(pen)是用於指定線條外觀和形狀輪廓的工具。畫筆是另一個GDI對象,像本章裏描述的其它GDI對象一樣,畫筆要被創建、選進設備描述表,使用、取消選擇,最後被銷燬。 同其它備用GDI對象一樣,可以使用GetStockObject來檢索備用畫筆。該函數原型如下:
HGDIOBJ GetStockObject (int fnObject);
所有版本的Windows都提供三種備用畫筆,每個1像素寬。這些備用畫筆有3種顏色:白色、黑色和NULL。當您使用GetStockObject時,該函數分別使用參數WHITE_PEN, BLACK_PEN和NULL_PEN來檢索這些畫筆中的一個。與應用程序創建的標準圖形對象不同,備用對象不應該被應用程序刪除。相反,當畫筆不再需要的時候,應用程序只應簡單地將畫筆從設備描述表中取消選擇即可。

要在Windows下創建自定義畫筆,可以使用以下兩個函數。第一個是:
HPEN CreatePen (int fnPenStyle, int nWidth, COLORREF crColor);
fnPenStyle規定要繪製的線條的外觀。例如,使用PS_DASH標誌可以創建一個虛線。Windows CE只支持PS_SOLID、PS_DASH和PS_NULL這三個風格標誌。nWidth參數規定畫筆的寬度。最後,crColor規定畫筆的顏色。crColor的參數類型是COLORREF,可以使用RGB宏來構造該類型。RGB宏定義如下:

COLORREF RGB (BYTE bRed, BYTE bGreen, BYTE bBlue);
因此要創建一個紅色實心線條,代碼看起來像這樣:
hPen = CreatePen (PS_SOLID, 1, RGB (0xff, 0, 0));

另一種畫筆創建函數如下:
HPEN CreatePenIndirect (const LOGPEN *lplgpn);
其中邏輯畫筆結構LOGPEN定義如下:
typedef struct tagLOGPEN {
    UINT lopnStyle;
    POINT lopnWidth;
    COLORREF lopnColor;
} LOGPEN;
CreatePenIndirect用不同的形式爲Windows提供了同樣的參數。用CreatePenIndirect創建同樣是1像素寬的紅色畫筆,代碼如下:
LOGPEN lp;
HPEN hPen;
lp.lopnStyle = PS_SOLID;
lp.lopnWidth.x = 1;
lp.lopnWidth.y = 1;
lp.lopnColor = RGB (0xff, 0, 0);
  
hPen = CreatePenIndirect (&lp);

Windows CE不支持複雜畫筆,比如寬度超過1像素的虛線。要確定支持什麼,我們熟悉的GetDeviceCaps就派上用場了,給它的第2個參數取LINECAPS即可。具體可以參考Windows CE文檔。

形狀
線條很有用,不過Windows還提供了繪製形狀的函數,包括填充和非填充的形狀。Windows CE提供了Windows程序員大部分常見的函數。

Rectangle, RoundRect, Ellipse和Polygon都支持。

畫刷
在討論矩形和橢圓形之前,需要先講述另一個曾經簡要提到過的GDI對象--畫刷(brush)。畫刷通常是一個8*8像素的位圖,用於填充形狀。
Windows也用它來填充客戶窗口地背景。Windows CE提供許多備用畫刷,並提供從應用程序定義的圖案創建畫刷的能力。許多純色備用畫刷可以使用GetStockObject來檢索。在衆多可用畫刷中,有一個是用於四色灰度級顯示器的每個灰度的,四種灰度是:白色、淺灰色、深灰色和黑色。

要創建純色畫刷,可以調用以下函數:
HBRUSH CreateSolidBrush (COLORREF crColor);
crColor規定了畫刷的顏色。顏色可以使用RGB宏來指定。
Windows CE下用Win32函數 CreateDIBPatternBrushPt創建自定義圖案的畫刷。函數原型如下:
HBRUSH CreateDIBPatternBrushPt (const void *lpPackedDIB, UINT iUsage);
第一個參數指向緊湊格式的DIB。這意味着指針指向一個緩衝區,包含有BITMAPINFO結構,並且緊隨其後的是位圖的位數據。您應該還記得BITMAPINFO結構實際上由BITMAPINFOHEADER結構及緊隨其後的RGBQUAD格式的調色板構成,所以該緩衝區包含了創建DIB所需要的每個信息,即位圖信息、調色板、位圖的位數據。如果第二個參數設置爲DIB_RGB_COLORS,則調色板在每個入口都包含有RGBQUAD值。對於每像素8位的位圖來說,可以設置DIB_PAL_COLORS標誌,但Windows CE會忽略位圖的顏色表。

在Windows CE下CreateDIBPatternBrushPt更加重要,因爲Windows CE下不支持陰影畫刷,而其它版本的Windows使用CreateHatchBrush函數來支持陰影畫刷。陰影畫刷是由水平線條、垂直線條或斜線構成的畫刷。這些畫刷在灰度級顯示器上特別有用,因爲您可以使用不同陰影圖案來突出圖表的不同區域。不過,您可以使用CreateDIBPatternBrushPt和適當的位圖圖案來複製出這些畫刷。本章後面的示例代碼演示了在Windows CE下創建陰影畫刷的方法。

默認情況下,畫刷原點在窗口左上角。這並不總是你所希望的。例如,一個條形圖使用陰影畫刷填充從(100,100)到(125,220)的矩形。因爲該矩形不能被8(畫刷通常是8*8像素的正方形)整除,所以就用一個不怎麼美觀的局部畫刷來填充條形圖的左上角。爲了避免這種情況,您可以移動畫刷的原點,這樣可以使用與形狀的邊角正確對齊的畫刷來繪製各個形狀了。用來完成這一調整的函數如下:BOOL SetBrushOrgEx (HDC hdc, int nXOrg, int nYOrg, LPPOINT lppt);
nXOrg和nYOrg允許將原點設置爲0到7之間,這樣就可以將原點定位在畫刷8*8範圍內任何一點。lppt填充的是畫刷先前的版本,這樣可以在必要的時候恢復先前的原點。

矩形
矩形函數繪製一個填充矩形或者一箇中空矩形。該函數定義如下:
BOOL Rectangle (HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
該函數使用當前選擇的畫筆繪製矩形外框,使用當前畫刷填充內部。要繪製中空矩形,需要在調用Rectangle之前把空畫刷選擇進設備描述表中。

理解繪製邊框的實際像素是很重要的。假定我們要在(0,0)處繪製一個5*7的矩形,函數調用如下:
Rectangle(0,0,5,7);
假設畫筆是1像素寬,結果矩形如圖2-6所示。
圖2-6:放大後的用Rectangele繪製的矩形視圖。
注意觀察矩形右邊界實際上是如何繪製到第4列的,底部邊緣是如何繪製到第6行的。這是標準的Windows慣例。矩形在Rectangle函數指定的右邊界和底邊界以內進行繪製。如果選擇的畫筆寬度超過1個像素,右邊界和底邊界以邊框矩形居中進行繪製。(Windows其它版本允許使用PS_INSIDEFRAME畫筆風格忽略畫筆寬度,強制在框架內繪製矩形)

圓和橢圓
可以用Ellipse函數繪製圓和橢圓,該函數原型如下:
BOOL Ellipse (HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
使用傳入的矩形作爲邊界矩形(bounding rectangle)來繪製橢圓,如圖2-7所示。對於Rectangle函數,使用當前畫刷來填充橢圓內部,使用當前畫筆來繪製橢圓外框。
圖2-7:展示了Ellipse使用傳入的邊界矩形繪製出的橢圓。

圓角矩形
RoundRect函數繪製一個圓角矩形,原型如下:
BOOL RoundRect (HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nWidth, int nHeight);
最後兩個參數給出了用於圓角的橢圓的寬度和高度,如圖2-8所示。指定橢圓的高度和寬度可以讓程序繪製出完全一樣的均勻的圓角。縮短橢圓的高度,可以使矩形的兩側更平,而縮短橢圓的寬度可以使矩形的頂部和底部更平。
圖2-8:橢圓的高度和寬度規定了由RoundRect繪製的矩形的圓角

多邊形
最後,Polygon繪製了一個多邊形,函數原型如下:BOOL Polygon (HDC hdc, const POINT *lpPoints, int nCount);
第2個參數是一個指向Point結構數組的指針,該數組定義了描述多邊形的各個點。從最終形狀上看,會被點數多一條邊,因爲函數自動把最後一個點和第一個點連接起來,繪製出多邊形的最後一條邊。

填充函數
前面提到的函數都是使用畫刷和畫筆的組合在設備描述表上繪製形狀的。只填充區域而不涉及繪製形狀輪廓的畫筆的函數也是有的。這些函數中的第一個就如下所示:
int FillRect (HDC hDC, CONST RECT* lprc, HBRUSH hbr);
FillRect的參數設備描述表句柄、需要填充的矩形以及用來填充矩形的畫刷。要在矩形區域裏繪製一個純色或者圖案,使用FillRect函數會是一個快捷方便的方式。
雖然FillRect很方便,但GradientFill可能更棒一些。GradientFill函數填充一個矩形區域,使用一個顏色從一邊開始繪製,並逐漸平滑過度到另外一個顏色直到另外一邊。圖2-9展示了一個客戶區使用GradientFill進行繪製的窗口。書中印刷的黑白插圖不能看出顏色的效果,但即使在這樣的圖上,依然能輕易的看到平滑過度的樣子。
圖2-9:使用GradientFill函數繪製的窗口。
GradientFill函數原型如下:
BOOL GradientFill (HDC hdc, PTRIVERTEX pVertex, ULONG dwNumVertex, PVOID pMesh, ULONG dwNumMesh, ULONG dwMode);
第一個參數依舊是設備描述表。pVertex是指向TRIVERTEX結構數組的指針,dwNumVertex是TRIVERTEX數組中入口的數量。TRIVERTEX結構定義如下:
struct _TRIVERTEX {   
    LONG        x;
    Long        y;
    COLOR16     Red;
    COLOR16     Green;
    COLOR16     Blue;
    COLOR16     Alpha;s
} TRIVERTEX;
TRIVERTEX結構的各個域描述了設備描述表裏的一個點和一個RGB顏色。這些點應該是要填充的矩形的左上角和右下角。pMesh是指向GRADIENT_RECT結構的指針,該結構定義如下:
struct _GRADIENT_RECT
{
    ULONG UpperLeft;
    ULONG LowerRight;
} GRADIENT_RECT;
GRADIENT_RECT結構簡單指出TRIVERTEX結構中的哪些入口是描述左上角或者是右下角的。最後,dwNumMesh參數包含GRADIENT_RECT結構的數量。dwMode結構包含標誌位,指出是從左到右(GRADIENT_FILL_RECT_H)填充還是從上到下(GRADIENT_FILL_RECT_V)填充。GradientFill函數實際上比表面上看到的要更復雜,因爲在桌面系統裏,它還執行三角形填充,這種填充方式在Windows CE下不支持。下面是創建圖2-9的窗口的代碼片段:
TRIVERTEX vert[2];
GRADIENT_RECT gRect;
  
vert [0] .x       =  prect->left;
vert [0] .y       =  prect->top;
vert [0] .Red     =  0x0000;
vert [0] .Green   =  0x0000;
vert [0] .Blue    =  0xff00;
vert [0] .Alpha   =  0x0000;
  
vert [1] .x       =  prect->right;
vert [1] .y       =  prect->bottom;
vert [1] .Red     =  0x0000;
vert [1] .Green   =  0xff00;
vert [1] .Blue    =  0x0000;
vert [1] .Alpha   =  0x0000;
  
gRect.UpperLeft = 0;
gRect.LowerRight = 1;
  
GradientFill(hdc,vert,2,&gRect,1,GRADIENT_FILL_RECT_H);
Shapes示例程序
清單2-3中,Shapes程序演示了很多相關函數。在Shapes中,繪製了4個圖形,每個使用不同的畫刷進行了填充。Listing 2-3: Shapes示例程序
Shapes.h
//================================================================
// Header file
//
// Written for the book Programming Windows CE
// Copyright (C) 2003 Douglas Boling
//======================================================================
// Returns number of elements
#define dim(x) (sizeof(x) / sizeof(x[0]))
  
//----------------------------------------------------------------------
// Generic defines and data types
//
struct decodeUINT {                             // Structure associates
    UINT Code;                                  // messages
                                                // with a function.
    LRESULT (*Fxn)(HWND, UINT, WPARAM, LPARAM);
};
struct decodeCMD {                              // Structure associates
    UINT Code;                                  // menu IDs with a
    LRESULT (*Fxn)(HWND, WORD, HWND, WORD);     // function.
};
  
//----------------------------------------------------------------------
// Defines used by MyCreateHatchBrush
//
typedef struct {
    BITMAPINFOHEADER bmi;
    COLORREF dwPal[2];
    BYTE bBits[64];
} BRUSHBMP;
  
#define HS_HORIZONTAL       0       /* ----- */
#define HS_VERTICAL         1       /* ||||| */
#define HS_FDIAGONAL        2       /* ///// */
#define HS_BDIAGONAL        3       /* ///// */
#define HS_CROSS            4       /* +++++ */
#define HS_DIAGCROSS        5       /* xxxxx */
  
//----------------------------------------------------------------------
// Function prototypes
//
HWND InitInstance (HINSTANCE, LPWSTR, int);
int TermInstance (HINSTANCE, int);
  
// Window procedures
LRESULT CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM);
// Message handlers
LRESULT DoPaintMain (HWND, UINT, WPARAM, LPARAM);
LRESULT DoDestroyMain (HWND, UINT, WPARAM, LPARAM);

Shapes.cpp
//======================================================================
// Shapes- Brush and shapes demo for Windows CE
//
// Written for the book Programming Windows CE
// Copyright (C) 2003 Douglas Boling
//======================================================================
#include <windows.h>                 // For all that Windows stuff
#include "shapes.h"                  // Program-specific stuff
  
//----------------------------------------------------------------
// Global data
//
const TCHAR szAppName[] = TEXT ("Shapes");
HINSTANCE hInst;                     // Program instance handle
  
// Message dispatch table for MainWindowProc
const struct decodeUINT MainMessages[] = {
    WM_PAINT, DoPaintMain,
    WM_DESTROY, DoDestroyMain,
};
  
//======================================================================
//
// Program entry point
//
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    LPWSTR lpCmdLine, int nCmdShow) {
    MSG msg;
    HWND hwndMain;
  
    // Initialize this instance.
    hwndMain = InitInstance(hInstance, lpCmdLine, nCmdShow);
    if (hwndMain == 0)
        return 0x10;
  
    // Application message loop
    while (GetMessage (&msg, NULL, 0, 0)) {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }
    // Instance cleanup
    return TermInstance (hInstance, msg.wParam);
}
//----------------------------------------------------------------------
// InitInstance - Instance initialization
//
HWND InitInstance (HINSTANCE hInstance, LPWSTR lpCmdLine, int nCmdShow){
    WNDCLASS wc;
    HWND hWnd;
  
    // Save program instance handle in global variable.
    hInst = hInstance;
  
#if defined(WIN32_PLATFORM_PSPC)
    // If Pocket PC, allow only one instance of the application.
    hWnd = FindWindow (szAppName, NULL);
    if (hWnd) {
        SetForegroundWindow ((HWND)(((DWORD)hWnd) | 0x01));   
        return 0;
    }
#endif   
    // Register application main window class.
    wc.style = 0;                             // Window style
    wc.lpfnWndProc = MainWndProc;             // Callback function
    wc.cbClsExtra = 0;                        // Extra class data
    wc.cbWndExtra = 0;                        // Extra window data
    wc.hInstance = hInstance;                 // Owner handle
    wc.hIcon = NULL,                          // Application icon
    wc.hCursor = LoadCursor (NULL, IDC_ARROW);// Default cursor
    wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
    wc.lpszMenuName =  NULL;                  // Menu name
    wc.lpszClassName = szAppName;             // Window class name
  
    if (RegisterClass (&wc) == 0) return 0;
    // Create main window.
    hWnd = CreateWindowEx (WS_EX_NODRAG,      // Ex Style
                         szAppName,           // Window class
                         TEXT("Shapes"),      // Window title
                         WS_VISIBLE,          // Style flags
                         CW_USEDEFAULT,       // x position
                         CW_USEDEFAULT,       // y position
                         CW_USEDEFAULT,       // Initial width
                         CW_USEDEFAULT,       // Initial height
                         NULL,                // Parent
                         NULL,                // Menu, must be null
                         hInstance,           // Application instance
                         NULL);               // Pointer to create
                                              // parameters
    // Return fail code if window not created.
    if (!IsWindow (hWnd)) return 0;
  
    // Standard show and update calls
    ShowWindow (hWnd, nCmdShow);
    UpdateWindow (hWnd);
    return hWnd;
}
//----------------------------------------------------------------------
// TermInstance - Program cleanup
//
int TermInstance (HINSTANCE hInstance, int nDefRC) {
  
    return nDefRC;
}
//======================================================================
// Message handling procedures for MainWindow
//
  
//----------------------------------------------------------------------
// MainWndProc - Callback function for application window
//
LRESULT CALLBACK MainWndProc (HWND hWnd, UINT wMsg, WPARAM wParam,
                              LPARAM lParam) {
    INT i;
    //
    // Search message list to see if we need to handle this
    // message. If in list, call procedure.
    //
    for (i = 0; i < dim(MainMessages); i++) {
        if (wMsg == MainMessages[i].Code)
            return (*MainMessages[i].Fxn)(hWnd, wMsg, wParam, lParam);
    }
    return DefWindowProc (hWnd, wMsg, wParam, lParam);
}
//----------------------------------------------------------------
// MyCreateHatchBrush - Creates hatched brushes
//
HBRUSH MyCreateHatchBrush (INT fnStyle, COLORREF clrref) {
    BRUSHBMP brbmp;
    BYTE *pBytes;
    int i;
    DWORD dwBits[6][2] = {
        {0x000000ff,0x00000000}, {0x10101010,0x10101010},
        {0x01020408,0x10204080}, {0x80402010,0x08040201},
        {0x101010ff,0x10101010}, {0x81422418,0x18244281},
    };
  
    if ((fnStyle < 0) || (fnStyle > dim(dwBits)))
        return 0;
    memset (&brbmp, 0, sizeof (brbmp));
  
    brbmp.bmi.biSize = sizeof (BITMAPINFOHEADER);
    brbmp.bmi.biWidth = 8;
    brbmp.bmi.biHeight = 8;
    brbmp.bmi.biPlanes = 1;
    brbmp.bmi.biBitCount = 1;
    brbmp.bmi.biClrUsed = 2;
    brbmp.bmi.biClrImportant = 2;
  
    // Initialize the palette of the bitmap.
    brbmp.dwPal[0] = PALETTERGB(0xff,0xff,0xff);
    brbmp.dwPal[1] = PALETTERGB((BYTE)((clrref >> 16) & 0xff),
                                (BYTE)((clrref >> 8) & 0xff),
                                (BYTE)(clrref & 0xff));
  
    // Write the hatch data to the bitmap. 
    pBytes = (BYTE *)&dwBits[fnStyle];
    for (i = 0; i < 8; i++)
        brbmp.bBits[i*4] = *pBytes++;
  
    // Return the handle of the brush created.
    return CreateDIBPatternBrushPt (&brbmp, DIB_RGB_COLORS);
}
//----------------------------------------------------------------------
// DoPaintMain - Process WM_PAINT message for window.
//
LRESULT DoPaintMain (HWND hWnd, UINT wMsg, WPARAM wParam,
                     LPARAM lParam) {
    PAINTSTRUCT ps;
    RECT rect;
    HDC hdc;
    POINT ptArray[6];
    HBRUSH hBr, hOldBr;
    TCHAR szText[128];
  
    GetClientRect (hWnd, &rect);
    hdc = BeginPaint (hWnd, &ps);
  
    // Draw ellipse.
    hBr = (HBRUSH) GetStockObject (DKGRAY_BRUSH);
    hOldBr = (HBRUSH) SelectObject (hdc, hBr);
    Ellipse (hdc, 10, 50, 90, 130);
    SelectObject (hdc, hOldBr);
  
    // Draw round rectangle.
    hBr = (HBRUSH) GetStockObject (LTGRAY_BRUSH);
    hOldBr = (HBRUSH) SelectObject (hdc, hBr);
    RoundRect (hdc, 95, 50, 150, 130, 30, 30);
    SelectObject (hdc, hOldBr);
  
    // Draw hexagon using Polygon.
    hBr = (HBRUSH) GetStockObject (WHITE_BRUSH);
    hOldBr = (HBRUSH) SelectObject (hdc, hBr);
    ptArray[0].x = 192;
    ptArray[0].y = 50;
    ptArray[1].x = 155;
    ptArray[1].y = 75;
    ptArray[2].x = 155;
    ptArray[2].y = 105;
    ptArray[3].x = 192;
    ptArray[3].y = 130;
    ptArray[4].x = 230;
    ptArray[4].y = 105;
    ptArray[5].x = 230;
    ptArray[5].y = 75;
  
    Polygon (hdc, ptArray, 6);
    SelectObject (hdc, hOldBr);
  
    hBr = (HBRUSH) MyCreateHatchBrush (HS_DIAGCROSS, RGB (0, 0, 0));
    hOldBr = (HBRUSH) SelectObject (hdc, hBr);
    Rectangle (hdc, 10, 145, 225, 210);
    SelectObject (hdc, hOldBr);
    DeleteObject (hBr);
  
    SetBkMode (hdc, OPAQUE);
    lstrcpy (szText, TEXT ("Opaque background"));
    ExtTextOut (hdc, 20, 160, 0, NULL,
                szText, lstrlen (szText), NULL);
  
    SetBkMode (hdc, TRANSPARENT);
    lstrcpy (szText, TEXT ("Transparent background"));
    ExtTextOut (hdc, 20, 185, 0, NULL,
                szText, lstrlen (szText), NULL);
  
    EndPaint (hWnd, &ps);
    return 0;
}
//----------------------------------------------------------------------
// DoDestroyMain - Process WM_DESTROY message for window
//
LRESULT DoDestroyMain (HWND hWnd, UINT wMsg, WPARAM wParam,
                       LPARAM lParam) {
    PostQuitMessage (0);
    return 0;
}
在Shapes裏,OnPaintMain使用先前討論過的那些不同的函數繪製了四個圖形。對每個形狀,都創建了一個不同的畫刷,並選擇進設備描述表,繪製圖形,最後從設備描述表中取消選擇。第一個圖形使用純灰色陰影來填充,用的是GetStockObject函數來裝載這些純色畫刷的。最後一個圖形則是使用由CreateDIBPatternBrushPt函數創建的畫刷來填充的。該畫刷的創建過程封裝到MyCreateHatchBrush函數裏了,該函數模擬了Windows CE下不支持的CreateHatchBrush函數。通過填充一個位圖結構和設置構成陰影圖案的位數據,創建了一個黑白位圖,用於創建陰影畫刷。這個位圖是一個由CreateDIBPatternBrushPta函數指定的8*8的位圖。因爲該位圖是單色的,所以包括調色板和頭在內,它的總大小隻有大約100字節。注意,因爲位圖的每個掃描行必須是雙字對齊的,所以每個一字節掃描行的最後3個字節是沒有使用的。

最後,程序寫兩行文字到最後的矩形裏。文本進一步演示了opaque和transparent這兩個系統繪圖模式之間的差異。在本例中,文本繪製時使用opaque模式會更適合實際情況,因爲在transparent模式下,陰影線會使字母變的模糊。圖2-10展示了Shapes窗口。
圖2-10演示瞭如何繪製不同填充的圖形。

爲了使事情簡單一些,例子Shapes假設其運行在至少240像素寬的顯示器上。這使得Shapes程序在手持式PC和Pocket PC上都能很好的運行。我只是淺顯的描述了Windows CE中GWE的GDI部分,本章的目標並不是爲GDI編程的各方面提供完整的描述。相反,我想去演示Windows CE下用於基本圖畫和文本的方法。在本書其它章節裏,擴展了本章涉及的技術。通常,在演示如何在代碼中使用的時候,我會談論這些新技術和新引入的函數。爲了擴展您的知識,我推薦《Windows 程序設計》(Programming Windows, 5th edition, by Charles Petzold)(Microsoft Press, 1998)一書作爲學習Windows GDI的最佳資料。

既然我們已經看了輸出,那麼是時候把注意力轉到系統輸出--鍵盤和觸摸板方面了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章