国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

37_MFC自繪UI你離不開GDI繪圖

這篇具有很好參考價(jià)值的文章主要介紹了37_MFC自繪UI你離不開GDI繪圖。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

MFC自繪UI你離不開GDI繪圖

GDI (Graphics Device Interface)是圖形設(shè)備接口的英文縮寫,處理Windows程序的圖形和圖像輸出。程序員不需要關(guān)心硬件設(shè)備及設(shè)備驅(qū)動(dòng),就可以將應(yīng)用程序的輸出轉(zhuǎn)換為硬件設(shè)備上的輸出,實(shí)現(xiàn)應(yīng)用程序與硬件設(shè)備的隔離,大大簡(jiǎn)化程序開發(fā)工作。在Windows操作系統(tǒng)中,圖形界面應(yīng)用程序通常離不開GDI,利用GDI所提供的眾多函數(shù)可以方便地在屏幕、打印機(jī)以及其他輸出設(shè)備上實(shí)現(xiàn)輸出文本、圖形等操作。

設(shè)備環(huán)境(DC)

設(shè)備無關(guān)性(也稱設(shè)備獨(dú)立性)是Windows的主要功能之一。應(yīng)用程序可以在各種設(shè)備上進(jìn)行繪制和打印輸出,系統(tǒng)統(tǒng)一把所有外部設(shè)備都當(dāng)作文件來看待,只要安裝了它們的驅(qū)動(dòng)程序,應(yīng)用程序就可以像使用文件一樣操縱、使用這些設(shè)備,GDI代表應(yīng)用程序和設(shè)備驅(qū)動(dòng)程序進(jìn)行交互。為了實(shí)現(xiàn)設(shè)備無關(guān)性,引入了邏輯設(shè)備和物理設(shè)備這兩個(gè)概念,在應(yīng)用程序中,使用邏輯設(shè)備名稱來請(qǐng)求使用某類設(shè)備,而系統(tǒng)在實(shí)際執(zhí)行時(shí),使用的是物理設(shè)備名稱。設(shè)備無關(guān)性的支持包含在兩個(gè)動(dòng)態(tài)鏈接庫(kù)中,第一個(gè)是GDI相關(guān)動(dòng)態(tài)鏈接庫(kù),稱為圖形設(shè)備接口﹔第二個(gè)是設(shè)備驅(qū)動(dòng)程序,設(shè)備驅(qū)動(dòng)程序的名稱取決于應(yīng)用程序繪制輸出的設(shè)備。GDI處理程序的繪圖酗數(shù)調(diào)用,將這些調(diào)用傳遞給設(shè)備驅(qū)動(dòng)程序,設(shè)備驅(qū)動(dòng)程序接收來自GDI的輸入,將輸入轉(zhuǎn)換為設(shè)備命今,并將這些命今傳遞給對(duì)應(yīng)的設(shè)備。

當(dāng)程序在客戶區(qū)中顯示文本或圖形時(shí),我們通常稱程序在“繪制"客戶區(qū)。GDI在加載驅(qū)動(dòng)程序后,準(zhǔn)備設(shè)備進(jìn)行繪制操作,例如選擇線條顏色和寬度、畫刷顏色和圖案、字體名稱、裁剪區(qū)域等。這些任務(wù)是通過創(chuàng)建和維護(hù)設(shè)備環(huán)境(DC)來完成的。DC是定義一組圖形對(duì)象及其關(guān)聯(lián)屬性以及影響輸出的圖形模式的結(jié)構(gòu)體。

與DC相關(guān)的部分圖形對(duì)象及屬性如下表所示。

圖形對(duì)象屬性

  • 畫筆樣式、寬度和顏色

  • 畫刷樣式、顏色、圖案和原點(diǎn)

  • 字體字體名稱、字體大小、字符寬度、字符高度、字符集等

  • 位圖大小(以字節(jié)為單位),尺寸(以像素為單位)、顏色格式、壓縮方案等

  • 路徑形狀

  • 區(qū)域位置和尺寸

與大多數(shù)結(jié)構(gòu)體不同,應(yīng)用程序不能直接訪問DC,而是通過調(diào)用各種函數(shù)間接地對(duì)DC結(jié)構(gòu)進(jìn)行操作。

Windows支持5種圖形模式,允許應(yīng)用程序指定顏色的混合方式、輸出的位置、輸出的縮放方式等。下表描述了存儲(chǔ)在DC中的這些模式。

圖形模式描述

  • 背景模式文本的背景色與現(xiàn)有窗口或屏幕顏色的混合方式等
  • 繪圖模式畫筆、畫刷的顏色與目標(biāo)顯示區(qū)域顏色的混合方式等
  • 映射模式如何將圖形輸出從邏輯坐標(biāo)映射到客戶區(qū)、屏幕或打印機(jī)紙張
  • 多邊形填充模式如何使用畫刷填充復(fù)雜區(qū)域的內(nèi)部
  • 拉伸模式當(dāng)位圖被放大或縮小時(shí)如何計(jì)算新位圖

Windows有4種類型的DC,分別是顯示設(shè)備DC、打印DC、內(nèi)存DC(也稱內(nèi)存兼容DC)、信息DC,每種類型的DC都有特定的用途,如下表所述。

DC類型描述

  • 顯示設(shè)備DC在顯示器上進(jìn)行繪圖操作
  • 打印DC在打印機(jī)或繪圖儀上進(jìn)行繪圖操作
  • 內(nèi)存DC通常是在內(nèi)存中的位圖上進(jìn)行繪圖操作
  • 信息DC獲取設(shè)備環(huán)境信息

也就是說,通過設(shè)備環(huán)境,不僅可以在屏幕窗口進(jìn)行繪圖,也可以在打印機(jī)或繪圖儀上進(jìn)行繪圖,還可以在內(nèi)存中的位圖上進(jìn)行繪圖。關(guān)于圖形對(duì)象、圖形模式以及各種DC類型,后面會(huì)分別進(jìn)行詳細(xì)介紹。

獲取顯示設(shè)備DC句柄

DC句柄是程序使用GDI函數(shù)的通行證,幾乎所有的GDI繪圖函數(shù)都需要一個(gè)DC句柄參數(shù),有了DC句柄,便能隨心所欲地繪制窗口客戶區(qū)。

前面說過,當(dāng)窗口客戶區(qū)的部分或全部變?yōu)?無效"且必須"更新"時(shí),比如說改變窗口大小、最小化/最大化窗口、拖動(dòng)窗口一部分到屏幕外再拖動(dòng)回來時(shí),應(yīng)用程序?qū)?huì)獲取到WM_PAINT消息。窗口過程的大部分繪圖操作是在處理WM_PAINT消息期間進(jìn)行的,可以通過調(diào)用BeginPaint函數(shù)來獲取顯示DC句柄。WM_PAINT消息的處理邏輯一般如下∶

 HDC hdc;//顯示設(shè)備DC句柄
 PAINTSTRUCT ps;//繪圖結(jié)構(gòu)體

 hdc = ::BeginPaint(hwnd, &ps);
 //TODO:在這里開始你的 繪圖代碼 編寫

 ::EndPaint(hwnd, &ps);

BeginPaint函數(shù)的返回值就是需要更新區(qū)域的DC句柄hdc。

BeginPaint返回的hdc對(duì)應(yīng)的尺寸僅是無效區(qū)域,程序無法通過該句柄繪制到這個(gè)區(qū)域以外的地方。由于窗口過程每次接收到WM_PAINT消息時(shí)的無效區(qū)域可能不同,因此這個(gè)hdc值僅在當(dāng)次WM_PAINT消息中有效,程序不應(yīng)該保存它并把它,用在WM_PAINT消息以外的代碼中。BeginPaint和EndPaint函數(shù)只能用在WM_PAINT消息中,因?yàn)橹挥羞@時(shí)才存在無效區(qū)域。BeginPaint函數(shù)還有一個(gè)作用就是把無效區(qū)域有效化,如果不調(diào)用BeginPaint,那么窗口的無效區(qū)域就一直不為空,系統(tǒng)會(huì)一直發(fā)送WM PAINT消息。

窗口客戶區(qū)中存在一個(gè)無效區(qū)域,這將導(dǎo)致Windows在應(yīng)用程序的消息隊(duì)列中放置一條WM_PAINT消息,即只有當(dāng)程序客戶區(qū)的一部分或全部無效時(shí),窗口過程才會(huì)接收到WM_PATNT消息。Windows在內(nèi)部為每個(gè)窗口都保存了一個(gè)繪制信息結(jié)構(gòu)PAINTSTRUCT,這個(gè)結(jié)構(gòu)保存著一個(gè)可以覆蓋該無效區(qū)域的最小矩形的坐標(biāo)和一些其他信息,這個(gè)最小矩形稱為無效矩形。如果在窗口過程處理一條WM_PAINT消息之前,窗口客戶區(qū)中又出現(xiàn)了另一個(gè)無效區(qū)域,那么Windows將計(jì)算出一個(gè)可以覆蓋這兩個(gè)無效區(qū)域的新的無效區(qū)域,并更新
PAINTSTRUCT結(jié)構(gòu)。Windows不會(huì)在消息隊(duì)列中放置多條WM_PAINT消息。

WM_PAINT消息是一個(gè)低優(yōu)先級(jí)的消息,Windows總是在消息循環(huán)為空的時(shí)候孑把WM_PAINT消息放入消息隊(duì)列。每當(dāng)消息循環(huán)為空的時(shí)候,如果Windows發(fā)現(xiàn)存在一個(gè)無效區(qū)域,就會(huì)在程序的消息隊(duì)列中放入一個(gè)WM_PAINT消息。前面說過“當(dāng)程序窗口被首次創(chuàng)建時(shí),整個(gè)客戶區(qū)都是無效的",因?yàn)榇藭r(shí)應(yīng)用程序尚未在該窗口上繪制任何東西。在WinMain中調(diào)用UpdateWindow函數(shù)時(shí)會(huì)發(fā)送第一條
wM_PAINT消息,指示窗口過程在窗口客戶區(qū)進(jìn)行繪制,
UpdateWindow函數(shù)將WM_PAINT消息直接發(fā)送到指定窗口的窗口過程,繞過應(yīng)用程序的消息隊(duì)列?,F(xiàn)在大家應(yīng)該明白,
UpdateWindow函數(shù)只不過是讓窗口過程盡快更新窗口,
HelloWindows程序去掉UpdateWindow函數(shù)調(diào)用也可以正常運(yùn)行。
如果應(yīng)用程序在其他任何時(shí)間(例如在處理鍵盤或鼠標(biāo)消息期間)需要進(jìn)行繪制,可以調(diào)用GetDC或GetDCEx函數(shù)來獲取顯示DC句柄∶

hdc = GetDC(hwnd);
//繪圖代碼
ReleaseDC(hwnd, hdc);

GetDC函數(shù)返回的hdc對(duì)應(yīng)指定窗口的整個(gè)客戶區(qū),通過GetDC 函數(shù)返回的hdc可以在客戶區(qū)的任何位置進(jìn)行繪制操作,不存在無效矩形的概念,無效矩形和BeginPaint才是原配。當(dāng)使用完畢時(shí),必須調(diào)用ReleaseDC函數(shù)釋放DC。對(duì)于用GetDC獲取的hdc,Windows建議使用的范圍限于單條消息內(nèi)。當(dāng)程序處理某條消息的時(shí)候,如果需要繪制客戶區(qū),可以調(diào)用GetDC函數(shù)獲取hdc,但在消息返回前,必須調(diào)用ReleaseDC函數(shù)將它釋放掉。如果在下一條消息中還需要用到hdc,那么可以重新調(diào)用GetDC函數(shù)獲取。如果將GetDC的hwnd參數(shù)設(shè)置為NULL,那么函數(shù)獲取的是整個(gè)屏幕的DC句柄。

現(xiàn)在我提出一個(gè)問題,相信讀者是可以理解的,按下鼠標(biāo)左鍵時(shí)將會(huì)產(chǎn)生WM_LBUTTONDOWN消息,鼠標(biāo)在客戶區(qū)中移動(dòng)的時(shí)候會(huì)不斷產(chǎn)生WM_MOUSEMOVE消息,這兩個(gè)消息的IParam參數(shù)中都含有鼠標(biāo)坐標(biāo)信息。按住鼠標(biāo)左鍵不放拖動(dòng)鼠標(biāo)會(huì)產(chǎn)生WM_LBUTTONDOWN消息和一系列WM_MOUSEMOVE消息,我們?cè)诖翱谶^程中處理WM_LBUTTONDOWN和WM_MOUSEMOVE消息,利用GetDC函數(shù)獲取DC句柄進(jìn)行繪圖,連接
WM_LBUTTONDOWN消息和一系列WM_MOUSEMOVE消息的這些坐標(biāo)點(diǎn)就會(huì)形成一條線,但是當(dāng)改變窗口大小、最小化然后最大化窗口、拖動(dòng)窗口一部分到屏幕外再拖回來時(shí),讀者會(huì)發(fā)現(xiàn)這條線沒有了,因?yàn)樵谛枰乩L的時(shí)候Windows會(huì)使用指定的背景畫刷擦除背景。如果希望這條線繼續(xù)存在,就必須在WM_PAINT消息中重新繪制(可以事先保存好那些點(diǎn))。如果可能,我們最好是在WM_PAINT消息中處理所有繪制工作。

GetWindowDC函數(shù)可以獲取整個(gè)窗口的DC句柄,包括非客戶區(qū)(例如標(biāo)題欄、菜單和滾動(dòng)條)。使用GetWindowDC函數(shù)返回的hdc可以在窗口的任何位置進(jìn)行繪制,因?yàn)檫@個(gè)DC的原點(diǎn)是窗口的左上角,而不是窗口客戶區(qū)的左上角,例如,程序可以使用
GetWindowDC函數(shù)返回的hdc在窗口的標(biāo)題欄上進(jìn)行繪制,這時(shí)程序需要處理WM_NCPAINT(非客戶區(qū)繪制)消息。

HDC GetWindowDC( _In_ HWND hWnd);

函數(shù)執(zhí)行成功,返回值是指定窗口的DC句柄。同樣的,完成繪制后必須調(diào)用ReleaseDC函數(shù)來釋放DC。如果將參數(shù)hWnd參數(shù)設(shè)置為NULL,GetWindowDC函數(shù)獲取的是整個(gè)屏幕的DC句柄。

Windows有4種類型的DC,關(guān)于其他類型DC句柄的獲取,后面用到的時(shí)候再講解。理論知識(shí)講解太多實(shí)在乏味,接下來先實(shí)現(xiàn)一個(gè)輸出(繪制)文本的示例,并實(shí)現(xiàn)滾動(dòng)條功能。

繪制文本

GetSystemMetrics函數(shù)用于獲取系統(tǒng)度量或系統(tǒng)配置信息,例如可以獲取屏幕分辨率、全屏窗口客戶區(qū)的寬度和高度、滾動(dòng)條的寬度和高度等,該函數(shù)獲取到的相關(guān)度量信息均以像素為單位∶

int WINAPI GetSystemMetrics(_In_ int nlndex);

該函數(shù)只有一個(gè)參數(shù),稱之為索引,這個(gè)索引有95個(gè)標(biāo)識(shí)符可以使用。

例如GetSystemMetrics(SM_CXSCREEN)獲取的是屏幕的寬度(Cx表示 Count X,X軸像素?cái)?shù)), SystemMetrics程序根據(jù)95個(gè)索引在客戶區(qū)中輸出95行,每行的格式類似下面的樣子∶

SM_CXSCREEN	屏幕的寬度	1366

通過TextOut函數(shù)輸出METRICS結(jié)構(gòu)數(shù)組的每個(gè)數(shù)組元素很簡(jiǎn)單。這里列舉下筆者的實(shí)現(xiàn)。

  • Metrics.h
#pragma once

struct
{
    int     m_nIndex;
    PTSTR   m_pLabel;
    PTSTR   m_pDesc;
}METRICS[] = {
    SM_CXSCREEN,                    TEXT("SM_CXSCREEN"),                    TEXT("屏幕的寬度"),
    SM_CYSCREEN,                    TEXT("SM_CYSCREEN"),                    TEXT("屏幕的高度"),
    SM_CXFULLSCREEN,                TEXT("SM_CXFULLSCREEN"),                TEXT("全屏窗口的客戶區(qū)寬度"),
    SM_CYFULLSCREEN,                TEXT("SM_CYFULLSCREEN"),                TEXT("全屏窗口的客戶區(qū)高度"),
    SM_ARRANGE,                     TEXT("SM_ARRANGE"),                     TEXT("如何排列最小化窗口"),
    SM_CLEANBOOT,                   TEXT("SM_CLEANBOOT"),                   TEXT("系統(tǒng)啟動(dòng)方式"),
    SM_CMONITORS,                   TEXT("SM_CMONITORS"),                   TEXT("監(jiān)視器的數(shù)量"),
    SM_CMOUSEBUTTONS,               TEXT("SM_CMOUSEBUTTONS"),               TEXT("鼠標(biāo)上的按鈕數(shù)"),
    SM_CONVERTIBLESLATEMODE,        TEXT("SM_CONVERTIBLESLATEMODE"),        TEXT("筆記本電腦或平板電腦模式"),
    SM_CXBORDER,                    TEXT("SM_CXBORDER"),                    TEXT("窗口邊框的寬度"),
    SM_CYBORDER,                    TEXT("SM_CYBORDER"),                    TEXT("窗口邊框的高度"),
    SM_CXCURSOR,                    TEXT("SM_CXCURSOR"),                    TEXT("光標(biāo)的寬度"),
    SM_CYCURSOR,                    TEXT("SM_CYCURSOR"),                    TEXT("光標(biāo)的高度"),
    SM_CXDLGFRAME,                  TEXT("SM_CXDLGFRAME"),                  TEXT("同SM_CXFIXEDFRAME,有標(biāo)題但不可調(diào)整大小的窗口邊框的寬度"),
    SM_CYDLGFRAME,                  TEXT("SM_CYDLGFRAME"),                  TEXT("同SM_CYFIXEDFRAME,有標(biāo)題但不可調(diào)整大小的窗口邊框的高度"),
    SM_CXDOUBLECLK,                 TEXT("SM_CXDOUBLECLK"),                 TEXT("鼠標(biāo)雙擊事件兩次點(diǎn)擊的X坐標(biāo)不可以超過這個(gè)值"),
    SM_CYDOUBLECLK,                 TEXT("SM_CYDOUBLECLK"),                 TEXT("鼠標(biāo)雙擊事件兩次點(diǎn)擊的Y坐標(biāo)不可以超過這個(gè)值"),
    SM_CXDRAG,                      TEXT("SM_CXDRAG"),                      TEXT("拖動(dòng)操作開始之前,鼠標(biāo)指針可以移動(dòng)的鼠標(biāo)下方點(diǎn)的任意一側(cè)的像素?cái)?shù)"),
    SM_CYDRAG,                      TEXT("SM_CYDRAG"),                      TEXT("拖動(dòng)操作開始之前,鼠標(biāo)指針可以移動(dòng)的鼠標(biāo)下移點(diǎn)上方和下方的像素?cái)?shù)"),
    SM_CXEDGE,                      TEXT("SM_CXEDGE"),                      TEXT("三維邊框的寬度"),
    SM_CYEDGE,                      TEXT("SM_CYEDGE"),                      TEXT("三維邊框的高度"),
    SM_CXFIXEDFRAME,                TEXT("SM_CXFIXEDFRAME"),                TEXT("同SM_CXDLGFRAME,有標(biāo)題但不可調(diào)整大小的窗口邊框的寬度"),
    SM_CYFIXEDFRAME,                TEXT("SM_CYFIXEDFRAME"),                TEXT("同SM_CYDLGFRAME,有標(biāo)題但不可調(diào)整大小的窗口邊框的高度"),
    SM_CXFOCUSBORDER,               TEXT("SM_CXFOCUSBORDER"),               TEXT("DrawFocusRect繪制的焦點(diǎn)矩形的左邊緣和右邊緣的寬度"),
    SM_CYFOCUSBORDER,               TEXT("SM_CYFOCUSBORDER"),               TEXT("DrawFocusRect繪制的焦點(diǎn)矩形的上邊緣和下邊緣的高度"),
    SM_CXFRAME,                     TEXT("SM_CXFRAME"),                     TEXT("同SM_CXSIZEFRAME,可調(diào)大小窗口邊框的寬度"),
    SM_CYFRAME,                     TEXT("SM_CYFRAME"),                     TEXT("同SM_CYSIZEFRAME,可調(diào)大小窗口邊框的高度"),
    SM_CXHSCROLL,                   TEXT("SM_CXHSCROLL"),                   TEXT("水平滾動(dòng)條中箭頭位圖的寬度"),
    SM_CYHSCROLL,                   TEXT("SM_CYHSCROLL"),                   TEXT("水平滾動(dòng)條中箭頭位圖的高度"),
    SM_CXVSCROLL,                   TEXT("SM_CXVSCROLL"),                   TEXT("垂直滾動(dòng)條中箭頭位圖的寬度"),
    SM_CYVSCROLL,                   TEXT("SM_CYVSCROLL"),                   TEXT("垂直滾動(dòng)條中箭頭位圖的高度"),
    SM_CXHTHUMB,                    TEXT("SM_CXHTHUMB"),                    TEXT("水平滾動(dòng)條中滾動(dòng)框(滑塊)的高度"),
    SM_CYVTHUMB,                    TEXT("SM_CYVTHUMB"),                    TEXT("垂直滾動(dòng)條中滾動(dòng)框(滑塊)的寬度"),
    SM_CXICON,                      TEXT("SM_CXICON"),                      TEXT("圖標(biāo)的默認(rèn)寬度"),
    SM_CYICON,                      TEXT("SM_CYICON"),                      TEXT("圖標(biāo)的默認(rèn)高度"),
    SM_CXICONSPACING,               TEXT("SM_CXICONSPACING"),               TEXT("大圖標(biāo)視圖中項(xiàng)目的網(wǎng)格單元格寬度"),
    SM_CYICONSPACING,               TEXT("SM_CYICONSPACING"),               TEXT("大圖標(biāo)視圖中項(xiàng)目的網(wǎng)格單元格高度"),
    SM_CXMAXIMIZED,                 TEXT("SM_CXMAXIMIZED"),                 TEXT("最大化頂層窗口的默認(rèn)寬度"),
    SM_CYMAXIMIZED,                 TEXT("SM_CYMAXIMIZED"),                 TEXT("最大化頂層窗口的默認(rèn)高度"),
    SM_CXMAXTRACK,                  TEXT("SM_CXMAXTRACK"),                  TEXT("具有標(biāo)題和大小調(diào)整邊框的窗口可以拖動(dòng)的最大寬度"),
    SM_CYMAXTRACK,                  TEXT("SM_CYMAXTRACK"),                  TEXT("具有標(biāo)題和大小調(diào)整邊框的窗口可以拖動(dòng)的最大高度"),
    SM_CXMENUCHECK,                 TEXT("SM_CXMENUCHECK"),                 TEXT("菜單項(xiàng)前面復(fù)選框位圖的寬度"),
    SM_CYMENUCHECK,                 TEXT("SM_CYMENUCHECK"),                 TEXT("菜單項(xiàng)前面復(fù)選框位圖的高度"),
    SM_CXMENUSIZE,                  TEXT("SM_CXMENUSIZE"),                  TEXT("菜單欄按鈕的寬度"),
    SM_CYMENUSIZE,                  TEXT("SM_CYMENUSIZE"),                  TEXT("菜單欄按鈕的高度"),
    SM_CXMIN,                       TEXT("SM_CXMIN"),                       TEXT("窗口的最小寬度"),
    SM_CYMIN,                       TEXT("SM_CYMIN"),                       TEXT("窗口的最小高度"),
    SM_CXMINIMIZED,                 TEXT("SM_CXMINIMIZED"),                 TEXT("最小化窗口的寬度"),
    SM_CYMINIMIZED,                 TEXT("SM_CYMINIMIZED"),                 TEXT("最小化窗口的高度"),
    SM_CXMINSPACING,                TEXT("SM_CXMINSPACING"),                TEXT("最小化窗口的網(wǎng)格單元寬度"),
    SM_CYMINSPACING,                TEXT("SM_CYMINSPACING"),                TEXT("最小化窗口的網(wǎng)格單元高度"),
    SM_CXMINTRACK,                  TEXT("SM_CXMINTRACK"),                  TEXT("窗口的最小拖動(dòng)寬度,用戶無法將窗口拖動(dòng)到小于這些尺寸"),
    SM_CYMINTRACK,                  TEXT("SM_CYMINTRACK"),                  TEXT("窗口的最小拖動(dòng)高度,用戶無法將窗口拖動(dòng)到小于這些尺寸"),
    SM_CXPADDEDBORDER,              TEXT("SM_CXPADDEDBORDER"),              TEXT("標(biāo)題窗口的邊框填充量"),
    SM_CXSIZE,                      TEXT("SM_CXSIZE"),                      TEXT("窗口標(biāo)題或標(biāo)題欄中按鈕的寬度"),
    SM_CYSIZE,                      TEXT("SM_CYSIZE"),                      TEXT("窗口標(biāo)題或標(biāo)題欄中按鈕的高度"),
    SM_CXSIZEFRAME,                 TEXT("SM_CXSIZEFRAME"),                 TEXT("同SM_CXFRAME,可調(diào)大小窗口邊框的寬度"),
    SM_CYSIZEFRAME,                 TEXT("SM_CYSIZEFRAME"),                 TEXT("同SM_CYFRAME,可調(diào)大小窗口邊框的厚度"),
    SM_CXSMICON,                    TEXT("SM_CXSMICON"),                    TEXT("小圖標(biāo)的建議寬度"),
    SM_CYSMICON,                    TEXT("SM_CYSMICON"),                    TEXT("小圖標(biāo)的建議高度"),
    SM_CXSMSIZE,                    TEXT("SM_CXSMSIZE"),                    TEXT("小標(biāo)題按鈕的寬度"),
    SM_CYSMSIZE,                    TEXT("SM_CYSMSIZE"),                    TEXT("小標(biāo)題按鈕的高度"),
    SM_CXVIRTUALSCREEN,             TEXT("SM_CXVIRTUALSCREEN"),             TEXT("虛擬屏幕的寬度"),
    SM_CYVIRTUALSCREEN,             TEXT("SM_CYVIRTUALSCREEN"),             TEXT("虛擬屏幕的高度"),
    SM_CYCAPTION,                   TEXT("SM_CYCAPTION"),                   TEXT("標(biāo)題區(qū)域的高度"),
    SM_CYKANJIWINDOW,               TEXT("SM_CYKANJIWINDOW"),               TEXT("屏幕底部的日文漢字窗口的高度"),
    SM_CYMENU,                      TEXT("SM_CYMENU"),                      TEXT("單行菜單欄的高度"),
    SM_CYSMCAPTION,                 TEXT("SM_CYSMCAPTION"),                 TEXT("小標(biāo)題的高度"),
    SM_DBCSENABLED,                 TEXT("SM_DBCSENABLED"),                 TEXT("User32.dll是否支持DBCS"),
    SM_DEBUG,                       TEXT("SM_DEBUG"),                       TEXT("是否安裝了User.exe的調(diào)試版本"),
    SM_DIGITIZER,                   TEXT("SM_DIGITIZER"),                   TEXT("設(shè)備支持的數(shù)字轉(zhuǎn)換器輸入類型"),
    SM_IMMENABLED,                  TEXT("SM_IMMENABLED"),                  TEXT("是否啟用了輸入法管理器/輸入法編輯器功能"),
    SM_MAXIMUMTOUCHES,              TEXT("SM_MAXIMUMTOUCHES"),              TEXT("系統(tǒng)中是否有數(shù)字化儀"),
    SM_MEDIACENTER,                 TEXT("SM_MEDIACENTER"),                 TEXT("當(dāng)前操作系統(tǒng)是不是Windows XP Media Center"),
    SM_MENUDROPALIGNMENT,           TEXT("SM_MENUDROPALIGNMENT"),           TEXT("下拉菜單是否與相應(yīng)的菜單欄項(xiàng)右對(duì)齊"),
    SM_MIDEASTENABLED,              TEXT("SM_MIDEASTENABLED"),              TEXT("系統(tǒng)是否啟用希伯來語(yǔ)和阿拉伯語(yǔ)"),
    SM_MOUSEHORIZONTALWHEELPRESENT, TEXT("SM_MOUSEHORIZONTALWHEELPRESENT"), TEXT("是否安裝了帶有水平滾輪的鼠標(biāo)"),
    SM_MOUSEPRESENT,                TEXT("SM_MOUSEPRESENT"),                TEXT("是否安裝了鼠標(biāo)"),
    SM_MOUSEWHEELPRESENT,           TEXT("SM_MOUSEWHEELPRESENT"),           TEXT("是否安裝了帶有垂直滾輪的鼠標(biāo)"),
    SM_NETWORK,                     TEXT("SM_NETWORK"),                     TEXT("是否存在網(wǎng)絡(luò)"),
    SM_PENWINDOWS,                  TEXT("SM_PENWINDOWS"),                  TEXT("是否安裝了Microsoft Windows for Pen Computing擴(kuò)展"),
    SM_REMOTECONTROL,               TEXT("SM_REMOTECONTROL"),               TEXT("當(dāng)前終端服務(wù)器會(huì)話是否被遠(yuǎn)程控制"),
    SM_REMOTESESSION,               TEXT("SM_REMOTESESSION"),               TEXT("調(diào)用進(jìn)程是否與終端服務(wù)客戶機(jī)會(huì)話關(guān)聯(lián)"),
    SM_SAMEDISPLAYFORMAT,           TEXT("SM_SAMEDISPLAYFORMAT"),           TEXT("所有顯示器的顏色格式是否相同"),
    SM_SECURE,                      TEXT("SM_SECURE"),                      TEXT("始終返回0"),
    SM_SERVERR2,                    TEXT("SM_SERVERR2"),                    TEXT("系統(tǒng)是否是Windows Server 2003 R2"),
    SM_SHOWSOUNDS,                  TEXT("SM_SHOWSOUNDS"),                  TEXT("用戶是否要求應(yīng)用程序在其他情況下以可視方式呈現(xiàn)信息"),
    SM_SHUTTINGDOWN,                TEXT("SM_SHUTTINGDOWN"),                TEXT("當(dāng)前會(huì)話是否正在關(guān)閉"),
    SM_SLOWMACHINE,                 TEXT("SM_SLOWMACHINE"),                 TEXT("計(jì)算機(jī)是否具有低端(慢速)處理器"),
    SM_STARTER,                     TEXT("SM_STARTER"),                     TEXT("當(dāng)前操作系統(tǒng)版本"),
    SM_SWAPBUTTON,                  TEXT("SM_SWAPBUTTON"),                  TEXT("鼠標(biāo)左鍵和右鍵的功能是否互換了"),
    SM_SYSTEMDOCKED,                TEXT("SM_SYSTEMDOCKED"),                TEXT("??磕J降臓顟B(tài)"),
    SM_TABLETPC,                    TEXT("SM_TABLETPC"),                    TEXT("是否啟動(dòng)了Tablet PC輸入服務(wù)"),
    SM_XVIRTUALSCREEN,              TEXT("SM_XVIRTUALSCREEN"),              TEXT("虛擬屏幕左側(cè)的坐標(biāo)"),
    SM_YVIRTUALSCREEN,              TEXT("SM_YVIRTUALSCREEN"),              TEXT("虛擬屏幕頂部的坐標(biāo)")
};
  • SystemMetrics.cpp
#include <Windows.h>
#include <tchar.h>
#include "Metrics.h"

const int NUMLINES = sizeof(METRICS) / sizeof(METRICS[0]); //寫入文本的行數(shù)
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wndclass;                            // RegisterClassEx函數(shù)用的WNDCLASSEX結(jié)構(gòu)
    TCHAR szClassName[] = TEXT("MyWindow");         // RegisterClassEx函數(shù)注冊(cè)的窗口類的名稱
    TCHAR szAppName[] = TEXT("GetSystemMetrics");   // 窗口標(biāo)題
    HWND hwnd;                                      // CreateWindowEx函數(shù)創(chuàng)建的窗口的句柄
    MSG msg;                                        // 消息循環(huán)所用的消息結(jié)構(gòu)體

    wndclass.cbSize = sizeof(WNDCLASSEX);
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = WindowProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);    // 窗口背景使用標(biāo)準(zhǔn)系統(tǒng)顏色
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szClassName;
    wndclass.hIconSm = NULL;
    ::RegisterClassEx(&wndclass);
    hwnd = ::CreateWindowEx(0, szClassName, szAppName, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
    ::ShowWindow(hwnd, nCmdShow);
    ::UpdateWindow(hwnd);
    while (::GetMessage(&msg, NULL, 0, 0) != 0)
    {
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    TCHAR szBuf[10];
    int y;

    if (uMsg == WM_PAINT)
    {
        hdc = ::BeginPaint(hwnd, &ps);
        for (int i = 0; i < NUMLINES; i++)
        {
            y = 18 * i; //行間距
            ::TextOut(hdc, 0, y, METRICS[i].m_pLabel, _tcslen(METRICS[i].m_pLabel));
            ::TextOut(hdc, 240, y, METRICS[i].m_pDesc, _tcslen(METRICS[i].m_pDesc));
            ::TextOut(hdc, 760, y, szBuf,
                wsprintf(szBuf, TEXT("%d"), ::GetSystemMetrics(METRICS[i].m_nIndex)));
        }
        ::EndPaint(hwnd, &ps);
        return 0;
    }
    else if (uMsg == WM_DESTROY)
    {
        ::PostQuitMessage(0);
        return 0;
    }
    return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
}

37_MFC自繪UI你離不開GDI繪圖,深入淺出WINDOW程序設(shè)計(jì),mfc,ui,c++

程序使用wndclass.hbrBackground =(HBRUSH)(COLOR_BTNFACE+ 1);把窗口背景設(shè)置為標(biāo)準(zhǔn)系統(tǒng)顏色(淺灰色),所以很容易發(fā)現(xiàn)文本其實(shí)是有背景色的,默認(rèn)是白色背景﹔字體是系統(tǒng)字體(System字體,標(biāo)題欄、菜單、對(duì)話框默認(rèn)情況下使用系統(tǒng)字體);對(duì)于每一行的行間距以及每一列的距離,我們大體設(shè)置了一個(gè)數(shù)值,這并不準(zhǔn)確;客戶區(qū)一共輸出了95行,但是由于屏幕分辨率的原因,無法完整顯示出來,很明顯程序需要一個(gè)垂直滾動(dòng)條。

格式化文本

文本輸出是程序客戶區(qū)中最常見的圖形輸出類型,有一些函數(shù)可以格式化和繪制文本。

格式化函數(shù)可以設(shè)置背景模式、背景顏色、對(duì)齊方式、文本顏色、字符間距等,這些都是DC的文本格式屬性。背景模式不透明、背景顏色為白色、對(duì)齊方式為左對(duì)齊、文本顏色為黑色等都是默認(rèn)的DC文本格式屬性。

格式函數(shù)可以分為三類∶

  • 獲取或設(shè)置DC的文本格式屬性的函數(shù)
  • 獲取字符寬度和高度的函數(shù)
  • 獲取字符串寬度和高度的函數(shù)。

文本格式屬性

  • 文本對(duì)齊方式

SetTextAlign函數(shù)為指定的DC設(shè)置文本對(duì)齊方式∶

UINT SetTextAlign
(
	_In_HDC hdc, //設(shè)備環(huán)境句柄
	_In_ UINT fMode  //文本對(duì)齊方式
);

fMode參數(shù)指定文本對(duì)齊方式,可用的值及含義如下表所示。

常量 常量含義
TA_TOP 起始點(diǎn)在文本邊界矩形的上邊緣
TA_BOTTOM 起始點(diǎn)在文本邊界矩形的下邊緣
TA_BASELINE 起始點(diǎn)在文本的基線上
TA_LEFT 起始點(diǎn)在文本邊界矩形的左邊緣
TA_RIGHT 起始點(diǎn)在文本邊界矩形的右邊緣
TA_CENTER 起始點(diǎn)在文本邊界矩形的中心(水平方向)
TA_UPDATECP 使用當(dāng)前位置作為起始點(diǎn),當(dāng)前位置在每次文本輸出函數(shù)調(diào)用后會(huì)更新
TA_NOUPDATECP 每次文本輸出函數(shù)調(diào)用以后,當(dāng)前位置不會(huì)更新

默認(rèn)值為TA_LEFT|TA_TOP |TA_NOUPDATECP.

調(diào)用SetTextAlign函數(shù)可以改變TextOutExtTextOut.TabbedTextOut等函數(shù)中nXStart和nYStart參數(shù)表示的含義

  • 使用TA_LEFT TA_RIGHTTA_CENTER標(biāo)志會(huì)影響nXStart表示的水平坐標(biāo)值。

  • 使用TA_TOP TA_BOTTOMTA_BASELINE標(biāo)志會(huì)影響nYStart表示的垂直坐標(biāo)值。

例如在SetTextAlign函數(shù)中指定TA_RIGHT標(biāo)志,那么TextOut函數(shù)的nXStart表示字符串中最后一個(gè)字符右側(cè)的水平坐標(biāo)。如果指定TA_TOP,則nYStart表示字符串中所有字符的最高點(diǎn),即所有字符都在nYStart指定的位置之下﹔如果指定TA_BOTTOM則表示字符串中所有字符都會(huì)在nYStart指定的位置之上。

如果設(shè)置了TA_UPDATECP標(biāo)志,Windows會(huì)忽略TextOut函數(shù)的nXStart和nYStart參數(shù)指定的值,而是將由先前調(diào)用的MoveToEx或LineTo函數(shù)(或其他一些可以改變當(dāng)前位置的函數(shù))指定的當(dāng)前位置坐標(biāo)值作為起始點(diǎn)。

如果沒有調(diào)用改變當(dāng)前位置的函數(shù),那么默認(rèn)情況下當(dāng)前位置的坐標(biāo)為(0,0),相對(duì)于客戶區(qū)左上角;設(shè)置
TA_UPDATECP標(biāo)志以后,對(duì)TextOut函數(shù)的每次調(diào)用也會(huì)更新當(dāng)前位置。

例如,如果設(shè)置為TA_LEFT|TA_UPDATECP,TextOut函數(shù)返回后新的當(dāng)前位置就是該字符串的結(jié)束位置,下次調(diào)用TextOut函數(shù)時(shí)就會(huì)從上一個(gè)字符串的結(jié)束位置開始繪制,有時(shí)候可能需要這個(gè)特性。

如果函數(shù)執(zhí)行成功,則返回值是原來的文本對(duì)齊設(shè)置 如果函數(shù)執(zhí)行失敗,則返回值為GDI_ERROR.

大家可以把SystemMetrics程序的最后一個(gè)TextOut改為∶

#include <Windows.h>
#include <tchar.h>
#include "Metrics.h"

const int NUMLINES = sizeof(METRICS) / sizeof(METRICS[0]); //寫入文本的行數(shù)
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wndclass;                            // RegisterClassEx函數(shù)用的WNDCLASSEX結(jié)構(gòu)
    TCHAR szClassName[] = TEXT("MyWindow");         // RegisterClassEx函數(shù)注冊(cè)的窗口類的名稱
    TCHAR szAppName[] = TEXT("GetSystemMetrics");   // 窗口標(biāo)題
    HWND hwnd;                                      // CreateWindowEx函數(shù)創(chuàng)建的窗口的句柄
    MSG msg;                                        // 消息循環(huán)所用的消息結(jié)構(gòu)體

    wndclass.cbSize = sizeof(WNDCLASSEX);
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = WindowProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);    // 窗口背景使用標(biāo)準(zhǔn)系統(tǒng)顏色
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szClassName;
    wndclass.hIconSm = NULL;
    ::RegisterClassEx(&wndclass);
    hwnd = ::CreateWindowEx(0, szClassName, szAppName, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
    ::ShowWindow(hwnd, nCmdShow);
    ::UpdateWindow(hwnd);
    while (::GetMessage(&msg, NULL, 0, 0) != 0)
    {
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    TCHAR szBuf[10];
    int y;

    if (uMsg == WM_PAINT)
    {
        hdc = ::BeginPaint(hwnd, &ps);
        for (int i = 0; i < NUMLINES; i++)
        {
            y = 18 * i; //行間距

            ::TextOut(hdc, 0, y, METRICS[i].m_pLabel, _tcslen(METRICS[i].m_pLabel));
            ::TextOut(hdc, 240, y, METRICS[i].m_pDesc, _tcslen(METRICS[i].m_pDesc));
           

            //設(shè)置最后一列右對(duì)齊
            ::SetTextAlign(hdc, TA_RIGHT | TA_TOP | TA_NOUPDATECP);
            ::TextOut(hdc, 760, y, szBuf, wsprintf(szBuf, TEXT("%d"), ::GetSystemMetrics(METRICS[i].m_nIndex)));
            //渲染完畢之后,恢復(fù)預(yù)設(shè)
            ::SetTextAlign(hdc, TA_LEFT | TA_TOP | TA_NOUPDATECP);
        }
        ::EndPaint(hwnd, &ps);
        return 0;
    }
    else if (uMsg == WM_DESTROY)
    {
        ::PostQuitMessage(0);
        return 0;
    }
    return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
}

37_MFC自繪UI你離不開GDI繪圖,深入淺出WINDOW程序設(shè)計(jì),mfc,ui,c++

將fMode參數(shù)設(shè)置為TA_RIGHT,那么TextOut的nXStart參數(shù)指定的就是字符串中最后一個(gè)字符右側(cè)的X坐標(biāo)。

可以看到數(shù)據(jù)從右開始變得對(duì)齊了。

可以通過調(diào)用GetTextAlign函數(shù)來獲取指定DC的當(dāng)前文本對(duì)齊設(shè)置∶

UINT GetTextAlign(_In_ HDC hdc);

調(diào)用SetTextAlign函數(shù)的時(shí)候通常使用按位或運(yùn)算符組合幾個(gè)標(biāo)志,調(diào)用GetTextAlign函數(shù)的時(shí)候可以使用按位”與"運(yùn)算符檢測(cè)返回值是否包含某標(biāo)志。

  • 字符間距

可以通過調(diào)用SetTextCharacterExtra函數(shù)設(shè)置指定DC中文本輸出的字符間距︰

int SetTextCharacterExtra
(
    HDC hdc, //設(shè)備環(huán)境句柄 
  
    int nCharExtra //字符間距,邏輯單位
);

大家可以在SystemMetrics程序的3個(gè)TextOut前調(diào)用SetTextCharacterExtra函數(shù)設(shè)置一下字符間距,看一下效果,比如說:

 //設(shè)置字符寬度
 ::SetTextCharacterExtra(hdc, 5);
 ::TextOut(hdc, 760, y, szBuf, wsprintf(szBuf, TEXT("%d"), ::GetSystemMetrics(METRICS[i].m_nIndex)));
 //恢復(fù)預(yù)設(shè)
 ::SetTextCharacterExtra(hdc, 0);

37_MFC自繪UI你離不開GDI繪圖,深入淺出WINDOW程序設(shè)計(jì),mfc,ui,c++

可以通過調(diào)用GetTextCharacterExtra函數(shù)來獲取指定DC的當(dāng)前字符間距∶

int GetTextCharacterExtra(HDC hdc);
  • 背景模式、背景顏色和文本顏色

可以通過調(diào)用SetTextColor函數(shù)設(shè)置繪制的文本顏色,以及在彩色打印機(jī)上繪制的文本顏色;

可以通過調(diào)用SetBkColor函數(shù)設(shè)置每個(gè)字符后顯示的顏色(也就是背景顏色);

可以通過調(diào)用SetBkMode函數(shù)設(shè)置背景模式為透明或不透明。

COLORREF SetTextColor
(
HDC hdc, //設(shè)備環(huán)境句柄
COLORREF crColor //文本顏色值
);

如果函數(shù)執(zhí)行成功,則返回原來的背景顏色值;如果函數(shù)執(zhí)行失敗,則返回值為CLR_INVALID.

int SetBkMode(
	HDC hdc,	//設(shè)備環(huán)境句柄
	int iBkMode //背景模式
);

iBkMode參數(shù)指定背景模式,可用的值只有兩個(gè)∶指定為OPAQUE表示不透明背景,指定為TRANSPARENT表示透明背景。

如果函數(shù)執(zhí)行成功,則返回原來的的背景模式﹔如果函數(shù)執(zhí)行失敗,則返回值為0。

COLORREF用于指定RGB顏色值,在windef.h頭文件中定義如下∶

typedef DWORD COLORREF;
typedef DWORD *LPCOLORREF;

COLORREF值的十六進(jìn)制為"Ox00BBGGRR"的形式,低位字節(jié)包含紅色值,倒數(shù)第2字節(jié)包含綠色值,倒數(shù)第3字節(jié)包含藍(lán)色值,高位字節(jié)必須為0,單字節(jié)的最大值為255.

要?jiǎng)?chuàng)建COLORREF顏色值,可以使用RGB宏分別指定紅色、綠色、藍(lán)色的值;

