七. 界面編程--Windows編程課程學習筆記

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; //刪除

 

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