明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

用VC完成對(duì)屬性表按鈕區(qū)的位圖繪制

[摘要]作者: 徐毅 許潤(rùn)濤 王宇 摘 要:本文通過詳細(xì)討論如何用VC實(shí)現(xiàn)對(duì)屬性表按鈕區(qū)的操作以改變屬性頁(yè)的外觀,從而提供一種對(duì)Windows應(yīng)用程序的非窗口客戶區(qū)進(jìn)行繪制的方法,并給出了一個(gè)簡(jiǎn)單的示例程序。 關(guān)鍵字:屬性表類、非窗口區(qū)、位圖 屬性表類(CPropertySheet Class)在編寫Wi...
作者: 徐毅 許潤(rùn)濤 王宇

摘 要:本文通過詳細(xì)討論如何用VC實(shí)現(xiàn)對(duì)屬性表按鈕區(qū)的操作以改變屬性頁(yè)的外觀,從而提供一種對(duì)Windows應(yīng)用程序的非窗口客戶區(qū)進(jìn)行繪制的方法,并給出了一個(gè)簡(jiǎn)單的示例程序。



關(guān)鍵字:屬性表類、非窗口區(qū)、位圖



屬性表類(CPropertySheet Class)在編寫Windows應(yīng)用程序時(shí)使用非常廣泛,如編寫安裝向?qū)С绦、?yīng)用程序配置等很多應(yīng)用程序都必須使用屬性表類,但是如何實(shí)現(xiàn)用VC對(duì)屬性表類的按鈕區(qū)進(jìn)行繪制卻是一個(gè)比較困難的問題。因?yàn)閂C的MFC類庫(kù)封裝了屬性表類,使得其外觀表現(xiàn)一般不容易改變。而在編寫應(yīng)用程序的過程中卻常常遇到要在屬性表的按鈕區(qū)域進(jìn)行繪制的問題,如在屬性表按鈕區(qū)加入公司的標(biāo)識(shí)等等。屬性表按鈕區(qū)是非窗口客戶區(qū),因此要對(duì)其直接進(jìn)行繪制需要采用一些特殊的處理。我們?cè)趯?shí)際編程開發(fā)過程中,對(duì)此問題進(jìn)行了一些探索。下面我們通過示例說明在VC5.0環(huán)境下實(shí)現(xiàn)對(duì)屬性頁(yè)按鈕區(qū)域位圖繪制的方法。



1、 實(shí)現(xiàn)非窗口區(qū)域繪制的基本思想:

要完成對(duì)屬性表按鈕區(qū)域(即非窗口客戶區(qū))的操作,必須得到相關(guān)的繪圖設(shè)備環(huán)境(CPaint DC),找出按鈕區(qū)域的具體位置,才能夠?qū)ζ溥M(jìn)行操作。為此,需要對(duì)MFC的CPropertySheet類進(jìn)行繼承,對(duì)其繼承類的OnPaint消息處理函數(shù)進(jìn)行重載,在OnPaint消息處理函數(shù)中,直接以當(dāng)前指針為變量定義一個(gè)設(shè)備環(huán)境對(duì)象,這就是我們所需的繪圖設(shè)備環(huán)境,再找出屬性表類的制表控件(table control)客戶區(qū)位置和屬性表類的缺省按鈕位置,就能夠計(jì)算出按鈕區(qū)域的具體位置。只要完成上述兩步,對(duì)屬性表按鈕區(qū)的操作也就不難實(shí)現(xiàn)了。



2.示例程序具體實(shí)現(xiàn)

首先,用VC的Wizard代碼生成器生成一個(gè)MFC應(yīng)用程序框架,在自動(dòng)生成的過程中,選擇應(yīng)用程序是基于對(duì)話框的程序。當(dāng)生成完畢后,在將自動(dòng)生成的對(duì)話框類全部刪除。再手動(dòng)添加一個(gè)從CPropertySheet類繼承的子類CPropertySheetWithLogoDlg類和一個(gè)基于CDialog類的CFirstPropertyPage類,同時(shí)在程序App類的InitInstance方法中刪除關(guān)于自動(dòng)生成的對(duì)話框類的代碼。并加入如下代碼:

