在眾多的Windows軟件中,位圖按鈕(BitmapButton)確實是一個相當重要的角色。與普通按鈕相比,它以圖形代替文字,形象直觀,使畫面更加活潑,使人機界面更加友善。筆者在用Visual C++編制軟件時,經常用到位圖按鈕。但在編制的過程中,發現它也還存在著美中不足的地方。
一、問題的提出
我們在上Internet時,經常使用各種浏覽器,例如IE或Netscape,它在工具條上的位圖按鈕不能不給使用者留下深刻印象。當鼠標未觸及時,正常狀態下的位圖按鈕只是平面圖形;一旦觸及,它立即“浮現”出來,一方面提示用戶,另一方面其色彩以及立體感的反差也給人以耳目一新的感覺。而現在眾多用Visual C++編寫的軟件中,位圖按鈕在觸及前後並不改變,盡管它較普通的按鈕已有很大的進步,但仍不免顯得有些呆板,缺乏“動感”。本文試利用位圖按鈕的“獲得輸入狀態”(focused)與鼠標操作相結合加以解決。
二、解決的方法及相關函數
Microsoft基本類庫(MFC)提供CBitmapButton類,其常用的成員函數有AutoLoad和LoadBitmaps。下面簡略加以介紹:
1. BOOL AutoLoad( UINT nID, CWnd* pParent );
該函數將一個普通按鈕與一個CBitmapButton類對象聯系起來。
BOOL LoadBitmaps( LPCSTR lpszBitmapResource, LPCSTR lpszBitmapResourceSel = NULL, LPCSTR lpszBitmapResourceFocus = NULL, LPCSTR lpszBitmapResourceDisabled = NULL );
位圖按鈕具有四種狀態:正常(U)狀態,按下(D)狀態,獲得輸入(F)狀態, 禁止(X)狀態。其中F狀態並不常用。
該函數將CBitmapButton類對象的上述四種狀態與四個位圖文件相對應,其中參數:
lpszBitmapResource是位圖按鈕正常狀態(U)下的位圖文件名。
lpszBitmapResourceSel 是位圖按鈕按下狀態(D)下的位圖文件名。
lpszBitmapResourceFocus 是位圖按鈕獲得輸入狀態(F)下的位圖文件名。
lpszBitmapResourceDisabled 是位圖按鈕禁止狀態(X)下的位圖文件名。
SetCapture( )和 ReleaseCapture( )
SetCapture()對鼠標進行”捕捉”,即使鼠標光標已經移出該窗口,窗口仍能夠接受到所有有關鼠標的消息。ReleaseCapture( )則用來釋放對鼠標的捕捉。
當鼠標觸及但尚未按下時,並不對應其中任何一種狀態,可見VC++並不提供相應的機制,以解決本文所提出的問題。本程序利用鼠標在該位圖按鈕所在范圍移動時,將其設置成獲得輸入狀態,調入第三資源文件“F”位圖文件加以實現。在鼠標觸及該位圖時,使之“浮現”出來,並將鼠標光標變成小手形狀,再加以振鈴以示提醒。同時由於使用SetCapture()函數,故需要對鼠標的各種操作進行設計。主要程序段如下。
三、主要程序段
筆者編寫了一個小演示程序,簡單模擬電器開關功能。它有兩個位圖按鈕和一個用作狀態顯示屏的編輯控制框。當鼠標位於位圖按鈕之上時,狀態顯示屏均顯示"鼠標的光標在位圖按鈕上"。電源開關開時,按“喇叭”位圖按鈕則會發聲;否則“喇叭”位圖按鈕變灰,不起作用。
void CBmpDlg::OnMouseMove(UINT nFlags, CPoint point)
{
CWnd * pWnd;
HCURSOR MyCursor;
CRgn m_regionPower; //Region of POWER Button
CRgn m_regionPlay; //Region of PLAY Button
//建立位圖按鈕的矩形區域
m_regionPower.CreateEllipticRgnIndirect(CRect(27,56,72,92));
m_regionPlay.CreateEllipticRgnIndirect(CRect(78,56,120,92));
CString ShowString0 = "鼠標的光標在位圖按鈕上!!!";
… … … …
m_bPlay = FALSE;
m_bPower= FALSE;
if (m_regionPower.PtInRegion(point)) //鼠標落在位圖按鈕之上
{
m_bPower = TRUE;
//將位圖按鈕設置成獲得輸入狀態
pWnd= GetDlgItem(IDC_BUTTON_POWER);
pWnd->SetFocus();
SetCapture();
InputEdit().SetWindowText(ShowString0);
InputEdit().ShowWindow(TRUE);
//將鼠標光標變成小手形狀
MyCursor = AfxGetApp()->LoadCursor(IDC_MYCURSOR);
::SetCursor(MyCursor);
VERIFY(m_Play.LoadBitmaps("PLAYU","PLAYD","PLAYF","PLAYX"));
m_bPressedPlay = FALSE;
return;
}
if (m_regionPlay.PtInRegion(point)) //鼠標落在位圖按鈕之上
{
if (m_bPowerOn) { //如果電源已被開啟
m_bPlay = TRUE;
pWnd= GetDlgItem(IDC_BUTTON_PLAY);
pWnd->SetFocus();
SetCapture();
InputEdit().SetWindowText(ShowString0);
InputEdit().ShowWindow(TRUE);
MyCursor = AfxGetApp()->LoadCursor(IDC_MYCURSOR);
::SetCursor(MyCursor);
VERIFY(m_Power.LoadBitmaps("POWERONU","POWEROND","POWERONF"));
}
else { //如果電源已被關閉
ReleaseCapture();
InputEdit().SetWindowText(ShowString0+ShowString2);
InputEdit().ShowWindow(TRUE);
VERIFY(m_Power.LoadBitmaps("POWEROFU","POWEROFD","POWEROFF"));
}
m_bPressedPower= FALSE;
return;
}
//鼠標落在所有的位圖按鈕之外
ReleaseCapture();
InputEdit().SetWindowText(ShowString1);
InputEdit().ShowWindow(TRUE);
pWnd= GetDlgItem(IDOK);
pWnd->SetFocus();
VERIFY(m_Play.LoadBitmaps("PLAYU","PLAYD","PLAYF","PLAYX"));
if (m_bPowerOn)
VERIFY(m_Power.LoadBitmaps("POWERONU","POWEROND","POWERONF"));
else
VERIFY(m_Power.LoadBitmaps("POWEROFU","POWEROFD","POWEROFF"));
m_bPressedPlay = FALSE;
m_bPressedPower= FALSE;
CDialog::OnMouseMove(nFlags, point);
}
void CBmpDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
CWnd *pWnd;
if (m_bPlay && m_bPowerOn) {
// Change Focus so as to Change the bitmap of m_Play
pWnd= GetDlgItem(IDOK);
pWnd->SetFocus();
VERIFY(m_Play.LoadBitmaps("PLAYD"));
m_Play.UpdateWindow();
m_Play.Invalidate(TRUE);
OnButtonPlay();
m_bPressedPlay = TRUE;
}
if (m_bPower== TRUE) {
// Change Focus so as to Change the bitmap of m_Power
pWnd= GetDlgItem(IDOK);
pWnd->SetFocus();
if (m_bPowerOn)
VERIFY(m_Power.LoadBitmaps("POWEROND"));
else
VERIFY(m_Power.LoadBitmaps("POWEROFD"));
m_Power.UpdateWindow();
m_Power.Invalidate(TRUE);
OnButtonPower();
m_bPressedPower = TRUE;
}
CDialog::OnLButtonDown(nFlags, point);
}
void CBmpDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
CWnd * pWnd;
if (m_bPressedPlay == TRUE) {
pWnd= GetDlgItem(IDOK);
pWnd->SetFocus();
VERIFY(m_Play.LoadBitmaps("PLAYF"));
m_Play.UpdateWindow();
m_Play.Invalidate(TRUE);
m_bPressedPlay = FALSE;
}
if (m_bPressedPower == TRUE) {
pWnd= GetDlgItem(IDOK);
pWnd->SetFocus();
if (m_bPowerOn)
VERIFY(m_Power.LoadBitmaps("POWERONF"));
else
VERIFY(m_Power.LoadBitmaps("POWEROFF"));
m_Power.UpdateWindow();
m_Power.Invalidate(TRUE);
m_bPressedPower = FALSE;
}
CDialog::OnLButtonUp(nFlags, point);
}