7.1更改窗口大小、標題、風格
7.1.1 在窗口創建之前更改
如果希望在應用程序窗口創建之前修改它的大小、標題和風格,應該在CMainFrame類的PreCreateWindow成員函數進行。該函數有個類型是CREATESTRUCT結構的參數,如果在修改了這個參數中的成員變量的值,那麼這種改變會反映到MFC底層代碼中,當MFC底層代碼調用CreateWindowEx函數去創建窗口時,它就會使用改變後的參數值去創建這個窗口。
1)更改窗口大小
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT&cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
//TODO: 在此處通過修改
// CREATESTRUCT cs 來修改窗口類或樣式
cs.cx = 400;
cs.cy = 200;
return TRUE;
}
2)更改應用程序標題
框架的默認窗口樣式是WS_OVERLAPPEDWINDOW和FWS_ADDTOTITLE樣式的組合。其中FWS_ADDTOTITLE是MFC特定的一種樣式,指示框架將文檔標題添加到窗口標題上。因此,如果想讓窗口顯示自己的標題,只需將窗口的FWS_ADDTOTITLE樣式去掉即可。設置窗口標題的代碼之前加上:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT&cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
//TODO: 在此處通過修改
// CREATESTRUCT cs 來修改窗口類或樣式
cs.cx = 400;
cs.cy = 200;
cs.style = cs.style & ~FWS_ADDTOTITLE;
// cs.style = WS_OVERLAPPEDWINDOW;
cs.lpszName = "標題";
return TRUE;
}
7.1.2在窗口創建之後更改其風格
在應用程序窗口創建之後修改它的風格屬性,可在CMainFrame類的OnCreate函數中調用SetWindowLong函數實現。
SetWindowLong(HWND hWnd, int nIndex, LONGdwNewLong)
該函數的作用是改變制定窗口的屬性(包括設置新的窗口風格、設置新的窗口過程、設置新的應用程序實例局柄等)。要改變窗口的風格,則將該函數的第二個參數指定爲GWL_STYLE,然後由第三個參數指定新的窗口風格。
如果是在已有類型的基礎上進行修改的話,那麼可以利用GetWindowLong這個函數獲得這個窗口的現有類型,然後修改。例如:
SetWindowLong(m_hWnd, GWL_STYLE, GetWindowLong(m_hWnd, GWL_STYLE) & ~WS_MAXIMIZEBOX);
7.1.3 在窗口創建之後更改標題與大小
在應用程序窗口創建之後修改標題,可在CMainFrame類的OnCreate函數中調用SetWindowText函數實現。
在應用程序窗口創建之後修改大小,可在CMainFrame類的OnCreate函數中調用SetWindowPos函數實現。
7.2 修改光標、圖標、背景
7.2.3 在窗口創建前更改
之前對於窗口的大小、標題和風格是在創建窗口時設定的。而光標、圖標和背景是在設計窗口類時指定的。窗口類的設計與註冊是由MFC底層代碼自動完成的,我們不可能、也不應該去修改MFC底層代碼。但是我們可以編寫自己的窗口類註冊,然後讓隨後的窗口按照我們編寫的窗口類去創建。
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT&cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
…
WNDCLASSMyWnd;
MyWnd.cbClsExtra = NULL;MyWnd.cbWndExtra = NULL;
MyWnd.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
MyWnd.hCursor = LoadCursor(NULL, IDC_CROSS);
MyWnd.hIcon = LoadIcon(NULL, IDI_WARNING);
MyWnd.hInstance = AfxGetInstanceHandle();
MyWnd.lpfnWndProc = ::DefWindowProc;
MyWnd.lpszClassName = "Hello";
MyWnd.lpszMenuName = NULL;
MyWnd.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&MyWnd);
cs.lpszClass = "hello";
return TRUE;
}
上述代碼的運行結果是:僅僅是程序的標題欄圖標發生了改變,但窗口的背景和光標沒有改變。原因是:視類窗口覆蓋在主窗口上面,我們看到的窗口實際上是視類窗口,而上述代碼修改的是框架類窗口的背景和光標。應用程序的圖標屬於框架窗口,因此上述程序運行後,圖標發生了改變。
結論:在MFC中,如果要修改應用程序窗口的圖標,則應該框架類中進行,因爲框架窗口才有標題欄;如果要修改程序窗口的背景和光標,則應該在視類中進行。解決方法:在視類的PreCreateWindow函數中添加代碼: cs.lpszClass= "hello";。
同時MFC爲我們提供了一個全局函數AfxRegisterWndClass()。
LPCTSTR AFXAPI AfxRegisterWndClass(UINTnClassStyle, HCRSOR hCursor = 0, HBRUSH hbrBackground = 0, HICON hIcon = 0);
7.2.2 在窗口創建之後更改
要在應用程序窗口創建之後修改它的光標、圖標和背景,可在OnCreate函數中調用SetClassLong函數實現。DWORD SetClassLong(HWNDhWnd, int nIndex, LONG dwNewLong)
該函數的作用是:重新設置指定窗口所屬窗口類的WNDCLASS結構體中指定數據成員的屬性(包括設置新的窗口背景畫刷、光標、圖標和窗口類樣式)。
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
…
SetClassLong(m_hWnd,GCL_HICON, (LONG)LoadIcon(NULL, IDI_WARNING));
return 0;
}
int CMyMFCAppView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
…
//7.2.2 在窗口創建之後更改光標、標題欄圖標、窗口背景
SetClassLong(m_hWnd, GCL_HBRBACKGROUND, (LONG)GetStockObject(BLACK_BRUSH));
SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_CROSS));
return 0;
}
7.3 模擬動畫圖標
7.3.1 加載圖標資源
添加IDI_ICON1-4資源,氣候在框架類定義一個圖標句柄成員變量,添加數組時,類型設置爲HICON [4]方能設置成功。在視類添加一下代碼。
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));
m_hIcons[3] = AfxGetApp()->LoadIcon(IDI_ICON4);
其中LoadIcon第一個參數,加載第一幅時,AfxGetInstanceHandle可以獲取應用程序當前句柄。第二個參數,通過MAKEINTRESOURSE宏將ID轉換爲相應的資源表示符字符串。第二幅應用theApp的獲取應用程序的CWinApp對象,其數據成員m_hInstance得到實例句柄。但是App文件中已經定義了一個theApp全局變量,所以在框架類OnCreate函數前extern CMyMFCApp theApp。第三幅加載,用AfxGetApp全局函數實現。
7.3.2設置定時器
在框架類OnCreate函數添加SetTime函數,沒1000ms觸發一次定時器消息。
SetTimer(1, 1000, NULL);
在框架類添加定時器消息(WM_TIMER)的響應函數,並在響應函數調用SetClassLong函數改變應用程序窗口圖標。
void CMainFrame::OnTimer(UINT_PTR nIDEvent)
{
//TODO: 在此添加消息處理程序代碼和/或調用默認值
static int index = 1;
SetClassLong(m_hWnd, GCL_HICON, (LONG)m_hIcons[index]);
index = ++index % 4;
CFrameWnd::OnTimer(nIDEvent);
CFrameWnd::OnTimer(nIDEvent);
}
因爲程序每次發送定時器消息都會調用OnTimer函數,所以把index定義爲靜態(分配在棧中)。
7.4工具欄編程
7.4.1 在工具欄添加按鈕
在資源的toolbar中在IDR_MAINFRAME的最右邊添加一個按鈕IDM_TEST。並在菜單欄【幫助】下添加一個同ID的按鈕,Caption設置爲Test。添加一個命令響應函數OnTestShow。可以將T按鈕享有拖動一點,此時幫助與T按鈕有一定空隙。想要刪除只需del。
void CMainFrame::OnTestShow()
{
//TODO: 在此添加命令處理程序代碼
MessageBox("Teston toolbar");
}
7.4.2創建工具欄——4個步驟
Step1:創建工具欄資源;
Step2:構造CToolBar對象;主框架添加私有變量
Step3:調用Create或CreateEx函數創建Window工具欄(工具欄也是窗口)
Step4:調用LoadToolBar函數加載工具欄資源。
7.4.3 創建自定義工具欄
在TOOLBAR添加新資源,在框架類加加一個CToolBar類型的成員變量,調用create函數創建工具欄,與CToolBar相關聯,可以在框架類的OnCreate函數實現。添加一下代碼。
<span style="white-space:pre"> </span>if (!m_newToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_newToolBar.LoadToolBar(IDR_TOOLBAR1))
{
TRACE0("Failed to create toolbar\n");
return-1; // fail to create
}
m_newToolBar.EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_newToolBar);
CreateEx函數創建工具欄,並與工具欄對象:m_newToolBar關聯,停靠位置設置爲CBRS_RIGHT。調用LoadToolBar加載資源。調用EnableDocking函數允許工具欄停靠客戶區任意位置。最後調用DockControlBar函數,讓工具欄停靠在主框架窗口上。
7.4.4 顯示和隱藏工具欄
在【視圖】自此阿達您下載添加一個菜單項。ID屬性爲IDM_VIEW_NEWTOOLBAR,Caption爲“新的工具欄”。接着添加命令響應函數。在響應函數中,實現先前新建的工具欄的顯示與隱藏。可以調用ShowWindow函數。之後需要調整他們的位置,調用RecalcLayout函數。限制或隱藏後再次調用框架類DockControlBar函數。讓工具欄停靠在主框架窗口上,使用DockControlBar函數。
void CMainFrame::OnViewNewtoolbar()
{
//TODO: 在此添加命令處理程序代碼
if (m_newToolBar.IsWindowVisible())
m_newToolBar.ShowWindow(SW_HIDE);
else
m_newToolBar.ShowWindow(SW_SHOW);
RecalcLayout();
DockControlBar(&m_newToolBar);
}
如何讓新建的工具欄舍在原先顯示位置顯示。需要調用ShowControlBar函數。
下面,添加複選編輯。爲此爲菜單項添加一個UPDATE_COMMAND_UI函數。內部添加代碼。
void CMainFrame::OnUpdateViewNewtoolbar(CCmdUI *pCmdUI)
{
//TODO: 在此添加命令更新用戶界面處理程序代碼
// 添加複選框
pCmdUI->SetCheck(m_newToolBar.IsWindowVisible());
}
7.5 狀態欄編程
7.5.1 狀態欄的提示行與指示器
狀態欄分爲兩部分:提示行與指示器。左邊最長的部分爲提示行,通常用於顯示菜單項或工具按鈕的提示信息。右邊由若干窗格組成的部分爲狀態欄指示器,通常用來顯示大小寫鍵、數字鎖定鍵等信息。
框架程序專門提供了一個indicators數組來管理提示行與指示器。如果要修改狀態欄的外觀,則只需在indicators數組中添加或減少相應的字符串資源ID即可。
① 在資源編輯器中新增字符串資源ID:
ID_TIMER 時鐘
② 將新的字符串資源ID添加到indicators數組中
③ 獲取系統當前時間(加在CMainFrame的OnCreate函數的後部)
CTime t = CTime::GetCurrentTime();
CString str = t.Format("%H:%M:%S");
④ 將字符串顯示到狀態欄的窗格上,調用CStatusBar類的成員函數SetPaneText。如果不知道窗格的索引,可以調用CStatusBar類的成員函數CommandToIndex獲得。m_wndStatusBar.CommandToIndex(ID_TIMER)
m_wndStatusBar.SetPaneText(1, str);
⑤ 調整窗格大小
CStatusBar類的成員函數:SetPaneInfo,該函數可以爲指定的窗格設置新的ID、樣式和寬度。
CClientDC dc(this);
CSize sz = dc.GetTextExtent(str);
m_wndStatusBar.SetPaneInfo(1, ID_TIMER, SBPS_NORMAL,sz.cx);
⑥ 在OnTimer中添加相關代碼。
7.6 在狀態欄中添加鼠標座標顯示
方法一:調用SetWindowText函數設置狀態欄提示行文本
需添加頭文件並把m_wndStatusBar改爲公有
CString str;
str.Format("x=%d, y=%d", point.x, point.y);
((CMainFrame*)GetParent())->m_wndStatusBar.SetWindowText(str);
方法二:利用CFrameWnd類的成員函數SetMessageText實現,該函數的作用是在狀態欄的提示行中設置文本。
((CMainFrame*)GetParent())->SetMessageText(str);
方法三:利用CFrameWnd類的成員函數GetMessageBar可以返回狀態欄對象的指針,這樣也不用再訪問CMainFrame類的保護成員變量:m_wndStatusBar。
((CMainFrame*)GetParent())->GetMessageBar()->SetWindowText(str);
在提示行中顯位圖(藉助位圖按鈕的方法)
在框架類添加CBitmapButton m_bmp變量。
CRect rc(100, 4, 120, 20);
if (!m_bmp.Create("", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, rc, &m_wndStatusBar, 0))
return FALSE;
if (!m_bmp.LoadBitmaps(IDB_BITMAP1, NULL, NULL, NULL))
return FALSE;
7.7添加啓動界面
7.7.1 利用VC++組件庫中提供的類完成
單擊[Project \ Add to Project \Components and controls…],在彈出的組件和控件庫對話框中雙擊“Visual C++ Components”目錄,在該目錄下找到Splashscreen組件。
替換splsh.bmp位圖文件可替換啓動界面;
更改SetTimer(1, 2000, NULL)可設定啓動畫面的停留時間。
7.7.2 VS添加啓動畫面
1)新建一個ID_BITMAP3的位圖資源。
2)現在項目下新建一個類CSplashWnd,基類爲CWnd;
3)在該類下添加一個protected型的變量CBitmap m_bitmap
4)添加一個Create函數加載位圖,創建窗口;
public:
BOOL Create();
BOOL CSplashWnd::Create()
{
if (!m_bitmap.LoadBitmap(IDB_BITMAP3))
return false;
BITMAP bm;
m_bitmap.GetBitmap(&bm);
return CreateEx(0, AfxRegisterWndClass(0,AfxGetApp()->LoadStandardCursor(IDC_ARROW)),
NULL, WS_POPUP | WS_VISIBLE, 0,0, bm.bmWidth, bm.bmHeight, NULL, NULL);
}
5)顯示窗口發送WM_PAINT消息,映射此消息;
void CSplashWnd::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: 在此處添加消息處理程序代碼
// 不爲繪圖消息調用 CWnd::OnPaint()
CDC dcimage;
if (!dcimage.CreateCompatibleDC(&dc)) return;
BITMAP bm;
m_bitmap.GetBitmap(&bm);
CBitmap* pOldBitmap = dcimage.SelectObject(&m_bitmap);
dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcimage, 0, 0, SRCCOPY);
dcimage.SelectObject(pOldBitmap);
}
6)在App類中包含新類的頭文件後,在InitInstance()函數中添加以下代碼:
CSplashWnd *pSplashWindow = new CSplashWnd;//創建對象
pSplashWindow->Create();
pSplashWindow->CenterWindow();
pSplashWindow->ShowWindow(SW_SHOW); //顯示窗口
pSplashWindow->UpdateWindow();
Sleep(2000); //表示啓動畫面持續時間
pSplashWindow->DestroyWindow(); //銷燬啓動畫面
delete pSplashWindow; //刪除