程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 用VC++仿制金山毒霸專殺工具界面

用VC++仿制金山毒霸專殺工具界面

編輯:關於VC++

金山毒霸2002自推出以來,廣受用戶的喜愛。今天在這裡我要談的不是金山毒霸的功能,而是其別具一格的界面。本人早就對金山毒霸的界面垂涎三尺,如果自己的程序裡能用上金山毒霸那樣的界面,那該多爽!

說干就干,本著由淺入深的原則,我選擇了金山毒霸的一個附帶工具:Duba_GOP.exe來開刀。該工具在金山毒霸的網站上可以下載到,其界面如圖所示:

好,開始准備工具:

提取資源工具:freeRes

編程工具:VC++

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

之所以不用大家都熟悉的eXeScope,是因為Duba_GOP.exe已經被壓縮過了,有些資源提取工具無法再用。

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

一.窗體背景問題

打開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)就是窗體背景顏色現在編譯一下,可以看到這三個按鈕已經融入窗體背景之中,按鈕問題已經全部解決了。

三.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嘛,只不過在它的風格裡去掉了邊框而已。自此,大功告成!

該程序在VC6+Win98/2k/xp下調試通過。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved