Стоит Windows 8 Pro, Visual Studio 2010 Express Edition . |
Работа 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(). Примерные возможности рассмотрим ниже при работе с растрами.