Составление линейных программ на С++ 10


НазваниеСоставление линейных программ на С++ 10
страница26/26
ТипПрактическая работа
1   ...   18   19   20   21   22   23   24   25   26
Тема. Разработка пользовательского интерфейса для разработанных классов

Цель: Изучить основные способы работы с интнрфейсом, получить практические навыки в разработке проекта

Теоретические сведения

Для создания переносимых многопоточных приложений предлагаю воспользоваться библиотекой Glib.

Glib — это достаточно большая кросс-платформенная библиотека, которая, кроме потоков, включает в себя поддержку интернационализации, работу со строками, массивами, файлами, таймерами, и много чего другого, вплоть до XML парсера и поддерки .ini конфигурационных файлов.

В тоже время эта библиотека достаточно маленькая и почти не имеет зависимостей, что позволяет без особых проблем включать её в Windows-проекты, а в unix-подобных системах Glib уже есть.

Рассматриваемый вариант в первую очередь подойдёт для кросс-платформенных консольных и графических GTK приложений.

Программирование потоков

Для использования потоков в приложении первым делом нужно выполнить функцию инициализации:
g_thread_init(NULL);

Создание нового потока

GThread* g_thread_create (GThreadFunc func, gpointer data, gboolean joinable, GError **error);
Описание параметров:
func – потоковая функция с прототипом вида: gpointer GThreadFunc (gpointer data);

data – указатель на дополнительные данные передаваемые в поток, может быть NULL.

joinable — можно ли будет ожидать завершение потока через g_thread_join()

error — код и описание ошибки при создании потока, может быть NULL.

Узнать GThread текущего потока

GThread* g_thread_self(void);

Сменить приоритет потока:

void g_thread_set_priority(GThread *thread_id, GThreadPriority priority);

Описание параметров:

thread_id — структура, полученная при создании потока через g_thread_create()

priority — приоритет, возможные варианты в порядке возрастания:

G_THREAD_PRIORITY_LOW

G_THREAD_PRIORITY_NORMAL

G_THREAD_PRIORITY_HIGH

G_THREAD_PRIORITY_URGENT

Ждать завершения другого потока:

gpointer g_thread_join (GThread *thread_id);

Описание параметров:

thread_id — структура, полученная при создании потока через g_thread_create()

Функция дождётся завершения потока, только если при его создании joinable=TRUE, и вернёт код завершения потокой функции,

При создании потока с joinable=FALSE, функция сразу завершит своё выполнение и вернёт 0.

Пример:

// потоковая функция;
gpointer thread_func(gpointer data)
{
printf("внутри потокаn");
return 0;
}

int main (int argc, char *argv[])
{
// инициализация потоков
g_thread_init(NULL);
// создаём дополнительный поток
GThread *thread_id = g_thread_create(thread_func,NULL,TRUE,NULL);
//ждём завершения потока
g_thread_join(thread_id);
printf("дождались конца потокаn");
return 0; }

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

Рассмотрим мьютексы (mutex) и сигналы (condition). Существуют ещё другие специфические методы, вроде блокировки битов, но практически все из них можно заменить мьютексами и/или сигналами.

Mutex

Мьютексы служат для защиты кода от совместного доступа. Это аналог критической секции для Windows.

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

Создание мьютекса:

GMutex* g_mutex_new();

Блокировка мьютекса:

void g_mutex_lock(GMutex *mutex);

Pазблокировка мьютекса:

void g_mutex_unlock(GMutex *mutex);

Попытка блокировки мьютекса:

gboolean g_mutex_trylock(GMutex *mutex);

Если мьютекс свободен, то он блокируется и функция возвращает TRUE, иначе функция сразу завершает свою работу и возвращает FALSE.

Удаление мьютекса:

void g_mutex_free(GMutex *mutex);

Пример, в котором функция critical_func() с защищаемым от совместного доступа кодом может быть вызвана одновременно из основного и дополнительного потоков:

void critical_func(GMutex *mutex)

