using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace cForm
{
public partial class cForm : Form
{
// Средства для отображения объектов на плоскости.
Color backColor;
Pen greedPen;
Pen pen0;
SolidBrush br;
// Действующие лица. Массив объектов xPoint.
xPoint[] pt;
// Количество точек.
const int nPT = 10000;
// Синхронизаторы изменения направления перемещения объектов.
public int NX, NY;
// Предельные характеристики размеров клиентской области.
const int minHeight = 100;
const int minWidth = 100;
const int maxHeight = 950;
const int maxWidth = 950;
// Средство масштабирования. Всеобщая единица измерения.
private double rPoint;
// Абсолютные неизменяемые характеристики рамки окна приложения.
int borderHeight;
int borderWidth;
// Область рисования. Изображение формируется в памяти.
// На "поверхности" битовой карты
// (объект - представитель класса Graphics,
// создается в результате выполнения метода FromImage),
// средствами векторной графики (методы класса Graphics)
// рисуется картинка.
// Изображение проецируется на поверхность элемента управления
// mainPictureBox
// путем модификации свойства Image этого элемента управления.
private Bitmap bmp;
// Таймер. Фактически представляет собой делегат,
// который через фиксированные интервалы
// времени активизирует соответствующее событие
// (передает управление методу mainTimer_Tick).
private System.Windows.Forms.Timer mainTimer;
// Конструктор формы.
public cForm()
{
int i;
// Цвет фона картинки. Используется при перерисовке изображения.
backColor = Color.FromArgb(255,0,0,0);
// Средства для рисования.
greedPen = new Pen(Color.FromArgb(50, 0, 0, 255), 1);
pen0 = new Pen(Color.FromArgb(255,0,0,0),1);
br = new SolidBrush(Color.FromArgb(0, 0, 0, 0));
// Обязательно смотреть код начальной инициализации элементов формы!
InitializeComponent();
// Определение неизменяемых характеристик окна приложения (формы).
GetBordersGabarits();
// Начальная коррекция размеров клиентской области окна приложения.
// "Прямой" вызов метода - обработчика события изменения размеров
// окна приложения.
bForm00_Layout(null, null);
// Определение предельных габаритов окна приложения.
SetMinMaxSize();
// Значения синхронизаторов.
// Неплохо приспособить специальные элементы управления,
// которые позволяли бы изменять эти значения в интерактивном режиме!
NX = 50;
NY = 50;
// Инициализация популяции.
// Все располагаются в одном месте – в центре клиентской области окна.
// Одинаковые значения двух последних параметров приводят к тому, что
// члены популяции синхронно изменяют направление движения.
pt = new xPoint[nPT];
for (i = 0; i < pt.Length; i++)
{
pt[i] = new xPoint(
(int)(this.ClientSize.Width / (2*rPoint)),
(int)(this.ClientSize.Height / (2*rPoint)),
0, //NX, // xPoint.rnd.Next(0, NX+1), // А такие значения нарушают
0 //NY // xPoint.rnd.Next(0, NY+1) // синхронность поведения объектов.
);
}
// Процесс пошел!
mainTimer.Start();
}
// Определение относительной величины rPoint реализовано как свойство.
// Замечательная особенность свойства!
// Оно имеет явную спецификацию возвращаемого значения.
// И точно такого же типа должен быть единственный параметр value!
private Size rPointSet
{
set
{
Size s = value;
rPoint = Math.Sqrt(2.0*s.Width*s.Height) * 0.002;
}
}
// А вот перегрузить свойство нельзя! Невидимый параметр value
// и возвращаемое значение свойства должны быть одного типа.
// Именно поэтому МНЕ пришлось вводить пару свойств.
public double rPointGet
{
get
{
return rPoint;
}
}
// Обработчик события перерисовки формы.
// В списке параметров ссылка на объект - инициализатор события,
// а также ссылка на объект – носитель информации об инкапсуляторе
// данной поверхности рисования.
// Способ получения этой информации простой – через свойство Graphics:
// Graphics gr = e.Graphics;
// И знай рисуй себе!
// Однако эта ссылка нам не понадобится, поскольку мы рисуем
// не на ПОВЕРХНОСТИ ЭЛЕМЕНТА УПРАВЛЕНИЯ,
// а в памяти, на ПОВЕРХНОСТИ БИТОВОЙ КАРТЫ.
private void bForm00_Paint(object sender, PaintEventArgs e)
{
xRedraw();
}
// Событие Layout возникает при удалении или добавлении дочерних
// элементов управления,
// изменении границ элемента управления и других изменениях,
// в том числе и изменении размеров формы, которые могут повлиять
// на макет элемента.
// Рекомендуется использовать именно это событие,
// а не события ..._Resize или ..._SizeChanged. Как сказано
// в руководстве, событие Layout возникает в ответ на события
// ..._Resize и ..._SizeChanged,
// а также в других ситуациях, когда может понадобиться применение макета.
private void bForm00_Layout(object sender, LayoutEventArgs e)
{
// Использование сразу ДВУХ величин – длины и ширины клиентской
// области окна!
// Вот оптимальное решение проблемы поддержки ПОСТОЯННОГО соотношения
// характеристик клиентской области
// (среднее арифметическое для поддержки равенства сторон).
// ПЛЮС поправка на размеры рамки окна приложения.
Size = new System.Drawing.Size
(
(ClientSize.Width + ClientSize.Height)/2 + borderWidth,
(ClientSize.Width + ClientSize.Height)/2 + borderHeight
);
// После коррекции размеров окна – устанавливаем значение величины
// rPoint, которое производится через обращение к свойству rPointSet.
rPointSet = this.ClientSize;
// Новая битовая карта под новый размер клиентской области.
bmp = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
// Объявляется недопустимой конкретная область элемента управления
// (здесь форма) и происходит отправка соответствующего сообщения
// (Paint) элементу управления (форме). При этом значение
// параметра (true)
// объявляет недопустимыми назначенные элементу управления
// дочерние элементы.
// Для каждого элемента автоматически формируется
// объект-представитель
// класса Graphics, инкапсулирующий поверхность для рисования.
// Для активизации процесса перерисовки соответствующего
// элемента управления требуется объявить метод – обработчик события
// (в нашем случае это bForm00_Paint).
this.Invalidate(false);
}
// Обработчик события таймера:
// всем амебам надлежит переопределить собственные координаты и
// перерисовать картинку! Здесь также можно было бы объявить
// недействительной и требующей перерисовки поверхность формы.
// Это просто: this.Invalidate(false);
// Однако никто не помешает нам сделать все напрямую, через метод xRedraw.
private void mainTimer_Tick(object sender, EventArgs e)
{
xPoint.setNextPosition(this, pt);
xRedraw();
}
// Перерисовка.
private void xRedraw()
{
// Поверхность для рисования на битовой карте!
Graphics gr = Graphics.FromImage(bmp);
// Очистить поверхность и закрасить ее в ненавязчивый черный цвет!
gr.Clear(backColor);
// Нарисовать решетку!
DrawGreed(gr);
// Нарисовать объекты!
foreach (xPoint xp in pt)
{
// Сообщили кисти цвет объекта...
br.Color = xp.xColor;
// Закрасили объект.
gr.FillEllipse(br,
(float)((xp.p.X * rPoint) - rPoint),
(float)((xp.p.Y * rPoint) - rPoint),
(float)(2 * rPoint),
(float)(2 * rPoint));
// Сообщили перу цвет объекта...
pen0.Color = xp.xColor;
// Нарисовали контур амебы...
gr.DrawEllipse(pen0,
(float)((xp.p.X * rPoint) - rPoint),
(float)((xp.p.Y * rPoint) - rPoint),
(float)(2 * rPoint),
(float)(2 * rPoint));
}
// Рисование закончено. Подготовить объект-поверхность к удалению.
gr.Dispose();
// Отобразить картинку!
// Это всего лишь модификация свойства Image элемента управления PictureBox.
this.mainPictureBox.Image = bmp;
}
// На поверхности битовой карты (параметр gr) рисуется координатная сетка.
private void DrawGreed(Graphics gr)
{
float i;
float w = (float)(this.ClientSize.Width/25.0F);
float h = (float)(this.ClientSize.Height/25.0F);
float W = this.ClientSize.Width;
float H = this.ClientSize.Height;
for (i = h; i < H; i += h)
{
gr.DrawLine(this.greedPen, 0, i, W, i);
}
for (i = w; i < W; i += w)
{
gr.DrawLine(this.greedPen, i, 0, i, H);
}
}
}
} |
Листинг 17.3. |
| Закрыть окно |