MFC——7.定製應用程序外觀

Lesson7:定製應用程序外觀

 

應用程序外觀是用戶體驗中一個重要因素,優美的程序外觀可以提升程序逼格。本文主要講解了MFC中應用程序外觀的修改,主要包括任務欄、工具欄、啓動畫面等。

 

1.      程序窗口的圖標、背景、光標修改

1.1  窗口創建之前修改

因爲應用程序的外觀主要是在程序的框架窗口上,通過框架類體現的,所以在定製程序外觀的時候,主要是在框架類進行修改。如果要修改應用程序框架外觀大小,通常在窗口創建之前。可以在CMainFrame類裏的PreCreateWindow()函數中實現。如果我們要修改窗口的圖標、背景、光標,應該怎麼修改?窗口的類型,大小是在創建窗口設定的,但前面Windows程序運行機制我們瞭解瞭如何創建一個窗口,它是通過一個窗口類,在這個類裏設計窗口的時候,就設計好了圖標、背景、光標,現有的窗口類的設計是MFC幫我們在底層已經設計好了,雖然我們不能改變這個底層代碼,但我們可以重新設計一個窗口類,然後用自己的這個窗口類進行修改圖標、背景、光標。

  

  BOOL CMainFrame::PreCreateWindow(CREATESTRUCT&cs) //窗口創建之前修改應用程序框架大小
{
if( !CFrameWnd::PreCreateWindow(cs) )
        return FALSE;
// TODO: 在此處通過修改
// CREATESTRUCT cs 來修改窗口類或樣式
/*********************    窗口創建之前修改應用程序框架大小  *****************/
cs.cx = 300;          //修改窗口大小(300*400大小)
cs.cy = 400;
//cs.style = ~FWS_ADDTOTITLE;  //修改標題欄名字,因爲會選用默認的名字,所以將默認的選項取反
//cs.style = cs.style & ~FWS_ADDTOTITLE; //這種方式和上面方式的效果一樣,選一種即可
cs.style = WS_OVERLAPPEDWINDOW;  //這種方式和上面方式的效果一樣,選一種即可
cs.lpszName = "http"; //窗口名稱
 
/**********************    自定義窗口類,然後註冊使用  *****************/
WNDCLASS wndcls;
wndcls.cbClsExtra = 0;          //類的額外內存不需要
wndcls.cbWndExtra = 0;                    //窗口的類的額外內存不需要
wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);  //窗口背景
wndcls.hCursor=LoadCursor(NULL,IDC_HELP);  //窗口光標
wndcls.hIcon = LoadIcon(NULL,IDI_ERROR);    //窗口tubiao
wndcls.hInstance = AfxGetInstanceHandle();     //獲得當前應用程序的句柄
wndcls.lpfnWndProc = ::DefWindowProc;        //窗口過程函數
wndcls.lpszClassName ="SUNXING";           //類的名稱
wndcls.lpszMenuName = NULL; //菜單的名稱,雖然設置爲NULL,但會用到MFC自帶的菜單
wndcls.style = CS_HREDRAW | CS_VREDRAW; //窗口類的類型,水平和垂直重繪
 
RegisterClass(&wndcls);     //註冊窗口
 
cs.lpszClass = "SUNXING";   //修改cs結構體成員變量的類名,用它來重新設置窗口樣式
 
//cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW| CS_VREDRAW, 0, 0, LoadIcon(NULL, IDI_WARNING));  //不用註冊窗口類,直接修改窗口樣式
       return TRUE;
}      

上面我們通過窗口類重新設計與註冊使用後發現,只有圖標發生了改變,而光標和背景沒有改變,這是因爲,程序在外觀上是view類覆蓋在frame類之上的,光標和背景消息首先被view類在獲得響應,所以我們在frame類裏修改後看不到效果。所以我們在view類裏的PreCreateWindow()函數裏添加一句代碼,修改窗口類爲我們以設計的類,就可以看到效果。 cs.lpszClass = "SUNXING";  

      

如果我們僅僅需要修改圖標、光標、背景而去重新設計窗口類,那就太麻煩了,MFC提供了取件函數進行直接修改。

