VC++60 第十四章 單文檔界面的程序

第十四章 單文檔界面的程序

 

用VC++的AppWizard生成的程序有三種樣式的界面,它們是單文檔、多文檔和對話框界面。前面各章我們都生成對話框樣式的界面,這可以方便我們學習各種常用控件的設計,本章要學習如何生成一個單文檔界面的應用程序,以及文檔類和視圖類的概念和相互關係。

 

本章要點

1 用AppWizard生成單文檔界面的操作方法
2 文檔類和視圖類的概念
3 如何保持文檔和視圖的同步關聯。

 

14.1 生成單文檔界面的文本編輯器

 

用AppWizard生成單文檔界面的操作方法和生成對話框界面的操作方法稍有不同,我們通過建立一個“文本編輯器”應用程序MyNote.exe來演示,具體過程如下:

1 打開應用程序嚮導,在d:\myVC\CH14創建應用程序MyNote。
2 在Step1中選擇“單文檔”和“文檔/視圖支持”,如圖chap14-01.

VC++60 <wbr>第十四章 <wbr>單文檔界面的程序
圖chap14-01

 

3 在step2和step3對話框中都用默認的。在step4中如圖chap14-02選擇前五項,當然也可以按你的需要選擇。
VC++60 <wbr>第十四章 <wbr>單文檔界面的程序
圖chap14-02

4 在Step5中選擇MFC標準、加備註和靜態連接庫。圖chap14-03
VC++60 <wbr>第十四章 <wbr>單文檔界面的程序
圖chap14-03

5 在step6中選擇視圖的基類(base class),因爲我們需要的是文本編輯器,所以要選類CEditView作爲基類。點擊[完成]按紐,應用程序的框架就創建好了。

 

14.2 文檔類和視圖類的概念

 

嚮導工作完成以後馬上編譯和連接,運行後就可以看到一個已經能夠使用的文本編輯器,它不僅可以輸入文字,還可以保存或打開文件,與Windows的記事本差不多了,只是沒有設置字體的功能。圖chap14-04是它運行時的窗口。

VC++60 <wbr>第十四章 <wbr>單文檔界面的程序
chap14-04

菜單和工具欄的響應函數都已經生成了相應的代碼,我們沒有做任何編寫工作就得到了一個“完整”的應用程序,甚至還創建了一個幫助文件呢。這就是VC++開發環境的巨大威力!我們從上圖中可以看到,編輯菜單中的複製和剪切都已經有效了。

圖中的窗口是主框架,對應於類CMainFrame,而其中的“編輯區域”叫用戶區,對應於視圖類CMyNoteView,而被編輯的文本對應於一個文檔類CMyNoteDoc。另外,每個程序還有一個對應於應用程序本身的類,本例中是CMyNoteApp。這四個類就是嚮導自動生成的應用程序框架類,打開工作區的類classView頁區,就可以看到,如圖chap14-05。

VC++60 <wbr>第十四章 <wbr>單文檔界面的程序
chap14-05

展開視圖類,可以找到一個函數GetDocument(),它是使視圖(的內容)和文檔保持同步關聯的紐帶。它返回一個CMyNoteDoc類型的對象指針m_pDocument。使用它在視圖中訪問文檔的內容。
在文檔類中有一個OnNewDocument()函數,在“新建文件”和程序第一次運行時被調用,它打開一個新文檔供用戶編輯。我們來看一下它的代碼:

BOOL CMyNoteDoc::OnNewDocument()
{
    if (!CDocument::OnNewDocument())
        return FALSE;
    ((CEditView*)m_viewList.GetHead())->SetWindowText(NULL);
    return TRUE;
}

if語句調用其父類的同名函數,第二個語句設置編輯區的文本爲空白。你試着用“這是一個新文檔”來代替NULL,重新編譯和運行,那每次打開時編輯區會出現這句話。
文檔類中還有一個叫Serialize,把它系列化對象CArchive& ar設置爲按行系列化,這是純文本文件存取時所需要的。下面是它的代碼。

void CMyNoteDoc::Serialize(CArchive& ar)
{
    // CEditView contains an edit control which handles all serialization
    ((CEditView*)m_viewList.GetHead())->SerializeRaw(ar);
}

在下一節中,我們將通過一個例程來演示,如何在文檔對象和視圖對象之間互相訪問和交換數據。

 

14.3 Circle程序的界面和功能

 

Circle程序的功能是:用鼠標左鍵在用戶區域任意的點一下,就以這一點爲圓心畫一個半徑爲50的圓。程序的界面和上例一樣,都是單文檔程序的基本形式麼。但是其客戶區年輸入文字,是畫圖形式的。

 

VC++60 <wbr>第十四章 <wbr>單文檔界面的程序
圖chap14-06

 

下面我們就來製作這一程序。
1 創建工程
打開應用程序嚮導,在d:\myVC\CH14創建應用程序Circle。選擇“單文檔”,後面的應答與上例一樣。不同的是最後一步視圖基類的選擇,不是選CEditView而是選CView。CEditView類是CView類的子類,適合於需要文字編輯的場合。

2 添加變量
畫圓需要與圓心和半徑,爲了文檔和視圖的同步,我們需要給兩者都引進三個變量m_PosX、 m_PosY和m_Reduse。定義要寫在他們的構造函數中:

public:
    int m_PosX, m_PosY;
    int m_Reduse ;

3 編寫代碼
(1)函數OnDraw(CDC* pDC)的功能是在客戶區畫圖,我們用它以試圖中的變量值來畫圓,代碼如下:

void CCircleView::OnDraw(CDC* pDC)
{
    CCircleDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    // TODO: add draw code for native data here
    //Draw a circle
    RECT rect;
    rect.left= m_PosX - m_Reduse ;
    rect.top = m_PosY - m_Reduse ;
    rect.right = m_PosX + m_Reduse ;
    rect.bottom= m_PosY + m_Reduse ;
    pDC->Ellipse(&rect);
}
其中pDC是由參數表傳遞過來的屏幕設備對象,可以畫圖。RECT是表示舉行的數據結構。是畫圖圓需要的參數。

(2)變量m_PosX等的值在初始更新函數OnInitialUpdate()中給定,而值是從文檔的同名函數中傳遞過來的。

    CCircleDoc* pDoc = GetDocument();
    m_PosX = pDoc->m_PosX ;
    m_PosY = pDoc->m_PosY ;
    m_Reduse = pDoc->m_Reduse ;

(3)要求當“按下鼠標時畫圓”,就要添加OnLButtonDown函數,其中使用Invalidate(),它會調用函數OnDraw重新畫客戶區,其代碼如下:

void CCircleView::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: Add your message handler code here and/or call default
    m_PosX = point.x ;
    m_PosY = point.y ;
    Invalidate();
    CCircleDoc* pDoc = GetDocument();
    pDoc->m_PosX = m_PosX;
    pDoc->m_PosY = m_PosY;
    pDoc->SetModifiedFlag(TRUE);
    CView::OnLButtonDown(nFlags, point);
}

變量point對應的是鼠標當前點的位置,傳遞給視圖的變量,然後畫圓;再把它傳遞給文檔,這就保證視圖和文檔數據的一致性。語句

        pDoc->SetModifiedFlag(TRUE);

設置文檔已經被修改的標誌,這使得程序在退出時會詢問“是否要保存?”。

(4)在文檔類中有一個函數OnNewDocument(),它是在按“文件/新建”時被調用的。我們用它給出圓的初始值:

   m_PosX = 100;
    m_PosY = 100;
    m_Reduse = 50 ;

需要的代碼就這些了,現在可以編譯和運行之。

 

思考和練習

1 文檔類應用程序是如何保持視圖和文檔數據的一致性的?
2 在MyNote程序中添加菜單及其代碼,擴展它的功能。例如,增加文字的大小和顏色等。
3 在Circle程序中添加菜單及其代碼,擴展它的功能。例如,可變的半徑,畫不同的圖形等。

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