好的軟件有好的開(kāi)始,微軟VS IDE的起始界面做的實(shí)在不錯(cuò),色調(diào)和布局都是很舒服,這里我動(dòng)手實(shí)現(xiàn)了一個(gè),下面是過(guò)程。
第一步:用spy++工具觀察VS IDE開(kāi)始界面構(gòu)成。

通過(guò)spy++,可以看到開(kāi)始頁(yè)由一個(gè)大窗口,里面是位圖背景,在上面有一些靜態(tài)窗口,按鈕等,之間夾一個(gè)小視圖(例如最近的項(xiàng)目里面是一個(gè)listctrl)。基本就是這樣,實(shí)現(xiàn)思路就是用位圖貼在靜態(tài)小窗口構(gòu)成一個(gè)小的欄,中間放一個(gè)小的主視圖,比如項(xiàng)目列表、msdn新聞等。
第二步:收集位圖素材。我沒(méi)有那么好的藝術(shù)細(xì)胞畫(huà)這么好的小圖片,所以只得偷vs的。由于使用vc6,所以下面全部基于vc6環(huán)境來(lái)說(shuō)。用資源的方式打開(kāi)vs ide執(zhí)行文件(\Microsoft Visual Studio 8\Common7\IDE\devenv.exe),可以看到位圖資源基本全是起始頁(yè)的。

第三步:實(shí)現(xiàn)思路確定。有一些問(wèn)題,里面的圖片好像沒(méi)有主界面那么大的位圖,頭部好像不是太符合尺寸:

這下我的思路是先用背景色繪制窗口,然后貼圖。背景色可以用取色工具獲取,我用firework里面的工具。
還有一個(gè)問(wèn)題就是小欄位圖的四角有顏色:

貼到主窗口上去會(huì)留下與環(huán)境不相稱(chēng)的一點(diǎn)點(diǎn)多余的角,這里我在網(wǎng)上搜到一篇mask位圖的文章,基于此,把位圖四角的淡白色去掉。
還有就是中間的位圖太小:

我準(zhǔn)備采取重復(fù)繪制來(lái)填滿(mǎn)一定長(zhǎng)度,注意水平方向和垂直方向稍有不同,所以實(shí)現(xiàn)的時(shí)候要進(jìn)行判斷。
這樣基本敲打?qū)崿F(xiàn)方法,接著就動(dòng)手實(shí)現(xiàn)。
第四步:開(kāi)工。vc6建立一個(gè)單文檔基于formview的程序。
工序一:繪制背景
對(duì)話(huà)框的背景顏色可以通過(guò)重載OnCtlColor來(lái)實(shí)現(xiàn),而不是OnEraseBackground。
HBRUSH?CVS2005StartView::OnCtlColor(CDC*?pDC,?CWnd*?pWnd,?UINT?nCtlColor)?


{
????HBRUSH?hbr?=?CFormView::OnCtlColor(pDC,?pWnd,?nCtlColor);
????
????//?TODO:?Change?any?attributes?of?the?DC?here
????if(nCtlColor?==?CTLCOLOR_DLG)

????
{
????????return?m_bkBrush;
????}
????//?TODO:?Return?a?different?brush?if?the?default?is?not?desired
????return?hbr;
}上面只修改對(duì)話(huà)框背景,所以進(jìn)行了判斷,m_bkBrush就是背景畫(huà)刷。
工序二:貼圖,在OnPaint里面繪制Visual studio的大位圖。
void?CVS2005StartView::OnPaint()?


{
????CPaintDC?dc(this);?//?device?context?for?painting
????
????//?TODO:?Add?your?message?handler?code?here
????CDC????????????memDC;
????HBITMAP????????hOldBmp????????=?NULL;
????BITMAP????????bmp;
????memDC.CreateCompatibleDC(&dc);
????hOldBmp?=?(HBITMAP)memDC.SelectObject(&m_bmpHeader);
????m_bmpHeader.GetBitmap(&bmp);
????BitBlt(dc,?0,?0,?bmp.bmWidth,?bmp.bmHeight,?memDC,?0,?0,?SRCCOPY);
????memDC.SelectObject(hOldBmp);
????//?Do?not?call?CFormView::OnPaint()?for?painting?messages
}這樣就所有存托背景,下面開(kāi)始實(shí)現(xiàn)每個(gè)小欄目。實(shí)現(xiàn)一個(gè)就ok,思路都是一樣的。
工序三:實(shí)現(xiàn)繪制位圖的靜態(tài)窗口。從CStatic派生CBmpStatic類(lèi)來(lái)實(shí)現(xiàn)繪制位圖功能。考慮到上面提及的情況,函數(shù)接口如下:
????void????SetBitmap(UINT?nBmpID,?BOOL?bHorzStretch=TRUE);
????void????SetTitle(CString?strTitle);

實(shí)現(xiàn)如下:
void?CBmpStatic::OnPaint()?


{
????CPaintDC?dc(this);?//?device?context?for?painting
????
????//?TODO:?Add?your?message?handler?code?here
????CDC????????????srcDC;
????CDC????????????mskDC;
????CBitmap????????mskBmp;
????BITMAP????????bmp;
????srcDC.CreateCompatibleDC(&dc);
????mskDC.CreateCompatibleDC(&dc);
????m_bmpBack.GetBitmap(&bmp);

????mskBmp.CreateBitmap(bmp.bmWidth,?bmp.bmHeight,?0,?1,?NULL);
????srcDC.SelectObject(&m_bmpBack);

????srcDC.SetBkColor(RGB(0xEB,?0xF1,?0xFE));
????mskDC.SelectObject(mskBmp);
????mskDC.BitBlt(0,?0,?bmp.bmWidth,?bmp.bmHeight,?&srcDC,?0,?0,?SRCCOPY);

????srcDC.SetBkColor(RGB(255,255,255));
????srcDC.SetTextColor(RGB(0,0,0));

????LONG????lXStart????????=?0;
????LONG????lXEnd????????=?bmp.bmWidth;
????LONG????lYStart????????=?0;
????LONG????lYEnd????????=?bmp.bmHeight;
????CRect????rc;
????GetClientRect(&rc);
????if(m_bHorzStretch)

????
{
????????while(lXStart?<=?rc.Width())

????????
{
????????????if(lXEnd?>?rc.Width())

????????????
{
????????????????lXEnd?=?rc.Width();
????????????}
????????????dc.BitBlt(lXStart,0,?lXEnd-lXStart,?bmp.bmHeight,?&srcDC,?0,?0,?SRCINVERT);
????????????dc.SetBkColor(RGB(255,255,255));
????????????dc.BitBlt(lXStart,?0,?lXEnd-lXStart,?bmp.bmHeight,?&mskDC,?0,?0,?SRCAND);
????????????dc.BitBlt(lXStart,?0,?lXEnd-lXStart,?bmp.bmHeight,?&srcDC,?0,?0,?SRCINVERT);
????????????lXStart?+=?bmp.bmWidth;
????????????lXEnd?+=?bmp.bmWidth;
????????}
????}
????else

????
{
????????while(lYStart?<=?rc.Height())

????????
{
????????????if(lYEnd?>?rc.Height())

????????????
{
????????????????lYEnd?=?rc.Height();
????????????}
????????????dc.BitBlt(0,lYStart,?bmp.bmWidth,?lYEnd-lYStart,?&srcDC,?0,?0,?SRCINVERT);
????????????dc.SetBkColor(RGB(255,255,255));
????????????dc.BitBlt(0,lYStart,?bmp.bmWidth,?lYEnd-lYStart,?&mskDC,?0,?0,?SRCAND);
????????????dc.BitBlt(0,lYStart,?bmp.bmWidth,?lYEnd-lYStart,?&srcDC,?0,?0,?SRCINVERT);
????????????lYStart?+=?bmp.bmHeight;
????????????lYEnd?+=?bmp.bmHeight;
????????}
????}
????srcDC.DeleteDC();
????mskDC.DeleteDC();

????if(!m_strTitle.IsEmpty())

????
{
????????dc.SelectObject(m_ftTitle);
????????dc.SetTextColor(RGB(255,?255,?255));
????????dc.SetBkMode(TRANSPARENT);
????????dc.TextOut(0,?4,?m_strTitle);
????}
}


void?CBmpStatic::SetBitmap(UINT?nBmpID,?BOOL?bHorzStretch)


{
????if(m_bmpBack.GetSafeHandle())

????
{
????????m_bmpBack.DeleteObject();
????}
????m_bmpBack.LoadBitmap(nBmpID);
????m_bHorzStretch?=?bHorzStretch;
}