要提取COLORREF顏色值中的的紅色、綠色和藍(lán)色值,可以分別使用GetRValue GetGValue和GetBValue宏。

這些宏在wingdi.h頭文件中定義如下∶

#define RGB(r,g,b)
((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(DWORD)(BYTE)(b))<<16)))
#define GetRValue(rgb)(LOBYTE(rgb))
#define GetGValue(rgb)(LOBYTE((WORD)(rgb)) >>8))
#define GetBValue(rgb)(LOBYTE((rgb)>>16))

現(xiàn)在,我們?cè)赟ystemMetrics程序的TextOut函數(shù)調(diào)用前面加上以下語(yǔ)句︰

#include <Windows.h>
#include <tchar.h>
#include<strsafe.h>
#include "Metrics.h"

const int NUMLINES = sizeof(METRICS) / sizeof(METRICS[0]); //寫入文本的行數(shù)
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wndclass;                            // RegisterClassEx函數(shù)用的WNDCLASSEX結(jié)構(gòu)
    TCHAR szClassName[] = TEXT("MyWindow");         // RegisterClassEx函數(shù)注冊(cè)的窗口類的名稱
    TCHAR szAppName[] = TEXT("GetSystemMetrics");   // 窗口標(biāo)題
    HWND hwnd;                                      // CreateWindowEx函數(shù)創(chuàng)建的窗口的句柄
    MSG msg;                                        // 消息循環(huán)所用的消息結(jié)構(gòu)體

    wndclass.cbSize = sizeof(WNDCLASSEX);
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = WindowProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);    // 窗口背景使用標(biāo)準(zhǔn)系統(tǒng)顏色
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szClassName;
    wndclass.hIconSm = NULL;
    ::RegisterClassEx(&wndclass);
    hwnd = ::CreateWindowEx(0, szClassName, szAppName, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
    ::ShowWindow(hwnd, nCmdShow);
    ::UpdateWindow(hwnd);
    while (::GetMessage(&msg, NULL, 0, 0) != 0)
    {
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    TCHAR szBuf[10];
    int y;

    if (uMsg == WM_PAINT)
    {
        hdc = ::BeginPaint(hwnd, &ps);
        for (int i = 0; i < NUMLINES; i++)
        {
            y = 18 * i; 

   

            //設(shè)置背景模式是透明的,文本顏色為藍(lán)色
            int preSetBkMode = ::SetBkMode(hdc, TRANSPARENT);
            COLORREF preSetTextColor =  SetTextColor(hdc, RGB(0, 0, 255));
 

            ::TextOut(hdc, 0, y, METRICS[i].m_pLabel, _tcslen(METRICS[i].m_pLabel));

            //恢復(fù)預(yù)設(shè)
            SetBkMode(hdc, preSetBkMode);
            SetTextColor(hdc, preSetTextColor);


            ::TextOut(hdc, 240, y, METRICS[i].m_pDesc, _tcslen(METRICS[i].m_pDesc));
            ::TextOut(hdc, 760, y, szBuf, wsprintf(szBuf, TEXT("%d"), ::GetSystemMetrics(METRICS[i].m_nIndex)));
            ::SetTextCharacterExtra(hdc, 0);

        }
        ::EndPaint(hwnd, &ps);
        return 0;
    }
    else if (uMsg == WM_DESTROY)
    {
        ::PostQuitMessage(0);
        return 0;
    }
    return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
}

37_MFC自繪UI你離不開GDI繪圖,深入淺出WINDOW程序設(shè)計(jì),mfc,ui,c++

可以看到背景模式是透明的,文本顏色為藍(lán)色。

顯示DC的默認(rèn)文本顏色TextColor為黑色,默認(rèn)背景顏色BkColor為白色,默認(rèn)背景模式BkMode為不透明。

程序可以通過調(diào)用GetTextColor函數(shù)獲取DC的當(dāng)前文本顏色。

可以通過調(diào)用GetBkColor函數(shù)獲取DC的當(dāng)前背景顏色。

可以通過調(diào)用GetBkMode函數(shù)獲取DC的當(dāng)前背景模式。

獲取字符串的寬度和高度

GetCharWidth32函數(shù)可以獲取指定DC當(dāng)前字體中指定范圍內(nèi)的連續(xù)字符的寬度︰

BOOL GetCharWidth32
(
_In_ HDC hdc,//設(shè)備環(huán)境句柄
_In_ UINT iFirstChar,//連續(xù)字符中的第一個(gè)字符
_In_ UINT iLastChar,//連續(xù)字符中的最后一個(gè)字符,不得位于指定的第一個(gè)字符之前
_out_ LPINT lpBuffer //接收每個(gè)字符寬度的INT數(shù)組,字符寬度是邏輯單位
); 

可以把iFirstCha和iLastChar參數(shù)指定為相同的值,只獲取一個(gè)字符的寬度。

GetTextExtentPoint32函數(shù)用于獲取指定DC中一個(gè)字符串的寬度和高度值︰

BOOL GetTextExtentPoint32
(
_In_ HDC hdc,//設(shè)備環(huán)境句柄
_In_ LPCTSTR lpString,//字符串指針,不要求以零結(jié)尾,因?yàn)閰?shù)c可以指定字符串長(zhǎng)度
_ln_ intc,//字符串長(zhǎng)度,可以使用_tcslen
_Out_LPSIZE lpSize //在這個(gè)SIZE結(jié)構(gòu)中返回字符串的寬度和高度,邏輯單位
);

lpSize是一個(gè)指向SIZE結(jié)構(gòu)的指針,在這個(gè)SIZE結(jié)構(gòu)中返回字符串的寬度和高度。SIZE結(jié)構(gòu)在windef.h頭文件中定義如下∶

typedef struct tagSIZE
{
	LONG	cx;
	LONG	cy;
}SIZE,*PSIZE,*LPSIZE;

前面說過∶“WM_CREATE消息是窗口過程較早收到的消息之一,程序通常會(huì)在這里做一些初始化的工作”。對(duì)于SystemMetrics程序,我們可以在WM_CREATE消息中獲取字符串高度,用于在TextOut函數(shù)中指定y坐標(biāo)值︰

#include <Windows.h>
#include <tchar.h>
#include<strsafe.h>
#include "Metrics.h"

const int NUMLINES = sizeof(METRICS) / sizeof(METRICS[0]); //寫入文本的行數(shù)
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	WNDCLASSEX wndclass;                            // RegisterClassEx函數(shù)用的WNDCLASSEX結(jié)構(gòu)
	TCHAR szClassName[] = TEXT("MyWindow");         // RegisterClassEx函數(shù)注冊(cè)的窗口類的名稱
	TCHAR szAppName[] = TEXT("GetSystemMetrics");   // 窗口標(biāo)題
	HWND hwnd;                                      // CreateWindowEx函數(shù)創(chuàng)建的窗口的句柄
	MSG msg;                                        // 消息循環(huán)所用的消息結(jié)構(gòu)體

	wndclass.cbSize = sizeof(WNDCLASSEX);
	wndclass.style = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc = WindowProc;
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hInstance = hInstance;
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);    // 窗口背景使用標(biāo)準(zhǔn)系統(tǒng)顏色
	wndclass.lpszMenuName = NULL;
	wndclass.lpszClassName = szClassName;
	wndclass.hIconSm = NULL;
	::RegisterClassEx(&wndclass);
	hwnd = ::CreateWindowEx(0, szClassName, szAppName, WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
	::ShowWindow(hwnd, nCmdShow);
	::UpdateWindow(hwnd);
	while (::GetMessage(&msg, NULL, 0, 0) != 0)
	{
		::TranslateMessage(&msg);
		::DispatchMessage(&msg);
	}
	return msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	static SIZE size = { 0 };
	TCHAR szBuf[10];
	int y;


	if (uMsg == WM_CREATE)
	{
		//查字符串高度和寬度
		hdc = GetDC(hwnd);
		GetTextExtentPoint32(hdc,METRICS[0].m_pLabel,_tcslen(METRICS[0].m_pLabel),&size);
		ReleaseDC(hwnd,hdc);
		return 0;
	}
	else if (uMsg == WM_PAINT)
	{
		hdc = ::BeginPaint(hwnd, &ps);



		for (int i = 0; i < NUMLINES; i++)
		{
			// y = 18 * i; //這里計(jì)算行間距就不用寫死了

			y = size.cy * i; //計(jì)算行間距

			::TextOut(hdc, 0, y, METRICS[i].m_pLabel, _tcslen(METRICS[i].m_pLabel));
			::TextOut(hdc, 240, y, METRICS[i].m_pDesc, _tcslen(METRICS[i].m_pDesc));
			::TextOut(hdc, 760, y, szBuf, wsprintf(szBuf, TEXT("%d"), ::GetSystemMetrics(METRICS[i].m_nIndex)));
			::SetTextCharacterExtra(hdc, 0);

		}
		::EndPaint(hwnd, &ps);
		return 0;
	}
	else if (uMsg == WM_DESTROY)
	{
		::PostQuitMessage(0);
		return 0;
	}
	return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
}

