Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
LR_8_Tekhnologia_programmirovania.docx
Скачиваний:
72
Добавлен:
20.03.2016
Размер:
41.27 Кб
Скачать

3.2. Работа с прямоугольной областью

Для задания координат и размера прямоугольника необходимо добавить в класс формы соответствующую переменную типа Rectangle:

Rectangle rect = new Rectangle(180, 110, 150, 100);

Рисование прямоугольника производится в обработчике события Paint формы:

private void Form1_Paint(object sender, PaintEventArgs e)

{

//получаем контекст устройства

Graphics g = e.Graphics;

//создаем черную кисть

Brush b = Brushes.Black;

//рисуем прямоугольник

g.FillRectangle(b, rect);

}

Если на этом этапе запустить программу, то можно увидеть, как круги, проходя сквозь прямоугольник, «стирают» на своем пути часть его. Это происходит из-за того, что при реализации движения круг «стирается» путем заливки его цветом формы. Устранить данный эффект можно путем перерисовки прямоугольника при попадании круга внутрь него. Таким образом, в методе MoveCircle() после строчки Thread.Sleep(30); следует добавить следующее:

//если круг или его часть - внутри прямоугольника,

if (y + 10 > rect.Y && y - 10 < rect.Y + rect.Height)

//то перерисовываем прямоугольник

Invalidate();

3.3. Синхронизация потоков

Так как в данной программе необходимо обеспечить управление доступом потоков (кругов) к общему ресурсу (прямоугольнику), то, прежде всего, нужно обеспечить блокировку объекта с помощью метода lock(). Эта блокировка должна действовать, только если один из кругов находится внутри прямоугольника, иначе блокировку нужно снять (метод Wait() класса Monitor) и уведомить об этом второй поток (метод Pulse() класса Monitor).

Также для корректного завершения работы потоков необходимо вызвать метод Pulse() при завершении работы потока.

Таким образом, окончательный вариант метода MoveCircle() будет выглядеть следующим образом:

private void MoveCircle()

{

//устанавливаем блокировку метода

lock (this)

{

//создаем контекст устройства

Graphics g = this.CreateGraphics();

//создаем красную кисть - для круга

Brush b1 = Brushes.Red;

//и кисть цвета формы - для стирания круга

Brush b2 = SystemBrushes.Control;

int x;

//координата x круга будет зависеть от имени потока

if (Thread.CurrentThread.Name == "First")

x = Width / 2 - 30;

else

x = Width / 2 + 30;

//цикл от верхнего до нижнего края формы

for (int y = 10; y < Height - 40; y++)

{

//рисуем круг

g.FillEllipse(b1, x - 10, y - 10, 20, 20);

//"усыпляем" поток на 30 миллисекунд

Thread.Sleep(30);

//если круг или его часть - внутри прямоугольника,

if (y+10 > rect.Y && y - 10 < rect.Y + rect.Height)

//то перерисовываем прямоугольник

Invalidate(rect);

else

{

//разрешаем выполнение другого потока

Monitor.Pulse(this);

//ждем приостановки/завершения другого потока

Monitor.Wait(this);

}

//стираем круг

g.FillEllipse(b2, x - 10, y - 10, 20, 20);

}

//выводим поток из режима ожидания

Monitor.Pulse(this);

}

//проверяем корректность завершения потока

MessageBox.Show("Поток " + Thread.CurrentThread.Name + " завершен!");

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]