本節主要學習了
1. 修改MFC AppWizard嚮導生成的框架程序外觀和大小,這既可以在窗口創建之前,也可以在窗口創建之後進行。
2. 修改程序窗口的圖標,光標,背景的方法。在創建窗口之前,通過設計窗口類來修改程序窗口的圖標,光標,背景;在窗口創建之後,通過SetClassLong函數修改窗口的圖標,光標和背景。
3. 實現一個動態變化的圖標的例子。
4. 工具欄和狀態欄編程。
5. 程序啓動畫面的創建。
BOOLCMainFrame::PreCreateWindow(CREATESTRUCT& cs)//這是一個虛函數
{
if(!CFrameWnd::PreCreateWindow(cs) )
returnFALSE;
//TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
//1.在窗口創建之前修改窗口的默認外觀。
/*cs.cx = 300;
cs.cy= 200;
cs.style&= ~FWS_ADDTOTITLE; //改變將文檔標題添加到窗口標題上。可以讓窗口顯示自己設置的標題。
//cs.style= cs.style & ~ FWS_ADDTOTITLE;
//cs.style= WS_OVERLAPPEDWINDOW;
//cs.style= WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE; //該成員的初始定義代碼。
cs.lpszName= "xiaobai";*/
//2.修改窗口的光標,圖標,背景
//通過編寫自己的窗口類並註冊,然後讓隨後的窗口按照自己編寫的窗口類去創建。
/*WNDCLASSwndclass;
wndclass.cbClsExtra= 0;
wndclass.cbWndExtra= 0;
wndclass.hbrBackground= (HBRUSH)GetStockObject(BLACK_BRUSH);
wndclass.hCursor= LoadCursor(NULL,IDC_HELP);
wndclass.hIcon= LoadIcon(NULL,IDI_ERROR);
wndclass.hInstance= AfxGetInstanceHandle(); //獲取當前應用程序的實例句柄。Afx開頭的函數都是應用程序框架類函數,也就是全局函數。
wndclass.lpfnWndProc= ::DefWindowProc;
wndclass.lpszClassName= "xiaobai";
wndclass.lpszMenuName= NULL;
wndclass.style= CS_HREDRAW | CS_VREDRAW;//這裏並不是窗口的類型,而是窗口類的類型。指定窗口類具有水平重繪和垂直重繪這兩種類型。
RegisterClass(&wndclass);
cs.lpszClass= "xiaobai"; */
//cs.lpszClass= AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,0,0,LoadIcon(NULL,IDI_WARNING));
cs.lpszClass= AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,0,0,0);
//用來設定窗口的類型,光標,背景,圖標。返回值是註冊之後的類名。
returnTRUE;
}
//SetWindowLong(m_hWnd,GWL_STYLE,WS_OVERLAPPEDWINDOW);
SetWindowLong(m_hWnd,GWL_STYLE,GetWindowLong(m_hWnd,GWL_STYLE) &~WS_MAXIMIZEBOX);//取消最大化
//GWL就是GetWindowLong的縮寫。GWL_STYLE指定獲取窗口的類型。
BOOLCStyleView::PreCreateWindow(CREATESTRUCT& cs)
{
//TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
//cs.lpszClass = "xiaobai"; //思考一下爲什在CMainFram中註冊的窗口類,在這裏還可以用。
//在MFC程序中,如果要修改應用程序窗口的圖標,則應在框架類中進行,因爲在框架窗口中才有標題欄,所以才能修改位於該標題欄上的圖標
//如果想要修改應用程序的背景和光標,就應該在視類中進行。
//cs.lpszClass= AfxRegisterWndClass(CS_HREDRAW |CS_VREDRAW,LoadCursor(NULL,IDC_CROSS),(HBRUSH)GetStockObject(BLACK_BRUSH),0);
cs.lpszClass= AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,0,0,0);//只給第一個參數賦值,其餘參數都爲0,會發現
//背景是透明的,圖標光標都是默認的。
returnCView::PreCreateWindow(cs);
}
ON_MESSAGE(UM_PROGRESS,OnProgress) //對於自定義消息來說,使用的是ON_MESSAGE宏實現這一功能。
END_MESSAGE_MAP()
static UINT indicators[] = //標識提示行和狀態欄指示器的ID數組
{
ID_SEPARATOR,// status line indicator 提示行
IDS_TIMER,
IDS_PROGRESS,
ID_INDICATOR_CAPS, //分別是Caps Lock,Num Lock,Scroll Lock鍵的狀態指示器。
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
extern CStyleApp theApp; //聲明這個變量是在外部的一個源文件中定義的
int CMainFrame::OnCreate(LPCREATESTRUCTlpCreateStruct)
{
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)) //MFC自動創建的工具欄和主菜單的資源ID是一樣的,也就是說,在MFC編程中,一個ID可以表示多種資源。
{
TRACE0("Failedto create toolbar\n");
return-1; // fail to create
}
if(!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failedto create status bar\n");
return-1; // fail to create
}
//TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); //設置工具欄停靠的位置
EnableDocking(CBRS_ALIGN_ANY);//上面的那個EnableDocking函數式工具欄對象的成員函數,目的是讓工具欄對象可以停靠,而這裏調用的是CFrameWnd對象的EnableDocking
//成員函數,目的是讓主框架窗口可以被停靠。
DockControlBar(&m_wndToolBar);//讓工具欄停靠在主框架窗口上。
//在窗口創建之後修改窗口的樣式
SetClassLong(m_hWnd,GCL_HICON,(LONG)LoadIcon(NULL,IDI_ERROR));
//模擬動畫圖標(3中加載自定義圖標的方式)
m_hIcons[0] =LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON1));
m_hIcons[1]= LoadIcon(theApp.m_hInstance,MAKEINTRESOURCE(IDI_ICON2));
m_hIcons[2]= LoadIcon(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDI_ICON3));//AfxGetApp可以獲得當前應用程序對象的指針
SetClassLong(m_hWnd,GCL_HICON,(LONG)m_hIcons[0]);
SetTimer(1,1000,NULL);
//創建自定義工具欄
if(!m_newToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_RIGHT
|CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_newToolBar.LoadToolBar(IDR_TOOLBAR1)) //MFC自動創建的工具欄和主菜單的資源ID是一樣的,也就是說,在MFC編程中,一個ID可以表示多種資源。
{
TRACE0("Failedto create toolbar\n");
return-1; // fail to create
}
m_newToolBar.EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_newToolBar);
//在窗口中創建進度欄(思考一下在框架類中創建的進度欄怎嘛可以在視類窗口中顯示)
//m_progress.Create(WS_CHILD| WS_VISIBLE | PBS_SMOOTH,CRect(100,100,200,120),this,123); //創建水平的進度欄
//m_progress.SetPos(50); //設置進度欄上當前位置
//m_progress.Create(WS_CHILD| WS_VISIBLE | PBS_VERTICAL,CRect(100,100,120,200),this,321); ///創建垂直的進度欄
//m_progress.SetPos(40);
//在狀態欄的窗格中創建進度欄
/*CRectrect;
m_wndStatusBar.GetItemRect(2,&rect);
m_progress.Create(WS_CHILD| WS_VISIBLE,rect,&m_wndStatusBar,123);
m_progress.SetPos(50);*/ //這種方式並不能讓進度條在窗格中顯示。只有在窗口創建完,即OnCreate函數執行完
//才能獲得窗口狀態欄上窗格的矩形區域。
//SendMessage(UM_PROGRESS); //發送消息在OnCreate函數沒有執行完,就去執行UM_PROGRESS消息的響應函數,
//消息響應函數返回又回到OnCreate函數中執行到函數結束,這和上面的那段代碼其實
//是一樣的效果
m_wndStatusBar.SetPaneInfo(2,IDS_PROGRESS,SBPS_NORMAL,100);//設置窗格的寬度
//PostMessage(UM_PROGRESS);//投遞消息,把消息投遞到消息隊列中,程序通過GetMessage函數按順序把消息一條一條的取出來
//對於本程序,等程序執行完WM_CREATE消息後,纔去執行UM_PROGRESS消息
myCtrl.Create(WS_CHILD |WS_VISIBLE | PBS_SMOOTH,CRect(100,100,200,120),this,123);
intnLower,nUpper;
myCtrl.GetRange(nLower,nUpper);
myCtrl.SetStep((nUpper-nLower)/4);
myCtrl.StepIt();
//CG: The following line was added by the Splash Screen component.
CSplashWnd::ShowSplashScreen(this);
return0;
}
void CMainFrame::OnTimer(UINT nIDEvent)
{
staticint index = 0; //作爲一個靜態的局部變量,他將存放在程序的數據區中,而不是在棧中分配空間。
SetClassLong(m_hWnd,GCL_HICON,(LONG)m_hIcons[index]);
index= ++index%3; //小技巧:如果希望把某個數值始終限制在一個範圍內,那麼最好的辦法就是進行取模運算(%)
//在時鐘狀態欄指示器中顯示時間
CTimet = CTime::GetCurrentTime();
CStringstr = t.Format("%H:%M:%S");
CClientDCdc(this);
CSizesz=dc.GetTextExtent(str); //獲得字符串的寬度和高度
//intindex = 0; //在不知道窗格的索引時,可以利用這個函數,根據窗格的ID來得到相應的索引。
//index= m_wndStatusBar.CommandToIndex(IDS_TIMER);
m_wndStatusBar.SetPaneInfo(1,IDS_TIMER,SBPS_NORMAL,sz.cx);
m_wndStatusBar.SetPaneText(1,str);
intnLower,nUpper;
m_progress.GetRange(nLower,nUpper);
m_progress.SetStep((nUpper-nLower)/10); //設置每次前進的步長
m_progress.StepIt(); //讓進度欄的當前位置按照一定的步長前進
CFrameWnd::OnTimer(nIDEvent);
}
//工具欄的顯示或隱藏
void CMainFrame::OnViewNewtoolbar()
{
//TODO: Add your command handler code here
/*if(m_newToolBar.IsWindowVisible()) //判斷工具欄是顯示還是隱藏了
{
m_newToolBar.ShowWindow(SW_HIDE);
}
else
{
m_newToolBar.ShowWindow(SW_SHOW);
}
RecalcLayout();
/*當標準工具欄或狀態欄隱藏或者顯示,或者窗口調整大小時,調用這個方法。
方法原型爲:virtualvoid RecalcLayout( BOOL bNotify = TRUE );
Parameters: bNotify
Determines whether the active in-place itemfor the frame window receives notification of the layout change. If TRUE, theitem is notified; otherwise FALSE.
決定是否將焦點項目傳遞這個變化,如果是TRUE就通知子項目,否則,不傳遞。
這裏m_wndToolBar1是自己定義的一個工具欄,:OnViewToolbar1()是一個菜單項的消息響應函數。
當工具欄顯示時,點擊這個菜單項,工具欄隱藏,然後調用RecalcLayout這個方法,重新佈置窗口。
當工具欄隱藏式,點擊這個菜單項,工具欄顯示,然後調用RecalcLayout這個方法,重新佈置窗口。
DockControlBar(&m_newToolBar);*/
ShowControlBar(&m_newToolBar,!m_newToolBar.IsWindowVisible(),FALSE);
//顯示或隱藏一個控件條
//pBar指向要顯示或隱含的控件條
//bShow如果爲TRUE ,指定控件條將顯示;如果爲FALSE,則隱藏。
//bDelay如果爲TRUE,延遲顯示控件條;如果爲FALSE,則立即顯示
}
//顯示或隱藏工具欄時,取消或顯示相應的菜單上的複選標記
void CMainFrame::OnUpdateViewNewtoolbar(CCmdUI*pCmdUI)
{
pCmdUI->SetCheck(m_newToolBar.IsWindowVisible());
//通過爲菜單項添加UPDATE_COMMAND_UI消息的響應,可以非常方便地爲該菜單項設置或取消複選標記。
}
//這種方法在窗口發生重繪時,進度條的顯示就會錯位,要在窗口重繪的消息響應函數中添加下面的代碼
void CMainFrame::OnProgress()
{
CRectrect;
m_wndStatusBar.GetItemRect(2,&rect);
m_progress.Create(WS_CHILD| WS_VISIBLE | PBS_SMOOTH,rect,&m_wndStatusBar,123);
m_progress.SetPos(50);
}
void CMainFrame::OnPaint()
{
CPaintDCdc(this); // device context for painting
CRectrect;
m_wndStatusBar.GetItemRect(2,&rect);
if(!m_progress.m_hWnd) //根據m_progress對象的窗口句柄是否爲空判斷進度欄是否被創建
{
m_progress.Create(WS_CHILD | WS_VISIBLE |PBS_SMOOTH,rect,&m_wndStatusBar,123);
}
else
{
m_progress.MoveWindow(rect);//用SetWindowPos函數設置進度欄的位置比較麻煩,但功能比較多,例如它可以將程序窗口設置爲頂層窗口
}
m_progress.SetPos(50);
//Do not call CFrameWnd::OnPaint() for painting messages
}