Вы должны помнить. что перед тем как создать делегата, надо объявить делегатный тип. Его сигнатура определяется соображениями удобства пользования. Я решил, что при вызове делегатной функции она должна нести информацию: индекс вычисленной точки графика (в массиве PointF[]) и координаты точки графика, то есть сама точка PointF. Поэтому напрашивается делегатный тип с такой сигнатурой.
public delegate void ProgressHandler (int id, PointF pt);
Теперь можно приступить к созданию класса, обслуживающего второй поток. В нем надо объявить событие Move. Событие, как следует из документации .NET, должно иметь делегатный тип, то есть его объявление должно выглядеть так:
private ProgressHandler Move; // Event
Кроме события класс CalcField должен иметь метод (назовем его Recalc), который будет вычислять поле в рамках отдельного (рабочего) потока. Адрес этого метода должен быть задан в качестве параметра при конструировании объекта класса ThreadStart. Главная форма создает и запускает вспомогательный поток таким образом:
CalcField field = new CalcField (this, new ProgressHandler(OnProgress));
thread = new Thread (new ThreadStart (field.Recalc));
thread.Start();
Приведем код класса CalcField.
class CalcField
{
private ProgressHandler Move; // Event
private Form1 form;
public CalcField (Form1 f, ProgressHandler cb)
{
form = f;
Move = cb;
}
public void Recalc()
{
Point2D step = (form.pLast - form.pFirst) * (1.0f / (form.nodes - 1));
Point2D pt = form.pFirst;
PointF p = new Point(0,0);
for (int i = 0; i < form.nodes; i++)
{
float
r1 = form.pPos.Dist (pt),
r2 = pt.Dist (form.pNeg),
r11 = r1 * r1,
r22 = r2 * r2,
cs = (pt - form.pPos).Cos (form.pNeg - pt),
d = r11 * r22;
p.Y = d > 0 ?
form.charge * (r11 + r22 - form.charge * (cs + cs)) / d :
p.Y = -1;
if (i > 0)
p.X += !step;
pt += step;
Thread.Sleep(2);
if (Move != null)
Move (i, p);
}
}
}
public class Point2D
{
public float x, y; // Real coordinates
public Point2D() { x=0; y=0; }
public Point2D (float xx, float yy) { x = xx; y = yy; }
public static Point2D operator+ (Point2D p1, Point2D p2)
{
return new Point2D (p1.x + p2.x, p1.y + p2.y);
}
public static Point2D operator- (Point2D p1, Point2D p2)
{
return new Point2D (p1.x - p2.x, p1.y - p2.y);
}
public static Point2D operator* (Point2D pt, float d)
{
return new Point2D (pt.x * d, pt.y * d);
}
public static float operator* (Point2D p1, Point2D p2)
{
return p1.x * p2.x + p1.y * p2.y;
}
//======= Convert to integer
public Point ToInt()
{
Point p = new Point();
p.X = (int)x; p.Y = (int)y;
return p;
}
//====== Vector norm
public static float operator! (Point2D pt)
{
return (float)Math.Sqrt (pt.x*pt.x + pt.y*pt.y);
}
public float Dist (Point2D pt)
{
float
dx = x - pt.x,
dy = y - pt.y;
return (float)Math.Sqrt (dx*dx + dy*dy);
}
public float Cos (Point2D pt)
{
return this * pt / (!this * !pt);
}
}
public class MainForm : Form
{
private Container components = null;
private PictureBox pbPos;
private PictureBox pbNeg;
private Label lblPercent;
private ProgressBar progress;
private Plot.PlotControl plot;
public uint nodes; // Количество узлов сетки
public float charge; // Величина зарядов диполя
public Point2D pPos, pNeg, pFirst, pLast;
private PointF[] points; // Массив координат точек графика
private bool isDragging = false;
private bool isCalculating = false;
private int x0, y0, x, y;
private Point org;
private Pen penFixed = new Pen (Color.Black, 1);
private Pen penDrag = new Pen (Color.Tan, 0);
private Thread thread;
private string title = "Electrostatic field";
public uint Nodes
{
get { return nodes; }
set
{
if (value < 4 || 1000 < value)
MessageBox.Show ("Количество узлов должно быть в диапазоне (4, 1000)");
else
nodes = value;
}
}
private void SetDefaults()
{
nodes = 200;
charge = 1e-6f / (4 * (float)Math.PI * 8.85e-12f);
points = new PointF[nodes];
}
public MainForm()
{
InitializeComponent();
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.