Опубликован: 17.08.2010 | Доступ: свободный | Студентов: 999 / 59 | Оценка: 4.11 / 3.89 | Длительность: 29:38:00
Самостоятельная работа 8:

Работа MFC с GDI (GDI+)

Подключение холста к главному окну приложения

Нам нужно в описании класса главного диалогового окна приложения включить переменную как экземпляр класса диалогового окна холста и через нее управлять холстом из главного окна. Для этого:

  • Перейдите на вкладку Class View и выделите класс CGraphicsDlg
  • Вызовите мастер Add Variable и настройте его так

    Мастер добавит код

    Файл GraphicsDlg.h
    // GraphicsDlg.h : header file
    //
      
    #pragma once
    #include "paintdlg.h"
      
    // CGraphicsDlg dialog
    class CGraphicsDlg : public CDialog
    {
    ...................................................
    private:
      // Экземпляр класса CPaintDlg для управления холстом
      CPaintDlg m_dlgPaint;
    };
    Файл GraphicsDlg.cpp
    CGraphicsDlg::CGraphicsDlg(CWnd* pParent /*=NULL*/)
      : CDialog(CGraphicsDlg::IDD, pParent)
      , m_iTool(0)
      , m_iShape(0)
      , m_iColor(7)
      , m_dlgPaint(0)
    {
      m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }
  • Удалите приведенную инициализацию переменной m_dlgPaint из конструктора класса CGraphicsDlg - она не нужна
  • Проверьте обязательно - должна быть включена инструкция #include "paintdlg.h" в начало файла GraphicsDlg.h
  • Добавьте в метод инициализации код
    Файл GraphicsDlg.cpp
    BOOL CGraphicsDlg::OnInitDialog()
    {
      CDialog::OnInitDialog();
      
      // Add "About..." menu item to system menu.
      
    ...........................................................
      
      // Set the icon for this dialog.  The framework does this automatically
      //  when the application's main window is not a dialog
      SetIcon(m_hIcon, TRUE);      // Set big icon
      SetIcon(m_hIcon, FALSE);    // Set small icon
      
      // TODO: Add extra initialization here
      
      // Создать диалоговое окно холста с текущим родителем
      m_dlgPaint.Create(IDD_PAINT_DLG, this);
      // Показать холст поверх родителя
      m_dlgPaint.ShowWindow(SW_SHOW);
      
      return TRUE;  // return TRUE  unless you set the focus to a control
    }
  • Постройте приложение и убедитесь, что холст появляется вместе с родителем, сворачивается и закрывается вместе с ним, при этом находится всегда поверх родителя

Такие же родительско-дочерние отношения существуют между главным диалоговым окном и всеми помещенными в него элементами управления. Каждый управляющий элемент - наследник своего диалогового окна. В некотором смысле второе диалоговое окно является просто еще одним управляющим элементом первого диалогового окна.

Добавление графических возможностей

Поскольку все закрепленные за переключателями переменные объвлены в первом окне как общедоступные, то второе диалоговое окно может их видеть и по их состоянию реагировать на рисование должным образом. Моно разместить все функции рисования графики в классе второго диалогового окна. Однако для того, чтобы своевременно обновлять значения переменных, а также сообщать второму диалоговому окну, что нужно вывести графику, некоторые функции должны находиться в первом диалоговом окне.

Всякий раз, когда окно должно быть перерисовано заново (если оно было заслонено другим окном или свернуто), операционная система вызывает функцию диалогового окна OnPaint(). В ней можно разместить все функции рисования графики. Но одновременно во втором диалоговом окне пока нет такой функции, но мы ее позже определим.. Как заставить второе диалоговое окно обновляться каждый раз, когда мы в нем что-нибудь нарисуем?

Для этого можно применить к нему функцию Invalidate() (Считать недействительным). Вызов этой функции автоматически вызывает OnPaint() как функцию-член базового класса CDialog. Функция Invalidate() не требует никаких параметров и является членом класса CWnd, так что может использоваться для любого окна или элемента управления. Она сообщает окну и операционной системе, что отображаемая область окна более не соответствует действительности и требуется ее перерисовка.

