Visual C++的程式設計技巧

來源:互聯網
上載者:User
        Microsoft Visual C++是一種可視化程式設計語言,因功能強大而受到廣大程式設計人員的青睞。但是,由於VC++的應用程式架構結構非常複雜,使得許多初學者望而卻步。本文通過對設定視圖背景顏色和改變對話方塊標題的幾種實現方法的分析研究,揭示了VC++程式碼執行時的一些本質特徵和有關的程式設計技巧,對理解MFC庫的結構和Windows作業系統的內部工作方式提供了一定的協助。
設定視圖背景顏色
    對於VC++文檔、視結構中的視圖,從使用者的角度來看,只是可以改變大小、位置的普通視窗,同其他基於Windows應用程式的視窗是一樣的;從程式員的角度來看,視圖並不是普通的視窗,而是從MFC庫中CView類派生的類對象。像任何VC++對象一樣,視圖對象的行為由類的成員函數(資料成員)決定,包括衍生類別中應用程式定義的函數和從基類繼承來的函數。
提出問題
    視圖的背景一般來說是白色的,在預設情況下,它和系統定義的顏色COLOR_WINDOW是一致的。設計者一般會希望自己的程式可以讓使用者輕鬆地改變視窗背景顏色,或是用漂亮的圖片來充填背景。我們可以用Windows函數SetSysColors來重新指定COLOR_WINDOW所對應的實際顏色,來達到改變視圖背景顏色的目的。但這樣會同時改變其他應用程式的視圖視窗背景,使得整個Windows系統的顏色設定產生混亂。另外,我們可能會用以下方法來設定視圖的背景顏色,即在CView的OnDraw函數中添寫如下一段程式碼:
void CTestView::OnDraw(CDC* pDC)
{
CTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CRect rectClient;
CBrush brushBkColor;
GetClientRect(rectClient);
brushBkColor.CreateSolidBrush(RGB(255,0,0));
pDC->DPtoLP(rectClient);
pDC->FillRect(rectClient,&brushBkColor);
}
    這樣可以達到改變當前應用程式的視圖背景的目的,但同時也產生了一些不良影響,使得程式運行效果不盡如人意。
分析問題
    我們知道,在VC++的文檔、視結構中,CView的OnDraw函數用於實現絕大部分圖形繪製的工作。如果使用者改變視窗尺寸,或者顯示隱藏的地區,OnDraw函數都將被調用來重畫視窗。並且,當程式文檔中的資料發生改變時,一般必須通過調用視圖的Invalidate(或InvalidateRect)成員函數來通知Windows所發生的改變,對Invalidate的調用也會觸發對OnDraw函數的調用。正因為OnDraw函數被頻繁調用,所以在其執行時,每次都重新整理填充一次視圖用戶端區域,便會使螢幕不穩定,產生閃爍現象。
    筆者通過對VC++應用程式架構結構和Windows訊息映射系統的仔細研究,找到另外一種改變視圖背景的方法,其執行效果比上述兩種方法都好。其實在程式調用OnDraw函數之前,會觸發一個Windows訊息:WM_ERASEBKGND,以擦除視圖重新整理地區。在預設情況下,Windows系統使用視圖視窗註冊時視窗類別中的成員hbrBackground所描述的畫刷來擦除螢幕,這一般會將螢幕重新整理成COLOR_WINDOW所對應的顏色。因此,在OnDraw函數中設定背景顏色的執行過程是這樣的:先將螢幕重新整理成COLOR_WINDOW所對應的顏色,接著又在OnDraw函數中填充其他顏色,這正是產生螢幕閃爍的根本原因。
解決問題
    通過上述分析,我們應將視圖背景顏色填充移到Windows訊息:WM_ERASEBKGND所對應的訊息映射函數中,而不是在OnDraw函數中。我們可以通過下列步驟實現這一過程:在文檔類中增加一成員變數m_viewBkColor儲存當前背景顏色,同時增加兩個成員函數GetViewBkColor和SetViewBkColor對其進行讀寫操作。這樣做的好處是可以對m_viewBkColor成員進行序列化,將其和文檔聯絡在一起,開啟某一文檔時,其背景將和上一次程式操作該文檔時的背景保持一致。在視圖類中為視圖的Windows訊息WM_ERASEBKGND增加訊息映射函數OnEraseBkgnd,代碼如下:
BOOL CTestView::OnEraseBkgnd(CDC* pDC)
{
CRect rect;
CBrush brush;
brush.CreateSolidBrush(GetDocument()->GetViewBkColor());
pDC->GetClipBox(rect);
pDC->FillRect(rect,&brush);
return true;
}
    在該函數中不需要對用戶端區域矩形進行裝置座標到邏輯座標的轉換,並且Windows在調用該函數時會自動進行裁剪地區的計算,使得需要重新整理的螢幕面積達到最小。這樣我們可以在程式中通過設計下列菜單函數輕鬆地改變視圖背景的顏色,而且運行效果相當令人滿意。
void CTestView::OnChangeViewBkcolor()
{
CColorDialog cdlg;
if(cdlg.DoModal()==IDOK)
{
GetDocument()->SetViewBkColor
(cdlg.GetColor());
InvalidateRect(NULL);
}
}
改變對話方塊標題
提出問題
    在VC++程式設計過程中經常會遇到這樣的情況:執行程式的多個地方需要調用同一個對話方塊,但在不同的情況下希望給對話方塊加上不同的標題。開始我們可能會用下面的一段程式以達到這一目的:
CTestDialog dlg;
dlg.SetWindowText(“標題-1");
dlg.DoModal();
    利用上述辦法,我們本希望在程式不同的地方,通過設定函數SetWindowText不同的參數,以達到使同一對話方塊具有不同標題的目的,但這樣做是行不通的。
分析問題
    利用這種方法,當執行該段程式時,在一個可以忽略的錯誤之後,對話方塊的標題不會發生任何改變。這是因為,VC++程式設計中,大部分表單是動態建立的。比如上述對話方塊,在對dlg.DoModal的調用之前,雖然已構造了對話方塊的VC++對象,但表單對象還沒有被建立,顯然對一個沒有建立表單對象的對話方塊設定標題是行不通的。另外,dlg.DoModal的調用結束時,對話方塊表單對象將立即被釋放,因此在該函數之後設定對話方塊標題也是不行的。
解決問題
     通過對VC++架構結構中函數的調用順序的分析,我們發現在dlg.DoModal執行的開始時,程式會自動調用對話方塊的一系列初始化函數,其中包括對對話方塊成員函數OnInitDialog的調用,從這裡入手,將找到改變對話方塊標題的辦法。為此,首先為對話方塊引進一個類型為CString的公有成員變數m_strCaption,並將上述程式段改為:
CTestDialog dlg;
dlg.m_strCaption = “標題-1";
dlg.DoModal();
然後重載對話方塊的虛成員函數OnInitDialog如下:
BOOL CTestDialog::OnInitDialog()
{
CDialog::OnInitDialog();
SetWindowText(m_strCaption);
return TRUE;
}
    通過這種辦法,每次在開啟對話方塊之前,只要將對話方塊公有成員變數m_strCaption設定為一個不同的值,就可使得對話方塊有不同的標題。
小 結
    本文介紹的2個技巧有一個相似之處,就是用於解決問題的程式實現代碼基本上是相同的,只是被放在了程式流程的不同地方。這正是學習和熟練掌握VC++的一個非常重要的方面,是影響其程式執行效率和效能的關鍵。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.