Стоит Windows 8 Pro, Visual Studio 2010 Express Edition . |
Работа MFC с GDI (GDI+)
Рисование встроенных примитивов GDI
Добавим в приложение код для рисования кругов и квадратов с помощью GDI -функций Ellipse() и Rectangle(). Обеим функциям передается объект типа CRect, задающий прямоугольник, в который будет вписана рисуемая фигура. Функция Rectangle() заполняет все место в прямоугольнике, а функция Ellipse() рисует эллипс или круг, причем середина каждой стороны прямоугольника касается края эллипса.
Будем использовать в этих функциях текущие настройки пера и кисти, которые выберет пользователь. Для этого нужно их создать. В случае с пером можно использовать нулевое перо (стиль пера PS_NULL ), но когда речь идет о кисти, то нужно будет создать сплошную кисть, имеющую цвет фона окна (светло-серый).
Прямоугольники и эллипсы расположим на холсте в две строки по четыре фигуры в каждой строке. Для рисования фигур создадим отдельный метод, как и в случае с рисованием линий, и назовем его DrawRegion().
- В панели Class View выберите класс CPaintDlg
-
Вызовите мастер Add Function и настройте его так
Мастер добавит код
Объявление функции DrawRegion() в файле PaintDlg.h class CPaintDlg : public CDialog { ............................................. public: // Таблица цветов static const COLORREF m_crColors[8]; private: // Рисование линий на холсте void DrawLine(CPaintDC * pDC, int iColor); public: afx_msg void OnPaint(); private: // Функция рисования примитивных фигур GDI - прямоугольников и эллипсов void DrawRegion(CPaintDC * pDC, int iTool, int iShape, int iColor); };
Заготовка определения функции DrawRegion() в файле PaintDlg.cpp // Функция рисования примитивных фигур GDI - прямоугольников и эллипсов void CPaintDlg::DrawRegion(CPaintDC * pDC, int iTool, int iShape, int iColor) { }
-
Заполните код функции DrawRegion() так
Функция DrawRegion() в файле PaintDlg.cpp // Функция рисования примитивных фигур GDI - прямоугольников и эллипсов void CPaintDlg::DrawRegion(CPaintDC * pDC, int iTool, int iShape, 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]); // Объявить и создать кисти CBrush brSolidBrush(m_crColors[iColor]); CBrush brBDiagBrush(HS_BDIAGONAL, m_crColors[iColor]); CBrush brCrossBrush(HS_CROSS, m_crColors[iColor]); CBrush brDiagCrossBrush(HS_DIAGCROSS, m_crColors[iColor]); CBrush brFDiagBrush(HS_FDIAGONAL, m_crColors[iColor]); CBrush brHorizBrush(HS_HORIZONTAL, m_crColors[iColor]); CBrush brVertBrush(HS_VERTICAL, m_crColors[iColor]); CBrush brNullBrush(RGB(208, 208, 208)); // Светло-серый системный цвет // Получить область рисования // Все размеры GDI в пикселах CRect rClientRect; GetClientRect(rClientRect); rClientRect.NormalizeRect(); // Параметры рисования const int iDisp = 8;// Высота и ширина междурядья и краев клиентской области int iHeight = (rClientRect.Height() - 3 * iDisp) / 2; // Высота фигуры для двух рядов int iWidth = (rClientRect.Width() - 5 * iDisp) / 4; // Ширина фигуры для четырех в ряд CRect rCurrentRect; // Текущие координаты рисования CPen* pOldPen = NULL; // Создали указатель пера и сразу обезопасили CBrush* pOldBrush = NULL; // Создали указатель кисти и сразу обезопасили // Перебираем в цикле все перья и кисти // и сразу рисуем for(int count = 0; count < 8; count ++){ // Вычисляем текущие координаты привязки фигуры if(count == 0){ // Начать первую строку rCurrentRect.left = rClientRect.left + iDisp;// Координата X rCurrentRect.right = rCurrentRect.left + iWidth;// Координата X rCurrentRect.top = rClientRect.top + iDisp;// Координата Y rCurrentRect.bottom = rCurrentRect.top + iHeight;// Координата Y } else if(count == 4){ // Начать вторую строку rCurrentRect.left = rClientRect.left + iDisp;// Координата X rCurrentRect.right = rCurrentRect.left + iWidth;// Координата X rCurrentRect.top = rClientRect.top + 2 * iDisp + iHeight;// Координата Y rCurrentRect.bottom = rCurrentRect.top + iHeight;// Координата Y } else{// Продолжить текущую строку rCurrentRect.left = rCurrentRect.right + iDisp;// Координата X rCurrentRect.right = rCurrentRect.left + iWidth;// Координата X } // Выбираем очередное перо и кисть switch(count){ case 0: // Сплошная линия и сплошная заливка // Сразу запомним старое перо и кисть pOldPen = pDC->SelectObject(&pnSolidPen); pOldBrush = pDC->SelectObject(&brSolidBrush); break; case 1: // Заливка штриховкой обратными косыми pDC->SelectObject(&pnDashPen); pDC->SelectObject(&brBDiagBrush); break; case 2: // Заливка вертикальной и горизонтальной штриховкой pDC->SelectObject(&pnDotPen); pDC->SelectObject(&brCrossBrush); break; case 3: // Заливка штриховкой по обеим диагоналям pDC->SelectObject(&pnDashDotPen); pDC->SelectObject(&brDiagCrossBrush); break; case 4: // Заливка диагональю из черточек и двух точек pDC->SelectObject(&pnDashDotDotPen); pDC->SelectObject(&brFDiagBrush); break; case 5: // Нулевая обводка, горизонтальная штриховка, pDC->SelectObject(&pnNullPen); pDC->SelectObject(&brHorizBrush); break; case 6: // Заливка вертикальной штриховкой pDC->SelectObject(&pnInsidePen); pDC->SelectObject(&brVertBrush); break; case 7: // Нулевая заливка pDC->SelectObject(&pnCombinationPen); pDC->SelectObject(&brNullBrush); } // end of switch // Анализируем переключатели группы Tool // Чем рисовать: пером или кистью (что включено)? // Мы заготовили и то и другое!!! switch(iTool){ case 0: // Включен режим Tool = Pen - рисовать только пером // Скрываем кисть pDC->SelectObject(&brNullBrush); break; case 1: // Включен режим Tool = Brush - отображать только заливку // Скрываем перо pDC->SelectObject(&pnNullPen); break; default: // Скрываем и то и другое на всякий случай pDC->SelectObject(&pnNullPen); pDC->SelectObject(&brNullBrush); } // Анализируем переключатели группы Shape // Что рисовать: эллипс или прямоугольник (что включено)? // Координаты расположения для каждой итерации у нас есть!!! switch(iShape){ case 2: // Включен режим Shape = Square - рисовать прямоугольник pDC->Rectangle(rCurrentRect); break; case 1: // Включен режим Shape = Circle - рисовать эллипс pDC->Ellipse(rCurrentRect); } } // end of for // Восстановить в контексте устройства первоначальные перо и кисть pDC->SelectObject(pOldPen); pDC->SelectObject(pOldBrush); }
Вызов функции DrawRegion() нужно размещать в том же самом месте, где линии будут рисоваться при каждом разрушении окна и куда мы ранее поместили вызов функции DrawLine(). Это место - в функции OnPaint() второго окна, обслуживаемого классом CPaintDlg.
-
Дополните функцию OnPaint() соответствующим новым кодом
Изменения в функции OnPaint() файла PaintDlg.cpp 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); // Рисуем линии if(pWnd->m_iTool != 2 // Если не выбран растр Bitmap && pWnd->m_iShape != 0) // Если не выбран режим Line // Рисуем прямоугольник, эллипс или их контуры текущим цветом DrawRegion(&dc, pWnd->m_iTool, pWnd->m_iShape, pWnd->m_iColor); }
-
Постройте приложение и убедитесь, что все работает как нужно
Должно получиться что-то подобное