CPropertySheetWithLogoDlg dlg("屬性表按鈕區(qū)繪制");

CFirstPropertyPage FirstPage; //進(jìn)行類的實(shí)例化

dlg.SetLogoText("Example Vision"); //對(duì)要在按鈕區(qū)域繪制的字符串進(jìn)行賦值

dlg.AddPage(&FirstPage); //向?qū)傩员碇刑砑訉傩皂?yè)

int nResponse = dlg.DoModal();

if (nResponse == IDOK){}

else if (nResponse == IDCANCEL){}

return FALSE;

這段代碼使由Wizard代碼生成器生成的應(yīng)用程序的主框架(mainframe)成為一個(gè)屬性表。其中SetLogoText是CPropertySheetWithLogoDlg類的用戶自定義方法,它是給寫在屬性表按鈕區(qū)的字符串賦值。

下面就是如何對(duì)按鈕區(qū)域進(jìn)行操作。屬性表按鈕區(qū)是非窗口客戶區(qū),因此我們不能通過重載CPropertySheetWithLogoDlg類的OnDraw方法來直接對(duì)屬性表按鈕區(qū)進(jìn)行操作。而必須重載CPropertySheetWithLogoDlg類的OnPaint方法。其具體實(shí)現(xiàn)代碼如下:

void CPropertySheetWithLogoDlg::OnPaint()

{

CPaintDC dc(this); //獲得繪制的設(shè)備環(huán)境。

if(m_LogoText.IsEmpty())//判斷字符串是否為空。

return;

CRect rectTabCtrl;

GetTabControl()->GetWindowRect(rectTabCtrl);//獲得屬性表的制表控件的客戶區(qū)屏幕坐標(biāo)。

ScreenToClient(rectTabCtrl);//屏幕坐標(biāo)轉(zhuǎn)換為窗口邏輯坐標(biāo)。

CRect rectOk;

GetDlgItem(IDOK)->GetWindowRect(rectOk);//獲得客戶區(qū)最左按鈕屏幕坐標(biāo)。

ScreenToClient(rectOk); //屏幕坐標(biāo)轉(zhuǎn)換為窗口邏輯坐標(biāo)。

dc.SetBkMode(TRANSPARENT);//背景模式設(shè)為透明。

CRect rectText;

rectText.left = rectTabCtrl.left;

rectText.top = rectOk.top;

rectText.bottom = rectOk.bottom;

rectText.right = rectOk.left;//獲得所需繪制按鈕區(qū)窗口邏輯坐標(biāo)。

CFont * OldFont = dc.SelectObject(&m_fontLogo);//選擇所需字體。

COLORREF OldColor = dc.SetTextColor( ::GetSysColor( COLOR_3DHILIGHT));//設(shè)置文本顏色。

dc.DrawText( m_LogoText, rectText + CPoint(1,1), DT_SINGLELINE DT_LEFT DT_VCENTER);//顯示字符串。

dc.SetTextColor( ::GetSysColor( COLOR_3DSHADOW));

dc.DrawText( m_LogoText, rectText, DT_SINGLELINE DT_LEFT DT_VCENTER);//顯示字符串3D陰影。

dc.SetTextColor( OldColor);//恢復(fù)原文本顏色。

dc.SelectObject(OldFont);//恢復(fù)原字體。

}

在這段代碼中,首先通過定義一個(gè)以thhis指針為變量的CPaintDC變量dc得到當(dāng)前繪圖設(shè)備環(huán)境。然后是要找出按鈕區(qū)的具體位置。按鈕區(qū)操作的位置實(shí)際就是屬性表的制表控件客戶區(qū)的最左端直到第一個(gè)按鈕最左端為此的區(qū)域。也就是說,先需要得到屬性表制表控件的指針,這可用CPropertySheet類的方法GetTabCtrl()得到。再通過WIN32API函數(shù)GetWindowRect()得到控件客戶區(qū)的屏幕坐標(biāo)。然后得到用GetDlgItem(IDOK)->GetWindowRect()得到客戶區(qū)最左OK按鈕的屏幕坐標(biāo)。將它們都轉(zhuǎn)換為窗口邏輯坐標(biāo),以控件客戶區(qū)的左坐標(biāo)作為操作按鈕區(qū)的左坐標(biāo),以最左OK按鈕的上、下坐標(biāo)作為操作按鈕區(qū)的上、下坐標(biāo),以最左OK按鈕的左坐標(biāo)作為操作按鈕區(qū)的右坐標(biāo)。就得到了所需按鈕區(qū)的具體位置。最后只需再選擇字體和文本顏色,用DrawText() 進(jìn)行顯示即可在屬性表按鈕區(qū)繪出字符串。

