Kselax.ru

Hacker Kselax — the best hacker in the world

Menu
  • Блог
  • Контакты
  • wp plugin генератор
  • Русский
    • Русский
    • English
Menu

Книга «Visual C++ полный курс» решение задач глава 16

Posted on 4 октября, 201429 октября, 2014 by admin

Visual C++ полный курсПосле прочтения этой главы вы должны четко понимать, как создавать обработчики сообщений мыши и выполнять операции рисования в программах Windows. Вы узнали, как использование полиморфизма с классами форм позволяет одинаковым способом работать с любой формой независимо от ее фактического типа. Версия С++/CLI приложения Sketcher демонстрирует, насколько проще работать в среде .NET, чем с базовым языком С++ и библиотекой MFC.

Упражнения

  1. Добавьте в версию MFC программы Sketcher пункт меню и кнопку панели инструментов для элемента типа эллипс так же, как это делалось в упражнениях главы 15, и определите класс для поддержки рисования эллипсов по двум заданным точкам в противоположных углах описывающего прямоугольника. Решение.
  2. Какие функции теперь нужно изменить, чтобы обеспечить поддержку рисования эллипса? Измените программу так, чтобы она позволяла рисовать эллипс. Решение.
  3. Какие функции следует изменить в предыдущем упражнении, чтобы первая точка обозначала центр эллипса, а текущая позиция курсора — угол описывающего прямоугольника? Внесите все необходимые для этого изменения. (Подсказка: просмотрите в справочной системе информацию о членах класса CPoint.). Решение.
  4. Добавьте в меню с идентификатором IDR_SketcherTYPE новое всплывающее меню Pen Style (Стиль пера), позволяющее выбирать для рисования сплошные, пунктирные, точечные и штрихпунктирные линии, а также штрихпунктирные линии с двойной точкой. Решение.
  5. Какие части программы нужно изменить далее для того, чтобы обеспечить работоспособность данного меню и поддержку рисования элементов с помощью линий этих типов? Решение.
  6. Реализуйте поддержку для этого нового всплывающего меню и рисования элементов с помощью линий любого из предлагаемых в нем типов. Решение.
  7. Измените версию приложения CLRSketcher так, чтобы оно поддерживало рисование овала по двум точкам в противоположных углах описывающего прямоугольника. Добавьте в панель инструментов кнопку, а в меню — пункт для выбора режима рисования овала. Решение.
  8. Реализуйте в приложении CLRSketcher меню Line Style (Стиль линии) со следующими пунктами: Solid (Сплошная), Dashed (Пунктирная) и Dotted (Точечная). Добавьте для этих элементов меню соответствующие кнопки панели инструментов вместе со всплывающими подсказками. Затем реализуйте в приложении CLRSketcher возможность рисования элементов с помощью линий любого из трех стилей, представленных в этом новом меню. Создайте свое собственное представление для этих стилей линии за счет соответствующей установки свойства DashPattern объекта Pen. Решение.

Упражнение 1

Добавьте в версию MFC программы Sketcher пункт меню и кнопку панели инструментов для элемента типа эллипс так же, как это делалось в упражнениях главы 15, и определите класс для поддержки рисования эллипсов по двум заданным точкам в противоположных углах описывающего прямоугольника.

И так приступим к решению упражнений. У нас имеется приложение такое которое описано в посту MFC заставляем редактор рисовать фигуры  .

MFC C++ applicationкак видно на рисунке у нас нету кнопки для рисования эллипса и так же нету элемента Ellipse в панели меню Element, поэтом давайте добавим эти кнопки, для этого переходим в Окно ресурсов , выбираем пункт Menu и идентификатор меню IDR_Sketcher13TYPE

mfc resourseвыбираем меню Element и добавляем новый подпункт Ellipse, у нас создастся новый элемент с идентификатором ID_ELEMENT_ELLIPSE

mfc ellipseкликаем правой кнопкой мышки по добавленному меню, в открывшемся контекстном меню выбираем пункт меню Добавить обработчик событий…

mfc Evente handlerпоявится окошко Мастер обработчика событий в нем будет сгенерировано название обработчика у меня это OnElementEllipse, так же выбираем класс в который будет добавлен обработчик мы добавляем в класс вида у меня это CSketcher13Doc, тип сообщения обработчика выбираем COMMAND. После выставления нужных настроек нажимаем кнопку Добавить/Править

mfc master doc

У нас создастся в файле CSketcher13Doc.cpp обработчик события выбора пункта меню OnElementEllipse и нас туда перенесет

1
2
3
4
void CSketcher13Doc::OnElementEllipse()
{
    // TODO: добавьте свой код обработчика команд
}

Добавим код этого обработчика

1
elementType=ELLIPSE;

Добавим ELLIPSE в наше перечисление ElementType в файле где мы создали все константы SketchersConstants.h

1
2
3
...
enum ElementType{LINE,RECTANGLE,CIRCLE,CURVE,ELLIPSE};
...

Дальше создаем обработчик сообщения UPDATE_COMMSNT_UI, снова выбираем меню Element и пункт Ellipse кликаем правой клавишей мышки и выбираем пункт Добавить обработчик событий…

mfc Evente handlerпоявится окошко выбираем класс в который будет добавлен обработчик у меня это CSketcher13Doc, тип сообщения UPTADE_COMMAND_UI, имя функции-обработчика OnUpdateElementEllipse и нажимаем кнопку Добавить/Править

mfc updateИ нас переносит в пустой обработчик событий

1
2
3
4
void CSketcher13Doc::OnUpdateElementEllipse(CCmdUI *pCmdUI)
{
// TODO: добавьте свой код обработчика ИП обновления команд
}

добавим в него код

1
pCmdUI->SetCheck(elementType==ELLIPSE);

Все с пунктом меню покончено, теперь нужно добавить кнопку на панели инструментов для этого переходим в Окно ресурсов -> Toolbar -> IDR_MAINFRAME_256 рисуем изображение кнопки эллипс и в свойствах присваиваем идентификатор элемента ID_ELEMENT_ELLIPSE так как на скрине ниже

mfc ellipse toolbar1как видим на рисунке кнопочка находится там где цвета, перенесем ее к элементам, просто перетащите мышкой

На этом все можно попробовать скомпилировать программу и посмотреть что у нас получилось

mfc applicationпункты в панели инструментов могут быть не на своих местах, для того чтобы они стали на свои места, нужно обновить панель элементов.

mfc toolbar updateпосле обновления кнопки должны стать на свои места. Кнопочки и пункт меню работает, но увы мы ничего рисовать не можем еще, в упражнении 1 нам нужно так же запрограммировать что б можно было рисовать. И так приступим к созданию класса Ellipse. Добавлять этот класс будем в класс вида CSketcher13View, идем в Окно классов, кликаем правой клавишей мышки и выбираем пункт меню Добавить, а дальше подпункт Класс

mfc add classУ нас появится окошко классов Добавление класса, выбираем класс С++ и нажимаем кнопку Добавить

mfc choose classПоявится окошко Мастер универсальных классов устанавливаем настройки такие как на скрине ниже

mfc class add masterУ нас создастся пустой класс в файле Elements.h и его реализация в файле Elements.cpp. Реализуем класс Ellipse я как что делал описывать не буду, просто смотрите код, там все хорошо будет закомментировано.

class Ellipse определение »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class CEllipse :
public CElement
{
protected:
CPoint m_StartPoint;
CPoint m_EndPoint;
public:
~CEllipse(void);
virtual void Draw(CDC* pDC);//функция рисования
//конструктор преобразования
CEllipse(const CPoint& start, const CPoint& end, COLORREF aColor);
protected:
CEllipse(void);//запрет вызова
};

class Ellipse реализация функций »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void CEllipse::Draw(CDC* pDC)
{
CPen aPen;//объект пера
//если не удалось создать перо
if(!aPen.CreatePen(PS_SOLID,m_PenWidth,m_Color))
{
//вывод сообщения
AfxMessageBox(_T("Не удалось создать перо для элипса"),MB_OK);
AfxAbort();//завершить программу
}
 
//выбрать перо и кисть
CPen* pOldPen=pDC->SelectObject(&aPen);
CBrush* pOldBrush=(CBrush*)pDC->SelectStockObject(NULL_BRUSH);
 
//нарисовать элипс
pDC->Ellipse(m_EnclosingRect);
 
//выбрать старые перо и кисть
pDC->SelectObject(pOldPen);
pDC->SelectObject(pOldBrush);
}

И изменяем функцию CSketcher13View::CreateElement

CreateElement »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CElement* CSketcher13View::CreateElement(void)
{
CSketcher13Doc* pDoc=GetDocument();//получаем указатель на класс документа
switch(pDoc->GetElementType())
{
case LINE:
return new CLine(m_StartPoint,m_EndPoint,pDoc->GetElementColor());
case RECTANGLE:
return new CRectangle(m_StartPoint, m_EndPoint, pDoc->GetElementColor());
case CIRCLE:
return new CCircle(m_StartPoint, m_EndPoint, pDoc->GetElementColor());
case CURVE:
return new CCurve(m_StartPoint, m_EndPoint, pDoc->GetElementColor());
case ELLIPSE:
return new CEllipse(m_StartPoint,m_EndPoint, pDoc->GetElementColor());
default:
AfxMessageBox(_T("не известный обьект, не удалось создать [CreateElement]"),MB_OK);
AfxAbort();//завершение программы
}
}

Компилируем программу и у нас уже можно рисовать эллипс

mfc ellipse paintВсе на этом мы упражнение 1 сделали, переходим ко второму упражнению

Упражнение 2

Какие функции теперь нужно изменить, чтобы обеспечить поддержку рисования эллипса? Измените программу так, чтобы она позволяла рисовать эллипс.

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

 

Упражнение 3

Какие функции следует изменить в предыдущем упражнении, чтобы первая точка обозначала центр эллипса, а текущая позиция курсора — угол описывающего прямоугольника? Внесите все необходимые для этого изменения. (Подсказка: просмотрите в справочной системе информацию о членах класса CPoint.)

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

код конструктора

1
2
3
4
5
6
7
8
9
10
11
CEllipse::CEllipse(const CPoint& start, const CPoint& end, COLORREF aColor)
{
m_StartPoint.x=start.x-(end.x-start.x);
m_StartPoint.y=start.y-(end.y-start.y);
m_EndPoint=end;
m_PenWidth=1;
m_Color=aColor;
m_EnclosingRect=CRect(m_StartPoint,end);
m_EnclosingRect.NormalizeRect();
}

и от что мы можем рисовать, реально мы рисуем сейчас эллипс от центра

mfc center ellipse

идем дальше

Упражнение 4

Добавьте в меню с идентификатором IDR_SketcherTYPE новое всплывающее меню Pen Style (Стиль пера), позволяющее выбирать для рисования сплошные, пунктирные, точечные и штрихпунктирные линии, а также штрихпунктирные линии с двойной точкой.

Ну тут все более менее ясно, нам нужно добавить переменную например DWORD elementStyle в класс документа CSketcher13Doc, в конструкторе инициализируем ее значением PS_SOLID (сплошная линия) это что б по умолчанию была выбрана сплошная линия. Дальше создаем меню так как мы создавали пункт меню для Ellipse так же и мы создаем целый пункт меню Pen Style и добавляем в него подпункты PS_SOLID, PS_DASH, PS_DOT и PS_DASHDOT. Добавляем для каждого из подпунктов меню обработчики событий COMMAND и UPDATE_COMMAND_UI. От код для обработчиков COMMAND

Показать »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void CSketcher13Doc::OnPenstyleSolid()
{
elementStyle=PS_SOLID;
}
 
 
void CSketcher13Doc::OnPenstyleDash()
{
elementStyle=PS_DASH;
}
 
 
void CSketcher13Doc::OnPenstyleDot()
{
elementStyle=PS_DOT;
}
 
 
void CSketcher13Doc::OnPenstyleDashdot()
{
elementStyle=PS_DASHDOT;
}

а это код для UPDATE_COMMAND_UI

Показать »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void CSketcher13Doc::OnUpdatePenstyleSolid(CCmdUI *pCmdUI)
{
pCmdUI->SetCheck(elementStyle==PS_SOLID);
}
 
 
void CSketcher13Doc::OnUpdatePenstyleDash(CCmdUI *pCmdUI)
{
pCmdUI->SetCheck(elementStyle==PS_DASH);
}
 
 
void CSketcher13Doc::OnUpdatePenstyleDot(CCmdUI *pCmdUI)
{
pCmdUI->SetCheck(elementStyle==PS_DOT);
}
 
 
void CSketcher13Doc::OnUpdatePenstyleDashdot(CCmdUI *pCmdUI)
{
pCmdUI->SetCheck(elementStyle==PS_DASHDOT);
}

так же в документе еще создаем функцию для возврата стиля элемента GetElementStyle

1
2
3
4
DWORD CSketcher13Doc::GetElementStyle(void)
{
return elementStyle;
}

и теперь переходим к функции класса вида CreateElement в ней пока что для элемента CEllipse создаем элемент и в конструкторе передаем четвертый параметр это стиль элемента pDC->GetElementStyle()

1
2
case ELLIPSE:
return new CEllipse(m_StartPoint,m_EndPoint, pDoc->GetElementColor(),pDoc->GetElementStyle());

Ну и все переходим к элементу CEllipse нам нужно изменить код конструктора на следующий

объявление конструктора

1
2
3
4
...
//конструктор преобразования
CEllipse(const CPoint& start, const CPoint& end, COLORREF aColor, DWORD aStyle
...

определение конструктора

1
2
3
4
5
6
7
8
9
10
11
CEllipse::CEllipse(const CPoint& start, const CPoint& end, COLORREF aColor, DWORD aStyle)
{
m_Style=aStyle;//переменная стиля
m_StartPoint.x=start.x-(end.x-start.x);
m_StartPoint.y=start.y-(end.y-start.y);
m_EndPoint=end;
m_PenWidth=1;
m_Color=aColor;
m_EnclosingRect=CRect(m_StartPoint,end);
m_EnclosingRect.NormalizeRect();
}

Тут мы видим новую переменную m_Style, ее нужно определить в абстрактном классе CElement, добавим ее туда

1
2
protected:
DWORD m_Style;//стиль линии

еще нужно изменить функцию рисования в классе CEllipse, от новое определение этой функции

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void CEllipse::Draw(CDC* pDC)
{
CPen aPen;//объект пера
//если не удалось создать перо
if(!aPen.CreatePen(m_Style,m_PenWidth,m_Color))
{
//вывод сообщения
AfxMessageBox(_T("Не удалось создать перо для элипса"),MB_OK);
AfxAbort();//завершить программу
}
 
//выбрать перо и кисть
CPen* pOldPen=pDC->SelectObject(&aPen);
CBrush* pOldBrush=(CBrush*)pDC->SelectStockObject(NULL_BRUSH);
 
//нарисовать элипс
pDC->Ellipse(m_EnclosingRect);
 
//выбрать старые перо и кисть
pDC->SelectObject(pOldPen);
pDC->SelectObject(pOldBrush);
}

Ну и дальше все компилируем и рисуем эллипсы разными стилями. ВУаля!

mfs pen styleДля всех остальных элементов так же само нужно изменить конструктор и функцию рисования Draw, это делается аналогично тому как мы делали для элемента CEllipse

mfc style paint

Переходим к решению следующих упражнений.

Упражнение 5

Какие части программы нужно изменить далее для того, чтобы обеспечить работоспособность данного меню и поддержку рисования элементов с помощью линий этих типов?

Мы изменили документ и вид, а также классы элементов, смотрим упражнение 4.

Упражнение 6

Реализуйте поддержку для этого нового всплывающего меню и рисования элементов с помощью линий любого из предлагаемых в нем типов.

Ну мы ее реализовали в упражнении 4, смотрите его.

Упражнение 7

Измените версию приложения CLRSketcher так, чтобы оно поддерживало рисование овала по двум точкам в противоположных углах описывающего прямоугольника. Добавьте в панель инструментов кнопку, а в меню — пункт для выбора режима рисования овала.

И так у нас пока что следующая программа есть создание которой описано в посте С++ CLI Рисование в окне

Она имеет следующий вид

CLI appРаботают кнопочки и можно рисовать фигуры, нам нужно добавить пункт в меню Element и кнопку на панели инструментов для рисования элемента Ellipse и так сделаем это. Идем в конструктор классов и добавляем пункт меню Ellipse

CLI Ellipse menuдальше выбираем этот пункт меню и кликаем два раза мышкой по пункту меню click этим мы создадим и перенесемся в обработчик

mfc obrabotchikсоздастся обработчик

1
2
3
4
private:
System::Void ellipseToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
}

в нем добавим код

1
2
elementType=ElementType::ELLIPSE;
ElementSet();

Но у нас в программе нет элемента ElementType::ELLIPSE, добавим его в наше перечисление (оно находится в начале файла)

1
enum class ElementType{LINE,RECTANGLE,CIRCLE,CURVE,ELLIPSE};

Также изменим функцию которая будет ставить галочку напротив элемента elementToolStripMenuItem_DropDownOpening

1
2
3
4
5
6
7
System::Void elementToolStripMenuItem_DropDownOpening(System::Object^  sender, System::EventArgs^  e) {
lineToolStripMenuItem->Checked=elementType==ElementType::LINE;
rectangleToolStripMenuItem->Checked=elementType==ElementType::RECTANGLE;
circleToolStripMenuItem->Checked=elementType==ElementType::CIRCLE;
curveToolStripMenuItem->Checked=elementType==ElementType::CURVE;
ellipseToolStripMenuItem->Checked=elementType==ElementType::ELLIPSE;
}

теперь добавим кнопку на панели инструментов нарисуем там элипс

CLI обработчик для кнопкиНу я нихо щас расписывать как создавать эту кнопку, это все написано в посте C++ CLI Рисование в окне   , мы просто добавили один и тот же обработчик как и для меню, так и для кнопки на панели инструментов ellipseToolStripMenuItem_Click, да и функцию которая будет выделять кнопку так же нужно добавить элемент с идентификатором кнопки, я его назвал toolStripEllipseButton

1
2
3
4
5
6
7
8
9
// Функция модифицирует панель элементов
void ElementSet(void)
{
toolStripLineButton->Checked=elementType==ElementType::LINE;
toolStripRectangleButton->Checked=elementType==ElementType::RECTANGLE;
toolStripCircleButton->Checked=elementType==ElementType::CIRCLE;
toolStripCurveButton->Checked=elementType==ElementType::CURVE;
toolStripEllipseButton->Checked=elementType==ElementType::ELLIPSE;
}

и теперь пробуем компелировать программу и как мы видим все у нас работает, все выделяется!

CLI ellipse toolbarДавайте теперь добавим код класса Ellipse который будет рисовать эллипс.

class Ellipse »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public ref class Ellipse : Element
{
protected:
int width;
int height;
public:
Ellipse(Color color,Point start,Point end)
{
pen=gcnew Pen(color);
this->color=color;
position=start;//позиция
height=Math::Abs(end.Y-start.Y);
width=Math::Abs(end.X-start.X);
//описывающий четырехугольник
boundRect=System::Drawing::Rectangle(position,Size(width,height));
}
 
virtual void Draw(Graphics^ g) override
{
g->DrawEllipse(pen,position.X,position.Y,width,height);
}
};

нужно чуток изменить функцию обработчика мышки от ее код

Показать »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
System::Void Form1_MouseMove(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e) {
if(drawing)
{
switch(elementType)
{
case ElementType::LINE:
tempElement=gcnew Line(color,firstPoint,e->Location);
break;
case ElementType::RECTANGLE:
tempElement=gcnew Rectangle(color,firstPoint,e->Location);
break;
case ElementType::CIRCLE:
tempElement=gcnew Circle(color,firstPoint,e->Location);
break;
case ElementType::CURVE:
if(tempElement==nullptr)
tempElement=gcnew Curve(color,firstPoint,e->Location);
else
safe_cast<Curve^>(tempElement)->Add(e->Location);
break;
case ElementType::ELLIPSE:
tempElement=gcnew Ellipse(color,firstPoint,e->Location);
break;
// MessageBox::Show("Hellow");
}
Invalidate();
}
}

Все компилируем программу и смотри что у нас получилось.

CLI ellipse paintв общем мы можем теперь рисовать эллипс, переходим к следующему упражнению.

 

Упражнение 8

Реализуйте в приложении CLRSketcher меню Line Style (Стиль линии) со следующими пунктами: Solid (Сплошная), Dashed (Пунктирная) и Dotted (Точечная). Добавьте для этих элементов меню соответствующие кнопки панели инструментов вместе со всплывающими подсказками. Затем реализуйте в приложении CLRSketcher возможность рисования элементов с помощью линий любого из трех стилей, представленных в этом новом меню. Создайте свое собственное представление для этих стилей линии за счет соответствующей установки свойства DashPattern объекта Pen.

И так начинаем, я только что построил чтобы работало это меню LineStyle пока только для Ellips. ну давайте разбираем, мы идем в конструктор форм и добавляем новое меню и его подпункты так как на рисунке

CLI  line styleДля каждого меню у нас создается обработчик и мы их заполняем смотрите код

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private:
System::Void ellipseToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
elementType=ElementType::ELLIPSE;
ElementSet();
}
private:
System::Void solidToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
Style=ElementStyle::SOLID;
}
private:
System::Void dasherToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
Style=ElementStyle::DASHER;
}
private:
System::Void dotterToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e) {
Style=ElementStyle::DOTTER;
}

также создаем переменную Style типа ElementStyle и инициализируем ее в конструкторе значением ElementStyle::SOLID

Мы еще создаем в файле Form.h перечисление ElementStyle в пространстве имен нашего приложения где находится класс Form1, добавляем наше перечисление перед подключением файла #include «Elements.h». Это специально сделано, чтобы данное перечисление было доступно и в классах элементов.

1
2
3
4
5
6
#pragma once
namespace CLRSketcher33{
enum class ElementStyle{SOLID,DASHER,DOTTER};
}
#include"Elements.h"
....

Подредактируем обработчик сообщения мышки, изменим немного код

Показать »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private:
System::Void Form1_MouseMove(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e) {
if(drawing)
{
switch(elementType)
{
case ElementType::LINE:
tempElement=gcnew Line(color,firstPoint,e->Location);
break;
case ElementType::RECTANGLE:
tempElement=gcnew Rectangle(color,firstPoint,e->Location);
break;
case ElementType::CIRCLE:
tempElement=gcnew Circle(color,firstPoint,e->Location);
break;
case ElementType::CURVE:
if(tempElement==nullptr)
tempElement=gcnew Curve(color,firstPoint,e->Location);
else
safe_cast<Curve^>(tempElement)->Add(e->Location);
break;
case ElementType::ELLIPSE:
tempElement=gcnew Ellipse(color,firstPoint,e->Location,Style);
break;
// MessageBox::Show("Hellow");
}
Invalidate();
}
}

мы добавили в конструктор Ellipse переменную Style, но теперь нам нужно и изменить конструктор элемента Ellipse, вот его измененный код

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Ellipse(Color color,Point start,Point end,ElementStyle aStyle)
{
pen=gcnew Pen(color);
//создаем переменную со стилем
pen->DashPattern=GetStyle(aStyle);//возвращает стиль
this->color=color;
 
position=start;//позиция
height=Math::Abs(end.Y-start.Y);
width=Math::Abs(end.X-start.X);
 
//описывающий четырехугольник
boundRect=System::Drawing::Rectangle(position,Size(width,height));
}

 

GetStyle — возвращает переменную типа array<float>^ которой мы модифицируем наше перо и с помощью модифицированного пера мы уже рисуем нашу фигуру. Этот код добавляется в класс Element — который является базовым для Ellipse и остальных классов фигур. Вот код этой функции

GetStyle »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
array<float>^ GetStyle(ElementStyle s)
{
switch(s)
{
case ElementStyle::SOLID:
{
array<float>^ b={10.0f};
return b;
break;
}
case ElementStyle::DASHER:
{
array<float>^ b={10.0f,10.0f};
return b;
break;
}
case ElementStyle::DOTTER:
{
array<float>^ b={1.0f,3.0f};
return b;
break;
}
default:
exit(1);
}
}

Да и это пожалуй вся модификация, компилируем проект и рисуем эллипс разными линиями

mfc dotter ellipse

CLI dasher ellipseОстальные классы фигур так же само модифицируются, я приводить как это делать не буду, делаем по аналогии с классом Ellipse

Elements.h модифицированный »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
//Elements.h
//Определяет типы элементов
#pragma once
using namespace CLRSketcher33;
#include <cliext/vector>
using cliext::vector;
 
using namespace System;
using namespace System::Drawing;
 
namespace CLRSketcher33
{
public ref class Element abstract
{
protected:
Point position;
Color color;
System::Drawing::Rectangle boundRect;
Pen^ pen;//указатель на перо
 
public:
virtual void Draw(Graphics^ g) abstract;
array<float>^ GetStyle(ElementStyle s)
{
switch(s)
{
case ElementStyle::SOLID:
{
array<float>^ b={10.0f};
return b;
break;
}
case ElementStyle::DASHER:
{
array<float>^ b={10.0f,10.0f};
return b;
break;
}
case ElementStyle::DOTTER:
{
array<float>^ b={1.0f,3.0f};
return b;
break;
}
default:
exit(1);
}
}
};
 
public ref class Line : Element
{
protected:
Point end;
 
public:
//конструктор
Line(Color color, Point start, Point end,ElementStyle aStyle)
{
pen=gcnew Pen(color);
pen->DashPattern=GetStyle(aStyle);
this->color=color;
position = start;
this->end=end;
boundRect=System::Drawing::Rectangle(
Math::Min(position.X,end.X),
Math::Min(position.Y,end.Y),
Math::Abs(position.X-end.Y),
Math::Abs(position.Y-end.Y));
//Для горизонтальных и вертикальных линий
if(boundRect.Width<2) boundRect.Width=2;
if(boundRect.Height<2) boundRect.Height=2;
}
 
//функция рисования линии
virtual void Draw(Graphics^ g) override
{
//Код для рисования самой линии
g->DrawLine(pen,position,end);
}
};
 
public ref class Circle : Element
{
protected:
int width;
int height;
public:
Circle(Color color,Point start,Point end,ElementStyle aStyle)
{
pen=gcnew Pen(color);
pen->DashPattern=GetStyle(aStyle);
this->color=color;
int radius=safe_cast<int>(Math::Sqrt(
(start.X-end.X)*(start.X-end.X)+
(start.Y-end.Y)*(start.Y-end.Y)));
width=height=2*radius;
position.X=start.X-radius;
position.Y=start.Y-radius;
//описывающий четырехугольник
boundRect=System::Drawing::Rectangle(position,Size(width,height));
}
 
virtual void Draw(Graphics^ g) override
{
g->DrawEllipse(pen,position.X,position.Y,width,height);
}
};
 
public ref class Rectangle : Element
{
protected:
int width;
int height;
 
public:
Rectangle(Color color, Point p1, Point p2,ElementStyle aStyle)
{
pen=gcnew Pen(color);
pen->DashPattern=GetStyle(aStyle);
this->color=color;
position=Point(Math::Min(p1.X,p2.X),Math::Min(p1.Y,p2.Y));
width=Math::Abs(p1.X-p2.X);
height=Math::Abs(p1.Y-p2.Y);
boundRect=System::Drawing::Rectangle(position,Size(width,height));
}
 
virtual void Draw(Graphics^ g) override
{
g->DrawRectangle(pen,position.X,position.Y,width,height);
}
};
 
 
public ref class Curve : Element
{
private:
vector<Point>^ points;
 
public:
Curve(Color color, Point p1, Point p2, ElementStyle aStyle)
{
pen=gcnew Pen(color);
pen->DashPattern=GetStyle(aStyle);
this->color=color;
points=gcnew vector<Point>();
position=p1;
points->push_back(p2-Size(position));
 
//Найдите минимальные и максимальные значения координат
int minX=p1.X<p2.X?p1.X:p2.X;
int minY=p1.Y<p2.Y?p1.Y:p2.Y;
int maxX=p1.X>p2.X?p1.X:p2.X;
int maxY=p1.Y>p2.Y?p1.Y:p2.Y;
int width=Math::Max(2,maxX-minX);
int height=Math::Max(2,maxY-minY);
boundRect=System::Drawing::Rectangle(minX,minY,width,height);
}
//Добавьте точку кривой
void Add(Point p)
{
points->push_back(p-Size(position));
 
//Изменение ограничивающего прямоугольника, так чтобы он вмещал
//новую точку
if(p.X<boundRect.X)
{
boundRect.Width=boundRect.Right-p.X;
boundRect.X=p.X;
}
else if(p.X>boundRect.Right)
boundRect.Width=p.X-boundRect.Left;
 
if(p.Y<boundRect.Y)
{
boundRect.Height=boundRect.Bottom-p.Y;
boundRect.Y=p.Y;
}
else if(p.Y>boundRect.Bottom)
boundRect.Height=p.Y-boundRect.Top;
}
 
virtual void Draw(Graphics^ g) override
{
Point previous(position);
Point temp;
for each(Point p in points)
{
temp=position+Size(p);
g->DrawLine(pen,previous,temp);
previous=temp;
}
}
};
 
public ref class Ellipse : Element
{
protected:
int width;
int height;
public:
Ellipse(Color color,Point start,Point end,ElementStyle aStyle)
{
pen=gcnew Pen(color);
pen->DashPattern=GetStyle(aStyle);
this->color=color;
position=start;//позиция
height=Math::Abs(end.Y-start.Y);
width=Math::Abs(end.X-start.X);
//описывающий четырехугольник
boundRect=System::Drawing::Rectangle(position,Size(width,height));
}
 
virtual void Draw(Graphics^ g) override
{
g->DrawEllipse(pen,position.X,position.Y,width,height);
}
};
};

обработчик события перемещения мышки модифицированный »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private:
System::Void Form1_MouseMove(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e) {
if(drawing)
{
switch(elementType)
{
case ElementType::LINE:
tempElement=gcnew Line(color,firstPoint,e->Location,Style);
break;
case ElementType::RECTANGLE:
tempElement=gcnew Rectangle(color,firstPoint,e->Location,Style);
break;
case ElementType::CIRCLE:
tempElement=gcnew Circle(color,firstPoint,e->Location,Style);
break;
case ElementType::CURVE:
if(tempElement==nullptr)
tempElement=gcnew Curve(color,firstPoint,e->Location,Style);
else
safe_cast<Curve^>(tempElement)->Add(e->Location);
break;
case ElementType::ELLIPSE:
tempElement=gcnew Ellipse(color,firstPoint,e->Location,Style);
break;
// MessageBox::Show("Hellow");
}
Invalidate();
}
}

Ну и скрин

CLI dotter rectangle

На этом все, 8 упражнений мы разобрали, в принципе ничего сложного в них нет 🙂 !!!

[youtube]https://www.youtube.com/watch?v=eK5t6x_rqWA[/youtube]

 

3 thoughts on “Книга «Visual C++ полный курс» решение задач глава 16”

  1. Александр:
    13 октября, 2016 в 13:27

    Сделал все как описано, но почему то не видится класс Line, Rectangle, и Circle выдает компилятор следующее:
    1> CLRSketcher.cpp
    1>\clrsketcher\Form1.h(742): error C2061: синтаксическая ошибка: идентификатор «Line»
    1>\clrsketcher\Form1.h(745): error C2061: синтаксическая ошибка: идентификатор «Rectangle»
    1>\clrsketcher\clrsketcher\Form1.h(748): error C2061: синтаксическая ошибка: идентификатор «Circle»
    Хотя в окне класса элементы Line Circle и Rectangle отображаются.

    Ответить
    1. Александр:
      13 октября, 2016 в 13:33

      Разобрался
      Элемент на форме называется Line и класс называется Line из за этого ошибка.
      Переименовал и все заработало!!!

      Ответить
      1. admin_kselax:
        9 ноября, 2016 в 20:52

        Good

        Ответить

Добавить комментарий Отменить ответ

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Рубрики

  • C++ (293)
  • JavaScript (1)
  • linux (1)
  • MFC (39)
  • node.js (2)
  • React (3)
  • uncategorized (3)
  • vBulletin (5)
  • Visual Studio (9)
  • wordpress (18)
  • Разное (121)

Метки

Ajax bootstrap CentOS CLI expressjs FormData GDlib google Invisible reCAPTCHA JWT media MFC php react-router-dom redux repository wordpress RTTI STL vBulletin vector Visual Studio WINAPI wordpress wp-plugins XMLHttpRequest Двоичное дерево Задачи С++ Игры С++ Исключения С++ О-большое Операторы_С++ Перегрузка операторов С++ Поиск С++ Потоки Проектирование_С++ С++ Типы_С++ Типы С++ Шаблоны С++ библиотеки локализация макросы С++ сортировка С++

Свежие комментарии

  • Proffirot к записи Программка для заполнения форума на vBulletin 3.8.7
  • RA3PKJ к записи visual C++, создание диалоговых окон.
  • JasonReant к записи Создание и использование статических библиотек .lib в visual studio.
  • MyWin2020 к записи Программка для заполнения форума на vBulletin 3.8.7
  • ScottJip к записи Создание и использование статических библиотек .lib в visual studio.
©2021 Kselax.ru Theme by ThemeGiant