Шаг 56.
Microsoft Visual C++ 2010. Начала.
Программирование. Графика. Карандаш (окончание)

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

    Программист может создать карандаш, который рисует пунктирную линию, отличную от стандартной. Чтобы это сделать, надо в свойство DashPattern поместить ссылку на массив описания отрезка линии, а свойству DashStyle присвоить значение DashStyle::Custom.

    Массив описания отрезка линии - это состоящий из двух элементов одномерный массив (типа float), который содержит информацию об отрезке пунктирной линии (цепочке "штрих - пропуск"). Первый элемент массива задает длину штриха, второй - пропуска.

    В качестве примера приведем приложение, которое позволяет строить пунктирные прямоугольники, определенные пользователем.


Рис.1. Приложение на этапе проектирования

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

    Ниже приведен текст приложения.

.   .   .   .   .
Form1(void)
{
	InitializeComponent();
	//
	//TODO: добавьте код конструктора
	//
	// создаем черный карандаш
	aPen = gcnew System::Drawing::Pen(Color::Black,1); 
	// устанавливаем начальный цвет
	textBox1->BackColor = Drawing::Color::Black;

	Count = -1; // количество прямоугольников (не более 25)
	Koord = gcnew array<int>(100); // координаты прямоугольников
	Ptrn = gcnew array<float>(50); // параметры "штрих - пропуск"
	Clr = gcnew array<Drawing::Color>(25); // цвет прямоугольника
}
.   .   .   .   .
private:
	System::Drawing::Pen^ aPen; // карандаш
	int Count; // количество фигур
	array <int> ^Koord; // координаты
	array <Drawing::Color> ^Clr; // цвет
	array <float> ^Ptrn; // стиль линии
	
// задание цвета
private: System::Void button1_Click(System::Object^  sender, 
		System::EventArgs^  e) {
	 colorDialog1->Color = textBox1->BackColor;
	 if (colorDialog1->ShowDialog() == 
		System::Windows::Forms::DialogResult::OK) 
	 {
		 aPen->Color = colorDialog1->Color;
		 textBox1->BackColor = colorDialog1->Color;
	 }
 }
// рисование фигуры
private: System::Void button2_Click(System::Object^  sender, 
		System::EventArgs^  e) {
	if (Count == 24) return;
	// запоминаем параметры очередного прямоугольника
	Count++; // очередной прямоугольник

	// стиль линии, определенный программистом
	Ptrn[Count*2] = float(numericUpDown1->Value); // штрих
	Ptrn[Count*2+1] = float(numericUpDown2->Value); // пропуск

	Clr[Count] = textBox1->BackColor; // цвет

	// координаты прямоугольника
	Koord[4*Count] = int(numericUpDown3->Value);
	Koord[4*Count+1] = int(numericUpDown4->Value);
	Koord[4*Count+2] = int(numericUpDown5->Value);
	Koord[4*Count+3] = int(numericUpDown6->Value);

	// вызываем перерисовку компонента pictureBox1 - 
	// метод Paint этого компонента
	pictureBox1->Invalidate();
 }
private: System::Void pictureBox1_Paint(System::Object^  sender,
		 System::Windows::Forms::PaintEventArgs^  e) {
	// стиль линии, определенный программистом
	array<float> ^myPattern;
	myPattern = gcnew array<float>(2);

	// ======= переписовываем прямоугольники ===============
	// цикл по количеству построенных прямоугольников
	for (int i = 0; i <= Count; i++)
	{
		// "вспомнили" параметры линии i-го прямоугольника
		myPattern[0] = Ptrn[i*2]; // штрих
		myPattern[1] = Ptrn[i*2+1]; // пропуск

		// "вспомнили" цвет линии i-го прямоугольника
		aPen->Color = Clr[i]; // цвет

		aPen->DashStyle = System::Drawing::Drawing2D::DashStyle::Custom;
		aPen->DashPattern = myPattern;

		// "вспомнили" координаты i-го прямоугольника
		int x1 = Koord[4*i];
		int y1 = Koord[4*i+1];
		int x2 = Koord[4*i+2];
		int y2 = Koord[4*i+3];

		// построили i-й прямоугольник
		e->Graphics->DrawRectangle(aPen,x1,y1,x2,y2); // прямоугольник
	}
 }
// предотвращение того, чтобы координаты левого верхнего угла
// прямоугольника всегда были меньше ккординат правого нижнего 
// угла прямоугольника
private: System::Void numericUpDown_ValueChanged(System::Object^  sender, 
		System::EventArgs^  e) {
	 if (numericUpDown5->Value <= numericUpDown3->Value)
		     numericUpDown5->Value = numericUpDown3->Value + 10;
	 if (numericUpDown6->Value <= numericUpDown4->Value)
		     numericUpDown6->Value = numericUpDown4->Value + 10;
 }
Архив проекта можно взять здесь.

    Результат работы приложения изображен на рисунке 2.


Рис.2. Результат работы приложения

    Прокомментируем приведенный фрагмент.

    Для работы нам понадобятся:

    В конструкторе также определяем начальный цвет:

  // устанавливаем начальный цвет
  textBox1->BackColor = Drawing::Color::Black;
задавая свойство BackColor (Цвет фона) компонента textBox1. В дальнейшем при выборе цвета, он будет помещаться в указанное свойство этого компонента.

    Значения параметров карандаша определяются с помощью двух компонентов numericUpDown, которые позволяют указать значения от 5 до 20.

    Для выбора цвета пунктирной линии используется компонент colorDialog. После его активизации на экране появляется окно выбора цвета, гду можно выбрать подходящий цвет. После указания цвета и нажатия кнопки OK, выбранный цвет помещается в карандаш и одновременно меняется свойство BackColor компонента textBox1:

 aPen->Color = colorDialog1->Color;
 textBox1->BackColor = colorDialog1->Color;

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

    Особый интерес представляет обработчик нажатия на кнопку Нарисовать (функция button2_Click). Здесь сначала проверяется, можно ли еще нарисовать фигуру. Если есть возможность изобразить еще один прямоугольник, то количество фигур (Count) увеличивается на единицу, в соответствующие элементы соответствующих массивов помещаются необходимые параметры и выполняется метод Invalidate(), основной задачей которого, в данном случае, является вызов метода Paint() компонента pictureBox1. В теле этого метода реализован цикл по количеству построенных прямоугольников, внутри которого считываются из соответствующих элементов массивов параметры очередного прямоугольника, устанавливаются соответствующие свойства и производится отрисовка очередного прямоугольника.

    Так здесь, через использование массивов, мы реализовали сохранение сохранение изображения. Теперь оно будет каждый раз перерисовываться при сворачивании/разворачивании окна приложения.

    На следующем шаге мы рассмотрим компонент ColorDialog.




Предыдущий шаг Содержание Следующий шаг