Visual C++: рисуем мышью на форме
Предыдущая заметка по теме была вот здесь, а дальше легко найти по цепочке :) Тем не менее, простого примера на рисование мышкой "как в Paint" что-то не видно, попробуем сделать его прямо сейчас.
1. Рисовать будем непосредственно на канве формы, хотя вообще-то лучше на PictureBox
, растянутом на всю форму. Тогда просто получите MyGraphics
от этого PictureBox
. В классе формы приложения Windows Forms пропишем нужные данные:
private: bool isPaint; //Флажок "рисовать" Graphics ^MyGraphics; //Объект Graphics для рисования Brush ^ MyBrush; //Кисть для рисования Point p; //Последняя точка, где рисовали
На событие загрузки формы (Load) проинициализируем данные:
MyGraphics = this->CreateGraphics(); MyBrush = gcnew SolidBrush(Color::Red); this->Text = "Рисуй кнопкой, стирай двойным щелчком"; isPaint = false; p.X = -1; p.Y = -1;
По событию MouseDown формы (нажатие кнопки мыши) будем разрешать рисование:
isPaint = true;
а по событию MouseUp (отпускание кнопки мыши) - запрещать:
isPaint = false;
По событию. "движение мыши" формы (MouseMove) будем рисовать, если включён флажок isPaint
и текущие координаты мыши отличаются от последних координат, сохранённых в переменной p
. Также запомним новые координаты:
if (!isPaint) return; else if (p.X != e->X || p.Y != e->Y) { p.X = e->X; p.Y = e->Y; MyGraphics->FillEllipse(MyBrush, p.X, p.Y, 2, 2); }
Вместо точки мы здесь выводим эллипс 2x2 пиксела. Работать с массивами отдельных пикселов можно, например, через System::Windows::Media::Imaging::WriteableBitmap.
Очищать рисунок можно по любому удобному событию или выбору кнопки (пункта меню). Используем для этого двойной щелчок (MouseDoubleClick) по форме:
MyGraphics->Clear(this->BackColor);
2. Увы, при быстром движении мыши обработчик события MouseMove не будет успевать рисовать маленькие эллипсы и линия получится разрывной.
Проще всего решить проблему, соединяя текущую точку p
и точку, полученную из текущего положения мыши, линией.
Вот как изменится весь написанный нами код:
private: bool isPaint; //Флажок "рисовать" Graphics ^MyGraphics; //Объект Graphics для рисования Pen ^ MyPen; //Перо для рисования Point p; //Последняя точка, где рисовали private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) { MyGraphics = this->CreateGraphics(); MyPen = gcnew Pen(Color::Red); this->Text = "Рисуй кнопкой, стирай двойным щелчком"; isPaint = false; p.X = -1; p.Y = -1; } private: System::Void Form1_MouseDown(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { isPaint = true; p.X = e->X; p.Y = e->Y; } private: System::Void Form1_MouseUp(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { isPaint = false; p.X = e->X; p.Y = e->Y; } private: System::Void Form1_MouseMove(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { if (!isPaint) return; else if (p.X != e->X || p.Y != e->Y) { MyGraphics->DrawLine(MyPen, p.X, p.Y, e->X, e->Y); p.X = e->X; p.Y = e->Y; } } private: System::Void Form1_MouseDoubleClick(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { MyGraphics->Clear(this->BackColor); }
3. Наконец, существует удобный способ рисования, связанный с классом System::Drawing::Drawing2D::GraphicsPath.
Ниже прилагается полный листинг для вставки в приложение Windows Forms. Его внимательный анализ поможет вам освоить и этот способ. Кроме того, здесь MouseDown различает кнопки мыши, MouseUp определяет число кликов, а MouseMove можно заставить рисовать "непрерывно", раскомментарив одну строчку.
private: System::Drawing::Drawing2D::GraphicsPath ^mousePath; Graphics ^MyGraphics; Point p; int fontSize; bool dblClicked; private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) { MyGraphics = this->CreateGraphics(); this->Text = "Рисуй кнопкой, стирай двойным щелчком"; mousePath = gcnew System::Drawing::Drawing2D::GraphicsPath(); p.X = -1; p.Y = -1; fontSize = 20; dblClicked = false; } private: System::Void Form1_MouseDown(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { Point mouseDownLocation = Point(e->X, e->Y); String^ eventString = nullptr; switch (e->Button) { //Различаем все возможные кнопки мыши case System::Windows::Forms::MouseButtons::Left: eventString = "L"; break; case System::Windows::Forms::MouseButtons::Right: eventString = "R"; break; case System::Windows::Forms::MouseButtons::Middle: eventString = "M"; break; case System::Windows::Forms::MouseButtons::XButton1: eventString = "X1"; break; case System::Windows::Forms::MouseButtons::XButton2: eventString = "X2"; break; case System::Windows::Forms::MouseButtons::None: default: break; } if (eventString != nullptr) { mousePath->AddString(eventString, FontFamily::GenericSerif, (int)FontStyle::Bold, (float)fontSize, mouseDownLocation, StringFormat::GenericDefault); } else { mousePath->AddLine(mouseDownLocation, mouseDownLocation); } this->Invalidate(); } private: System::Void Form1_MouseUp(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { Point mouseUpLocation = System::Drawing::Point(e->X, e->Y); if (dblClicked) { dblClicked = false; return; } int numberOfClicks = e->Clicks; mousePath->AddString (String::Format(" {0}", numberOfClicks), FontFamily::GenericSerif, (int)FontStyle::Bold, (float)fontSize, mouseUpLocation, StringFormat::GenericDefault); this->Invalidate(); } private: System::Void Form1_MouseMove(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { if (p.X == -1 || p.Y == -1) { p.X = e->X; p.Y = e->Y; } else if (p.X != e->X || p.Y != e->Y) { mousePath->AddLine(p.X, p.Y, e->X, e->Y); p.X = e->X; p.Y = e->Y; //this->Invalidate(); //раскомментарить для "непрерывной" перерисовки } } private: System::Void Form1_MouseDoubleClick(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { MyGraphics->Clear(this->BackColor); delete mousePath; mousePath = gcnew System::Drawing::Drawing2D::GraphicsPath; this->Invalidate(); dblClicked = true; //Был двойной щелчок, не рисовать лишнее число кликов в MouseUp } private: System::Void Form1_Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e) { //главный метод - именно Paint. Это его вызывают Invalidate MyGraphics->DrawPath(System::Drawing::Pens::Red, mousePath); } //Часть ниже совсем необязательна :) private: System::Void Form1_MouseEnter(System::Object^ sender, System::EventArgs^ e) { this->Text = String::Concat(sender->GetType(), ": MouseEnter"); //Просто пишем в заголовке окна о событии } private: System::Void Form1_MouseHover(System::Object^ sender, System::EventArgs^ e) { this->Text = String::Concat(sender->GetType(), ": MouseHover"); } private: System::Void Form1_MouseLeave(System::Object^ sender, System::EventArgs^ e) { this->Text = String::Concat(sender->GetType(), ": MouseLeave"); }
15.11.2016, 14:54 [8484 просмотра]