void?CBmpStatic::SetTitle(CString?strTitle)


{
????m_strTitle?=?strTitle;
}好了,有了顯示位圖的窗口,下面我們就來(lái)擺出一個(gè)欄目(最近的項(xiàng)目)。
工序四:擺置窗口,實(shí)現(xiàn)欄目。這個(gè)是細(xì)致活,先把中間的小主視圖控件擺上,然后四周放置8個(gè)static,基本如下(可能需要根據(jù)顯示結(jié)果來(lái)適當(dāng)調(diào)整)。

然后為每個(gè)static控件關(guān)聯(lián)一個(gè)CBmpStatic,并設(shè)置位圖和顯示文本。
void?CVS2005StartView::OnInitialUpdate()


{
????CFormView::OnInitialUpdate();
????GetParentFrame()->RecalcLayout();
????ResizeParentToFit();

????m_wndPrjUpLeft.SetBitmap(6609);
????m_wndPrjUpMiddle.SetBitmap(6610);
????m_wndPrjUpMiddle.SetTitle(_T("最近的項(xiàng)目"));
????m_wndPrjUpRight.SetBitmap(6611);
????m_wndMiddleLeft.SetBitmap(6612,?FALSE);
????m_wndMiddleRight.SetBitmap(6613,?FALSE);
????m_wndBottomLeft.SetBitmap(6614);
????m_wndBottomMiddle.SetBitmap(6615);
????m_wndBottomRight.SetBitmap(6616);

????m_imgProject.Create(16,?16,?ILC_COLOR8|ILC_MASK,?2,?0);
????m_imgProject.Add(AfxGetApp()->LoadIcon(MAKEINTRESOURCE(6826)));
????m_wndPrjList.SetImageList(&m_imgProject,?LVSIL_SMALL);
????m_wndPrjList.InsertItem(0,?_T("HTMLKit"),?0);
????m_wndPrjList.InsertItem(1,?_T("Mapgis7"),?0);


????m_wndNewsUpLeft.SetBitmap(6609);
????m_wndNewsUpMiddle.SetBitmap(6610);
????m_wndNewsUpMiddle.SetTitle(_T("Visual?Studio?開(kāi)發(fā)人員新聞"));
????m_wndNewsUpRight.SetBitmap(6611);
????m_wndNewsMiddleLeft.SetBitmap(6612,?FALSE);
????m_wndNewsMiddleRight.SetBitmap(6613,?FALSE);
????m_wndNewsBottomLeft.SetBitmap(6614);
????m_wndNewsBottomMiddle.SetBitmap(6615);
????m_wndNewsBottomRight.SetBitmap(6616);

????m_wndNewsInfo.SetFont(&m_ftNewInfo);
????m_wndNewsInfo.AddString(_T("當(dāng)前的新聞?lì)l道可能無(wú)效或者你的?Internet"));
????m_wndNewsInfo.AddString(_T("連接不可用.若要更新新聞?lì)l道,請(qǐng)?jiān)赲"工具\(yùn)"菜單上點(diǎn)擊\"選項(xiàng)\",然后展開(kāi)
"));
}?
好了,下面來(lái)看看我們的窗口。

花費(fèi)半天時(shí)間,只是圖實(shí)現(xiàn),封裝性不是很好。
總結(jié):
看過(guò)很多漂亮的界面,qq、泡泡堂登錄界面等,思路差不多,都是基于貼圖來(lái)做的,包括游戲的實(shí)現(xiàn)方式也差不多。界面的美觀其實(shí)主要靠藝術(shù)家,包括圖片效果以及窗口布局。
不足:
1、沒(méi)有使用雙緩存,拖動(dòng)的時(shí)候背景有閃爍。
2、滾動(dòng)條滑動(dòng)的時(shí)候有問(wèn)題,暫時(shí)沒(méi)時(shí)間處理。
3、代碼凌亂,不曉得資源句柄有沒(méi)有釋放干凈。
4、開(kāi)發(fā)新聞那個(gè)listbox是自繪的,可以通過(guò)spy++看到,我沒(méi)時(shí)間做。
還有。。。
代碼下載
posted on 2006-11-16 20:39
萬(wàn)連文 閱讀(3098)
評(píng)論(3) 編輯 收藏 引用 所屬分類(lèi):
MFC