{
g_mutex_lock (mutex);

// какие-то вычисления

...
g_mutex_unlock (mutex);

}

// потоковая функция;
gpointer thread_func(gpointer data)
{
GMutex *mutex = (GMutex*)data;
critical_func(mutex);
return 0;
}

int main (int argc, char *argv[])

{
GMutex *mutex = g_mutex_new();

// создаём дополнительный поток

GThread *thread_id = g_thread_create(thread_func,mutex,TRUE,NULL);

critical_func(mutex);
//ждём завершения потока

g_thread_join(thread_id);
return 0;

}

Внимание: Повторный вызов g_mutex_lock() внутри уже заблокированного мьютекса не заблокирует программу и будет просто проигнорирован, что защищает от повторных блокировок.

Condition

Condition переводится как Условие, но по технике дела больше подходит слово Сигнал. Это аналог Событий для Windows, но не полный: Если сигнал послан раньше, чем его начали ждать, то он уйдёт в пустоту и ждать его будет бесполезно. Поэтому здесь нет понятия сброса события, как в Windows.

Создание сигнала (условия):

GCond* g_cond_new(void);

Послать сигнал:

void g_cond_signal (GCond *cond);

Бесконечно ждать сигнала:

void g_cond_wait (GCond *cond, GMutex *mutex);

Ждать сигнала не более заданного времени:

gboolean g_cond_timed_wait (GCond *cond, GMutex *mutex, GTimeVal *abs_time);

Пример

Пример демонстрирует применение сигналов для ожидания начала запуска потока после его создания.

GMutex *mutex = NULL;

GCond *cond = NULL;

// потоковая функция;

gpointer thread_func(gpointer data)

{
// инициализация потока

// ...

// Послать сигнал что инициализация завершена

g_mutex_lock (mutex);

g_cond_signal(cond);
g_mutex_unlock(mutex);// сигнал установится только после покидания мьютекса

// ...

return 0;

}

// Создание потока и ожидание его запуска с помощью условий

int main (int argc, char *argv[])

{
GTimeVal timeval;

gboolean return_val;

// инициализация потоков

g_thread_init(NULL);
// создать мьютекс и сигнал(условие)

mutex = g_mutex_new();

cond = g_cond_new();

// мьютекс заблокирован раньше создания потока, чтобы сигнал не был послан раньше начала его ожидания

g_mutex_lock(mutex);
// запускаем поток

g_thread_create( thread_func,NULL,TRUE,NULL);

// задаём время ожидания

g_get_current_time(&timeval);// узнаём текущее время

g_time_val_add(&timeval,G_USEC_PER_SEC);// добавляем секунду

// ждём запуска потока не более секунды

return_val = g_cond_timed_wait(cond,mutex,&timeval);// внутри mutex будет временно разблокирован, чтобы можно было послать сигнал также внутри if(!return_val)

printf("так и не дождались создания потокаn");g_mutex_unlock(mutex); return 0; }

Внимание: Ожидание сигнала должно быть внутри заблокированного мьютекса, и посылать сигнал тоже рекомендуется внутри заблокированного мьютекса, хотя это и не обязательно.

Во время ожидания мьютекс временно разблокируется для того чтобы можно было зайти внутрь этого же мьютекса из другого потока и послать сигнал.
Задание для самостоятельного выполнения

Разработать интерфейс для кросс-платформенного приложения.

Написать обработчик для приложения.

Протестировать работу приложения
Литература

Справочник C#. https://msdn.microsoft.com/ru

C# 5.0 и платформа .NET 4.5.

Полное руководство по языку программирования С# 6.0 и платформе NET 4.6. http://metanit.com/sharp/tutorial/

Оценка

Критерии

5

Студент написал правильно программу

4

Правильно написана программа, но есть не большие отклонения

3

Код программы написан, верно, но есть отклонения в работе программы

2

не справился с заданием (программа не написана)

Практическая работа №20

Тема. Разработка кросс поточного приложения. Создание пользовательского интерфейса

Цель: Изучить основные способы работы кросспоточным приложением, получить практические навыки в разработке проекта

Теоретические сведения

Для работы с потоками нам необходимо подключить пространстве имен System.Threading. Добавьте строку using System.Threading после строки using System.Text.

Непосредственно перед функцией Main добавим функцию WriteString, которая будет отвечать за вывод символов, назначенных данному потоку (мы будем назначать номер потока) на экран. В качестве параметра функция будет получать объект _Data, который впоследствии будет преобразован в строку в коде функции.

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

 static void WriteString(object _Data)

{

//для получения строки используем преобразование типов:
// приводим переменную _Data к типу string и записываем
// в переменную str_for_out
string str_for_out = (string) _Data;
// теперь поток 1 тысячу раз выведит полученную строку (свой номер)
for (int i = 0; i <= 1000; i++)
Console.Write(str_for_out);

}

Теперь перейдем непосредственно к коду функции Main. Здесь реализуем следующий код:

Сначала мы создадим 4 потока, каждому из которых укажем, что они будут выполнять функцию WriteString.

Далее назначим потокам приоритеты.

После этого запустим все четыре потока, передав в качестве параметра их номера.

Далее останется только дождаться завершения все четырех потоков и ожидать ввода пользователем какого-либо символа, чтобы завершить выполнение программы.
Код функции Main теперь будет выглядеть следующим образом:

static void Main(string[] args) //точка входа в программу
{

//создаем 4 потока, в качестве параметров передаем имя Выполняемой функции
Thread th_1 = new Thread(WriteString);
Thread th_2 = new Thread(WriteString);
Thread th_3 = new Thread(WriteString);
Thread th_4 = new Thread(WriteString);

//расставляем приоритеты для потоков
th_1.Priority = ThreadPriority.Highest; // самый высокий
th_2.Priority = ThreadPriority.BelowNormal; // выше среднего
th_3.Priority = ThreadPriority.Normal; // средний
th_4.Priority = ThreadPriority.Lowest; // низкий
// запускаем каждый поток, в качестве параметра передаем номер потока
th_1.Start( "1");
th_2.Start( "2");
th_3.Start( "3");
th_4.Start( "4");

Console.WriteLine( "все потоки запущены ");
//Ждем заврешения каждого потока
th_1.Join();
th_2.Join();
th_3.Join();
th_4.Join();
Console.ReadKey(); // прочитать символ (пока пользователь не нажмет клавишу программа не завершиться (чтобы можно было успеть посмотреть результат)).

}

Откомпилируйте и запустите программу (F5). Пример результата работы программы можно увидеть на рисунке 1. Так же, необходимо помнить, что при каждом запуске программы, выводимый на экран результат будет отличаться от предыдущего. А если запустить созданное приложение не из среды Visual Studio (без отладки), а просто, из операционной системы, то, до вывода сообщения «Все потоки запущены», по несколько раз может успеть выполнится назначенная функция каждого потока.

Чтобы создать компонент "Калькулятор", выполните следующие действия.

В меню Проект выберите Добавить компонент.

Задайте компоненту имя Calculator.

Чтобы добавить в компонент "Калькулятор" общие переменные, выполните следующие действия.

Откройте Редактор кода для компонента Calculator.

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

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

public int varAddTwo;

public int varFact1;

public int varFact2;

public int varLoopValue;

public double varTotalCalculations = 0;

Чтобы добавить в компонент "Калькулятор" методы и события, выполните следующие действия.

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

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

// This delegate will be invoked with two of your events.

public delegate void FactorialCompleteHandler(double Factorial, double TotalCalculations);

public delegate void AddTwoCompleteHandler(int Result, double TotalCalculations);

public delegate void LoopCompleteHandler(double TotalCalculations, int Counter);

Объявите события, используемые компонентом для связи с приложением. Для этого добавьте следующий код непосредственно под кодом, введенным на предыдущем шаге.

public event FactorialCompleteHandler FactorialComplete;

public event FactorialCompleteHandler FactorialMinusOneComplete;

public event AddTwoCompleteHandler AddTwoComplete;

public event LoopCompleteHandler LoopComplete;

Сразу после предыдущего кода введите следующий код.

// This method will calculate the value of a number minus 1 factorial

// (varFact2-1!).

public void FactorialMinusOne() {

double varTotalAsOfNow = 0;

double varResult = 1;

// Performs a factorial calculation on varFact2 - 1.

for (int varX = 1; varX <= varFact2 - 1; varX++) {

varResult *= varX;

// Increments varTotalCalculations and keeps track of the current

// total as of this instant.

varTotalCalculations += 1;

varTotalAsOfNow = varTotalCalculations; }

// Signals that the method has completed, and communicates the

// result and a value of total calculations performed up to this

// point.

FactorialMinusOneComplete(varResult, varTotalAsOfNow); }

// This method will calculate the value of a number factorial.

// (varFact1!)

public void Factorial() {

double varResult = 1;

double varTotalAsOfNow = 0;

for (int varX = 1; varX <= varFact1; varX++) {

varResult *= varX;

varTotalCalculations += 1;

varTotalAsOfNow = varTotalCalculations; }

FactorialComplete(varResult, varTotalAsOfNow); }

// This method will add two to a number (varAddTwo+2).

public void AddTwo() {

double varTotalAsOfNow = 0;

int varResult = varAddTwo + 2;

varTotalCalculations += 1;

varTotalAsOfNow = varTotalCalculations;

AddTwoComplete(varResult, varTotalAsOfNow); }

// This method will run a loop with a nested loop varLoopValue times.

public void RunALoop() {

int varX;

double varTotalAsOfNow = 0;

for (varX = 1; varX <= varLoopValue; varX++) {

// This nested loop is added solely for the purpose of slowing down

// the program and creating a processor-intensive application.

for (int varY = 1; varY <= 500; varY++)

{

varTotalCalculations += 1;

varTotalAsOfNow = varTotalCalculations; } }

LoopComplete(varTotalAsOfNow, varLoopValue); }

Передача введенных пользователем данных в компонент

Следующим шагом является добавление в форму frmCalculations кода для получения введенных пользователем данных, а также для обмена значениями с компонентом Calculator.

Чтобы реализовать в форме "frmCalculations" интерфейс пользователя, выполните следующие действия.

Откройте форму frmCalculations в Редакторе кода.

Найдите оператор public partial class frmCalculations. Непосредственно после знака { введите:

Calculator Calculator1;

Найдите конструктор. Непосредственно перед знаком } добавьте следующую строку.

// Creates a new instance of Calculator.

Calculator1 = new Calculator();

В окне конструктора нажмите поочередно каждую кнопку, чтобы создать структуру кода для обработчика события Click для этой кнопки и добавить код обработчика.

В результате обработчики событий Click должны выглядеть следующим образом.

// Passes the value typed in the txtValue to Calculator.varFact1.

private void btnFactorial1_Click(object sender, System.EventArgs e)

{

Calculator1.varFact1 = int.Parse(txtValue.Text);

// Disables the btnFactorial1 until this calculation is complete.

btnFactorial1.Enabled = false;

Calculator1.Factorial(); }

private void btnFactorial2_Click(object sender, System.EventArgs e) {

Calculator1.varFact2 = int.Parse(txtValue.Text);

btnFactorial2.Enabled = false;

Calculator1.FactorialMinusOne(); }

private void btnAddTwo_Click(object sender, System.EventArgs e) {

Calculator1.varAddTwo = int.Parse(txtValue.Text);

btnAddTwo.Enabled = false;

Calculator1.AddTwo(); }

private void btnRunLoops_Click(object sender, System.EventArgs e) {

Calculator1.varLoopValue = int.Parse(txtValue.Text);

btnRunLoops.Enabled = false;

// Lets the user know that a loop is running

lblRunLoops.Text = "Looping";

Calculator1.RunALoop(); }

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

