我用vc+仿照金山毒霸軟件工具界面(創世紀篇)

   金山毒霸軟件軟件很炫,一直想仿照,終於摸透它的程序開發原理。 編程

說幹就幹,本着由淺入深的原則,我選擇了金山毒霸的一個附帶工具:Duba_GOP.exe來開刀。該工具在金山毒霸的網站上能夠下載到,如圖: 編輯器


one,開始準備工具: 工具

提取資源工具:freeRes 字體

編程工具:VC++ 網站

還有一個Vc自帶的小工具:spy++ this

之因此不用你們都熟悉的eXeScope,是由於Duba_GOP.exe已經被壓縮過了,有些資源提取工具沒法再用。 spa

用freeRes打開Duba_GOP.exe,可看到其帶有20個bmp位圖,有整個窗體的背景圖,右上角兩個小按鈕「主頁」和「關閉」的三態位圖,以及兩個大按鈕「瀏覽文件夾」和「開始掃描」的三態位圖。看到這些圖片,便可猜到該軟件是沒有標題欄的,而顯示出來的標題欄只是背景,並且連同學體下部的金山毒霸的標誌都是屬於同一幅背景圖片!那麼「標題欄」上的「主頁」,「關閉」是怎麼回事?用spy++來試一下,發現這兩個是Button,而不是Bitmap。一樣「瀏覽文件夾」和「開始掃描」也是Button,隨即想到這四個Button能夠用VC中的CBitmap類來實現。而窗體下部的超連接僅僅是Static靜態框。把這些難點分析出來了,下面就能夠開始咱們的編程之旅了,不過記得把有用的圖片保存下來。  three

一.窗體背景問題 事件

打開vc,新建一個對話框工程,名爲Interface。去掉缺省的一個Static和兩個Button,在窗體上點右鍵,在出現的屬性對話框中,去掉標題欄,再將用freeRes提取的全部圖片Import進工程的資源中。修改CInterfaceDlg::OnPaint()以下: 圖片

void CInterfaceDlg::OnPaint()
{
  if (IsIconic())
  {
    CPaintDC dc(this); // device context for painting
    SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
    // Center icon in client rectangle
    int cxIcon = GetSystemMetrics(SM_CXICON);
    int cyIcon = GetSystemMetrics(SM_CYICON);
    CRect rect;
    GetClientRect(&rect);
    int x = (rect.Width() - cxIcon + 1) / 2;
    int y = (rect.Height() - cyIcon + 1) / 2;
    // Draw the icon
    dc.DrawIcon(x, y, m_hIcon);
  }
  else
  {
//   CDialog::OnPaint();//將這一句註銷掉
    ***************************************************************
    CPaintDC dc(this);
    CRect rect;
    GetClientRect(&rect);//獲得窗體的大小
    CDC dcMem;
    dcMem.CreateCompatibleDC(&dc);
    CBitmap bmpBackground;
    bmpBackground.LoadBitmap(IDB_BITMAPBACKGROUND);//加載背景圖片
    BITMAP bitMap;
    bmpBackground.GetBitmap(&bitMap);
    CBitmap *pbmpOld=dcMem.SelectObject(&bmpBackground);
    dc.StretchBlt(0,0,rect.Width(),rect.Height(),&dcMem,0,0,bitMap.bmWidth,bitMap.bmHeight,SRCCOPY);//畫窗體
    **************************************************************
  }
}


其中兩個「*」行之間的部分爲所添加部分。

這段代碼的做用是將那幅背景圖片畫在窗體上, 其中我使用了StretchBlt來畫出窗體,StretchBlt比BitBlt要慢許多,若是你想獲得更好的速度,能夠考慮創建與背景位圖相同尺寸的窗體,而後用BitBlt來畫出。CBitmap bmpBackground;最好做爲CInterfaceDlg的成員變量並在CInterfaceDlg::OnInitDialog中提早加載位圖,感興趣的朋友能夠試試。

編譯,運行。可看到修改後的效果,因爲該圖片是平鋪在窗體上的,若是圖片和窗體尺寸不一致就會致使圖片發生扭曲。所以可將窗體調整到與圖片相同或相近的尺寸大小,那麼運行後看起來就順眼多了。可是窗體邊框仍是不大對勁,因而再進vc的資源編輯器,將窗體的Border由「Dialog Frame」該爲「Thin」,從新編譯,運行,搞定!

可是沒過一秒鐘就以爲這話說早了,標題欄沒了,窗體怎麼移動啊?

別急,車到山前必有路,咱們不妨騙騙Windows。當咱們的鼠標在窗體任意位置上拖動鼠標時,讓Windows覺得鼠標在標題欄上拖動,不就能夠實現任意點擊窗體的什麼地方均可以移動窗體了嗎?因而在CInterfaceDlg::OnLButtonDown(UINT nFlags, CPoint point)中添加下面一句:PostMessage(WM_NCLBUTTONDOWN,HTCAPTION,MAKELPARAM(point.x, point.y)); 該語句的做用是向系統發送HTCAPTION消息,讓系統覺得鼠標點在標題欄上。

如今編譯,運行,真的搞定了!

二.按鈕問題

Duba_GOP.exe中包括兩類按鈕,第一類就是上面所說的四個圖片按鈕,能夠CBitmap類來實現:

在窗體上添加四個Button,設爲Bitmap和OwnerDraw風格。爲窗體添加4個CBitmap的成員變量,好比:

CBitmapButton  m_StartBtn; 並與這四個Button關聯上,再在CInterfaceDlg::OnInitDialog()中添加:m_StartBtn.LoadBitmaps(IDB_BITMAPONNORMAL,IDB_BITMAPONDOWN);//讓窗體初始化時就加載按鈕位圖 其中IDB_BITMAPONNORMA是通常狀態下的按鈕的圖片ID,IDB_BITMAPONDOWN是鼠標按下時的按鈕的圖片ID。 合理擺放這四個按鈕的位置,使其與Duba_GOP.exe界面上的位置一致,如今運行一下看看,界面增色很多吧。只是有一點:「開始掃描」這個按鈕比較特殊,當鼠標點擊時,會變成中止的位圖,當再次點擊時,又變成開始的位圖,所以這個按鈕擁有兩套,4個位圖。爲此,再爲CInterfaceDlg添加一個成員變量:BOOL m_bEnable; 並在CInterfaceDlg::OnInitDialog()中設其初值爲True。


而後在點擊「開始掃描」按鈕的相應事件CInterfaceDlg::OnStartbtn()中添加:if(m_bEnable)
  {
    m_StartBtn.LoadBitmaps(IDB_BITMAPOFFNORMAL,IDB_BITMAPOFFDOWN);//加載位圖
    m_bEnable=false;
    m_StartBtn.RedrawWindow();
  }
  else
  {
    m_StartBtn.LoadBitmaps(IDB_BITMAPONNORMAL,IDB_BITMAPONDOWN);//加載另外一套位圖
    m_bEnable=true;
    m_StartBtn.RedrawWindow();
  }以上代碼的做用是控制兩套位圖的切換。

好了,如今輪到Duba_GOP.exe界面中上部的那三個CheckBox風格的Button了。首先添加三個這樣的按鈕,但看上去與Duba_GOP.exe的按鈕不太同樣,因而將個人三個按鈕加上「平坦」的風格,OK,行了。

編譯,運行,頓時大吃一驚,原來新添加的三個CheckBox的背景仍是缺省的灰色,與白色的窗體背景極不協調,很是難看。看來須要改變該類Button的背景顏色了。因而,從CButton類派生出一個CColorButton類,其主要代碼以下:// ColorButton.h : header file
class CColorButton : public CButton
{
……//省略了無關代碼
public:
  CBrush m_brush;
  void SetBackColor(COLORREF BackColor);
protected:
  COLORREF m_BackColor;
  //{{AFX_MSG(CColorButton)
  afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
……//省略了無關代碼
}
// ColorButton.cpp
BEGIN_MESSAGE_MAP(CColorButton, CButton)
//{{AFX_MSG_MAP(CColorButton)
ON_WM_CTLCOLOR_REFLECT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CColorButton::SetBackColor(COLORREF BackColor)
{
m_BackColor=BackColor; //設置背景顏色
m_brush.CreateSolidBrush(m_BackColor); //建立畫刷
}
HBRUSH CColorButton::CtlColor(CDC* pDC, UINT nCtlColor)
{
pDC->SetBkMode(TRANSPARENT);//將背景設爲透明
return (HBRUSH)m_brush;//返回自定義畫刷
// return NULL;//將缺省的處理註銷掉
} 好了,新類構造完成了。如何使用呢?將這三個CheckBox按鈕聲明爲CColorButton類的三個成員變量,好比: CColorButton m_ColorBtn1;不過要記得在CInterfaceDlg::OnInitDialog()中添加:m_ColorBtn1.SubclassDlgItem(IDC_CHECK1,this);// IDC_CHECK1是其中一個CheckBox的ID
m_ColorBtn1.SetBackColor(RGB(222,223,222));// RGB(222,223,222)就是窗體背景顏色如今編譯一下,能夠看到這三個按鈕已經融入窗體背景之中,按鈕問題已經所有解決了。



three.Static問題

這個界面上Static很多,中上部有一個Static有一種凹下去的效果,其實只須要通常的Static設置了「下沉」的風格便可。其他幾個Static可算做一類,存在的問題和前面的同樣,也就是背景顏色問題,爲此又從CStatic中派生出CcolorStatic類,主要代碼以下:

// ColorStatic.h : header file
class CColorStatic : public CStatic
{
……//省略了無關代碼
public:
void SetTextColor(COLORREF TextColor);
COLORREF m_TextColor;
void SetBackColor(COLORREF BackColor);
void SetCaption(CString strCaption);
void Create(CString strCaption,COLORREF BackColor);
COLORREF m_BackColor;
CString m_strCaption;
protected:
//{{AFX_MSG(CColorStatic)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnPaint();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
}
// ColorStatic.cpp
BEGIN_MESSAGE_MAP(CColorStatic, CStatic)
//{{AFX_MSG_MAP(CColorStatic)
ON_WM_CREATE()
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CColorStatic::OnPaint() //重畫Static
{
CPaintDC dc(this); // device context for painting
CRect rect;
GetClientRect(&rect);
dc.SetBkColor(m_BackColor);
dc.SetBkMode(TRANSPARENT);
CFont *pFont=GetParent()->GetFont();//獲得父窗體的字體
CFont *pOldFont;
pOldFont=dc.SelectObject(pFont);//選用父窗體的字體
dc.SetTextColor(m_TextColor);//設置文本顏色
dc.DrawText(m_strCaption,&rect,DT_CENTER);//將文本畫在Static的中央
dc.SelectObject(pOldFont);
// Do not call CStatic::OnPaint() for painting messages
}
void CColorStatic::SetCaption(CString strCaption)
{
m_strCaption=strCaption;//設置Static文本
}
void CColorStatic::SetBackColor(COLORREF BackColor)
{
m_BackColor=BackColor;//設置背景顏色
}
void CColorStatic::SetTextColor(COLORREF TextColor)
{
m_TextColor=TextColor;//設置文字顏色
}OK,這也是個很簡單的類,主要功能就是能夠設置該Static的文字顏色和背景顏色,可是已經基本知足咱們的須要了。有一點缺陷就是下面三個Static應該還具有超連接的功能,不過你能夠經過修改這個類來實現。或者直接用一個超連接類來替代也能夠。 總之,這個問題也解決了,如今咱們的程序運行起來已經很是像金山毒霸的Duba_GOP.exe了,作到這一步仿製任務已經基本完成,可是低頭看看系統的任務欄你會發現本身的程序還不夠完美,由於在任務欄上屬於本身程序的那個小方塊上空空如也,太不專業了。

請注意Windows是將程序的標題欄上的Caption和圖標顯示在任務欄上,而個人這個程序沒有標題欄,故而什麼也顯示不出來,怎麼辦呢?辦法在這裏:

1.恢復標題在對話框的OnInitDialog()中添加:

SetWindowText("金山毒霸專殺工具");//設置對話框的標題爲金山毒霸專殺工具

2.恢復圖標

在對話框上打開屬性對話框,從新選上「System Menu」和「Title Bar」風格。而後在對話框的OnInitDialog()中添加:

ModifyStyle(WS_CAPTION,WS_MINIMIZEBOX,SWP_DRAWFRAME);

如今運行起來看看,瞧!系統任務欄上熟悉的圖標和標題又回來了。可是這樣又帶來一個問題:窗體最下面的那個Static在運行後與背景圖片上金山毒霸2002幾個字重疊在一塊兒,很很差看。並且因爲對話框的尺寸有限制,這個Static也移不到合適的位置,因而我們只好在程序裏動動腦筋了。好比在OnInitDialog()里加上幾句:

CRect rect1;
m_Link3.GetWindowRect(&rect1);
rect1.top+=17;
rect1.bottom+=17;
m_Link3.MoveWindow(rect1.left,rect1.top,rect1.Width(),rect1.Height());//往下移17其中的m_Link3就是表明那個Static的成員變量。至於那個ListCtrl嘛,只不過在它的風格里去掉了邊框而已。

OK,能夠dedug vc+程序啦

end。

vc+開發日記。

相關文章
相關標籤/搜索