在Windows95/98中實現蘋果窗口界面
發表于:2007-07-14來源:作者:點擊數:
標簽:
高波 馬惠業 有沒有想過在 Windows 環境下實現蘋果電腦窗口界面的風格?下面就以實現蘋果電腦窗口風格為例,進行一次奇妙的旅行。 原 理 仔細觀察蘋果窗口,發現和Windows窗口的區別主要體現在標題欄和控制按鈕(即最小化、恢復、關閉按鈕)。所以我們應該把
高波 馬惠業
有沒有想過在
Windows環境下實現蘋果電腦窗口界面的風格?下面就以實現蘋果電腦窗口風格為例,進行一次奇妙的旅行。
原 理
仔細觀察蘋果窗口,發現和Windows窗口的區別主要體現在標題欄和控制按鈕(即最小化、恢復、關閉按鈕)。所以我們應該把主要精力集中在這兩點上,直接對Windows窗口已有的標題欄和控制按鈕進行修改。
由于標題欄和控制按鈕都屬于非客戶區,所以關鍵是獲得非客戶區的CDC,可以通過GetWindowDC()來獲得。GetWindowDC()可以獲得整個窗口的CDC,當然也包括非客戶區的CDC,得到此CDC后,確定標題條的確切位置,就可以在標題欄上為所欲為了。如圖1所示,在標題欄的位置裝入一幅位圖(截取了蘋果窗口的一幅位圖),在位圖上加上文字標題(此標題具有3D效果,感覺還不錯吧,其實就是把相同的字用不同的顏色和坐標寫了兩次)和控制按鈕(實際也是一幅位圖,只不過在鼠標單擊時顯示另一幅位圖,看起來就像是一個按鈕),由于控制按鈕是自己加的,所以要由自己負責單擊按鈕的處理。到此為止,雖然準備好了窗口的標題欄和按鈕,但還沒有機會顯示。我們知道要在窗口的客戶區上畫東東,只需響應Windows的客戶區重畫消息,在此消息處理函數中實現具體的操作。同理,要在非客戶區上畫東東,也只需響應Windows的非客戶區重畫消息,在消息處理函數中完成標題欄和按鈕的繪制。
具體實現
采用VC6.0在Windows98下實現這種技術。
下面以生成一個蘋果界面風格的對話框為例對這種方法進行詳細的闡述。
1、用APPWIZARD(應用程序向導)生成一個新的應用程序(SDI與MDI均可),在 RESOURCE VIEW里面添加一個DIALOG資源。
2、添加一個新的對話框類。在ClassWizard中選擇添加新類,輸入類名CTestDlg并且選取基類CDIALOG。這樣就建立起對話框類和對話框資源之間的聯系。
3、在RESOURCE VIEW 中加入按鈕和標題欄和背景位圖。
在主菜單中的INSERT 菜單項下面選擇RESOURCE,然后選擇添加BITMAP,這樣你就可以在RESOURCEVIEW 中看到BITMAP項,下面點擊鼠標右鍵,選擇IMPORT,從已有的位圖文件中選出蘋果風格的按鈕和標題欄,并且分別賦予不同的ID。
4、在自己創建的CTestDlg類中添加新的按鈕和新的標題欄。
(1)首先在CTestDlg的構造函數中裝入位圖資源。程序如下:
CTestDlg::CTestDlg(int nID,
CWnd* pParent /*=NULL*/)
: CDialog(nID, pParent)
{
//{{AFX_DATA_INIT(CTestDlg)
// NOTE: the ClassWizard will add
member initialization here
//}}AFX_DATA_INIT
m_bPressed=FALSE;
//load the bitmap of button_down
m_bitmapPressed.LoadBitmap(IDB_BUTTONDOWN);
//load the bitmap of button_up
m_bitmapUnpressed.LoadBitmap(IDB_BUTTONUP);
//load the bitmap of caption
m_bitmapCaption.LoadBitmap(IDB_CAPTION);
//load the bitmap of background
m_bmpBk.LoadBitmap(IDB_BKGROUND);
}
(2)分別得到標題欄和按鈕的位置。
首先得到按鈕的位置:
void CTestDlg::GetButtonRect(CRect& rect)
{
GetWindowRect(&rect);
// for small caption use SM_CYDLGFRAME
rect.top += GetSystemMetrics(SM_CYFRAME)+1;
// for small caption use SM_CYSMSIZE
rect.bottom =rect.top +GetSystemMetrics
(SM_CYSIZE)-4;
// for small caption use SM_CXDLGFRAME
rect.left =rect.right -GetSystemMetrics
(SM_CXFRAME) -
// for small caption use SM_CXSMSIZE
GetSystemMetrics(SM_CXSIZE))-1;
// for small caption use SM_CXSMSIZE
rect.right =rect.left +GetSystemMetrics
(SM_CXSIZE)-3;
}
然后得到標題欄的位置:
void CTestDlg::GetCaptionRect(CRect &rect)
{
GetWindowRect(&rect);
// for small caption use SM_CYSMSIZE
rect.bottom =rect.top +GetSystemMetrics
(SM_CYSIZE)+3;
}
5.在按鈕和標題欄對應的位置上分別畫出蘋果風格的按鈕和標題欄。
首先畫出按鈕:
void CTestDlg::DrawButton()
{
// if window isn't visible or is minimized, skip
if (!IsWindowVisible() || IsIconic())
return;
// get appropriate bitmap
CDC memDC;
CDC* pDC = GetWindowDC();
memDC.CreateCompatibleDC(pDC);
memDC.SelectObject(m_bPressed ?
&m_bitmapPressed : &m_bitmapUnpressed);
// get button rect and convert it into non
-client area coordinates
CRect rect, rectWnd;
GetButtonRect(rect);
GetWindowRect(rectWnd);
rect.OffsetRect(-rectWnd.left, -rectWnd.top);
int width,height;
BITMAP *pBitMap;
pBitMap = new BITMAP;
if (m_bPressed)
m_bitmapPressed.GetBitmap(pBitMap);
else
m_bitmapUnpressed.GetBitmap(pBitMap);
width=pBitMap->bmWidth;
height=pBitMap->bmHeight;
// draw it
pDC->StretchBlt( rect.left, rect.top, rect.Width(),
rect.Height(), &memDC, 0, 0,
width,height,SR
CCOPY );
memDC.DeleteDC();
ReleaseDC(pDC);
delete pBitMap;
}
然后畫出標題欄:
void CTestDlg::DrawCaption()
{
if (!IsWindowVisible() || IsIconic())
return;
// get appropriate bitmap
CDC memDC;
CDC* pDC = GetWindowDC();
memDC.CreateCompatibleDC(pDC);
memDC.SelectObject(m_bitmapCaption);
// get button rect and convert it into non
-client area coordinates
CRect rect, rectWnd;
GetCaptionRect(rect);
GetWindowRect(rectWnd);
rect.OffsetRect(-rectWnd.left, -rectWnd.top);
// draw the caption
int width,height;
BITMAP *pBitMap;
pBitMap = new BITMAP;
m_bitmapCaption.GetBitmap(pBitMap);
width=pBitMap->bmWidth;
height=pBitMap->bmHeight;
pDC->StretchBlt( rect.left, rect.top, rect.Width(),
rect.Height(), &memDC, 0, 0, width,
height, SRCCOPY );
//get the the text of the caption and
draw it with 3D style
pDC->SetBkColor(RGB(209,209,209));
CString caption;
GetWindowText(caption);
caption = “ "+caption+“ ";
rect.OffsetRect(0,4);
//draw the text of the caption with gray color
pDC->SetTextColor(RGB(128,128,128));
pDC->DrawText
(caption,rect,DT_CENTER|DT_VCENTER);
//move the coordinate to left and up
rect.OffsetRect(-1,-1);
pDC->SetBkMode(TRANSPARENT);
//draw the text of the caption with white color
pDC->SetTextColor(RGB(255,255,255));
//255,255,255 128,128,128
pDC->DrawText
(caption,rect,DT_CENTER|DT_VCENTER);
memDC.DeleteDC();
ReleaseDC(pDC);
delete pBitMap;
}
6.處理鼠標點擊按鈕的消息。
要響應鼠標左鍵在標題欄上的單擊,需要添加相應的消息映射函數。
通過在OnNcLButtonDown中給關閉按鈕換一副圖像,來實現按鈕被按下的效果,同時完成窗口的關閉。
void CTestDlg::OnNcLButtonDown
(UINT nHitTest, CPoint point)
{
if (nHitTest == HTCAPTION)
{
// see if in area we reserved for button
CRect rect;
GetButtonRect(rect);
if (rect.PtInRect(point))
{
m_bPressed = !m_bPressed;
DrawButton();
CDialog::OnCancel();
}
}
CDialog::OnNcLButtonDown(nHitTest, point);
}
7.處理窗口非客戶區的重畫。
這里主要是對標題欄和按鈕的重畫。通過ClassWizard給對話框添加非客戶區重畫的消息映射函數。
void CTestDlg::OnNcPaint()
{
// draw caption first
CDialog::OnNcPaint();
// then draw button on top
DrawCaption();
DrawButton();
}
8.給對話框加上背景,在此為一幅位圖:
void CTestDlg::OnPaint()
{
CPaintDC dc(this);
// device context for painting
CDC memDC;
memDC.CreateCompatibleDC(&dc);
memDC.SelectObject(m_bmpBk);
CRect rect, rectWnd
GetWindowRect(rect);
GetClientRect(rect);
int width,height;
BITMAP *pBitMap;
pBitMap = new BITMAP;
m_bmpBk.GetBitmap(pBitMap);
width=pBitMap->bmWidth;
height=pBitMap->bmHeight;
dc.StretchBlt( rect.left, rect.top, rect.Width(),
rect.Height(),
&memDC, 0, 0,width,height, SRCCOPY );
}
至此為止,一個具有蘋果窗口風格的對話框就新鮮出爐了!怎么樣?味道還不錯吧?
但是,如果每次要用到對話框的時候都如此這般,豈不是太...那個了吧!不要驚慌,只需稍做改變就可一勞永逸了。將此對話框的構造函數的說明部分改為下面黑體所示即可,就這么簡單。(用黑體表示強調的部分)
CTestDlg::CTestDlg(int nID, CWnd
* pParent /*=NULL*/)
: CDialog(nID, pParent)
{
//{{AFX_DATA_INIT(CTestDlg)
// NOTE: the ClassWizard will add
member initialization here
//}}AFX_DATA_INIT
m_bPressed=FALSE;
m_bitmapPressed.LoadBitmap
(IDB_BUTTONDOWN);
m_bitmapUnpressed.LoadBitmap
(IDB_BUTTONUP);
m_bitmapCaption.LoadBitmap(IDB_CAPTION);
m_bmpBk.LoadBitmap(IDB_BKGROUND);
m_brushButton.CreateSolidBrush
(RGB(192,192,255));
}
以后,凡是用到對話框的時候,在VC的資源編輯器中把對話框設置好,把父類改為此對話框類即可,當然,要把此對話框類包括在你的Project中,圖1所示的對話框就是繼承于此對話框。
在CMyDialog的.h文件中將CDialog 改為CTestDlg:
Class CMyDialog: public CTestDlg
void CNewapple1Doc::OnDialog1()
{
// TODO: Add your command handler code here
CMyDialog dlg;
dlg.DoModal();
}
原文轉自:http://www.anti-gravitydesign.com