private void FactorialHandler(double Value, double Calculations)

// Displays the returned value in the appropriate label. {

lblFactorial1.Text = Value.ToString();

// Re-enables the button so it can be used again.

btnFactorial1.Enabled = true;

// Updates the label that displays the total calculations performed

lblTotalCalculations.Text = "TotalCalculations are " +

Calculations.ToString(); }

private void FactorialMinusHandler(double Value, double Calculations) {

lblFactorial2.Text = Value.ToString();

btnFactorial2.Enabled = true;

lblTotalCalculations.Text = "TotalCalculations are " +

Calculations.ToString(); }

private void AddTwoHandler(int Value, double Calculations) {

lblAddTwo.Text = Value.ToString();

btnAddTwo.Enabled = true;

lblTotalCalculations.Text = "TotalCalculations are " +

Calculations.ToString(); }

private void LoopDoneHandler(double Calculations, int Count) {

btnRunLoops.Enabled = true;

lblRunLoops.Text = Count.ToString();

lblTotalCalculations.Text = "TotalCalculations are " +

Calculations.ToString(); }

В окне конструктора формы frmCalculations непосредственно перед знаком } добавьте следующий код для обработки пользовательских событий, которые форма будет получать из компонента Calculator1.

Calculator1.FactorialComplete += new

Calculator.FactorialCompleteHandler(this.FactorialHandler);

Calculator1.FactorialMinusOneComplete += new

Calculator.FactorialCompleteHandler(this.FactorialMinusHandler);

Calculator1.AddTwoComplete += new

Calculator.AddTwoCompleteHandler(this.AddTwoHandler);

Calculator1.LoopComplete += new

Calculator.LoopCompleteHandler(this.LoopDoneHandler);

Проверка работы приложения

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

Чтобы проверить проект, выполните следующие действия.

В меню Отладка выберите команду Начать отладку.

Приложение начнет работу и появится форма frmCalculations.

В текстовом поле введите 4, а затем нажмите кнопку с надписью Прибавить два.

Под кнопкой должна появиться цифра "6", а в метке lblTotalCalculations должен быть отображен текст "Всего вычислений — 1".

Теперь нажмите кнопку с надписью Факториал - 1.

Под кнопкой должна появиться цифра 6, а метка lblTotalCalculations теперь содержит текст "Всего вычислений — 4".

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

Под кнопкой должно появиться число "2.43290200817664E+18", а метка lblTotalCalculations теперь содержит текст "Всего вычислений — 24".

Измените значение текстового поля на 50000, а затем нажмите кнопку с надписью Выполнить цикл.

Заметьте, что перед тем, как кнопка вновь станет доступна, пройдет небольшой, но заметный интервал времени. В метке под кнопкой должно отображаться "50000", а общее количество вычислений теперь равно 25000024.

Измените значение текстового поля на 50000, нажмите кнопку с надписью Выполнить цикл и непосредственно после этого нажмите кнопку Добавить два. Нажмите кнопку еще раз.

Кнопка не будет реагировать (так же как и все остальные элементы управления в форме), пока не завершится цикл.

Если в программе запускается только один поток выполнения, занимающие процессор вычисления (аналогичные приведенным выше) могут приостанавливать программу, пока они не будут закончены. В следующем разделе приложение будет дополнено поддержкой многопоточности, в результате чего несколько потоков смогут выполняться одновременно.

Задание для самостоятельного выполнения

Разработать интерфейс для поточного приложения.

Написать обработчик для приложения.

Протестировать работу приложения
Литература

Справочник C#. https://msdn.microsoft.com/ru

C# 5.0 и платформа .NET 4.5.

Полное руководство по языку программирования С# 6.0 и платформе NET 4.6. http://metanit.com/sharp/tutorial/

Оценка

Критерии

5

Студент написал правильно программу

4

Правильно написана программа, но есть не большие отклонения

