日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

VC++ WIN32 sdk实现按钮自绘详解.

發(fā)布時(shí)間:2025/3/17 c/c++ 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 VC++ WIN32 sdk实现按钮自绘详解. 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
網(wǎng)上找了很多,可只是給出代碼,沒有詳細(xì)解釋,不便初學(xué)者理解.我就抄回冷飯.把這個(gè)再拿出來說說. 實(shí)例圖片: 首先建立一個(gè)標(biāo)準(zhǔn)的Win32 Application?工程.選擇a simple Win32 Application. 然后建立我們的資源文件首先新建一個(gè)對(duì)話框資源,資源ID改為IDD_MAIN_DLG 然后在其上新建一個(gè)按鈕控件資源ID改為IDC_ODBUTTON,此按鈕的styles中必須選中owenerdraw屬性. 然后將其保存為.rc的資源文件.并將其導(dǎo)入我們的工程.同理新建一個(gè)圖標(biāo)文件資源ID改為IDI_OWNERDRAW保存為.ico的圖標(biāo)然后導(dǎo)入. 準(zhǔn)備工作做完了下面開始寫代碼. 首先聲明如下全局變量. #include?"stdafx.h"
#include "resource.h"
HINSTANCE?odInst?=?NULL;??//接收程序?qū)嵗木浔?br />HWND?hMainWnd?=?NULL;?????//接收主窗口的句柄
HWND?hDlgNow?=?NULL;??????//接收對(duì)話框的句柄
staticHICON?hOwnerDrawIcon?=?NULL;??//用作自繪按鈕的圖標(biāo)
staticLONG?prev_proc;?????????????????//儲(chǔ)存按鈕先前的回調(diào)函數(shù)
staticHICON?hIcon?=?NULL;???????????//對(duì)話框圖標(biāo)句柄
然后開始寫WinMain()函數(shù) int?APIENTRY?WinMain(HINSTANCE?hInstance,
?????????????????????HINSTANCE?hPrevInstance,
?????????????????????LPSTR?????lpCmdLine,
?????????????????????int???????nCmdShow)
{
?????//?TODO:?Place?code?here.
????odInst?=?hInstance;
????
????WNDCLASS??wc;
????wc.style?????????=?0;
????wc.lpfnWndProc???=?(WNDPROC)ODWndProc;?//定義一個(gè)窗口默認(rèn)函數(shù),這里我們會(huì)交由默認(rèn)窗口函數(shù)處理
wc.cbClsExtra????=?0;
????wc.cbWndExtra????=?0;
????wc.hInstance?????=?hInstance;
????wc.hIcon?????????=?LoadIcon(odInst,MAKEINTRESOURCE(IDI_OWNERDRAW));
????wc.hCursor???????=?NULL;
????wc.hbrBackground?=?0;
????wc.lpszClassName?=?"OwnerDraw";
????wc.lpszMenuName?????=?NULL;

????RegisterClass(&wc);

MSG?msg;
????
????HWND?onlywin=?FindWindow("OwnerDraw","MyOwnerDraw");

????if(onlywin)
????????{
????????ExitProcess(1);
????????}
????
????hMainWnd=CreateWindow("OwnerDraw","MyOwnerDraw",WS_OVERLAPPEDWINDOW,
????????????????CW_USEDEFAULT,0,CW_USEDEFAULT,0,NULL,NULL,hInstance,NULL);

????
????if(!hMainWnd)
????????{
????????????returnFALSE;
????????}

????
????hDlgNow?=?DoMainDlg(hMainWnd);
????ShowWindow(hDlgNow,?nCmdShow);


????while(GetMessage(&msg,?NULL,?0,?0))?
????{
????????if(NULL?==?hDlgNow?||?!IsDialogMessage(hDlgNow,?&msg))
????????{
????????????TranslateMessage(&msg);
????????????DispatchMessage(&msg);
????????}
????}

????returnmsg.wParam;
}
首先注冊(cè)一個(gè)標(biāo)準(zhǔn)的窗口類,的WNDCLASS結(jié)構(gòu)體,默認(rèn)的窗口過程為ODWndProc.其定義如下. LRESULT?CALLBACK?ODWndProc(HWND?hWnd,?UINT?message,?WPARAM?wParam,?LPARAM?lParam)
{
????return?DefWindowProc(hWnd,?message,?wParam,?lParam);//返回系統(tǒng)默認(rèn)的窗口過程
}
然后判斷有無相同實(shí)例存在如有則結(jié)束之 HWND?onlywin=?FindWindow("OwnerDraw","MyOwnerDraw");