LPCTSTR AFXAPIAfxRegisterWndClass( UINT nClassStyle, HCURSORhCursor= 0, HBRUSH hbrBackground = 0,HICON hIcon = 0 );

 上面註釋起來的就是這個函數的應用,同理這個函數可以在view類裏使用。

1.2    窗口創建之後修改

如果我們已經創建了窗口,那麼在窗口創建之後如果要修改窗口外觀,需要在CMainFrame類和View類裏的OnCreate()裏通過SetWindowLong()函數進行操作,下面是兩個例子的具體代碼。

 

SetWindowLong(m_hWnd,GWL_STYLE, WS_OVERLAPPEDWINDOW); //取消了窗口名稱

 

SetWindowLong(m_hWnd,GWL_STYLE, GetWindowLong(m_hWnd, GWL_STYLE) & ~WS_MAXIMIZEBOX);    //取消了最大化

 

1.3  循環顯示窗口的圖標

如果我們需要在窗口顯示中有幾幅圖標輪流顯示,該怎麼做呢?首先設計我們要加載的圖標,然後加載圖標到圖標數組中。假設我們添加了三幅圖標,這裏需要添加含有三個元素的圖標數組,

HICON m_hIcons[3]。並通過添加timer函數定時地不斷地切換圖標。循環顯示圖標顯然是在窗口建立了以後進行的,所以理所當然的在CMainFrame類的OnCreate()函數中添加代碼。

int CMainFrame::OnCreate(LPCREATESTRUCTlpCreateStruct)
{
//三種方式加載圖標,三選一就行
       m_hIcons[0] = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_ICON1));
       m_hIcons[1] = LoadIcon(theApp.m_hInstance,MAKEINTRESOURCE(IDI_ICON2));//這裏需要將另一個源文件定義的theApp變量聲明一下,延伸作用域。
       m_hIcons[2] = LoadIcon(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDI_ICON3));
 
       SetClassLong(m_hWnd, GCL_HICON, (LONG)m_hIcons[0]);//先將第一幅圖標加載上
 
       SetTimer(1,1000,NULL);  //設置定時器  調用定時器函數timer()
       return 0;
}

添加timer函數。

void CMainFrame::OnTimer(UINT_PTRnIDEvent)
{
       // TODO:  在此添加消息處理程序代碼和/或調用默認值
       static  int index = 2;       //index定義爲靜態變量
       SetClassLong(m_hWnd, GCL_HICON, (LONG)m_hIcons[index]);
       index = (++index) % 3;
CFrameWnd::OnTimer(nIDEvent);
}

     

2.      狀態欄中顯示鼠標位置和系統時間

2.1   顯示鼠標位置

View類窗口覆蓋在frame類窗口之上,鼠標是在view類窗口裏動作的,所以這裏捕獲鼠標消息首先要在view類裏添加一個鼠標移動的消息,來獲得鼠標的位置。

void CStyleView::OnMouseMove(UINTnFlags, CPoint point)
{
       // TODO:  在此添加消息處理程序代碼和/或調用默認值
       CString str;
       str.Format("x=%d,y=%d",point.x,point.y);
 
       //幾種在狀態欄裏獲得放置鼠標位置的方式
       //((CMainFrame*)GetParent())->m_wndStatusBar.SetWindowText(str);//通過獲取框架類窗口的指針,調用框架類定義的狀態欄對象,用對象的方法設定文本
       //((CMainFrame*)GetParent())->SetMessageText(str);
       //((CMainFrame*)GetParent())->GetMessageBar()->SetWindowText(str);
       GetParent()->GetDescendantWindow(AFX_IDW_STATUS_BAR)->SetWindowText(str);
       CView::OnMouseMove(nFlags, point);
}

2.2   顯示系統時間

顯示系統時間同樣是在窗口建立之後的動作,所以需要在OnCreate()函數裏不斷的調用timer()函數,這裏只需要在OnCreate()函數裏添加一句調用定時器的代碼,其餘代碼都是嚮導自動生成的。SetTimer(1, 1000, NULL);  //設置定時器,  調用定時器函數timer()

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
         if(CFrameWnd::OnCreate(lpCreateStruct) == -1)
                   return-1;
 
         if(!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER| CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
                   !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
         {
                   TRACE0("未能創建工具欄\n");
                   return-1;      // 未能創建
         }
 
         if(!m_wndStatusBar.Create(this))
         {
                   TRACE0("未能創建狀態欄\n");
                   return-1;      // 未能創建
         }
         m_wndStatusBar.SetIndicators(indicators,sizeof(indicators)/sizeof(UINT));
 
         //TODO:  如果不需要可停靠工具欄,則刪除這三行
         m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
         EnableDocking(CBRS_ALIGN_ANY);
         DockControlBar(&m_wndToolBar);
 
         SetTimer(1,1000, NULL);  //設置定時器,  調用定時器函數timer()
         return0;
}

添加定時器函數,在這個函數裏進行響應

void CMainFrame::OnTimer(UINT_PTR nIDEvent)
{
         //TODO:  在此添加消息處理程序代碼和/或調用默認值
         CTimet = CTime::GetCurrentTime();
         CStringstr = t.Format("%H:%M:%S");
 
         CClientDCdc(this); //定義一個dc對象,用來獲得str的尺寸,調整狀態欄裏時鐘顯示框的大小
         CSizesz = dc.GetTextExtent(str);
         //intindex = m_wndStatusBar.CommandToIndex(IDS_TIMER);    //如果不知道時鐘在狀態欄的第幾個窗格,可以這樣找到
         m_wndStatusBar.SetPaneInfo(1,IDS_TIMER, SBPS_NORMAL, sz.cx);
         m_wndStatusBar.SetPaneText(1,str);    //1就是前面的可以用index代替的數,通過狀態欄的對象調用函數,其中函數有缺省的參數值
         CFrameWnd::OnTimer(nIDEvent);
}

 


3.      添加啓動畫面

添加啓動畫面時,需要準備一幅位圖資源,當我們操作資源的時候,一般是和類相關聯的。

①添加一個類CWzdSplash,基類是CWnd,並在類裏定義一個位圖變量CBitmapm_bitmap;

②通過嚮導添加消息響應函數OnPaint()和 手動添加自己的函數Create()。

 

準備工作做好後我們來實現啓動畫面三部曲。

①在frame類的OnCreate()函數裏添加代碼

int CMainFrame::OnCreate(LPCREATESTRUCTlpCreateStruct)
{
         CWzdSplashwndSplash;    //創建啓動窗口類的實例
         wndSplash.Create();      //CWzdSplash類裏定義的函數
         wndSplash.CenterWindow();     //啓動畫面出現在屏幕中間
         wndSplash.UpdateWindow();   //send WM_PAINT
         Sleep(2000);                   //畫面停留時間2s
         wndSplash.DestroyWindow();      //銷燬初始畫面窗口
}
 

②在CWzdSplash的OnPaint()函數中添加代碼

void CWzdSplash::OnPaint()
{
         CPaintDCdc(this); // device context for painting
         //TODO:  在此處添加消息處理程序代碼
         //不爲繪圖消息調用 CWnd::OnPaint()
 
         BITMAPbitmap;
         m_bitmap.GetBitmap(&bitmap);
 
         CDCdcComp;
         dcComp.CreateCompatibleDC(&dc);
         dcComp.SelectObject(&m_bitmap);
         //draw bitmap
         dc.BitBlt(0,0, bitmap.bmWidth, bitmap.bmHeight, &dcComp, 0, 0, SRCCOPY);
}


③在CWzdSplash的Create()函數中添加代碼

void CWzdSplash::Create()
{
         m_bitmap.LoadBitmap(IDB_BITMAP1);
         BITMAPbitmap;
         m_bitmap.GetBitmap(&bitmap);
        //CreateEx(0,AfxRegisterWndClass(0),"",WS_POPUP|WS_VISIBLE|WS_BORDER,0,0,bitmap.bmWidth,bitmap.bmHeight,NULL,0);
        CreateEx(0,AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW)),
                   NULL,WS_POPUP | WS_VISIBLE, 0, 0, bitmap.bmWidth, bitmap.bmHeight, NULL, NULL);
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章