Пользовательский элемент управления. Создание клиентского приложения. Развитие серверного проекта, страница 4

public class PlotControl : UserControl

{

private Container components = null;

private Graph graph;// Ссылка на объект класса, код которого предстоит разработать

public PlotControl()

{

InitializeComponent();

graph = new Graph (ClientSize, this); // Инициализация объекта

}

protected override void OnPaint (PaintEventArgs e)

{

graph.Draw (e.Graphics);// Вызов метода, изображающего график функции

base.OnPaint (e);      

}

// Здесь должны быть методы Dispose и InitializeComponent

}

Класс графика

С помощью студии введите в состав проекта новый класс с именем Graph. Это также можно сделать двумя способами:

¨  Дать комаду Add4Add Class, выбрав ее из контекстного меню узла Plot (в окне ClassView).

¨  Дать комаду Project4Add Class, выбрав ее из меню главного окна студии.

Заметьте, что в дереве классов ClassView есть два узла с именем Plot. Один из них соответствует пространству имен Plot (он нам и нужен), а другой — классу Plot. При создании класса первым способом будет работать мастер. В окне этого мастера для класса Graph не надо указывать имя базового класса, так как им будет только object. Во вновь созданный файл Graph.cs вручную введите код, необходимость которого мы уже обсудили.

using System;

using System.Collections;

using System.ComponentModel;

using System.Drawing;

using System.Drawing.Drawing2D;

using System.Windows.Forms;

namespace Plot

{

struct AxisData // Параметры координатной оси

{

public bool bX;  // Флаг оси X (для оси Y он равен false)

public float

min, max, // Экстремумы

scale,   // Коэффициент растяжения-сжатия

power,   // Порядок в нормализованном представлении числа

factor,     // Множитель (10 в степени Power)

step, dStep,// Шаг сетки оси (мантисса и реальное значение)

start, end, // Первая и последняя координаты сетки (мантисса)

dStart, dEnd;// Первая и последняя координаты сетки (реальное значение)

};

class Graph     // Класс, реализующий плоский график функции

{

private PlotControl wnd;  // Обратный указатель

private PointF[] points;  // Массив точек графика

private string title, sX; // Заголовок и наименования осей

private SizeF size;       // Размеры окна графика

private int h, hh, h2;    // Высота буквы, две высоты и половина высоты

private PointF lt, rb, bc;  // Опорные точки(лево-верх, право-низ, низ-центр)

private AxisData dataX, dataY; // Атрибуты осей

public Graph (SizeF sz, PlotControl w)

{

SetDefaultPlot();

size = sz;

wnd = w;

h = wnd.Font.Height;    hh = h + h;      h2 = h / 2;

int dx = 65;

lt = new PointF (dx, 0.6f*dx);

rb = new PointF (sz.Width - 0.7f*dx, sz.Height - dx);

bc = new PointF ((lt.X+rb.X)/2, rb.Y + hh);

}

~Graph() {}

public void SetDefaultPlot() // График, отображаемый по умолчанию

{

points = new PointF[300];

title = "Oscillating Impulse Response";

sX = "t (c.)";

dataX.bX = true;

dataY.bX = false;

float h = 0.01f; // Вычисляем точки графика осциллирующего процесса

for (int i=0; i < points.Length; i++)

{

points[i].X = i * h;

points[i].Y = (float)OscillatingDelta (points[i].X, 0.08, 0.12, 10);

}

}

//==== Колебательный импульсный переходный процесс

double OscillatingDelta (double x,  double T, double c, double k)

{

// T — постоянная времени, c — декремент затухания, k - коэффициент усиления

double d = Math.Sqrt (1 - c * c);  // колебательность

return k * Math.Exp (-c * x / T) * Math.Sin (d * x / T) / (T * d);

}

//=== Смена данных графика

public void SetData (PointF[] pts, string s, string x)

{

points = pts;

title = s;

if (title.Length > 45)

title = title.Substring (0, 45);

sX = x;

if (sX.Length > 8)

sX = sX.Substring (0,8);

}

//=== Выбор шага сетки

public float CalcStep (double span)

{

//=== Мантисса диапазона д.б.в пределах (1 < span < 10)

double factor = Math.Pow (10, Math.Floor (Math.Log10(span)));

span /= factor;

double step = // Выбор стандартного шага сетки

span < 1.99 ? 0.2  :

span < 2.49 ? 0.25 :

span < 4.99 ? 0.5  : 1.0;

return (float)(step * factor);