GetTextExtentPoint32函數(shù)適用于字符串中不包含制表符的情況,如果字符串中包含制表符,則應(yīng)該調(diào)用GetTabbedTextExtent函數(shù)︰

DWORD GetTabbedTextExtent(
_In_	HDC	hDC,//設(shè)備環(huán)境句柄
_In_	LPCTSTR lpString,//字符串指針,不要求以需結(jié)尾,因?yàn)閚Count指定字符串長(zhǎng)度
_In_ int	nCount, //字符串長(zhǎng)度,可以使用_tcslen
_In_ int nTabPositions,//lpnTabStopPositions數(shù)組中元素的個(gè)數(shù)
_In_opt_ const LPINT lpnTabStopPositions //指向包含制表符位置的數(shù)組
);
  • 如果將nTabPositions參數(shù)設(shè)置為0,并將lpnTabStopPositions參數(shù)設(shè)置為NULL,制表符會(huì)自動(dòng)按平均字符寬度的8倍來擴(kuò)展

  • 如果將nTabPositions參數(shù)設(shè)置為1,則所有制表符按lpnTabStopPositions參數(shù)指向的數(shù)組中的第一個(gè)數(shù)組元素指定的距離來分隔。

  • 如果函數(shù)執(zhí)行成功,則返回值是字符串的寬度和高度(邏輯單位),高度值在高位字中,寬度值在低位字中;如果函數(shù)執(zhí)行失敗,則返回值為0.

