MFC實現漂亮界面之美化按鈕
上次我們學習了如何美化對話框的界面,這次我們?yōu)樯洗蔚膶υ捒蛱砑觾蓚€按鈕,一個是關閉按鈕,另一個是最小化按鈕,好,現在我們先看一下效果:
是不是很難看,因為我們的對話框美化了,所以我們的按鈕也要美化,因為采用貼圖的方式來美化,所以,我先給出這兩個按鈕的PNG格式的圖片,該圖片支持透明色,具體如下:
關閉按鈕效果圖:
最小化按鈕效果圖:
這兩張效果圖是我自己從網上找的,可能不是很合適,但是用來教學,完全沒有問題,它們的尺寸都是108*21,每張圖片都有四個小圖片,第一張和第四張小圖片都是透明的,所以看不見效果,我們使用這兩張圖片來完成按鈕的美化,每張圖片從左向右有四張小圖片,我們只用前三張,分別對應默認狀態(tài),焦點狀態(tài),按下狀態(tài)。
下面,我們來說一下如何美化按鈕?
第1步,我們先在對話框上放置兩個按鈕,一個是關閉按鈕,另一個是最小化按鈕,它們對應的ID分別是IDC_BUTTON_CLOSE和IDC_BUTTON_MIN,然后將我們的按鈕設置為自繪制模式,方法如下:
選擇按鈕,右鍵屬性,在屬性列表中找到Owner Draw選項,將其設置為True,效果圖如下:
再為它們添加兩個成員變量,具體如下:
CButton m_btnClose; CButton m_btnMin;
第2步,我們新建一個類,繼承自CButton,我們取名為CMyButton,為其添加3個成員變量,分別如下:
//按鈕背景圖像 CImage m_imgButton; //按鈕png路徑,包括焦點,正常,按下3個狀態(tài) CString m_strImgPath; //父窗口背景圖片背景路徑,透明png需要使用 CString m_strImgParentPath;
第3步,我們?yōu)镃MyButton添加3個成員函數,分別如下:
//設置按鈕背景圖片路徑,父窗口背景圖片路徑 void SetImagePath(CString strImgPath, CString strParentImgPath); //初始化按鈕,主要是調整按鈕的位置,處理透明色 bool InitMyButton(int nX/*左上角X坐標*/, int nY/*左上角Y坐標*/,int nW/*圖像寬*/, int nH/*圖像高*/, bool bIsPng/*是否是PNG圖片*/); //自繪制函數 void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
CMyButton的聲明最終如下:
class CMyButton : public CButton
{
DECLARE_DYNAMIC(CMyButton)
public:
CMyButton();
virtual ~CMyButton();
//按鈕背景圖像
CImage m_imgButton;
//按鈕png路徑,包括焦點,正常,按下3個狀態(tài)
CString m_strImgPath;
//父窗口背景圖片背景路徑,透明png需要使用
CString m_strImgParentPath;
//設置按鈕背景圖片路徑,父窗口背景圖片路徑
void SetImagePath(CString strImgPath, CString strParentImgPath);
//初始化按鈕,主要是調整按鈕的位置,處理透明色
bool InitMyButton(int nX/*左上角X坐標*/, int nY/*左上角Y坐標*/,int nW/*圖像寬*/, int nH/*圖像高*/, bool bIsPng/*是否是PNG圖片*/);
//自繪制函數
void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
protected:
DECLARE_MESSAGE_MAP()
};
第4步,我們實現SetImagePath函數,它的功能是為按鈕背景圖片和父窗口背景圖片成員函數初始化,具體如下:
void CMyButton::SetImagePath(CString strImgPath, CString strParentImgPath)
{
m_strImgPath = strImgPath;
m_strImgParentPath = strParentImgPath;
}
第5步,我們實現InitMyButton函數,它的功能是調整按鈕在對話框上的位置,其中的參數代表該按鈕在父窗口的左上角X坐標,Y坐標,寬度,高度,最后一個參數是為PNG格式圖片準備的,如果是PNG帶透明色的圖片,需要對它進行特殊處理,具體定義如下:
bool CMyButton::InitMyButton(int nX, int nY, int nW, int nH, bool bIsPng)
{
HRESULT hr = 0;
if (m_strImgPath.IsEmpty())
return false;
hr = m_imgButton.Load(m_strImgPath);
if (FAILED(hr))
return false;
if (bIsPng)
{
if (m_imgButton.GetBPP() == 32)
{
int i = 0;
int j = 0;
for (i = 0; i < m_imgButton.GetWidth(); i++)
{
for (j = 0; j < m_imgButton.GetHeight(); j++)
{
byte * pbyte = (byte *)m_imgButton.GetPixelAddress(i, j);
pbyte[0] = pbyte[0] * pbyte[3] / 255;
pbyte[1] = pbyte[1] * pbyte[3] / 255;
pbyte[2] = pbyte[2] * pbyte[3] / 255;
}
}
}
}
MoveWindow(nX,nY,nW,nH);
return true;
}
其中MoveWindow函數是用來調整按鈕位置的函數,其中的參數分別代表其在父窗口的左上角X坐標,左上角Y坐標,寬度,高度。
第6步,我們實現DrawItem函數,它是美化Button的核心函數,當我們將Button設置為自繪制后,每次按鈕需要刷新,重新繪制的時候,MFC框架會調用它的DrawItem函數,在這個函數中,我們可以根據按鈕當前的狀態(tài)為其貼上相應的背景圖。當我們按鈕按鈕的時候,為其貼上被按下的背景圖;當我們的按鈕獲取焦點的時候,為其貼上獲取焦點的背景圖;當我們的按鈕沒有焦點,我們?yōu)槠滟N上默認的背景圖片,它們對應的位置前面已經說過。為了避免閃爍,我們采用雙緩沖的方式,具體代碼如下:
void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
if (!lpDrawItemStruct)
return;
HDC hMemDC;
HBITMAP bmpMem;
HGDIOBJ hOldObj;
bmpMem = CreateCompatibleBitmap(lpDrawItemStruct->hDC, lpDrawItemStruct->rcItem.right - lpDrawItemStruct->rcItem.left, lpDrawItemStruct->rcItem.bottom - lpDrawItemStruct->rcItem.top);
if (!bmpMem)
return;
hMemDC = CreateCompatibleDC(lpDrawItemStruct->hDC);
if (!hMemDC)
{
if (bmpMem)
{
::DeleteObject(bmpMem);
bmpMem = NULL;
}
return;
}
hOldObj = ::SelectObject(hMemDC, bmpMem);
RECT rectTmp = { 0 };
rectTmp = lpDrawItemStruct->rcItem;
MapWindowPoints(GetParent(), &rectTmp);
int nW = lpDrawItemStruct->rcItem.right - lpDrawItemStruct->rcItem.left;
int nH = lpDrawItemStruct->rcItem.bottom - lpDrawItemStruct->rcItem.top;
if (lpDrawItemStruct->itemState & ODS_SELECTED)
{
//按鈕被選擇
m_imgButton.BitBlt(hMemDC, 0, 0, nW, nH, nW*2, 0, SRCCOPY);
}
else if (lpDrawItemStruct->itemState & ODS_FOCUS)
{
//焦點狀態(tài)
m_imgButton.BitBlt(hMemDC, 0, 0, nW, nH, nW, 0, SRCCOPY);
}
else
{
//默認狀態(tài)
CImage imgParent;
imgParent.Load(m_strImgParentPath);
imgParent.Draw(hMemDC, 0, 0, nW, nH, rectTmp.left, rectTmp.top, nW, nH);
m_imgButton.AlphaBlend(hMemDC, 0, 0, nW, nH, 0, 0, nW, nH);
imgParent.Destroy();
}
::BitBlt(lpDrawItemStruct->hDC, 0, 0, nW, nH, hMemDC, 0, 0, SRCCOPY);
SelectObject(hMemDC, hOldObj);
if (bmpMem)
{
::DeleteObject(bmpMem);
bmpMem = NULL;
}
if (hMemDC)
{
::DeleteDC(hMemDC);
hMemDC = NULL;
}
return;
}
這里我們重點說一下默認狀態(tài)的背景圖,因為它是透明的,并且我們采用的是雙緩沖,所以,為了避免最終透明色變成黑色,我們先在內存DC上貼上按鈕在父窗口位置的背景圖,這樣可以解決透明色變成黑色的問題,如果你采用GDI+,就不用這么做,但是我們采用的是GDI。
第7步,用CMyButton替代對話框頭文件中的CButton。
第8步,在對話框的InitDialog中,對兩個按鈕進行初始化,具體如下:
m_btnMin.SetImagePath(_T("./res/btn_min.png"), _T("./res/Background.png"));
m_btnMin.InitMyButton(516, 8, 27, 21, true);
m_btnClose.SetImagePath(_T("./res/btn_close.png"),_T("./res/Background.png"));
m_btnClose.InitMyButton(545,8,27,21,true);
第9步,編譯程序,最終效果圖如下:
今天,我們已經為它添加了最小化,關閉按鈕,下次,我們?yōu)槠涮砑泳庉嬁颍?/p>
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持我們。
您可能感興趣的文章
- 01-10數據結構課程設計-用棧實現表達式求值的方法詳解
- 01-10使用OpenGL實現3D立體顯示的程序代碼
- 01-10求斐波那契(Fibonacci)數列通項的七種實現方法
- 01-10C語言 解決不用+、-、&#215;、&#247;數字運算符做加法
- 01-10使用C++實現全排列算法的方法詳解
- 01-10用C++實現DBSCAN聚類算法
- 01-10深入全排列算法及其實現方法
- 01-10全排列算法的非遞歸實現與遞歸實現的方法(C++)
- 01-10用C語言實現單鏈表的各種操作(一)
- 01-10用C語言實現單鏈表的各種操作(二)


閱讀排行
本欄相關
- 04-02c語言函數調用后清空內存 c語言調用
- 04-02func函數+在C語言 func函數在c語言中
- 04-02c語言的正則匹配函數 c語言正則表達
- 04-02c語言用函數寫分段 用c語言表示分段
- 04-02c語言中對數函數的表達式 c語言中對
- 04-02c語言編寫函數冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數 round c語言
- 04-02c語言分段函數怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數 c語言中怎
- 04-02c語言調用函數求fibo C語言調用函數求
隨機閱讀
- 04-02jquery與jsp,用jquery
- 01-10C#中split用法實例總結
- 01-11ajax實現頁面的局部加載
- 01-10SublimeText編譯C開發(fā)環(huán)境設置
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 08-05dedecms(織夢)副欄目數量限制代碼修改
- 01-10delphi制作wav文件的方法
- 08-05DEDE織夢data目錄下的sessions文件夾有什