3

Код программы написан, верно, но есть отклонения в работе программы

2

не справился с заданием (программа не написана)

Практическая работа №21

Тема. Определение и кодирование ключевых ситуаций. Разработка обработчиков событий

Цель: Изучить основные способы разработки обработчиков событий, получить практические навыки в разработке проекта

Теоретические сведения

Каждый объект является экземпляром некоторого класса. Класс задает свойства и поведение своих экземпляров. Методы класса определяют поведение объектов, свойства - их состояние. Все объекты обладают одними и теми же методами и, следовательно, ведут себя одинаково. Можно полагать, что методы задают врожденное поведение объектов. Этого нельзя сказать о свойствах - значения свойств объектов различны, так что экземпляры одного класса находятся в разных состояниях. Объекты класса "человек" могут иметь разные свойства: один - высокий, другой - низкий, один - сильный, другой - умный. Но методы у них одни: есть и спать, ходить и бегать. Как сделать поведение объектов специфическим? Как добавить им поведение, характерное для данного объекта? Один из наиболее известных путей - это наследование. Можно создать класс-наследник, у которого, наряду с унаследованным родительским поведением, будут и собственные методы. Например, наследником класса "человек" может быть класс "человек_образованный", обладающий методами: читать и писать, считать и программировать.

Есть еще один механизм, позволяющий объектам вести себя по-разному в одних и тех же обстоятельствах. Это механизм событий, рассмотрением которого мы сейчас и займемся. Класс, помимо свойств и методов, может иметь события. Содержательно, событием является некоторое специальное состояние, в котором может оказаться объект класса. Так, для объектов класса "человек" событием может быть рождение или смерть, свадьба или развод. О событиях в мире программных объектов чаще всего говорят в связи с интерфейсными объектами, у которых события возникают по причине действий пользователя. Так, командная кнопка может быть нажата - событие Click, документ может быть закрыт - событие Close, в список может быть добавлен новый элемент - событие Changed.

Интерфейсные и многие другие программные объекты обладают стандартным набором предопределенных событий. В конце этой лекции мы поговорим немного об особенностях работы с событиями таких объектов. Сейчас же наше внимание будет сосредоточено на классах, создаваемых программистом. Давайте разберемся, как для таких классов создаются и обрабатываются события. Класс, решивший иметь события, должен уметь, по крайней мере, три вещи:

• объявить событие в классе;

• зажечь в нужный момент событие, передав обработчику необходимые для обработки аргументы. (Под зажиганием или включением события понимается некоторый механизм, позволяющий объекту уведомить клиентов класса, что у него произошло событие.);

• проанализировать, при необходимости, результаты события, используя значения выходных аргументов события, возвращенные обработчиком.

Заметьте, что, зажигая событие, класс посылает сообщение получателям события - объектам некоторых других классов. Будем называть класс, зажигающий событие, классом - отправителем сообщения (sender). Класс, чьи объекты получают сообщения, будем называть классом - получателем сообщения (receiver). Класс-отправитель сообщения, в принципе, не знает своих получателей. Он отправляет сообщение в межмодульное пространство. Одно и то же сообщение может быть получено и по-разному обработано произвольным числом объектов разных классов. Взгляните на схему, демонстрирующую взаимодействие объектов при посылке и получении сообщения.

Формальный синтаксис объявления таков:

Пример:

[атрибуты] [модификаторы]event [тип, заданный делегатом] [имя события]

Есть еще одна форма объявления, но о ней чуть позже. Чаще всего, атрибуты не задаются, а модификатором является модификатор доступа - public. Приведу пример объявления делегата и события, представляющего экземпляр этого делегата:

namespace Events

{

public delegate void FireEventHandler(object Sender, int time, int build);

public class TownWithEvents

{

public event FireEventHandler FireEvent;

}//TownWithEvents

}//namespace Events

Здесь делегат FireEventHandler описывает класс событий, сигнатура которых содержит три аргумента. Событие FireEvent в классе TownWithEvents является экземпляром класса, заданного делегатом.