HIWORD宏可以得到一個(gè)32位數(shù)的高16位;

LOWORD宏可以得到一個(gè)32位數(shù)的低16位;

HIBYTE宏可以得到一個(gè)16位數(shù)的高字節(jié);

LOBYTE宏可以得到一個(gè)16位數(shù)的低字節(jié)。

類似的還有,MAKELONG宏可以將兩個(gè)16位的數(shù)合成為一個(gè)32位的LONG型;MAKEWORD宏可以將兩個(gè)8位的數(shù)合成為一個(gè)16位的WORD型,等等。這些宏在minwindef.h頭文件中定義如下︰文章來源地址http://www.zghlxwxcb.cn/news/detail-833736.html

#define MAKEWORD(a, b)      ((WORD)(((BYTE)(((DWORD_PTR)(a)) & 0xff)) | ((WORD)((BYTE)(((DWORD_PTR)(b)) & 0xff))) << 8))
#define MAKELONG(a, b)      ((LONG)(((WORD)(((DWORD_PTR)(a)) & 0xffff)) | ((DWORD)((WORD)(((DWORD_PTR)(b)) & 0xffff))) << 16))
#define LOWORD(l)           ((WORD)(((DWORD_PTR)(l)) & 0xffff))
#define HIWORD(l)           ((WORD)((((DWORD_PTR)(l)) >> 16) & 0xffff))
#define LOBYTE(w)           ((BYTE)(((DWORD_PTR)(w)) & 0xff))
#define HIBYTE(w)           ((BYTE)((((DWORD_PTR)(w)) >> 8) & 0xff))

TabPositions參數(shù)設(shè)置為1,則所有制表符按lpnTabStopPositions參數(shù)指向的數(shù)組中的第一個(gè)數(shù)組元素指定的距離來分隔。

  • 如果函數(shù)執(zhí)行成功,則返回值是字符串的寬度和高度(邏輯單位),高度值在高位字中,寬度值在低位字中;如果函數(shù)執(zhí)行失敗,則返回值為0.

