Чтение онлайн

ЖАНРЫ

ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание

Троелсен Эндрю

Шрифт:

}

После установки размеров каждого прямоугольника в рамках конструктора, заданного по умолчанию, вызывается StretchBox.

public CarControl {

 InitializeComponent;

 StretchBox;

}

Определение пользовательских событий

Тип CarControl обеспечивает поддержку двух событий, отправляемых содержащей тип форме в зависимости от текущей скорости автомобиля. Первое событие, AboutToBlow, генерируется тогда, когда скорость CarControl приближается к верхнему пределу.

Событие BlewUp отправляется контейнеру тогда, когда текущая скорость становится больше позволенного максимума. Каждое из этих событий использует пользовательский делегат (CarEventHandler), который может содержать адрес любого метода, возвращающего void и получающего System.String в качестве параметра. Мы обработаем эти события чуть позже, a пока что добавьте к группе открытых элементов CarControl следующие члены.

// События и пользовательский делегат Car.

public delegate void CarEventHandler(string msg);

public event CarEventHandler AboutToBlow;

public event CarEventHandler BlewUp;

Замечание. Напомним, что "настоящий и полноценный" делегат (см. главу 8) должен указать два аргумента, первым из которых должен быть System.Object (представляющий отправителя), а вторым – тип, производный от System.EventArgs. Однако для нашего примера вполне подойдет и предложенный выше делегат.

Определение пользовательских свойств

Как и любой другой тип класса, элемент управления может определять набор свойств, с помощью которых внешние объекты смогут выяснить (или изменить) состояние этого элемента. Нам понадобится определить только три свойства. Сначала рассмотрим свойство Animate. Это свойство включает или отключает тип Timer.

// Используется для конфигурации внутреннего типа Timer.

public bool Animate {

 get { return IsAnim; }

 set {

IsAnim = value;

imageTimer.Enabled = IsAnim;

 }

}

Свойство PetName выполняет то, что и следует ожидать, исходя из его имени, и не требует подробных комментариев. Однако заметьте, что при установке пользователем соответствующего имени выполняется вызов Invalidate, чтобы это имя CarControl отобразилось в нижней прямоугольной области элемента управления (сам этот шаг будет сделан чуть позже).

// Выбор имени машины.

public string PetName {

 get { return carPetName; }

 set {

CarPetName = value;

Invalidate;

 }

}

Далее, у нас есть свойство Speed. Вдобавок к простому изменению члена currSp, свойство Speed – это элемент, "стимулирующий" генерирование событий AboutToBlow и BlewUp, в зависимости от текущей скорости CarControl. Вот как выглядит соответствующая программная логика.

// Проверка currSp и currMaxFrame и генерирование событий.

public int Speed {

 get { return currSp; }

 set {

// В
пределах безопасной скорости?

if (currSp ‹= maxSp) {

currSp = value;

currMaxFrame = AnimFrames.Lemon3;

}

// Вблизи взрывоопасной ситуации?

if ((maxSp – currSp) ‹= 10) {

if (AboutToBlow != null) {

AboutToBlow("Чуть помедленнее, парень!");

currMaxFrame = AnimFrames.AboutToBlow;

}

}

// Превышаем?

if (currSp ›= maxSp) {

currSp = maxSp;

if (BlewUp != null) {

BlewUp("М-да… тебе крышка… ");

currMaxFrame = AnimFrames.EngineBlown;

}

}

 }

}

Как видите, если текущая скорость становится лишь на 10 км/ч ниже максимальной допустимой скорости, вы генерируете событие AboutToBlow и сдвигаете верхний предел фреймов анимации к значению AnimFrames.AboutToBlow. Если пользователь превышает возможности вашего автомобиля, вы генерируете событие BlewUp и сдвигаете верхнюю границу фреймов к AnimFrames.EngineBlown. Если скорость ниже максимальной, верхний предел фреймов остается равным AnimFrames.Lemon3.

Контроль анимации

Следующей задачей является обеспечение гарантий того, что тип Timer сместит текущий фрейм визуализации в рамках PictureBox. Снова напомним, что число фреймов в цикле анимации зависит от текущей скорости автомобиля. Необходимость изменений изображений в PictureBox возникает только тогда, когда свойство Animate равно true (истина). Начните с обработки события Tick для типа Timer, используя следующий программный код.

private void imageTimer_Tick(object sender, EventArgs s) {

 if (IsAnim) currentImage.Image = carImages.Images[(int)currFrame];

 // Сдвиг фрейма.

 int nextFrame = ((int)currFrame) + 1;

 currFrame = (AnimFrames)nextFrame;

 if (currFrame › currMaxFrame) currFrame = AnimFrames.Lemon1;

}

Отображение названия

Чтобы завершить создание элемента управления, вы должны отобразить название автомобиля. Для этого обработайте событие Paint для CarControl и в рамках обработчика этого события отобразите PetName вашего CarControl в нижней прямоугольной области клиента.

private void CarControl_Paint(object sender, PaintEventArgs e) {

 // Отображение названия в нижнем прямоугольнике.

 Graphics g = e.Graphics;

 g.FillRectangle(Brushes.GreenYellow, bottomRect);

 g.DrawString(PetName, new Font("Times New Roman", 15), Brushes.Black, bottomRect);

}

На этом начальный этап построения CarControl завершается. Теперь выполните компоновку своего проекта.

Поделиться с друзьями: