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

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

Изменение размеров холста

Созданное нами окно-холст имеет фиксированные размеры, установленные нами при проектировании его графического ресурса и не может их менять в процессе работы. Дадим возможность пользователю изменять размеры холста. Для этого:

  • Откройте диалоговый ресурс с идентификатором IDD_PAINT_DLG второго диалогового окна в окне дизайнера ресурсов и измените два его свойства так
    • Border = Resizing (с изменяемым размером)
    • Title Bar = True (с заголовком окна)
  • Постройте приложение и убедитесь, что теперь холст способен изменять свои размеры

Но при изменении размеров рисунки в нем размазываются и перерисовываются только после того, как окно закроется другим окном и возникнет необходимость перерисовать его полностью. Исправим это:

  • Вновь выделите ресурс диалогового окна холста в окне дизайнера ресурсов и в таблице свойств включите режим Messages
  • Найдите сообщение WM_SIZE, которое выдает Windows каждый раз, когда меняется размер окна, и создайте функцию-обработчик OnSize()

Поскольку обработчик создается для диалогового окна холста, то именно это окно и будет обрабатывать это сообщение Windows, когда пользователь изменит его размеры.

  • Заполните обработчик так

    Изменения в функции OnSize() файла PaintDlg.cpp
    void CPaintDlg::OnSize(UINT nType, int cx, int cy)
    {
      CDialog::OnSize(nType, cx, cy);
      
      Invalidate(); // Перерисовать второе окно
    }
  • Постройте приложение и убедитесь, что при изменении размеров окна холста все работает как нужно

    Здесь осталась еще одна проблема, о которой мы упоминали ранее. При первом запуске приложения в холсте не прорисовываются стили линий или фигур. Для исправления этого можно поместить в функцию OnPaint() принудительный вызов обработчика OnRadioSelection(), который будет имитировать нажатие мышью на радиокнопке. Но чтобы этот вызов сработал только один раз при первом появлении окна, посадим его на условие. Для этого введем логическую переменную-флаг как член класса CGraphicsDlg, который поднимем в функции OnInitDialog(), а после первого срабатывания вызова OnRadioSelection() сразу опустим и более поднимать не будем.

  • Введите в класс CGraphicsDlg объявление переменной-флага вручную

    Добавление в классе CGraphicsDlg файла GraphicsDlg.h
    class CGraphicsDlg : public CDialog
    {
    ...............................................
    private:
      bool b_singleFlag;// для первой прорисовки холста
    };
  • Введите инициализацию переменной-флага в функцию OnInitDialog() класса CGraphicsDlg

    Добавление в функции OnInitDialog() файла GraphicsDlg.cpp
    BOOL CGraphicsDlg::OnInitDialog()
    {
    ......................................................
      // TODO: Add extra initialization here
      
      // Создать диалоговое окно холста с текущим родителем
      m_dlgPaint.Create(IDD_PAINT_DLG, this);
      // Показать холст поверх родителя
      m_dlgPaint.ShowWindow(SW_SHOW);
      b_singleFlag = true;
      
      return TRUE;  // return TRUE  unless you set the focus to a control
    }
  • Добавьте принудительный вызов обработчика в функцию OnPaint() класса CGraphicsDlg

    Добавление в функцию OnPaint() файла GraphicsDlg.cpp
    void CGraphicsDlg::OnPaint() 
    {
    ................................................
      else
      {
        CDialog::OnPaint();
      }
      
      if(b_singleFlag) // Вызов один раз
        OnRadioSelection(); // для имитации нажатия на радиокнопке
      if(b_singleFlag) // Сбросить флаг
        b_singleFlag = !b_singleFlag;
    }
  • Постройте приложение и убедитесь, что при начальном появлении окна все прорисовывается правильно

    Здесь осталась еще одна проблема, требующая решения. Поперемещайте холст за заголовок, после его начального появления, по экрану и частично за границы экрана. Вы увидете, что прорисовка опять разрушается и не восстанавливается или восстанавливается неверно. Исправим это (чтобы кот не гулял сам по себе, как Мельникова):

  • Вновь выделите диалоговый ресурс IDD_PAINT_DLG в окне дизайнера ресурсов и в таблице свойств включите режим Messages
  • Найдите сообщение WM_MOVE, которое выдает Windows каждый раз, когда окно перемещается по экрану за его заголовок пользователем, и создайте функцию-обработчик OnMove()