如果我們要在按鈕區(qū)顯示一幅位圖,只須對(duì)以上代碼作出很少修改,具體代碼如下:

CBitmap bmp, *poldbmp;

CDC memdc;

CRect rect;

bmp.LoadBitmap(IDB_BITMAPLOGO); //載入位圖資源。

memdc.CreateCompatibleDC(&dc);//生成一個(gè)與當(dāng)前設(shè)備環(huán)境兼容的內(nèi)存設(shè)備環(huán)境。

poldbmp = memdc.SelectObject(&bmp);//將位圖寫入內(nèi)存設(shè)備環(huán)境。

GetClientRect(&rect);//獲得屬性表客戶區(qū)的大小



//從內(nèi)存設(shè)備環(huán)境向屏幕挎貝位圖。

dc.BitBlt(left, rect.bottom - lower, w, h, &memdc, 0, 0, SRCCOPY);

//w,h為位圖的寬度和高度。Left為位圖距屬性頁(yè)左邊框的距離,lower 為位圖距下邊框的距離。

memdc.SelectObject(poldbmp);

通過引入位圖資源,再將其選入內(nèi)存設(shè)備環(huán)境,最后用BitBlt函數(shù)顯示到實(shí)際設(shè)備環(huán)境,我們就在按鈕區(qū)繪出了所選位圖。這一步驟與其它在正常窗口顯示位圖的方法是基本一致的。

3.實(shí)現(xiàn)所需注意問題

需要注意的是,屬性表有兩種模式,一種是正常屬性表模式,另一種是向?qū)J剑╓izard)。我們可以通過加入如下代碼檢測(cè)屬性表的模式:

BOOL bWizMode;

//從PROPSHEETHEADER 結(jié)構(gòu)中得到當(dāng)前屬性表的模式。

if( m_psh.dwFlags & PSH_WIZARD )

bWizMode = TRUE; //是向?qū)J?

else

bWizMode = FALSE; // 是正常屬性表模式

其中,m_psh是CPropertySheet類的公有成員變量,它是PROPSHEETHEADER結(jié)構(gòu),可以通過訪問該成員變量獲取屬性表的基本屬性。

在正常屬性表模式下,上述獲取屬性表按鈕區(qū)位置的方法可以正確通過。而在向?qū)J较,屬性表沒有制表控件,無法得到制表控件客戶區(qū)位置。在這時(shí),需要用屬性表對(duì)話框窖口代替控件客戶區(qū)?稍谠a中加入如下代碼:

if( bWizMode ) {

GetWindowRect(rectTabCtrl); //得到對(duì)話框窗口屏幕坐標(biāo)。

rectTabCtrl.OffsetRect(14,0); // 對(duì)窗口位置校正

}

else{

GetTabControl()->GetWindowRect(rectTabCtrl);

}

通過以上代碼,我們就能夠正確得到屬性表按鈕區(qū)域位置。

4.結(jié)論

由上述討論可知,對(duì)于屬性表按鈕區(qū)進(jìn)行操作,關(guān)鍵是要了解對(duì)非窗口客戶區(qū)進(jìn)行繪制是不同于在一般窗口繪制的過程時(shí),在一般窗口繪制位圖或?qū)懭胱址麜r(shí),只需重載窗口類的OnDraw方法,而對(duì)非窗口客戶區(qū)進(jìn)行繪制時(shí),必須重載OnPaint函數(shù)。這一法則適用于對(duì)任何非窗口客戶區(qū)的操作。



參考文獻(xiàn)

1.Microsoft Widnows 95 開發(fā)者必讀 翟炯 石秋云譯 電子工業(yè)出版社 1997年2月。

2.Visual C++開發(fā)指南 屠強(qiáng)等譯 電子工業(yè)出版社 1998年1月