Объекты класса Sender создают события и уведомляют о них объекты, возможно, разных классов, названных нами классами Receiver, или клиентами. Давайте разберемся, как должны быть устроены классы Receiver, чтобы вся эта схема заработала.

Понятно, что класс receiver должен:

• иметь обработчик события - процедуру, согласованную по сигнатуре с функциональным типом делегата, который задает событие;

• иметь ссылку на объект, создающий событие, чтобы получить доступ к этому событию - event-объекту;

• уметь присоединить обработчик события к event-объекту. Это можно реализовать по-разному, но технологично это делать непосредственно в конструкторе класса, так что когда создается объект, получающий сообщение, он изначально готов принимать и обрабатывать сообщения о событиях. Вот пример, демонстрирующий возможное решение проблем:

public class FireMen

{

private TownWithEvents MyNativeTown;

public FireMen(TownWithEvents TWE)

{

this.MyNativeTown=TWE;

MyNativeTown.FireEvent += new

FireEventHandler(FireHandler);

}

private void FireHandler(object Sender, int time, int build)

{

Console.WriteLine("Fire at day {0}, in build {1}!",

time, build);

}

public void GoOut()

{

MyNativeTown.FireEvent -= new FireEventHandler(FireHandler);

}

}//FireMan

В классе Fireman есть ссылка на объект класса TownWithEvents, создающий события. Сам объект передается в конструкторе класса. Здесь же происходит присоединение обработчика события к event-объекту. Обработчик события FireHandler выводит сообщение на консоль.

В этом примере строится класс ListWithChangedEvent, являющийся потомком встроенного класса ArrayList, который позволяет работать со списками. В класс добавляется событие Changed, сигнализирующее обо всех изменениях элементов списка. Строятся два класса - Receiver1 и Receiver2, получающие сообщения. В примере рассматривается взаимодействие нескольких объектов: два объекта посылают сообщения, три - принимают.

Начнем с объявления делегата:

// Объявление делегата

public delegate void ChangedEventHandler(object sender,

ChangedEventArgs args);

Здесь объявлен делегат ChangedEventHandler, по всем правилам хорошего стиля - его имя и его форма соответствует всем требованиям. Второй аргумент, задающий аргументы события, принадлежит классу ChangedEventArgs, производному от встроенного класса EventArgs. Рассмотрим, как устроен этот производный класс:

public class ChangedEventArgs:EventArgs {

private object item;

private bool permit;

public object Item

{

get {return(item);}

set { item = value;}

}

public bool Permit

{

get {return(permit);}

set { permit = value;}

}

}//class ChangedEventArgs

У класса два закрытых свойства, доступ к которым осуществляется через процедуры-свойства get и set. Конечно, можно было бы в данной ситуации сделать их просто public - общедоступными. Свойство Item задает входной аргумент события, передаваемый обработчику события. Булево свойство Permit задает выходной аргумент события, получающий в обработчике значение True, если обработчик события дает добро на изменение элемента.
Задание для самостоятельного выполнения

Разработать приложения по обработке событий на примере калькулятор.

Написать обработчик для приложения.

Протестировать работу приложения
Литература

Справочник C#. https://msdn.microsoft.com/ru

C# 5.0 и платформа .NET 4.5.

Полное руководство по языку программирования С# 6.0 и платформе NET 4.6. http://metanit.com/sharp/tutorial/

Оценка

Критерии

5

Студент написал правильно программу

4

Правильно написана программа, но есть не большие отклонения

3

Код программы написан, верно, но есть отклонения в работе программы

2

не справился с заданием (программа не написана)

Практическая работа №22

Тема. Разработка логики приложения. Отладка и тестирование приложения

Цель: Изучить основные способы логики при отладки и тестировании приложения, получить практические навыки в разработке проекта

Теоретические сведения

Выбора что встраивать под маком нету. Поэтому используем MonoMac и стандартный браузер. Но тут есть подвох в лицензиях. Можно свободно распространять приложение без Mono, т.е. пользователь сам должен будет поставить Mono и, следовательно, приложение не может попасть в AppStore. Если же мы хотим встроить Mono в приложение, то придется покупать Xamarin.Mac, который обойдется в 300 или 1000 долларов в зависимости от размера компании за одного программиста.
Под мак получился самый лаконичный код. Единственное не интуитивно понятное место — вызов С# из js.
После инициализации браузера нам надо создать объект, через который js сможет вызывать методы контроллера из C#. Назовем объект interaction:

webView.WindowScriptObject.SetValueForKey(this, new NSString("interaction"));


Определяем методы и указываем, какие из них могут быть вызваны из js:

[Export("callFromJs")]

public void CallFromJs(NSString message)

{

CallJs("showMessage", message + " Ответ из C#");

}

[Export ("isSelectorExcludedFromWebScript:")]

public static bool IsSelectorExcludedFromScript(MonoMac.ObjCRuntime.Selector sel)

{

if (sel.Name == "callFromJs")

return false;

return true; // Запрещаем вызов всех остальных методов

}

public partial class MainWindowController : MonoMac.AppKit.NSWindowController

{

/*Автоматически сгенерированный код*/

//Интерфейс из xib(nib) построен, инициализорован и все ссылки на UI компоненты установлены

public override void AwakeFromNib ()

{

base.AwakeFromNib ();

// Создаем объект через который js сможет обращаться к C#. Назовем его interaction

// window.interaction.callFromJs(param1, param2, param3) - вызываем метод из js.

webView.WindowScriptObject.SetValueForKey(this, new NSString("interaction"));

webView.MainFrame.LoadHtmlString (@"







Интерфейс





1   ...   18   19   20   21   22   23   24   25   26

Похожие:

Составление линейных программ на С++ 10 iconПорядок учетно-кадастровых процедур в отношении сооружений (линейных объектов недвижимости)
В соответствии с Федеральным законом от 24. 07. 2007 №221-фз «О государственном кадастре недвижимости» (далее Закон) в отношении...

Составление линейных программ на С++ 10 icon«Составление индивидуальных корреционно развивающих программ развития...

Составление линейных программ на С++ 10 iconО подготовке к государственной аккредитации образовательных программ в 2018 г
Количество образовательных программ бакалавриата, специалитета и магистратуры (без учета программ, реализация которых завершается...

Составление линейных программ на С++ 10 iconОао мгтс
...

Составление линейных программ на С++ 10 iconЛекция: Организация похода выходного дня
Составление плана подготовки и проведения путешествия. Разработка маршрута, подбор картографического материала, составление схемы...

Составление линейных программ на С++ 10 iconАдминистративный регламент №36
«Выдача разрешений на ввод линейных объектов, расположенных на территории двух и более поселений Добрянского муниципального района,...

Составление линейных программ на С++ 10 iconУльяновский институт повышения квалификации и переподготовки работников...
Портфолио учащегося: составление и использование: методические рекомендации./ Автор-составитель: Т. Б. Табарданова – Ульяновск: уипк...

Составление линейных программ на С++ 10 iconАннотация к рабочей программе профессионального модуля «Составление...
Рабочая программа профессионального модуля «Составление и использование бухгалтерской отчётности» является частью основной профессиональной...

Составление линейных программ на С++ 10 iconРабочая программа производственной практики пп. 03 Пм. 04 «Составление...
Программа практики является составной частью профессионального модуля 04 Составление и использование бухгалтерской отчетности основной...

Составление линейных программ на С++ 10 iconИ составление «рабочего» плана курсовой работы 7
Предварительная проработка литературы по теме и составление «рабочего» плана курсовой работы 7

Вы можете разместить ссылку на наш сайт:


Все бланки и формы на filling-form.ru




При копировании материала укажите ссылку © 2019
контакты
filling-form.ru

Поиск