HIWORD宏可以得到一個(gè)32位數(shù)的高16位;

LOWORD宏可以得到一個(gè)32位數(shù)的低16位;

HIBYTE宏可以得到一個(gè)16位數(shù)的高字節(jié);

LOBYTE宏可以得到一個(gè)16位數(shù)的低字節(jié)。

類似的還有,MAKELONG宏可以將兩個(gè)16位的數(shù)合成為一個(gè)32位的LONG型;MAKEWORD宏可以將兩個(gè)8位的數(shù)合成為一個(gè)16位的WORD型,等等。這些宏在minwindef.h頭文件中定義如下︰

#define MAKEWORD(a, b)      ((WORD)(((BYTE)(((DWORD_PTR)(a)) & 0xff)) | ((WORD)((BYTE)(((DWORD_PTR)(b)) & 0xff))) << 8))
#define MAKELONG(a, b)      ((LONG)(((WORD)(((DWORD_PTR)(a)) & 0xffff)) | ((DWORD)((WORD)(((DWORD_PTR)(b)) & 0xffff))) << 16))
#define LOWORD(l)           ((WORD)(((DWORD_PTR)(l)) & 0xffff))
#define HIWORD(l)           ((WORD)((((DWORD_PTR)(l)) >> 16) & 0xffff))
#define LOBYTE(w)           ((BYTE)(((DWORD_PTR)(w)) & 0xff))
#define HIBYTE(w)           ((BYTE)((((DWORD_PTR)(w)) >> 8) & 0xff))

到了這里,關(guān)于37_MFC自繪UI你離不開GDI繪圖的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 人人都離不開的算法:AI 時(shí)代的生存指南

    人人都離不開的算法:AI 時(shí)代的生存指南

    在數(shù)字化、智能化的今天,算法已經(jīng)深入滲透到我們生活的每一個(gè)角落,無論是工作、學(xué)習(xí)還是娛樂,算法都在以其獨(dú)特的方式改變著我們的生活方式。 早晨,我們被智能鬧鐘喚醒,這背后是算法根據(jù)我們的睡眠習(xí)慣和日?;顒?dòng)計(jì)算出的最佳起床時(shí)間。打開手機(jī),社交媒體平

    2024年04月17日
    瀏覽(31)
  • 生活中離不開無線電,了解無線電管理常識(shí)

    一、無線電設(shè)備管理規(guī)定摘要 為維護(hù)空中電波秩序,防止有害干擾,確保無線電頻率資源的有效利用保障用戶合法權(quán)益,嚴(yán)厲打擊走私活動(dòng),國(guó)家信息產(chǎn)業(yè)部無線電管理局信部無〔1999〕363號(hào)文《關(guān)于加強(qiáng)無線電發(fā)射設(shè)備管理的通告》中對(duì)如何加強(qiáng)無線電設(shè)備管理作出如下規(guī)

    2024年02月05日
    瀏覽(32)
  • 嗯?大火的ChatGPT和new bing都離不開它?

    嗯?大火的ChatGPT和new bing都離不開它?

    概述:本文是對(duì) WhalePaper 向量檢索領(lǐng)域第一次直播活動(dòng)內(nèi)容的文字版,會(huì)對(duì)向量檢索這個(gè) ChatGPT 和 new bing 都離不開的技術(shù)進(jìn)行介紹,結(jié)合了 ChatGPT 以及 new bing 的應(yīng)用場(chǎng)景進(jìn)行講解,相信被標(biāo)題騙進(jìn)來的你還真能有所收獲的(手動(dòng)狗頭)!本期內(nèi)容入門友好,對(duì)課件進(jìn)行了一

    2024年02月03日
    瀏覽(35)
  • VR/AR/XR背后的邏輯?離不開三維引擎相機(jī)

    VR/AR/XR背后的邏輯?離不開三維引擎相機(jī)

    作者:木一 自從Apple Vision Pro問世以來,這款被譽(yù)為開啟“ 空間計(jì)算時(shí)代 ”的產(chǎn)品迅速吸引了眾多科技博主的深度關(guān)注。業(yè)界對(duì)它的評(píng)價(jià)褒貶不一,一些人認(rèn)為它是一款具有里程碑意義的創(chuàng)新產(chǎn)品,而另一些人則認(rèn)為它不過是眾多高質(zhì)量虛擬現(xiàn)實(shí)(VR)產(chǎn)品中的一員。盡管市

    2024年04月12日
    瀏覽(33)
  • 【人人都離不開的算法】為年后的春招加把勁吧

    【人人都離不開的算法】為年后的春招加把勁吧

    馬上又到了春招的季節(jié),你需要問下你自己,算法那一關(guān),你過了嗎? 2022年TIOBE年度編程語(yǔ)言排行榜的結(jié)果出來了,Python穩(wěn)居榜首,C++終于超越了Java,上升到第三位。 在之前的幾年中,這個(gè)榜單的排名也都不盡相同。 前幾年Java是比較火的,但最近兩年隨著人工智能(AI)的

    2024年01月21日
    瀏覽(24)
  • 有哪些工具軟件是一旦用了就離不開的

    在現(xiàn)代社會(huì)中,工具軟件已經(jīng)成為我們?nèi)粘9ぷ骱蜕畹谋貍淦贰_@些軟件通過提供各種功能和服務(wù),幫助我們提高效率、簡(jiǎn)化工作流程,并且在許多方面大大改變了我們的生活方式。本文將介紹一些在使用過程中讓人離不開的工具軟件,這些軟件不僅滿足了我們的各種需求

    2024年02月06日
    瀏覽(19)
  • idea熱部署插件JRebel激活(強(qiáng)烈推薦,試試就離不開了)

    idea熱部署插件JRebel激活(強(qiáng)烈推薦,試試就離不開了)

    JRebel可以實(shí)現(xiàn)在idea中熱部署項(xiàng)目,修改后不用重啟項(xiàng)目,讓開發(fā)更絲滑。 JRebel需要激活才可以正常使用。 博主最近在找工作,Java前后端全站工程師一枚,有合適的請(qǐng)幫博主推薦一下 有項(xiàng)目的也可以聯(lián)系我,感謝感謝 博主在北京 2023-07-04 發(fā) V:y393016244 FileSettingsPlugins 搜索

    2024年02月13日
    瀏覽(35)
  • 測(cè)試了Copilot輔助編程后,就離不開這個(gè)AI工具了

    測(cè)試了Copilot輔助編程后,就離不開這個(gè)AI工具了

    微軟用·chatGPT 4· 對(duì)·github copilot X·升級(jí)后,本是懷著贈(zèng)熱點(diǎn)的心態(tài)測(cè)試了一下其功能。但 Copilot 智能化程度之高,令我吃驚,兩周下來已離開不這個(gè)工具了。 下面簡(jiǎn)單分享一下其使用過程,以及對(duì)如何使用好這個(gè)工具的個(gè)人看法. IDE開發(fā)環(huán)境我使用的是 VSCode 與 Visual Studio2

    2024年02月06日
    瀏覽(30)
  • 什么是棧,為什么函數(shù)式編程語(yǔ)言都離不開棧?

    什么是棧,為什么函數(shù)式編程語(yǔ)言都離不開棧?

    ? 棧是一種具有特殊訪問方式的存儲(chǔ)空間,它的特殊性在于, 最后進(jìn)入這個(gè)空間的數(shù)據(jù),最先出去 ,可以畫圖來描述一下這種操作方式。 假設(shè)有一個(gè)盒子和三本書,依次將三本書他們放入盒子中。 入棧模擬圖 ? 現(xiàn)在有一個(gè)問題,如果一次只能取一本,我們?nèi)绾螌鴱暮凶?/p>

    2024年02月06日
    瀏覽(31)
  • 效率與性能并存——離不開 Visual Studio Code 的前端開發(fā)與我

    效率與性能并存——離不開 Visual Studio Code 的前端開發(fā)與我

    許久不見的軟文來啦,今天久違的參與討論一下這個(gè)話題,以此寫一篇博客來發(fā)表一些我的看法和想法。話題的內(nèi)容是: 有哪些工具軟件是一旦用了就離不開的? 。作為一名前端開發(fā)的博主,這次的內(nèi)容當(dāng)然也是關(guān)于前端的,接觸前端也快兩年了,有這么一個(gè)編譯器(工具

    2024年02月05日
    瀏覽(27)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包