????if?(onlywin)
????????{
????????ExitProcess(1);
????????}
接下來創(chuàng)建主窗口 hMainWnd=CreateWindow("OwnerDraw","MyOwnerDraw",WS_OVERLAPPEDWINDOW,
????????????????CW_USEDEFAULT,0,CW_USEDEFAULT,0,NULL,NULL,hInstance,NULL);
需要注意的是我們這里并不調(diào)用ShowWindow()和UpdateWindow();因?yàn)槲覀儾恍枰@示主窗口 hDlgNow?=?DoMainDlg(hMainWnd);
????ShowWindow(hDlgNow,?nCmdShow);
這里調(diào)用DoMainDlg函數(shù)創(chuàng)建一個(gè)對(duì)話框并顯示之. DoMainDlg函數(shù)實(shí)現(xiàn)如下. HWND?DoMainDlg(HWND?parent)
{
????DWORD?dwErr;
????HWND?hRet?=?CreateDialog(odInst,?(LPCTSTR)IDD_MAIN_DLG,?parent,?(DLGPROC)MainDlgProc);
????if(hRet?==?NULL)
????????dwErr?=?GetLastError();

????return?hRet;

}
最后為消息循環(huán) while(GetMessage(&msg,?NULL,?0,?0))?
????{
????????if?(NULL?==?hDlgNow?||?!IsDialogMessage(hDlgNow,?&msg))
????????{
????????????TranslateMessage(&msg);
????????????DispatchMessage(&msg);
????????}
????}
其中IsDialogMessage(hDlgNow, &msg)主要作用是把指定對(duì)話框的消息,路由給其處理. 下面是對(duì)話框窗口的默認(rèn)消息響應(yīng)回調(diào)函數(shù)MainDlgProc 我這里主要講響應(yīng)WM_DRAWITEM消息與WM_INITDIALOG.. 首先是響應(yīng)WM_INITDIALOG case?WM_INITDIALOG:
????????????
????????????if(hIcon?==?NULL)
????????????????hIcon?=?LoadIcon(odInst,?MAKEINTRESOURCE(IDI_OWNERDRAW));
????????????
????????????if(hOwnerDrawIcon?==?NULL)
????????????????hOwnerDrawIcon?=?(HICON)LoadImage(odInst,?
????????????????????????????????????????MAKEINTRESOURCE(IDI_OWNERDRAW),?
????????????????????????????????????????IMAGE_ICON,?
????????????????????????????????????????38,
????????????????????????????????????????38,
????????????????????????????????????????0);
????????????prev_proc?=?SetWindowLongPtr(GetDlgItem(hDlg,?IDC_ODBUTTON),?GWLP_WNDPROC,?(LONG)ButtWindProc);
????????????
????????????SendMessage(hDlg,?WM_SETICON,?ICON_SMALL,?(LPARAM)hIcon);

????????????SetFocus(GetDlgItem(hDlg,?IDC_ODBUTTON));
????????????
????????????
????????????break;
首先為對(duì)話框加載一個(gè)圖標(biāo),我這里圖省事全部都用了一個(gè)圖標(biāo),在實(shí)際應(yīng)用中.可以隨需要更換. 然后是為自繪按鈕加載圖標(biāo).接下來改變默認(rèn)的自繪按鈕的窗口過程.將原按鈕過程存與prev_proc中. 最后發(fā)送WM_SETICON消息設(shè)置對(duì)話框圖標(biāo)和設(shè)置焦點(diǎn). 接下來是響應(yīng)WM_DRAWITEM消息,需要說明的是這個(gè)消息必須要設(shè)置了BS_OWNERDRAW 我們用記事本打開我們的對(duì)話框資源文件會(huì)看到類似下面的設(shè)置 IDD_MAIN_DLG?DIALOG?DISCARDABLE??0,?0,?250,?142
STYLE?DS_MODALFRAME?|?WS_POPUP?|?WS_CAPTION?|?WS_SYSMENU
CAPTION?"Dialog"
FONT?10,?"System"
BEGIN
????DEFPUSHBUTTON???"OK",IDOK,193,7,50,14
????PUSHBUTTON??????"Cancel",IDCANCEL,193,24,50,14
????CONTROL?????????"OwnerDraw",IDC_ODBUTTON,"Button",BS_OWNERDRAW?|?
????????????????????WS_TABSTOP,49,31,79,26
END
此處資源文件中的BS_OWNERDRAW即對(duì)應(yīng)創(chuàng)建按鈕時(shí)選中的Ownerdraw屬性.之所以這樣作是因?yàn)橹挥羞@樣 對(duì)話框才能響應(yīng)WM_DRAWITEM消息.下面為代碼. case?WM_DRAWITEM:
????????????{
????????????????LPDRAWITEMSTRUCT?lpDIS?=?(LPDRAWITEMSTRUCT)?lParam;
????????????????//聲明一個(gè)指向DRAWITEMSTRUCT結(jié)構(gòu)體的指針并將其指向存儲(chǔ)著按鈕構(gòu)造信息的lParam

????????????????if(lpDIS->CtlID?!=?IDC_ODBUTTON)
????????????????????return(0);
????????????????
????????????????HDC?dc?=?lpDIS->hDC;?//用于按鈕繪制的DC
BOOL?bIsPressed??=?(lpDIS->itemState?&?ODS_SELECTED);
????????????????BOOL?bIsFocused??=?(lpDIS->itemState?&?ODS_FOCUS);
????????????????BOOL?bIsDisabled?=?(lpDIS->itemState?&?ODS_DISABLED);
????????????????BOOL?bDrawFocusRect?=?!(lpDIS->itemState?&?ODS_NOFOCUSRECT);
????????????????//判斷按鈕各種狀態(tài)的BOOL值
RECT?itemRect?=?lpDIS->rcItem;?//按鈕的矩形區(qū)域

????????????????SetBkMode(dc,?TRANSPARENT);?//設(shè)置繪制按鈕時(shí)的背景狀態(tài)
if(bIsFocused)??//判斷按鈕是否獲得了焦點(diǎn)并對(duì)其邊框進(jìn)行處理
{
????????????????????HBRUSH?br?=?CreateSolidBrush(RGB(0,0,0));??
????????????????????FrameRect(dc,?&itemRect,?br);
????????????????????InflateRect(&itemRect,?-1,?-1);
????????????????????DeleteObject(br);
????????????????}?//?if????????

????????????????COLORREF?crColor?=?GetSysColor(COLOR_BTNFACE);//得到系統(tǒng)按鈕顏色

????????????????HBRUSH????brBackground?=?CreateSolidBrush(crColor);//創(chuàng)建畫刷

????????????????FillRect(dc,?&itemRect,?brBackground);//繪制按鈕

????????????????DeleteObject(brBackground);
????????????????
????????????????//?這里畫被按下去的按鈕
if(bIsPressed)
????????????????{
????????????????????HBRUSH?brBtnShadow?=?CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
????????????????????FrameRect(dc,?&itemRect,?brBtnShadow);
????????????????????DeleteObject(brBtnShadow);
????????????????}
????????????????
????????????????else?//如果沒有被按下就這樣畫
{
????????????????????UINT?uState?=?DFCS_BUTTONPUSH?|
????????????????????????((bIsPressed)???DFCS_PUSHED?:?0);
????????????????????
????????????????????DrawFrameControl(dc,?&itemRect,?DFC_BUTTON,?uState);
????????????????}
????????????????
????????????????charsTitle[100];
????????????????GetWindowText(GetDlgItem(hDlg,?IDC_ODBUTTON),?sTitle,?100);//得到按鈕的文本

????????????????RECT?captionRect?=?lpDIS->rcItem;//把文本的區(qū)域設(shè)置為按鈕區(qū)域

????????????????
????????????????BOOL?bHasTitle?=?(sTitle[0]?!='/0');//按鈕上是否有文本存在
????????????????
//這里畫按鈕上的圖標(biāo),具體實(shí)現(xiàn)見下面
(GetDlgItem(hDlg,?IDC_ODBUTTON),?&dc,?bHasTitle,?
????????????????????&lpDIS->rcItem,?&captionRect,?bIsPressed,?bIsDisabled);
????????????????
????????????????
????????????????
????????????????if(bHasTitle)//如果按鈕有文本標(biāo)題
{
????????????????????//?按鈕被按下的處理
if(bIsPressed)
????????????????????????OffsetRect(&captionRect,?1,?1);
????????????????????
????????????????????//?將文本居中
RECT?centerRect?=?captionRect;
????????????????????DrawText(dc,?sTitle,?-1,?&captionRect,?DT_WORDBREAK?|?DT_CALCRECT|DT_CENTER);
????????????????????LONG?captionRectWidth?=?captionRect.right?-?captionRect.left;
????????????????????LONG?captionRectHeight?=?captionRect.bottom?-?captionRect.top;
????????????????????LONG?centerRectWidth?=?centerRect.right?-?centerRect.left;
????????????????????LONG?centerRectHeight?=?centerRect.bottom?-?centerRect.top;
????????????????????OffsetRect(&captionRect,?(centerRectWidth?-?captionRectWidth)/2,?(centerRectHeight?-?captionRectHeight)/2);
????????????????????
????????????????????
????????????????????
????????????????????SetBkMode(dc,?TRANSPARENT);
????????????????????
????????????????????if(bIsDisabled)//如果按鈕被禁用
{
????????????????????????OffsetRect(&captionRect,?1,?1);
????????????????????????SetTextColor(dc,?::GetSysColor(COLOR_3DHILIGHT));
????????????????????????DrawText(dc,?sTitle,?-1,?&captionRect,?DT_WORDBREAK?|?DT_CENTER);
????????????????????????OffsetRect(&captionRect,?-1,?-1);
????????????????????????SetTextColor(dc,?::GetSysColor(COLOR_3DSHADOW));
????????????????????????DrawText(dc,?sTitle,?-1,?&captionRect,?DT_WORDBREAK?|?DT_CENTER);
????????????????????}?
????????????????????else?//如果沒被禁用正常畫
{
????????????????????????SetTextColor(dc,?::GetSysColor(COLOR_BTNTEXT));
????????????????????????SetBkColor(dc,?::GetSysColor(COLOR_BTNFACE));
????????????????????????DrawText(dc,?sTitle,?-1,?&captionRect,?DT_WORDBREAK?|?DT_CENTER);
????????????????????}?
????????????????????
????????????????}
????????????????
????????????????//?畫按鈕得到焦點(diǎn)時(shí)的虛線方框
if(bIsFocused?&&?bDrawFocusRect)
????????????????{
????????????????????RECT?focusRect?=?itemRect;
????????????????????InflateRect(&focusRect,?-3,?-3);
????????????????????DrawFocusRect(dc,?&focusRect);
????????????????}?//?if
return(TRUE);
????????????}
????????????break;
到此WM_DRAWITEM消息響應(yīng)完畢.下面我們看看DrawTheIcon這個(gè)函數(shù). static?void?DrawTheIcon(HWND?hButtonWnd,?HDC*?dc,?BOOL?bHasTitle,?RECT*?rpItem,?RECT*?rpTitle,?BOOL?bIsPressed,?BOOL?bIsDisabled)
{
????RECT????rImage;
????PrepareImageRect(hButtonWnd,?bHasTitle,?rpItem,?rpTitle,?bIsPressed,?38,?38,?&rImage);
????
????//?調(diào)用API函數(shù)按準(zhǔn)備好的形式將圖片畫到按鈕上
DrawState(????*dc,
????????NULL,
????????NULL,
????????(LPARAM)hOwnerDrawIcon,
????????0,
????????rImage.left,
????????rImage.top,
????????(rImage.right?-?rImage.left),
????????(rImage.bottom?-?rImage.top),?
????????(bIsDisabled???DSS_DISABLED?:?DSS_NORMAL)?|?DST_ICON);
}
還有其中的PrepareImageRect函數(shù) static?void?PrepareImageRect(HWND?hButtonWnd,?BOOL?bHasTitle,?RECT*?rpItem,?RECT*?rpTitle,?BOOL?bIsPressed,?DWORD?dwWidth,?DWORD?dwHeight,?RECT*?rpImage)
{
????RECT?rBtn;
????
????CopyRect(rpImage,?rpItem);
????
????
????GetClientRect(hButtonWnd,?&rBtn);
????if?(bHasTitle?==?FALSE)//如果按鈕上有文本內(nèi)容
{
????????//?使圖片水平居中
LONG?rpImageWidth?=?rpImage->right?-?rpImage->left;
????????rpImage->left?+=?((rpImageWidth?-?(long)dwWidth)/2);
????}
????else
????{???//控制圖片與焦點(diǎn)方框內(nèi)部
LONG?rpTitleWidth?=?rpTitle->right?-?rpTitle->left;
????????rpTitle->right?=?rpTitleWidth?-?dwWidth?-?30;
????????rpTitle->left?=?30;
????????rpImage->left?=?rBtn.right?-?dwWidth?-?22;
????????
????????LONG?rpImageHeight?=?rpImage->bottom?-?rpImage->top;
????????rpImage->top?+=?((rpImageHeight?-?(long)dwHeight)/2);
????}
????if(bIsPressed)//按鈕被按下的處理
OffsetRect(rpImage,?1,?1);
????
}
行了到這里主要的工作都作完了還要說明的就是ButtWindProc這個(gè)按鈕窗口的回調(diào)函數(shù).寫它的主要目的是為了 實(shí)現(xiàn)按鈕的連續(xù)單擊,在此函數(shù)中我們處理了WM_LBUTTONDBLCLK鼠標(biāo)雙擊事件,并將其轉(zhuǎn)化為一個(gè)單擊事件.像這樣: LRESULT?CALLBACK?ButtWindProc(
??????????????????????????????HWND?hWnd,????????????????????????????//window?handle???????????????????
??????????????????????????????UINT?message,?????????????????????????//?type?of?message?????????????????
??????????????????????????????WPARAM?wParam,????????????????????????//?additional?information??????????
??????????????????????????????LPARAM?lParam)????????????????????????//additional?information??????????
{
????switch?(message)
????{
????case?WM_LBUTTONDBLCLK:
????????PostMessage(hWnd,?WM_LBUTTONDOWN,?wParam,?lParam);
????????break;
????
????}
????//將不做處理的消息路由給原默認(rèn)函數(shù)
returnCallWindowProc((WNDPROC)prev_proc,?hWnd,?message,?wParam,?lParam);
????
}
下面只需再響應(yīng)WM_SETICON, WM_SYSCOMMAND, WM_COMMAND.這三個(gè)沒什么好說的.前兩個(gè)交由系統(tǒng)默認(rèn)過程處理,最后一個(gè)對(duì)應(yīng)對(duì)話框上的確定和取消,都是銷毀窗口的行為. case?WM_SETICON:
????????????????DefWindowProc(hDlg,?message,?wParam,?lParam);
????????????break;
????
????case?WM_SYSCOMMAND:
????????????????{
????????????????????return?DefWindowProc(hDlg,?message,?wParam,?lParam);
????????????????}
????case?WM_COMMAND:
????????????????switch?(LOWORD(wParam))
????????????????{
????????????????case?IDCANCEL:
????????????????case?IDOK:
????????????????????
????????????????????DestroyIcon(hOwnerDrawIcon);
????????????????????
????????????????????PostQuitMessage(0);
????????????????????return?TRUE;
????????????????}//switch
????????????????break;
本文部分內(nèi)容參考自http://www.codeproject.com/buttonctrl/nativewin32xpthemes.asp 本實(shí)例源代碼http://geniusdot.googlepages.com/new.rar 新人創(chuàng)作打卡挑戰(zhàn)賽發(fā)博客就能抽獎(jiǎng)!定制產(chǎn)品紅包拿不停!

總結(jié)

以上是生活随笔為你收集整理的VC++ WIN32 sdk实现按钮自绘详解.的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。