На данном этапе замкнем все переключатели на один комбинированный обработчик, в котором будет организована синхронизация работы элементов управления и значений закрепленных за ними переменных с помощью функции UpdateData(TRUE) ( TRUE - привести переменные в соответсвие с экранным представлением элементов управления "экран->переменные", FALSE - привести экранное представление элементов управления в соответствие со значениями ассоциированных с ними переменных "переменные->экран"). Здесь же, принимая во внимание, что любое изменение состояния переключателей должно приводить к изменению графики на холсте, предусмотрим вызов обновления второго диалогового окна с помощью функции Invalidate() второго окна.

  • Откройте первое диалоговое окно и выделите на нем первый переключатель IDC_RPEN. Через контекстное меню элемента выполните опцию Add Event Handler


    Появится мастер, который заполните так


    Мастер создаст шаблон обработчика и зарегистрирует его в карте сообщений

    Объявление обработчика в файле GraphicsDlg.h
    class CGraphicsDlg : public CDialog
    {
    ...................................................
    private:
      // Экземпляр класса CPaintDlg для управления холстом
      CPaintDlg m_dlgPaint;
    public:
      afx_msg void OnRadioSelection();
    };
    Шаблон обработчика в файле GraphicsDlg.cpp
    void CGraphicsDlg::OnRadioSelection()
    {
      // TODO: Add your control notification handler code here
    }
    Регистрация обработчика в карте сообщений в файле GraphicsDlg.cpp
    BEGIN_MESSAGE_MAP(CGraphicsDlg, CDialog)
      ON_WM_SYSCOMMAND()
      ON_WM_PAINT()
      ON_WM_QUERYDRAGICON()
      //}}AFX_MSG_MAP
      ON_BN_CLICKED(IDC_BEXIT, OnBnClickedBexit)
      ON_BN_CLICKED(IDC_RPEN, OnRadioSelection)
    END_MESSAGE_MAP()
  • Отредактируйте обработчик и карту сообщений так

    Обработчик в файле GraphicsDlg.cpp
    void CGraphicsDlg::OnRadioSelection()
    {
      UpdateData(TRUE); // Обновляем переменные с экрана
      m_dlgPaint.Invalidate(); // Перерисовать второе окно
      
    // Ниже код для отладки, потом убрать !!!!!
      CString str;
      str.Format("Tool=%d; Shape=%d; Color=%d", m_iTool, m_iShape, m_iColor);
      MessageBox(str, "Состояние переключателей");
    }
    Карта сообщений в файле GraphicsDlg.cpp
    BEGIN_MESSAGE_MAP(CGraphicsDlg, CDialog)
      ON_WM_SYSCOMMAND()
      ON_WM_PAINT()
      ON_WM_QUERYDRAGICON()
      //}}AFX_MSG_MAP
      ON_BN_CLICKED(IDC_BEXIT, OnBnClickedBexit)
      ON_BN_CLICKED(IDC_RPEN, OnRadioSelection)
      ON_BN_CLICKED(IDC_RBRUSH, OnRadioSelection)
      ON_BN_CLICKED(IDC_RBITMAP, OnRadioSelection)
      ON_BN_CLICKED(IDC_RLINE, OnRadioSelection)
      ON_BN_CLICKED(IDC_RCIRCLE, OnRadioSelection)
      ON_BN_CLICKED(IDC_RSQUARE, OnRadioSelection)
      ON_BN_CLICKED(IDC_RBLACK, OnRadioSelection)
      ON_BN_CLICKED(IDC_RBLUE, OnRadioSelection)
      ON_BN_CLICKED(IDC_RGREEN, OnRadioSelection)
      ON_BN_CLICKED(IDC_RCYAN, OnRadioSelection)
      ON_BN_CLICKED(IDC_RRED, OnRadioSelection)
      ON_BN_CLICKED(IDC_RMAGENTA, OnRadioSelection)
      ON_BN_CLICKED(IDC_RYELLOW, OnRadioSelection)
      ON_BN_CLICKED(IDC_RWHITE, OnRadioSelection)
    END_MESSAGE_MAP()
  • Запустите приложение и проверьте с помощью отладочного кода реагирование обработчика на нажатия на все переключатели, затем уберите отладочный код из обработчика

Создание таблицы цветов

Чтобы имет возможность рисовать фигуры различным цветом в соответствии с состоянием группы переключателей Color, создадим в класса CPaintDlg массив структур типа COLORREF, необходимый для выбора цвета пера и кисти рисования. Массив будет состоять из 8 элементов, каждый из которых будет содержать цвет, соответствующий переключателям группы Color главного окна.

  • Добавьте новую глобальную переменную в класс второго диалогового окна, которая будет являться массивом цветов. Для этого в конец объявления класса CPainDlg введите код

    Объявление цвета в файле PaintDlg.h
    class CPaintDlg : public CDialog
    {
    ............................................
    public:
      // Таблица цветов
      static const COLORREF m_crColors[8];
    };

В конце файла PaintDlg.cpp вне любой из функций (глобально) введите код

Определение цвета в файле PaintDlg.cpp
const COLORREF CPaintDlg::m_crColors[] = {
  RGB(0, 0, 0),    // Black - черный
  RGB(0, 0, 255),    // Blue - синий
  RGB(0, 255, 0),    // Green - зеленый
  RGB(0, 255, 255),  // Cyan - голубой
  RGB(255, 0, 0),    // Red - красный
  RGB(255, 0, 255),  // Magenta - сиреневый
  RGB(255, 255, 0),  // Yellow - желтый
  RGB(255, 255, 255)  // White - белый
};
Александр Даниленко
Александр Даниленко
Стоит Windows 8 Pro, Visual Studio 2010 Express Edition .