Шаг 126.
Microsoft Visual C++ 2010. Язык С/С++.
Приложения Windows Forms. Рисование графиков в форме

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

    В заключение покажем, как в форме можно рисовать графики. Вид формы графиками функций sin(x) и tan(x) показан на рисунке 1. Коды обработчиков кнопок (фрагменты h-файла приложения, выводящего графики фукнций) приведены ниже.

#pragma once

namespace My126_1 {

	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;

	//Объявление функций приложения
	//--sin(x)---------------------
	//математические функции берутся из класса Math 
	double fs(double x)
	{
		return(Math::Floor(Math::Sin(x)));
	}
	//--tan(x)---------------------
	double  ft(double x)
	{
		return(Math::Floor(Math::Tan(x)));
	}

	/// <summary>
	/// Сводка для Form1
	/// </summary>
	public ref class Form1 : public System::Windows::Forms::Form
	{

.     .     .     .     .
		}
#pragma endregion
//=====Обработчики кнопок вывода графиков функций ===========
private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
	 Color ^col = gcnew Color();
	 Pen ^pen = gcnew Pen (col->Red);
	 //чтобы создать графический объект, надо получить ссылку на него, 
	 //выполнив метод CreateGraphics() компонента (формы) 
	 Graphics ^im = this->CreateGraphics(); 
	 //вывод графика функции с использованием DrawLine() 
	 im->Clear(col->White); //закрасить предыдущее графическое 
                                //изображение белым цветом
	 float x1, y1, x2, y2;  //текущие координаты в пикселях в форме 
	 x1 = 0; y1 = 0;   //начальные координаты графика функции f(х)
	 //вычисление функции y=f(x) в точках x1, x2, ...
	 x2 = x1;
	 while ( x2 < this->Width && y2 < this->Height)
	 {
		 x2+=5; //следующая точка в пикселях по оси X
		 y2 = fs(x2) * 100;   // эта функция определена в начале модуля
                                      //(*100 - для увеличения амплитуды, чтобы 
                                      //было нагляднее)
		 if ( y2 < 0 ) y2*=-1;   //чтобы выводить отрицательные значения 
		 im->DrawLine(pen, x1, y1, x2, y2); 
		 // вывод линии между 2-мя точками 
		 // точка 2 должна стать точкой 1,
		 // а точкой 2 должна стать следующая текущая точка:
		 x1 = x2; 
		 y1 = y2; 
		 continue;
	 }
 }
private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) {
	 Color ^col = gcnew Color();
	 Pen ^pen = gcnew Pen (col->Red);
	 //чтобы создать графический объект, надо получить ссылку на него, 
	 //выполнив метод CreateGraphics() компонента (формы) 
	 Graphics ^im = this->CreateGraphics(); 
	 //вывод графика функции с использованием DrawLine() 
	 im->Clear(col->White); //закрасить предыдущее графическое 
                                      //изображение белым цветом
	 float x1, y1, x2, y2;  //текущие координаты в пикселях в форме 
	 x1 = 0; y1 = 0;   //начальные координаты графика функции f(х)
	 //вычисление функции y=f(x) в точках x1, x2, ...
	 x2 = x1;
	 while ( x2 < this->Width && y2 < this->Height)
	 {
		 x2+=10; //следующая точка в пикселях по оси X
		 y2 = ft(x2) * 50;   // эта функция определена в начале модуля
                                     //(*50 - для увеличения амплитуды, 
                                     //чтобы было нагляднее)
		 if ( y2 < 0 ) y2*=-1;   //чтобы выводить отрицательные значения 
		 im->DrawLine(pen, x1, y1, x2, y2); 
		 // вывод линии между 2-мя точками 
		 // точка 2 должна стать точкой 1,
		 // а точкой 2 должна стать следующая текущая точка:
		 x1 = x2; 
		 y1 = y2; 
		 continue;
	 }
 }
private: System::Void button3_Click(System::Object^  sender, System::EventArgs^  e) {
	 this->Close();   //завершение приложения
 }
Архив проекта можно взять здесь.


Рис.1. Графики синусоиды и тангенсоиды, построенные в форме


   Примечание. Символ :: - это так называемый оператор контекстного разрешения (оператор уточнения области видимости) (мы должны сказать компилятору, что будет использован глобальный идентификатор вместо локального, предваряя такой идентификатор символом ::). Примеры:

    При выводе графика любой функции мы применили метод DrawLine() класса Graphics. Но напрямую сформировать указатель на этот класс, чтобы воспользоваться его членами (в частности методом DrawLine()), нельзя. Над сначала получить ссылку на этот графический объект через специальный метод формы, который называется CreateGraphics().

    Если написать оператор

  Graphics  ^im =  this->CreateGraphics();
то получим желаемое (метод, по его определению, формирует ссылку на графический объект).

    Теперь через определенную нами ссылку типа Graphics можем добраться до членов класса Graphics (в частности до необходимого нам метода DrawLine(), который рисует прямую линию между двумя точками). Рисование происходит с помощью специального механизма, находящегося в классе Pen (перо или ручка с пером). Чтобы добраться до этого механизма, надо объявить ссылку на этот класс, а потом через нее добраться до нужного нам члена класса.

    Формирование ссылки на класс происходит не само по себе, а с помощью утилиты gcnew, запускающей специальную программу-конструктор класса, который, в свою очередь, создает в выделенной утилитой памяти экземпляр класса, чтобы с ним можно было работать. Конструктор всегда имеет то же имя, что и класс, для которого он создается, только это обычная функция, выполняющая определенные действия по инициализации членов-данньх класса (она придает им некоторые начальные значения).

    Конструктор для класса Pen имеет один параметр (цвет), потому что перо должно рисовать линии определенным цветом. Следовательно, прежде чем задавать работу конструктору класса Pen, нам нужно как-то определиться с цветом, который потом следует задать в качестве параметра этому конструктору. Цвета находятся в специальном классе Color (цвет). Чтобы добраться до нужного цвета в этом классе, надо сформировать ссылку на этот класс, а потом уже через нее достать нужный цвет. Отсюда имеем:

  Color^ col = gcnew Color();

    Утилита gcnew запускает конструктор класса Color, формирует экземпляр класса в памяти и выдает ссылку на этот экземпляр в переменную col. Теперь любой цвет из Color можно достать через полученную ссылку так:

  col->

    При этом откроется окно подсказчика, из которого остается только выбрать подходящий цвет. Когда вы начнете вводить начальные буквы нужного вам объекта, среда сразу установит подсветку на ближайший объект, имя которого начинается на вводимые вами символы, что ускоряет процесс выбора нужной строки. После выбора строки нажмите клавишу Enter и она попадет в ваш оператор. Если вы не нашли подходящую строку, значит в объекте, на который вы сформировали ссылку, такого члена-данного нет.

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

  Pen^ pen = gcnew Pen (col->Red);

    Чтобы график выводился на поле формы, не занятое предыдущим графиком, следует графический объект, которым мы пользуемся для рисования (он фактически задает специальный холст для рисования, состоящий из точек-пикселей), закрасить нейтральным цветом, на фоне которого будет выводиться новый график.

    Чтобы рисовать график, из непрерывной функции получают в цикле дискретные значения ее точек и между двумя соседними точками проводят прямую линию. Естественно, чем больше точек на данной поверхности, тем более точным будет график.

    Со следующего шага мы начнем знакомиться с компонентами, используемыми при создании интерфейса приложения.




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