Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Уроки по Visual C++ (MFC, платформа .NET)


Информационный Канал Subscribe.Ru

Visual C++. MFC. Уроки по программированию с сайта http://progs.biz

Рассылка №34

Visual C++. MFC. Урок 31. Связывание Вида и Документа.
Visual C++. MFC. Урок 32. Несколько Видов с одним Документом.

Полные версии уроков (с картинками) можно найти по адресам
Урок 31. Связывание Вида и Документа.
Урок 32. Несколько Видов с одним Документом.

Visual C++. MFC. Урок 31. Связывание Вида и Документа

Это занятие посвящено тому, как организовать связь между документом и видом. Напомним, что в соответствии с концепцией Документ-Вид в классе Документа данные хрянятся, а класс Вида ответственен за показ данных на экране (это, конечно, очень упрощено, но для этого урока хватит и этого).

Итак, возьмите программу, созданную на прошлом уроке. Так так именно класс Документа хранит данные, то заведите в нем некоторую переменную для данных, например типа int:

class CMyDoc: public CDocument{
 ...
public:
    int m_nNum;//данные
};

Для упрощения мы пометили эти данные в public-секции класса (надо бы в protected или в private, да лень возиться с дополнительными функциями).

Далее где-нибудь задайте начальное значение для нашей переменной. Например, в конструкторе:

    ...
    CMyDoc(){
        m_nNum=123;
    };
    ...

Теперь переходим к классу Вида. Добавляем в него метод GetDocument():

class CMyView: public CView{
 ...
public:
 CMyDoc* GetDocument();
    ...

Обратите внимание на тип возвращемого значения для нашего метода - это указатель на класс документа: CMyDoc*.

Пишем теперь реализацию этого метода:

CMyDoc* CMyView::GetDocument()
{
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMyDoc)));
    return (CMyDoc*)m_pDocument;
}

Здесь есть одна проблема - мы в этом методе используем наш класс Документа, но по тексту программы он расположен ниже класса Вида, так что компилятор нашего класса Документа в этом месте еще не увидит (правила "сначала вводим, а затем используем" пока никто не отменял). Выход очень простой - просто перенесите класс Документа выше - разместите его перед классом Вида.

Теперь осталось только написать код, который продемонстрирует нам, что связь между Документом и Видом есть. Например, это можно сделать в OnDraw:

void CMyView::OnDraw(CDC *pDC){
    //Заводим временную переменную
    CString s;
    //Получаем указатель на документ
    CMyDoc* pDoc=GetDocument();
    //Записываем данные из документа в переменную
    s.Format("%d", pDoc->m_nNum);
    //Выводим переменную в окно
    pDC->TextOut(10, 10, s);
}

А вот и результат нашей программы - прии запуске в окне появится строка 123.

Связь между Документом и Видом установлена.

Наверх

Visual C++. MFC. Урок 32. Несколько Видов с одним Документом

У одного документа может быть несколько видов (вспомните, например, Word). На этом занятии мы с вами и посмотрим, как это реализовать. В качестве основы берем программу, созданную на двух предыдущих уроках.

Для начала пишем второй класс Вида:

...
class CMyView2: public CView{
public:
    CMyView2(){};
protected:
    DECLARE_DYNCREATE(CMyView2)
public:
    CMyDoc* GetDocument();
    virtual void OnDraw(CDC *pDC);
};
IMPLEMENT_DYNCREATE(CMyView2, CView)
void CMyView2::OnDraw(CDC *pDC){
    //Заводим временную переменную
    CString s;
    //Получаем указатель на документ
    CMyDoc* pDoc=GetDocument();
    //Записываем данные из документа в переменную
    s.Format("%d", pDoc->m_nNum);
    //Выводим переменную в окно
    pDC->TextOut(40, 40, s);
}
CMyDoc* CMyView2::GetDocument()
{
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMyDoc)));
    return (CMyDoc*)m_pDocument;
}
 ...

Разместить этот код можно сразу за первым классом. Как хорошо видно, наш новый класс CMyView2 - полная аналогия класса CMyView (класса для первого вида). Но обратите внимание на отличия - мы слегка изменили метод OnDraw:

...
    pDC->TextOut(40, 40, s); //Текст выводим из точки (40, 40)
 ...

Еще одно отличие - конструктор класса CMyView2 находится в public-секции класса. Это нам надо потому, что экземпляры классов видов мы будем создавать в обработчике меню. Кстати, перенесите конструктор в классе CMyView тоже в public-секцию:

...
public:
    CMyView(){};
    ...

Теперь добавьте в класс Окна-рамки метод для переключения видов:

class CMyWnd: public CFrameWnd{
    ...
    void Switch(int nView);

Напишите следующую реализацию для нашего метода:

void CMyWnd::Switch(int nView){
    //Указатель на текущий вид
    CView* pOldView=GetActiveView();
    //Указатель на другой вид
    CView* pNewView=(CView*)GetDlgItem(nView);
 //Если второй вид не создан, то создаем его
    if (pNewView == NULL) {
        switch (nView) {
        case 1:
            pNewView = (CView*) new CMyView;
            break;
        case 2:
            pNewView = (CView*) new CMyView2;
            break;
        }
        //Создаем контекст
        CCreateContext context;
        //Запоминаем в контексте документ
        context.m_pCurrentDoc = pOldView->GetDocument();
        //Связываем новый вид с окном-рамкой
        pNewView->Create(NULL, NULL, WS_BORDER,
            CFrameWnd::rectDefault, this, nView, &context);
        pNewView->OnInitialUpdate();
    }
    SetActiveView(pNewView);
    //Показываем новый вид
    pNewView->ShowWindow(SW_SHOW);
    //Прячем старый вид
    pOldView->ShowWindow(SW_HIDE);
    //
    pOldView->SetDlgCtrlID(
        pOldView->GetRuntimeClass() ==
        RUNTIME_CLASS(CMyView) ? 1 : 2);
    pNewView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
    RecalcLayout();
}

В приведенном коду мы используем класс CCreateContext. Добавьте для него соответствующий заголовочный файл:

#include <afxwin.h>
#include "resource.h"
#include <afxext.h>
 ...

Добавьте в наше меню два подпункта - в нашем примере они называются View1 и View2 и имеют идентификаторы ID_VIEWS_VIEW1 и ID_VIEWS_VIEW2 соответственно. Добавьте для наших пунктов меню два обработчика View1 и View2. Для этого добавьте в класс окна-рамки карту собщений:

BEGIN_MESSAGE_MAP(CMyWnd, CFrameWnd)
//связывание идентификатора с функцией
ON_COMMAND(ID_VIEWS_VIEW1, View1)
ON_COMMAND(ID_VIEWS_VIEW2, View2)
// конец карты сообщений
END_MESSAGE_MAP()

И добавьте макрос DECLARE_MESSAGE_MAP() в класс Окна-рамки:

class CMyWnd: public CFrameWnd{
    ...
    DECLARE_MESSAGE_MAP()
};

Осталось только добавить методы View1 и View2 в класс окна-рамки:

class CMyWnd: public CFrameWnd{
public:
    void View2();
    void View1();

Реализация у них будет следующая:

void CMyWnd::View1()
{
    Switch(1);
}

void CMyWnd::View2()
{
    Switch(2);
}

Все! Запускаем программу. Сначала у нас будет первый вид.

После переключения на другой вид расположение цифр на форме изменилось - оно стало ниже и правее.

Наверх

Copyright Алексеев Игорь, 2002

Copyright cайт progs.biz, 2002



http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное