double arrow

Объектно-ориентированное

Этап 6

Этап 5

Этап 4

Этап 3

Этап 2

Этап 1

Класс MenuItemCollection

В классе Menu объявлен внутренний класс MenuItemCollection, который наследуется классами MainMenu, ContextMenu и MenuItem. В классе MenuItemCollection реализованы методы, позволяющие добавлять дочерние пункты меню к главному или контекстному меню либо другому пункту.

Некоторые методы:

Menultem Add(string caption)

Menultem Add(string caption, EventHandler onClick)

Menultem Add(string caption, MenuItem [] items)

int Add(MenuItem item)

int Add(int index, MenuItem item)

void AddRange(MenuItem[] items)

Для определения количества пунктов меню в коллекции можно использовать свойство Count класса MenuItemCollection.

Рассмотрим использование метода Add для создания контекстного меню.

В приведенном примере цвет фона формы меняется в соответствии с выбранным пунктом контекстного меню.

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

namespace CntMn

{

public partial class Form1: Form

{

MenuItem myClr; // пункт меню

ContextMenu ctmn;//Контекстное меню

public Form1()

{

InitializeComponent();

ctmn = new ContextMenu();// создание контекстного меню

//Передаем конструкору делегата функцию обработчик пункта меню

EventHandler ev = new EventHandler(MnClick);

//добавляем в меню пункты

ctmn.MenuItems.Add("Red", ev);

ctmn.MenuItems.Add("Blue", ev);

ctmn.MenuItems.Add("Green", ev);

foreach (MenuItem itm in ctmn.MenuItems)

itm.RadioCheck = true;

// Выбираем второй пункт меню

myClr = ctmn.MenuItems[2];

myClr.Checked = true;

//Устанавливаем цвет фона

this.BackColor = Color.FromName(myClr.Text);

//связываем с формой контекстное меню

this.ContextMenu = ctmn;

}

// Это обработчик пункта меню

void MnClick(object sr, EventArgs e)

{

myClr.Checked = false;//снимаем флажок со старого пункта меню

myClr = (MenuItem)sr; //получаем ссылку на текущий пункт меню

myClr.Checked = true;//устанавливаем на нем флажок

this.BackColor = Color.FromName(myClr.Text);

}

}

}

После запуска приложения мы получим на экране монитора форму, фон которой по умолчанию зеленый.

После щелчка правой кнопкой мыши на форме появится контекстное меню:

Рис

 
 

Здесь на рис слева хорошо видно, что флажок установлен на пункте меню Green. После выбора пункта Red цвет фона изменится на красный, и флажок будет установлен соответственно на пункте Red.

Поэтапная разработка многопоточного приложения

Разработаем многопоточное Balls –приложение, в прикладном окне которого перемещаются одноцветные шары, отталкиваясь от границ области клиента. Управление движением шаров и изменение их цвета осуществляется с помощью кнопки и управляющего элемента списка, размещённых в дочернем окне. Последовательное нажатие на кнопку приостанавливает или возобновляет движение шаров. Цвет шаров выбирается из списка.

В Balls –приложении каждый шар представляется своим потоковым объектом, так что функционирование приложения сводится к функционированию совокупности потоковых объектов-шаров.

Разработка приложения будет осуществляться поэтапно. Вначале разработаем класс Ball потокового объекта и протестируем его. Затем создадим и отладим класс Balls потоковых объектов, который управляет шарами. Для просмотра результатов тестирования мы воспользуемся консолью.

В дальнейшем мы наследуем класс Balls из базового класса Form и будем отображать шары в области клиента прикладного окна (в форме) в виде кругов одного цвета. Нам придётся модифицировать класс Ball потокового объекта, добавив в него координаты и их приращения. Для обеспечения перерисовки шаров мы воспользуемся событием, которое будет генерироваться после каждого изменения их координат.

Убедившись в совместном функционировании шаров и их отображении в области клиента прикладного окна, мы перейдём к разработке дочернего окна, на котором разместим управляющие элементы – кнопку и список.

При поэтапной реализации Balls –приложения мы одновременно будем использовать консоль и окна. Отладочная информация на консоли отразит полезную информацию о внутреннем функционировании приложения. Отладив Balls –приложение, следует отменить выдачу на консоль.

Поэтапная разработка будет вестись на языке С#. Для каждого этапа приводится фрагмент отлаживаемой программы с надлежащим тестом. В конце будет приведена разработанная программа целиком.

С точки зрения пользователя Balls –приложение будет представлено двумя окнами. В поле клиента прикладного окна перемещаются шары. Дочернее окно содержит кнопку и элемент списка цветов. Пользователь выполняет действия:

- установить цвет шаров,

– приостановить движение шаров,

– возобновить движение шаров.

Если шары перемещались, то после нажатия кнопки они приостановятся. Если шары были неподвижны, то после нажатия кнопки они продолжат своё перемещение.

Разработаем поэтапно последовательность классы Balls -приложения и их реализацию на языке C#.

На первом этапе создадим основной класс Ball потокового объекта, который включает самые необходимые данные:

num – номер потокового объекта,

life – признак жизни потока (life= true - поток выполняется, life= false

поток завершён),

run – признак выполнения потока (run= true - поток выполняется,

run= false - поток приостановлен),

thread – поток класса Thread.

Включим в класс Ball функции:

Ball () – конструктор класса,

~Balls () – деструктор класса,

Start () – запустить потоковый объект,

Suspend () – приостановить выполнение потокового объекта,

Resume () – возобновить выполнение потокового объекта.

Пример 10.2.1. Реализация Balls–приложения на первом этапе разработки.

////////////////////

// C# File BallsCs1.cs

using System;

using System.Threading;

class Ball // Класс потокового объекта

{

int num;

Thread thread;

bool run;

bool life;

public Ball (int Num) // Конструктор

{

num= Num; life= false; run= false;

Start ();

}

//---------------

~Ball () {life= false;} // Деструктор

//---------------

public void Start () // Стартовать

{

if (!run)

{

run= true;

life= true;

thread= new Thread (new ThreadStart (BallFunc));

thread.Start ();

}

}

//---------------

public void Suspend () // Приостановить

{

if (run)

{

run= false;

thread.Suspend ();

}

}

//---------------

public void Resume () // Возобновить

{

if (!run)

{

run= true;

thread.Resume ();

}

}

//---------------

void BallFunc () // Выполнить поток

{

int n= 0;

while (life)

{

Console.Write ("Объект {0}", num.ToString ());

Console.WriteLine (" n= {0}", n.ToString ());

n++;

Thread.Sleep (10);

}

Console.Write ("Объект {0}", num.ToString ());

Console.WriteLine (" завершился");

}

};

//-------------------------------------

class BallsCs1

{

static void Main (string[] args)

{

Ball ball1= new Ball (1); // Создать первый потоковый объект

Ball ball2= new Ball (2); // Создать второй потоковый объект

Console.WriteLine ("Объекты функционируют");

Thread.Sleep (20); // Объекты функционируют 20 мс

ball1.Suspend (); // Приостановить первый потоковый объект

ball2.Suspend (); // Приостановить второй потоковый объект

Console.WriteLine ("Объекты приостановлены и возобновлены");

ball1.Resume (); // Возобновить выполнение первого объекта

ball2.Resume (); // Возобновить выполнение второго объекта

Thread.Sleep (20); // Объекты функционируют 20 мс

ball1.Suspend (); // Приостановить первый потоковый объект

ball2.Suspend (); // Приостановить второй потоковый объект

}

}

/*

Результат:

Объекты функционируют

Объект 1 n= 0

Объект 2 n= 0

Объект 1 n= 1

Объект 2 n= 1

Объекты приостановлены и возобновлены

Объект 1 n= 2

Объект 2 n= 2

Объект 1 n= 3

Объект 2 n= 3

*/

Все данные класса Ball закрыты и допускают их использование извне только открытыми функциями Start, Suspend и Resume.

Для обеспечения функционирования потока и управления им в класс Ball введены переменные life и run, а в потоковую функцию BallFunc – целочисленная переменная n. Булевская переменная life поддерживает жизненный цикл потока совместно с задержкой, заданной функцией Sleep класса Thread.

Переменная n является вспомогательной и требуется только для отладки Balls- приложения. Эта переменная определяет номер выполняемого потоком цикла. Последовательность её значений, выдаваемых потоком на консоль, не только подтверждает выполнение потока, но и может способствовать выделению отдельных циклов при отладке. На следующем этапе разработки будут запускаться одновременно несколько параллельных потоков, о чём будут свидетельствовать чередующиеся последовательности номеров num потоковых объектов и возрастающие значения переменной n для каждого из них на консоли. Также в дальнейшем значение вспомогательной переменной n может оказаться полезным и для фиксации генерирования события потоковым циклом с номером n. После отладки Balls- приложения полезные при отладке и теперь ненужные переменные, подобные n, надо удалить.

Булевская переменная run предотвращает приостановку приостановленного потока и возобновление выполнения выполняющегося потока. Она используется функциями Suspend и Resume.

Перед запуском потока конструктор присваивает переменным life и run значения true, предопределяя тем самым, что поток сейчас оживёт и начнёт выполняться. При создании потока конструктор класса Thread использует делегат типа ThreadStart, которому передаётся текущий адрес this потокового объекта и адрес потоковой функции BallFunc.

Для отладки класса Ball в функции Main создаются два объекта класса Ball. Так как конструктор класса Ball запускает поток, то на консоли сразу появляются строки, подтверждающие параллельное выполнение этих потоковых объектов.

На этом этапе реализуем класс Balls, содержащий массив потоковых объектов класса Ball и осуществляющий их одновременный запуск, а также приостановку и возобновление их функционирования. Также класс Balls содержит функции, выполняющие запуск (Start), приостановку выполнения (Suspend) и возобновление выполнения (Resume) всей совокупности потоковых объектов.

Реализация второго этапа разработки Balls –приложения дана в примере 10.2.2.

Пример 10.2.2. Реализация второго этапа разработки Balls–приложения.

////////////////////

// C# File BallsCs2.cs

// Файл BallsCs2.cs полностью включает файл BallsCs1.cs, дополнив его

// нижеследующим описанием класса Balls и изменённой функцией Main

...

//-------------------------------------

class Balls // Класс потоковых объектов

{

Ball [] pBall;

public Balls ()

{

pBall= new Ball [2];

for (int i= 0; i < 2; i++)

pBall[i]=new Ball (i);

Start ();

}

//---------------

public void Start () // Стартовать

{

for(int i=0; i < 2; i++)

{

pBall[i]. Start ();

}

}

//---------------

public void Suspend () // Возобновить

{

for (int i=0; i < 2; i++)

pBall[i].Suspend ();

}

//---------------

public void Resume () // Приостановить

{

for (int i= 0; i < 2; i++)

pBall[i].Resume ();

}

};

//-------------------------------------

class BallsCs2

{

static void Main (string[] args)

{

Balls pBalls= new Balls (); // Создать объект класса Balls

Console.WriteLine("Объекты функционируют");

Thread.Sleep (20); // Объект функционирует 20 мс

pBalls.Suspend (); // Приостановить функционирование

Console.WriteLine("Объекты приостановлены и возобновлены");

pBalls.Resume (); // Возобновить функционирование

Thread.Sleep (20); // Объект функционирует 20 мс

pBalls.Suspend (); // Приостановить функционирование

}

}

/*

Результат:

Потоковые объекты функционируют

Объект 1 n= 0

Объект 2 n= 0

Объект 1 n= 1

Объект 2 n= 1

Объекты приостановлены и возобновлены

Объект 2 n= 2

Объект 1 n= 2

Объект 1 n= 3

Объект 2

Программа пополнилась классом Balls - владельцем совокупности потоковых объектов. Для работы с ними класс Balls предоставляет открытые функции Start, Suspend и Resume, позволяющие одновременно запустить, приостановить или возобновить функционирование потоковых объектов.

В дальнейшем класс Balls обеспечит рисование шаров, координаты которых будут вычисляться потоками соответствующих объектов. Для этого класс Balls будет дополнен необходимыми данными и функциями. Но сейчас класс Balls только стартует и управляет совокупностью спрятанных в нём потоковых объектов.

В функции Main создаётся один объект класса Balls, содержащий массив из двух потоковых объектов. Сразу запускаются оба потоковых объекта, о чём свидетельствует отладочная информация на консоли.

Включим в класс Ball потокового объекта событие ev, сигнализирующее об очередном цикле выполнения потока. Это событие обрабатывается функцией HandlerEv класса Balls, что будет использовано при перерисовке шаров в области клиента прикладного окна на четвёртом этапе.

Пример 10.2.3. Реализация третьего этапа разработки Balls–приложения.

////////////////////

// С# File BallsCs3.cs

// Файл BallsCs3.cs полностью включает файл BallsCs2.cs, дополнив

// его объявлением события ev в классе Ball и функцией HandlerEv

// класса Balls, обеспечивающей обработку этого события.

// Изменения файла BallsCs2.cs выделены жирным шрифтом.

...

//-------------------------------------

delegate void delEv (); // Объявление типа delEv делегата события ev

class Ball

{

public event delEv ev; // Объявление события ev

...

//---------------

void BallFunc () // Выполнить поток

{

int n= 0;

while (life)

{

Console.Write ("Объект {0}", num.ToString ());

Console.WriteLine (" n= {0}", n.ToString ());

n++;

if (ev!= null) // Если событие активизировано, то

{

Console.WriteLine (" Event");

ev (); // свершить событие

}

Thread.Sleep (10);

}

Console.Write ("Объект {0}", num.ToString ());

Console.WriteLine (" завершён");

}

};

//-------------------------------------

class Balls // Класс потоковых объектов

{

Ball [] pBall;

public void HandlerEv () // Обработчик события ev

{

Console.WriteLine (" HandlerEv");

}

public Balls () // Конструктор

{

pBall= new Ball [2];

for (int i= 0; i < 2; i++)

{

pBall[i]=new Ball (i);

pBall[i].ev+= new delEv(HandlerEv); // Добавить

}

Start ();

}

...

};

class BallsCs3

{

static void Main (string[] args)

{

Balls pBalls= new Balls (); // Создать объект класса Balls

Console.WriteLine("Объекты функционируют");

Thread.Sleep (20); // Объект функционирует 20 мс

pBalls.Suspend (); // Приостановить функционирование

}

}

Результат:

Объекты функционируют

Объект 0 n= 0

Event

HandlerEv

Объект 1 n= 0

Event

HandlerEv

Объект 0 n= 1

Event

HandlerEv

Объект 1 n= 1

Event

HandlerEv

*/

Объявленное в классе Ball тип delEv делегата задаёт формат обработчика с отсутствующими аргументами и с возвращаемым значением void. Обработчик HandlerEv такого формата описан в классе Balls и подписан на события ev потоковых объектов перед запуском объектов в теле функции Start.

Функция Main, создав объект класса Balls позволяет потоковым объектам функционировать в течение 20 мс. Отладочная выдача на консоли подтверждает генерацию событий ev и реакцию на них функции HandlerEv.

Наступил этап разработки, когда появится прикладное окно приложения с перемещающимися шарами.

Наследовав класс Form, класс Balls существенно расширит свою функциональность. Теперь можно создать прикладное окно (основную форму) и дочернее окно (дочернюю форму). Но дочернее окно будет создано потом в классе User, порождённым из класса Balls

Пример 10.2.4. Реализация четвёртого этапа разработки Balls–приложения.

////////////////////

// C# File Balls4Cs.cs

// Файл BallsCc4.cs полностью включает файл BallsCs3.cs, дополнив его

// данными класса Ball и класса Balls, необходимыми для рисования шаров.

// В результате наследования класса Balls из базового класса Form появилось

// прикладное окно, свойства которого установлены в конструкторе класса

// Balls. Переопределена функция OnPaint перерисовки. Функция HandlerEv,

// реагируя на событие ev из потоков, вызывает перерисовку шаров.

// Изменения файла BallsCs3.cs выделены жирным шрифтом

//

using System;

using System.Drawing;

using System.Windows.Forms;

using System.Threading;

delegate void delEv ();

class Ball // Класс потокового объекта

{

public event delEv ev;

public int x, y;

public int w, h;

public int dx, dy;

...

public Ball (int Num, int X, int Y, int Dx, int Dy) // Конструктор

{

num= Num; life= false; run= false;

w= 100; h= 100; x= X; y= Y; dx= Dx; dy= Dy;

}

//---------------

...

void BallFunc () // Выполнить поток

{

int n= 0;

while ((life)&&(n<=2))

{

Console.Write ("Объект {0}", num.ToString ());

Console.WriteLine (" n= {0}", n.ToString ());

n++;

x += dx; y += dy;

if (x>w || x<0) dx= -dx;

if (y>h || y<0) dy= -dy;

if (ev!= null)

{

Console.WriteLine (" Event");

ev ();

}

Thread.Sleep (100);

}

Console.Write ("Объект {0}", num.ToString ());

Console.WriteLine (" завершён");

}

}

//-------------------------------------

class Balls: Form

{

Ball [] pBall;

Color col;

public Balls ()

{

col= System.Drawing.Color.FromArgb (0, 0, 255);

pBall= new Ball [2];

for (int i= 0; i < 2; i++)

{

pBall[i]=new Ball (i, i*3+10,

1*3+15, i*3+5, i*3+5);

pBall[i].ev+= new delEv(HandlerEv);

}

Text= "Balls";

Start ();

}

...

protected override void OnPaint (PaintEventArgs arg)

{

base.OnBase (arg);

for (int i= 0; i < 2; i++)

{

arg.Graphics.DrawEllipse

(new Pen (col), pBall[i].x,

pBall[i].y, 20, 20);

pBall[i].w= Width;

pBall[i].h= Height;

}

}

void HandlerEv ()

{

Console.WriteLine (" HandlerEv");

Invalidate ();

}

//-------------------------

static void Main()

{

Application.Run(new Balls ());

}

}

/*

Результат:

Появилось прикладное окно с двумя нарисованными шарами.

Объект 0 n= 0

Event

HandlerEv

Объект 1 n= 0

Event

HandlerEv

Объект 0 n= 1

Event

HandlerEv

Объект 1 n= 1

Event

HandlerEv

Объект 0 завершился

Объект 1 завершился

*/

Конструктор класса Balls кроме создания потоковых объектов класса Ball определяет основную форму, задав её имя, заголовок и размер области клиента прикладного окна.

В класс Balls включена функция OnPaint, перерисовывающая одновременно все шары при каждом изменении их координат в любом потоковом объекте. Рисование отдельного шара осуществляется функцией DrawEllipse, использующей перо заданного цвета.

Но функция OnPaint здесь также передаёт каждому потоковому объекту ширину w и высоту y области клиента, которыми воспользуются потоковые функции для ограничения перемещения шаров.

Кстати оказалась реализация события ev в предыдущем этапе. Теперь достаточно в тело обработчика HandlerEv события ev поместить Invalidate, и событие ev вызовет событие Paint, на которое среагирует функция OnPaint. В результате шары отображаются в области клиента прикладного окна.

При запуске Balls –приложения появляется прикладное окно с перемещающимися шарами и консоль с отладочной выдачей. Для ограничения времени выполнения потоковых объектов только для этого этапа изменёно условие цикла while потоковой функции.

Рис. 10.2.4. Прикладное окно с консолью Balls–приложения 4 этапа


Создадим дочернее окно с кнопкой, управляющей перемещением шаров в области клиента прикладного окна.

Пример 10.2.5. Реализация пятого этапа разработки Balls–приложения.

// C# File BallsCs5.cs

// Файл BallsCs5.cs полностью включает файл BallsCs4.cs, дополнив его

// новым классом User, порождённым из класса Balls. Класс User содержит

// управляющий элемент–кнопку, нажатие на которую приостанавливает

// или возобновляет перемещение шаров.

// Изменения файла BallsCs4.cs выделены жирным шрифтом

...

//-------------------------------------

class Ball // Класс потокового объекта

{...

void BallFunc ()

{

int n= 0;

while (life)

{

...

}

Console.Write ("Объект {0}", num.ToString ());

Console.WriteLine (" завершён");

}

}...

//-------------------------------------

class User: Balls // Класс пользователя шаров

{

private bool run;

Form pChildForm;

Button pBut;

public User ()

{

run= true;

//---------------

pBut= new Button();

pBut.Location = new Point (32, 24);

pBut.Name = "pBut";

pBut.Size = new System.Drawing.Size (32, 24);

pBut.Text = "OK";

pBut.Click += new EventHandler (OnBut);

ClientSize = new System.Drawing.Size (200, 150);

//---------------

pChildForm= new Form ();

pChildForm.Location= new Point (250, 10);

pChildForm.Size= new Size (250, 250);

pChildForm.Text= "User";

pChildForm.Show ();

pChildForm.Controls.Add (pBut);

pChildForm.ClientSize = new System.Drawing.Size (200, 62);

} //---------------

void OnBut (object obj, EventArgs arg) // Обработчик кнопки

{

Console.WriteLine ("OkMouse");

if (run)

{

run= false;

Suspend ();

}

else

if (!run)

{

run= true;

Resume ();

}

}

//-------------------------

static void Main ()

{

Application.Run (new User ());

}

}

/*

Результат:

Появились прикладное окно с перемещающимися шарами и дочернее окно

с кнопкой. При нажатии на кнопку можно приостанавливать или возобновлять

движение шаров.

*/

Из класса Balls порождён класс User. Основное назначение класса – обеспечить управление совокупностью шаров с помощью управляющих элементов. Наследовав функции управления совокупностью потоковых объектов, класс User использует их в функциях-обработчиках кнопки и списка.

На пятом этапе создано дочернее окно (форма pChildForm) и размещена в нём кнопка pBut. С кнопкой связан обработчик OnBut, реализация которого проста: используя булевскую переменную run, осуществляется приостановка и возобновление движения шаров. В конструкторе класса User обработчик OnBut копки подписан на событие Click типа EventHandler.

Рис. 10.2.5. Две формы с консолью Balls–приложения 5 этапа

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

Убедившись в нормальном функционировании приложения, целесообразно убрать выдачу на консоль, поскольку при дальнейшем создании программы для отладки достаточно информации, отображаемой на форме.

Этот этап последний. Добавим в дочернее окно управляющий элемент-список для выбора одного из трёх цветов шаров.


Пример 10.2.6. Реализация шестого этапа разработки Balls–приложения.

////////////////////

// C# File BallsCs6.cs

// Файл BallsCs6.cs полностью включает файл BallsCs5.cs, дополнив класс

// User элементом списка и включив его в дочернее окно. Используя список,

// можно изменить цвет шаров.

// Изменения файла BallsCs5.cs выделены жирным шрифтом

...

//-------------------------------------

class Balls: Form // Класс потоковых объектов

{

Ball [] pBall;

Color col;

...

public void SetColor (Color Col) // Установить цвет

{

col= Col;

Invalidate ();

}

...

}

//-------------------------------------

class User: Balls // Класс пользователя шаров

{

...

Color col;

ListBox pListBox;


public User () // Конструктор

{

...

pListBox= new ListBox ();

pBut.MouseDown += new MouseEventHandler (OnBut);

pListBox.Items.Add ("red");

pListBox.Items.Add ("green");

pListBox.Items.Add ("blue");

pListBox.Location = new Point (104, 24);

pListBox.Name = "listBox";

pListBox.Size = new System.Drawing.Size (56, 17); pListBox.SelectedIndexChanged += new

System.EventHandler (SelectedItem); pChildForm.Controls.Add (pListBox);

}

...

void SelectedItem (object obj, EventArgs arg)

{

Console.WriteLine ("OkList");

if(pListBox.GetSelected (0))

col= Color.Red;

if(pListBox.GetSelected (1))

col= Color.Green;

if(pListBox.GetSelected (2))

col=Color.Blue;

SetColor (col);

}

...

}

/*

Результат:

Появились прикладное окно с перемещающимися шарами и дочернее окно

с кнопкой и со списком. При нажатии на кнопку можно приостанавливать

или возобновлять движение шаров. Используя список, можно изменить цвет

шаров.

*/

В классе User объявлена ссылка pListBox на объект списка класса ListBox. Объект списка создан в конструкторе, а его элемент с помощью свойств Location и Size размещён в дочернем окне справа от кнопки. Со списком связана функция-обработчик SelectedItem, которая выбирает выделенный цвет из списка, используемый функцией OnPaint для перерисовки шаров с этим цветом. В конструкторе класса User обработчик SelectedItem подписан на событие SelectedIndexChanged управляющего элемента-списка типа EventHandler.

Рис. 10.2.5. Прикладное и дочернее окна Balls–приложения 6 этапа


Полный текст программы Balls–приложения

Полный текст разработанной программы выглядит следующим образом:

////////////////////

// C# File BallsCs.cpp

using System;

using System.Drawing;

using System.Windows.Forms;

using System.Threading;

delegate void delEv (); // Делегат события

class Ball // Класс потокового объекта

{

public event delEv ev; // Объявление события

public int x, y; // Координаты шара

public int w, h; // Ширина и высота области клиента

public int dx, dy; // Приращения координат шара

Thread thread; // Поток

bool run; // Признак выполнения потока

bool life; // Признак существования потока

public Ball (int X, int Y, int Dx, int Dy) // Конструктор

{

life= false; run= false; w= 100; h= 100;

x= X; y= Y; dx= Dx; dy= Dy;

}

//---------------

~Ball () {life= false;} // Деструктор

//---------------

public void Start () // Стартовать

{

if (!run) // Если поток не выполнялся, то

{

run= true; // пусть выполняется и

life= true; // пусть живёт.

thread= new Thread (new ThreadStart (BallFunc));

thread.Start ();// Стартовать поток

}

}

//---------------

public void Finish () {life= true;} // Завершить

//---------------

public void Suspend () // Приостановить

{

if (run) // Если поток выполняется, то

{

run= false; // прекратить выполнение.

thread.Suspend (); // Приостановить

}

}

//---------------

public void Resume () // Возобновить

{

if (!run) // Если поток приостановлен, то

{

run= true; // пусть выполняется

thread.Resume (); // Возобновить

}

}

//---------------

void BallFunc () // Выполнить поток

{

while (life) // Пока существует, выполнить

{

x += dx; y += dy;

if (x>w || x<0) dx= -dx;

if (y>h || y<0) dy= -dy;

if (ev!= null)

{

ev (); // Генерировать событие

}

Thread.Sleep (100);

}

}

}

//-------------------------------------

class Balls: Form // Класс потоковых объектов

{

Ball [] pBall; // Массив потоковых объектов

bool run; // Признак выполнения потоковых объектов

Color col; // Цвет шаров

public Balls () // Конструктор

{

run= true;

col= System.Drawing.Color.FromArgb (0, 0, 255);

pBall= new Ball [2];

for (int i= 0; i < 2; i++)

{

pBall[i]=new Ball (i*3+10, 1*3+15, i*3+5, i*3+5);

pBall[i].ev += new delEv (HandlerEv); // Добавить функцию

}

Text= "Balls"; // Заголовок прикладного окна

Start (); // Стартовать потоковые объекты

}

//---------------

~Balls () {Finish ();}

//---------------

public void Start () // Стартовать

{

for (int i=0; i < 2; i++)

pBall[i]. Start ();

}

//---------------

public void Finish () // Завершить

{

for (int i=0; i < 2; i++)

pBall[i]. Finish ();

}

//---------------

public void Suspend () // Приостановить

{

if (run) // Если потоковые объекты выполнялись, то

{

run= false; // прекратить выполнение.

for (int i=0; i < 2; i++)

pBall[i].Suspend (); // Приостановить

}

}

//---------------

public void Resume () // Возобновить

{

if (!run) // Если потоковые объекты приостановлены, то

{

run= true; // продолжить выполнение.

for(int i= 0; i < 2; i++)

pBall[i].Resume (); // Возобновить

}

}

//---------------

public void SetColor (Color Col) // Установить цвет

{

col= Col;

Invalidate ();

}

//---------------

protected override void OnPaint (PaintEventArgs arg) // Перерисовать

{

for (int i= 0; i < 2; i++)

{

arg.Graphics.DrawEllipse (new Pen (col), pBall[i].x, pBall[i].y, 20, 20);

pBall[i].w= Width;

pBall[i].h= Height;

}

}

//---------------

void HandlerEv () // Обработать событие

{

Invalidate ();

}

}

//----------

class User: Balls // Класс пользователя шаров

{

private bool run; // Признак перемещения шаров

Form pChildForm; // Дочерняя форма (окно)

Color col; // Цвет шаров

Button pBut; // Кнопка

ListBox pListBox; // Список

public User () // Конструктор

{

run= true;

//---------------

pBut= new Button(); // Создать кнопку

pBut.Location = new Point (32, 24); // Разместить кнопку

pBut.Name = "pBut"; // Дать имя кнопке

// Задать размер кнопки в области клиента дочерней формы

pBut.Size = new System.Drawing.Size (32, 24);

pBut.Text = "OK"; // Поместить текст в кнопку

//---------------

pListBox= new ListBox (); // Создать список

// Определить функцию-обработчика кнопки

pBut.MouseDown += new MouseEventHandler (OnBut);

pListBox.Items.Add ("red"); // Добавить red

pListBox.Items.Add ("green"); // Добавить green

pListBox.Items.Add ("blue"); // Добавить blue

pListBox.Location = new Point (104, 24); // Разместить список

pListBox.Name = "listBox"; // Дать имя списку

// Задать размер списка в области клиента дочерней формы

pListBox.Size = new System.Drawing.Size (56, 17);

// Определить функцию-обработчика списка

pListBox.SelectedIndexChanged += new System.EventHandler

(SelectedItem);

// Задать размер области клиента прикладного окна

ClientSize = new System.Drawing.Size (200, 150);

//---------------

pChildForm= new Form (); // Создать дочернее окно (форму)

pChildForm.Location= new Point (250, 10); // и разместить его.

pChildForm.Size= new Size (250, 250); // Определить размер

pChildForm.Text= "User"; // Задать заголовок дочернего окна

pChildForm.Show (); // Показать дочернее окно

pChildForm.Controls.Add (pBut); // Добавить в доч.окно кнопку

pChildForm.Controls.Add (pListBox); // и список.

pChildForm.ClientSize = new System.Drawing.Size (200, 62);

}

//---------------

void OnBut (object obj, MouseEventArgs arg) // Обработать кнопку

{

if (run) // Если шары перемещаются, то

{

run= false; // пусть перестанут перемещаться.

Suspend (); // Приостановить

}

else // Иначе,

if(!run) // если шары неподвижны, то

{

run= true; // пусть перемещаются.

Resume (); // Возобновить

}

}

//---------------

void SelectedItem (object obj, EventArgs arg) // Выбрать из списка

{

if(pListBox.GetSelected (0))

col= Color.Red;

if(pListBox.GetSelected (1))

col= Color.Green;

if(pListBox.GetSelected (2))

col=Color.Blue;

SetColor (col);

}

//-------------------------

static void Main()

{

Application.Run(new User()); // Выполнить приложение

}

}


Введение.. 4

Краткая характеристика платформы.NET.. 5

Преимущества платформы.NET.. 5

Процессы, происходящие при запуске программ в среде.NET.. 6

Историческая справка. 8

Вопросы: 11

Терминология и основные определения ООП.. 12

Система типов C#. 13

Типы по значению.... 15

Встроенные типы по значению.... 16

Вопросы: 17

Пользовательские типы по значению.... 18

Типы по ссылке. 19

Упакованные типы по значению. 19

Классы... 21

Вопросы: 24

Член функции класса.. 25

Методы... 25

Методы с параметрами переменной длины... 29

Перегруженные функции.. 31

Конструкторы... 31

Конструктор по умолчанию.... 32

Вопросы: 34

Статический конструктор.. 35

Конструкторы с аргументами.. 36

Использование конструкторов для инициализации полей только для чтения.. 38

Вопросы: 41

Вызов конструкторов из других конструкторов. 42

Свойства.. 44

Массивы... 46

Не выровненные массивы... 48

Вопросы: 50

Индексаторы... 51

Наследование.. 53

Порядок вызовов конструкторов при наследовании.. 54

Изолированные классы... 56

Сокрытие методов базового класса.. 57

Вопросы: 59

Чистый полиморфизм... 60

Виртуальные методы (функции) 60

Переопределение виртуальных функций.. 61

Правила вызова методов (функций) 62

Абстрактные классы... 65

Вопросы: 66

Интерфейсы... 67

Запрос о реализации интерфейса. 69

Вопросы: 74

Делегаты и события.. 75

Многоадресные делегаты... 78

События.. 80

Вопросы: 85

Обработка исключений.. 86

Вопросы: 91

Генерация исключений.. 92

Программирование под Windows. 95

Вопросы: 100

Создание приложения с помощью мастера интегрированной рабочей среды Visual Studio.NET 101

Вопросы: 108

Простейшие графические объекты... 109

Структура Size.. 109

Структура Point.. 110

Структура Rectangle.. 111

Представление цвета.. 114

Кисти и перья.. 115

Вопросы: 118

Интерфейс графического устройства− GDI+. 119

Рисование линий и фигур.. 120

Рисование текста.. 122

Перерисовка окна приложения.. 124

Вопросы: 126

Потоки.. 128

Создание потока.. 128

Приоритеты потоков. 134

Остановка и возобновление работы потоков.. 135

Вопросы: 139

Пример приложения с потоками.. 140

Синхронизация работы потоков.. 146

Класс Interlocked.. 148

Класс Monitor.. 148

Вопросы: 153

Создание меню.... 155

Главное меню MainMenu.. 155

Контекстное меню ContextMenu.. 156

Конечные пункты меню MenuItem... 156

Свойства класса MenuItem... 162

Класс MenuItemCollection.. 162

Поэтапная разработка многопоточного приложения.. 165

Этап 1. 167

Этап 2. 172

Этап 3. 175

Этап 4. 178

Этап 5. 184

Этап 6. 187

Полный текст программы Balls–приложения.. 191


ВАФИН Радик Рашитович

МЕДВЕДЕВ Владислав Иосифович


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



Сейчас читают про: