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

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

Рисование линий GDI

Линии будем рисовать во втором диалоговом окне, выбирая для каждой перо со своим цветом и стилем. Для этого вначале создадим все перья. Перед рисованием каждой линии нужно вычислять ее расположение на окне рисования. Для всего этого создадим для класса CPaintDlg отдельный метод, который назjвем DrawLine().

  • В панели Class View выберите класс CPaintDlg
  • Вызовите мастер Add Function и настройте его так


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

    Объявление функции в файле PaintDlg.h
    class CPaintDlg : public CDialog
    {
    ............................................
    public:
      // Таблица цветов
      static const COLORREF m_crColors[8];
    private:
      // Рисование линий на холсте
      void DrawLine(CPaintDC * pDC, int iColor);
    };
    Заготовка определения функции в файле PaintDlg.cpp
    // Рисование линий на холсте
    void CPaintDlg::DrawLine(CPaintDC * pDC, int iColor)
    {
    }
  • Заполните код функции DrawLine() так

    Функция DrawLine() в файле PaintDlg.cpp
    // Рисование линий на холсте
    void CPaintDlg::DrawLine(CPaintDC * pDC, int iColor)
    {
      // Объявить и создать перья
      CPen pnSolidPen(PS_SOLID, 1, m_crColors[iColor]);
      CPen pnDashPen(PS_DASH, 1, m_crColors[iColor]);
      CPen pnDotPen(PS_DOT, 1, m_crColors[iColor]);
      CPen pnDashDotPen(PS_DASHDOT, 1, m_crColors[iColor]);
      CPen pnDashDotDotPen(PS_DASHDOTDOT, 1, m_crColors[iColor]);
      CPen pnNullPen(PS_NULL, 1, m_crColors[iColor]);
      CPen pnInsidePen(PS_INSIDEFRAME, 1, m_crColors[iColor]);
      CPen pnCombinationPen(PS_DOT | PS_GEOMETRIC | PS_ENDCAP_ROUND
              , 1, m_crColors[iColor]);
      
      // Получить область рисования
      CRect rRect;
      GetClientRect(rRect);
      rRect.NormalizeRect();
      
      // Вычислить расстояние между линиями
      CPoint ptStart;
      CPoint ptEnd;
      int iDisp = rRect.Height() / 8; // Высота междурядья
      CPen* pOldPen = NULL; // Обезопасили указатель
      // Определить начальные точки линий
      ptStart.y = rRect.top + iDisp / 2;
      ptStart.x = rRect.left + iDisp / 2;
      ptEnd.y = ptStart.y;
      ptEnd.x = rRect.right - iDisp / 2;
      
      // Рисуем каждую линию со своим пером
      for(int count = 0; count < 8; count++){
      
        // Выбрать для текущей линии перо
        switch(count){
          case 0: // Запоминаем старое перо контекста перед
              // первой линией, чтобы затем вновь вернуть
              // его контексту после прорисовки всех линий
            pOldPen = pDC->SelectObject(&pnSolidPen);
            break;
          case 1:
            pDC->SelectObject(&pnDashPen);
            break;
          case 2:
            pDC->SelectObject(&pnDotPen);
            break;
          case 3:
            pDC->SelectObject(&pnDashDotPen);
            break;
          case 4:
            pDC->SelectObject(&pnDashDotDotPen);
            break;
          case 5:
            pDC->SelectObject(&pnNullPen);
            break;
          case 6:
            pDC->SelectObject(&pnInsidePen);
            break;
          case 7:
            pDC->SelectObject(&pnCombinationPen);
        } // end of switch
      
        // Нарисовать линию
        pDC->MoveTo(ptStart);
        pDC->LineTo(ptEnd);
      
        // Переместиться на позицию слудующей линии
        ptStart.y += iDisp;
        ptEnd.y = ptStart.y;
      
      } // end of for
      
      // Вернуть контексту его прежнее перо
      pDC->SelectObject(pOldPen);
    }

Вызов функции DrawLine() нужно размещать в месте, где линии будут рисоваться при каждом разрушении окна. Такое место одно - в функции OnPaint() второго окна. Но ее пока нет, поэтому ее нужно создать как обработчик сообщения WM_PAINT операционной системы.

Добавим обработчик события WM_PAINT в класс второго диалогового окна. Для этого:

  • Выделите в панели Class View класс CPaintDlg и через панель свойств в режиме Messages найдите сообщение WM_PAINT

  • Скорректируйте сгенерированный оболочкой обработчик так

    Обработчик сообщения WM_PAINT класса CPaintDlg
    void CPaintDlg::OnPaint()
    {
      CPaintDC dc(this); // Локальный контекст устройства 
    
      // Получить указатель на родительское окно
      CGraphicsDlg* pWnd = (CGraphicsDlg*) GetParent();
    
      if(!pWnd) return; // Если родитель не существует - выйти
    
      if(pWnd->m_iTool == 0 // Если выбран режим Pen
         && pWnd->m_iShape == 0) // и если выбран режим Line
        DrawLine(&dc, pWnd->m_iColor); // Рисуем линии текущим цветом
    }

    Отметьте для себя, что здесь создается указатель на на класс главного окна и ему присваевается содержимое, возвращенное API -функцией GetParent(). Используется также операция приведение указателя.

  • Для видимости объявления класса CGraphicsDlg в файле PaintDlg.cpp включите в начало этого файла инструкцию препроцессора #include "GraphicsDlg.h"

    Включение инструкции препроцессора в файл PaintDlg.cpp
    // PaintDlg.cpp : implementation file
    //
      
    #include "stdafx.h"
    #include "Graphics.h"
    #include "PaintDlg.h"
    #include ".\paintdlg.h"
      
    #include "GraphicsDlg.h"
    
    // CPaintDlg dialog
      
    IMPLEMENT_DYNAMIC(CPaintDlg, CDialog)
    CPaintDlg::CPaintDlg(CWnd* pParent /*=NULL*/)
      : CDialog(CPaintDlg::IDD, pParent)
    {
    }
      
    CPaintDlg::~CPaintDlg()
    {
    }
    .....................................................
  • Закомментируйте отладочный код в обработчике OnRadioSelection() файла GraphicsDlg.cpp
  • Постройте приложение и убедитесь, что все пока работает как нужно

    Должно получиться что-то подобное


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

Александр Даниленко
Александр Даниленко
Стоит Windows 8 Pro, Visual Studio 2010 Express Edition .