Поскольку обработчик создается для диалогового окна холста, то именно это окно и будет обрабатывать это сообщение Windows, когда пользователь переместит холст.

  • Заполните обработчик так

    Функция-обработчик OnMove() файла PaintDlg.cpp
    void CPaintDlg::OnMove(int x, int y)
    {
      CDialog::OnMove(x, y);
      
      // TODO: Add your message handler code here
      
      Invalidate(); // Перерисовать второе окно
    }
  • Постройте приложение

Теперь при любом перемещении окна функция Invalidate() заставляет срабатывать обработчик OnPaint() класса CPaintDlg. А там мы встроили вызовы функций рисования фигур DrawLine() и DrawRegion(), которые срабатывают по текущим настройкам элементов управления главного окна.

Вместо городьбы огорода с флагом b_singleFlag и принудительным вызовом функции-обработчика OnRadioSelection(), можно поступить иначе. Можно просто послать холсту после его создания сообщение WM_MOVE, предварительно создав обработчик сообщения WM_ACTIVATE и поместив туда код PostMessage(WM_MOVE) . Можете подумать и попробовать, лично мне лень...

Использование растров GDI

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

  1. Создать растровый рисунок как ресурс и разместить его сразу в диалоговом окне в элементе управления Picture Control
  2. Создать растровые рисунки как ресурсы, а затем загружать и отображать их в диалоговое окно программно в процессе выполнения приложения
  3. Загружать и отображать растровые рисунки из файлов .bmp, хранящихся на диске

Рассмотрим все эти способы.

Размещение растрового ресурса в окне About

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

  • Откройте диалоговый ресурс приложения с идентификатором IDD_ABOUTBOX
  • Выделите на форме элемент управления Picture Control, содержащий пиктограмму с иконкой приложения, и удалите его
  • Удалите все остальные элементы управления формы IDD_ABOUTBOX, включая и кнопку OK
  • Измените размеры формы на, примерно, 320x220 (для рисунка с запасом)
  • Поместите на форму из панели Toolbox новый элемент управления Picture Control и расположите его в верхнем левом углу рамки направляющих линий формы
  • Через контекстное меню панели Resource View


    импортируйте файл MyPhoto.bmp из каталога Pictures этой лабораторной работы ( перед демонстрацией приложения преподавателю эту картинку обязательно замените на другую )

Заметьте при этом, что в каталоге res проекта появился новый файл с тем же именем. Оболочка при импорте "как Плюшкин" тащит все к себе. Это и понятно, завтра импортируемый файл могут удалить, а вдруг послезавтра опять придется строить приложение.

  • Переименуйте идентификатор ресурса на ID=IDB_ABOUT
  • Выделите на форме элемент Picture Control и через панель свойств настройте его параметры
    • Type=Bitmap
    • Image = IDB_ABOUT
    • Real Size Image = True
  • Подгоните форму под размеры рисунка
  • Отметьте для себя, что окно импорта ресурса готово было импортировать рисунок не только в формате .bmp. Если хотите, проверьте, можно ли загрузить в элемент Picture Control рисунок другого формата
  • Постройте приложение, запустите его
  • На заголовке главного окна вызовите контекстное меню и выполните опцию About... Должно получиться примерно следующее


  • Далее выполните следующее...
    • выпейте (чашечку кофе, и только...)
    • полюбуйтесь результатами проделанной работы (заодно, пока, и на самого меня - дорогого доцента Снеткова Владимира Михайловича)
    • порадуйтесь за Билла Гейтса и за его прекрасный инструмент
    • порадуйтесь Жизни и за Себя (но не сильно увлекайтесь!!!)
    • вдохните (или вздохните) глубже и поехали дальше...
Александр Даниленко
Александр Даниленко
Стоит Windows 8 Pro, Visual Studio 2010 Express Edition .