Шаг 63.
Microsoft Visual C++ 2010. Начала.
Программирование. Графика. Графические примитивы. Линия

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

    Метод DrawLine рисует прямую линию. В инструкции вызова метода следует указать карандаш, которым надо нарисовать линию, и координаты точек начала и конца линии:

  DrawLine(aPen, x1, y1, x2, y2)
или
  DrawLine(aPen, p1, p2)

    Параметр aPen (типа Brush) задает карандаш, которым рисуется линия, x1 и y1 или p1 - точку начала линии, а x2 и y2 или p2 - точку конца линии. Параметры x1, y1, x2 и y2 должны быть одного типа (Integer или Single). Тип параметров p1 и p2 - Point.

    Например, инструкция

  e->Graphics->DrawLine(Pens::Green,10,10,300,10);
рисует зеленую линию толщиной в один пиксель из точки (10, 10) в точку (300, 10).

    Эту же линию можно нарисовать и так:

  Point p1 = Point(10,10);
  Point p2 = Point(300,10);
  e->Graphics->DrawLine(Pens::Green, p1, p2);

    Программа "График" (ее окно приведено на рисунке 1) показывает использование метода DrawLine. Данные, отображаемые в окне программы, загружаются из текстового файла.


Рис.1. Программа "График"

    Загружает данные из файла конструктор формы (файл данных usd.dat должен находиться в папке приложения, при запуске программы в режиме отладки из среды разработки - в папке Debug). Он же выполняет обработку массива данных - ищет минимальный и максимальный элементы ряда. Конструктор также, в случае успешной загрузки данных, задает функцию обработки события Paint формы. Непосредственно вывод графика на поверхность формы выполняет функция drawDiagram. Ее вызывает функция обработки события Paint формы, а также косвенно (путем вызова метода Refresh) - функция обработки события Resize формы.

// конструктор
Form1(void)
{
	InitializeComponent();
	//
	//TODO: добавьте код конструктора
	//
	// чтение данных из файла в массив
	System::IO::StreamReader^ sr; // поток для чтения
	try
	{
		sr = gcnew System::IO::StreamReader(Application::StartupPath + 
                     "\\usd.dat");
		// создаем массив
		d = gcnew array<double>(10);
		// читаем данные из файла
		int i = 0;
		String^ t = sr->ReadLine();
		while ((t != String::Empty) && (i < d->Length))
		{
			// записываем считанное число в массив
			d[i++] = Convert::ToDouble(t);
			t = sr->ReadLine();
		}
		// закрываем поток
		sr->Close();
		// определить минимальное и максимальное значения ряда
		min = d[0];
		max = d[0];
		for (int i = 1; i < d->Length; i++)
		{
			if (d[i] > max) max = d[i];
			if (d[i] < min) min = d[i];
		}
		// Данные загружены.
		// Задаем функцию обработки события Paint
		this->Paint += gcnew System::Windows::Forms::PaintEventHandler(this,
			&Form1::drawDiagram);
		}
		// Обработка исключений: файл данных не найден
	catch (System::IO::FileNotFoundException^ ex)
	{
		MessageBox::Show(ex->Message + "\n", "График", MessageBoxButtons::OK, 
			MessageBoxIcon::Error);
	}
}
.   .   .   .   .   .
private:
	array<double>^ d; // ряд данных
	double max; // максимальный элемент массива
	double min; // минимальный элемент массива

// строим график
void drawDiagram(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e) {
	// графическая поверхность
	System::Drawing::Graphics^ g = e->Graphics;
	// шрифт подписей данных
	System::Drawing::Font^ dFont = gcnew System::Drawing::Font("Tahoma", 9);
	// шрифт заголовка
	System::Drawing::Font^ hFont = gcnew System::Drawing::Font("Tahoma", 13, 
               FontStyle::Regular);
	String^ header = "Изменение курса доллара";
	// ширина области отображения текста
	int wh =(int)g->MeasureString(header, hFont).Width;
	int x = (this->ClientSize.Width - wh) / 2;
	g->DrawString(header,hFont, Brushes::DarkGreen, x, 5);
	/* Область построения графика.
	Отступы: сверху - 100; 	снизу - 20; слева - 20; справа - 20.
	ClientSize - размер внутренней области окна
	График строим в отклонениях от минимального значения
	ряда данных так, чтобы он занимал всю область построения
	*/
	// рисуем график
	int x1, y1, x2, y2;
	// расстояние между точками графика (шаг по Х)
	int sw = (int)((this->ClientSize.Width - 40) / (d->Length - 1));
	// первая точка
	x1 = 20;
	y1 = this->ClientSize.Height - 20 - (int)((this->ClientSize.Height - 100) *
		(d[0] - min) / (max - min));
	// маркер первой точки
	g->DrawRectangle(Pens::Black, x1 - 2, y1 - 2, 4, 4);
	// подпись численного значения первой точки
	g->DrawString(Convert::ToString(d[0]), dFont, Brushes::Black, x1 - 10, 
              y1 - 20);
	// остальные точки
	for (int i = 1; i < d->Length; i++)
	{
		x2 = 8 + i * sw;
		y2 = this->ClientSize.Height - 20 - 
                        (int)((this->ClientSize.Height - 100) *
			(d[i] - min) / (max - min));
		// маркер точки
		g->DrawRectangle(Pens::Black, x2 - 2, y2 - 2, 4, 4);
		// соединим текущую точку с предыдущей
		g->DrawLine(Pens::Black, x1, y1, x2, y2);
		// подпись численного значения
		g->DrawString(Convert::ToString(d[i]), dFont, 
                       Brushes::Black, x2 - 10, y2 - 20);
		x1 = x2;
		y1 = y2;
	}
}

private: System::Void Form1_Resize(System::Object^  sender, System::EventArgs^  e) {
		 this->Refresh();
 }
Архив проекта можно взять здесь.

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




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