標籤:
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; //刪除
七. 介面編程--Windows編程課程學習筆記