Розробка уроку — практичної роботи

Тема: елементи мови подійно-орієнтованого програмування C#.

Мета: знати:

По завершенню вивчення учень (учениця):

Обладнання: комп’ютери зі встановленими ОС і середовищем програмування мовою C# (наприклад, MonoDevelop), (дана) інструкція.

Структура уроку

  1. Організаційний момент.
  2. Актуалізація опорних знань.
  3. Інструктаж з ТБ.
  4. Вивчення нового матеріалу.
  5. Вироблення практичних навичок.
  6. Підбиття підсумків уроку.
  7. Домашнє завдання.

Хід уроку

1. Організаційний момент
Вітання з класом. Перевірка присутності і готовності учнів до уроку. Перевірка виконання домашнього завдання.

2. Актуалізація опорних знань
Дати означення (опис) поняттям, виділеним жирним шрифтом, і порівняти з очікуваним.

Об'єкт (від латинською objectum — предмет, явище) — це те, на що спрямована певна діяльність (на противагу суб'єкту, який здійснює таку діяльність).

Властивість об'єктавеличина (параметр), значення якої описує стан об'єкта. Наприклад, об'єкт «учень» має такі властивості (подано невичерпний перелік): вік, зріст, маса тіла, успішність з певного предмету тощо.

Властивості бувають:

Подіязміна властивостей об'єкта, взаємодія між об'єктами, утворення нового об'єкта або знищення наявного об'єкта.

Подійно-орієнтоване програмування (ПОП, англійською EDP — event driven programming) — підхід до програмування з наголосом на опрацювання подій.

3. Інструктаж з ТБ
4. Вивчення нового матеріалу


Інколи все перелічене у осначенні події (див. вище) називають дією, а подією називають лише повідомлення про дію — спосіб класу надавати сповіщення клієнтам цього класу, коли з об’єктом щось трапляється. При такому тлумаченні, якого будемо дотримуватися далі, подія — це результат дії.

Опанування навчальним матеріалом складається з таких трьох етапів:

У разі потреби кожний з цих етапів потрібно вивчати на окремому уроці. Для кожного з поданих далі кодів потрібно пересвідчитися у правильності роботи програми.

Загально вживані терміни:

Опис (оголошення) делегата здійснюють за допомогою службового слова delegate, за яким вказують тип повернення та опис аргументів методів, які йому можна делегувати.

Наприклад, опис

public delegate int MyDelegate(int a, float b);

визначає делегата під назвою MyDelegate, який буде інкапсулювати (приймати) будь-який метод, який приймає як параметри 2 значення типів int i float та повертає значення з діапазону int.

Створення представника делегатакрок, на якому можна вказати метод, який потрібно викликати.

Наприклад, як у коді

public void MyMethod() { MyDelegate a = new MyDelegate(MyDelegateMethod);}

MyDelegateMethod — це метод, який має опис аргументів, подібний до MyDelegate. Якщо це не так, компілятор C# повідомить про помилку.

Події використовують таким чином:

Опис (оголошення) події найчастіше здійснюють таким чином:

event делегат_події назва_події;

Розглянемо код:

using System;
namespace Rextester              // Для rextester.com
{ delegate void MyEventHandler();// 1. Оголошення типу делегата
  class MyEvent                  // 2. Клас опису події
  { public event MyEventHandler SomeEvent;  // оголошення події SomeEvent
    public void OnSomeEvent()               // метод породження події
    { if  (SomeEvent != null)   SomeEvent();
    }
  }
  class EventDemo                 // 3. Головнмй клас
  { static void Handler()         // обробник події.
    { Console.WriteLine("Є подія!");
    }
    static void Main()            // точка входження
    { MyEvent evt = new MyEvent();
      evt.SomeEvent += Handler;   // додати метод Handler() до списку подій
      evt.OnSomeEvent();          // створити подію
    }
  }
}

з таким виведенням:

Є подія!

Цей приклад коду містить таке.

Основні елементи, необхідні для опрацювання події

  1. Оголошення типу делегата (MyEventHandler).

  2. Клас (MyEvent), у якому:

    • оголошено подію (SomeEvent);

    • описано метод породження події (OnSomeEvent). У методі викликано обробник подій за допомогою делегата SomeEvent:

      if (SomeEvent != null) SomeEvent();

      Чутливість до події має бути зареєструваною в інших частинах програми, щоб отримувати повідомлення про подію. Метод породження події (OnSomeEvent) може бути викликаний до реєстрації будь-якого обробника події. Щоб уникнути виклику за порожнім посиланням, делегат події потрібно перевірити, щоб пересвідчитися, що він не є порожнім.
  3. Головний клас (EventDemo), у якому:

    • описано обробник подій (Handler). У поданому прикладі обробник подій просто виводить повідомлення, але інші обробники можуть викону­вати змістовніші функції;

    • описано головний метод (точка входження Main), у якому:

      • створено об'єкт класу події (MyEvent)

      • зареєстровано обробник події (Handler) додаванням до списку (evt.SomeEvent). В даному випадку метод Handler є статичним, але обробники подій можуть також служити методи екземпляра.
    • створено подію (методом OnSomeEvent).

Групова адресації події дає можливість декільком об'єктам реагувати на повідомлення про одну й ту саму подію — див. такий приклад коду.

using System;
namespace Rextester
{ delegate void MyEventHandler() ;
  class MyEvent
  { public event MyEventHandler SomeEvent;
    public void  OnSomeEvent() { if(SomeEvent != null) SomeEvent();}
  }
  class X {public void Xhandler() {Console.WriteLine("Почуто в X");}}
  class Y {public void Yhandler() {Console.WriteLine("Почуто в Y");}}
  class EventDemo
  { static void Handler() 
    { Console.WriteLine("Отримано об'єктом класу EventDemo");
    }
    static void Main()
    { MyEvent evt = new MyEvent();
      X x = new X();
      Y y = new Y();
      evt.SomeEvent += Handler;
      evt.SomeEvent += x.Xhandler;
      evt.SomeEvent += y.Yhandler;
      evt.OnSomeEvent();
      Console.WriteLine("----");
      evt.SomeEvent -= x.Xhandler;
      evt.OnSomeEvent() ;
    }
  }
}

з таким виведенням.

Отримано об'єктом класу EventDemo
Почуто в X
Почуто в Y
-------------
Отримано об'єктом класу EventDemo
Почуто в Y

У цьому прикладі створено два додаткові класи X і Y, у яких також визначено обробники подій, сумісні з делегатом MyEventHandler. Тому ці обробники можуть бути включені в ланцюжок подій. Обробники в класах X та Y не є статичними. Це означає, що спочатку потрібно створити об'єкти кожного з цих класів, а потім у ланцюжок подій можна ввести обробники, пов'язані з їхніми екземплярами.

Методи екземпляра та статичні методи можуть бути використані як обробники подій, але між ними є одна істотна відмінність:

В останньому випадку кожен об'єкт певного класу, якому потрібно отримати повідомлення про подію, потрібно реєструвати окремо.

У поданій нижче програмі створено клас X, у якому метод екземпляра визначено як обробник подій. У цьому випадку кожний об'єкт класу X потрібно зареєструвати окремо, щоб отримувати сповіщення про події.

using System;
namespace Rextester
{ delegate void MyEventHandler();
  class MyEvent
  { public event MyEventHandler SomeEvent;
    public void OnSomeEvent() { if(SomeEvent != null) SomeEvent();}
  }
  class X
  { int id;
    public X(int x) {id = x;}
    public void Xhandler() {Console.WriteLine("Об'єкт "+id);}
  }
  class EventDemo
  { static void Main()
    { MyEvent evt = new MyEvent();
      X x1 = new X(1);
      X x2 = new X(2);
      X x3 = new X(3);
      evt.SomeEvent += x1.Xhandler;
      evt.SomeEvent += x2.Xhandler;
      evt.SomeEvent += x3.Xhandler;
      evt.OnSomeEvent();
    }
  }
}

Ця програма здійснює таке виведення.

Об'єкт 1
Об'єкт 2
Об'єкт 3

У поданому нижче коді обробником події є статичний метод.

using System;
namespace Rextester
{ delegate void MyEventHandler();
  class MyEvent
  { public event MyEventHandler SomeEvent;
    public void OnSomeEvent()
    { if (SomeEvent != null) SomeEvent();
    }
  }
  class X
  { public static void Xhandler()
    { Console.WriteLine("Подія отримана класом.");
    }
  }
  class EventDemo
  { static void Main()
    { MyEvent evt = new MyEvent();
      evt.SomeEvent += X.Xhandler;
      evt.OnSomeEvent();
    }
  }
}

При виконанні коду буде виведено таке.

Подія отримана класом.

При цьому об'єктів класу X взагалі не створено!

У поданих вище прикладах присутнє автоматичне керування списком викликів обробників подій з можливістю додавати й вилучати обробник події зі списку. Керування таким списком не потрібно організовувати вручну. Але організувати керування списком викликів обробників подій можна і вручну, щоб, наприклад, реалізувати спеціальний механізм збереження подій.

Розширена форма вказівки event із засобами доступу (аксесорами подій) add i remove для керування списком обробників подій має такий вигляд.

event делегат_події назва_ події
{ add    { // Код додавання події в ланцюжок подій.
         }
  remove { // Код видалення події з ланцюжка подій.
         }
}

Код додавання події буде викликано при додаванні обробника події за допомогою оператора +=.

Код видалення події буде викликано при видаленні обробника події за допомогою оператора -=.

Викликаний засіб доступу (аксесор) приймає обробник події як неявний параметр з назвою value — див. приклад програми, що заносить значення цієї змінної у масив довжини 3, якщо він має вільне місце.

using System;
namespace Rextester
{ delegate void MyEventHandler();
  class MyEvent
  { MyEventHandler[] evnt = new MyEventHandler[3]; // список подій (до 3)
    public event MyEventHandler SomeEvent
    { add    { int i;
               for (i=0; i<3; i++) if(evnt[i] == null)
               { evnt[i] = value;
                 break;
               }
               if (i==3) Console.WriteLine("Список подій заповнено.");
             }
      remove { int i;
               for (i=0; i < 3; i++) if(evnt[i] == value)
               { evnt[i] = null;
                 break;
               }
               if (i == 3) Console.WriteLine("Обробника подій не знайдено.");
             }
    }
    public void OnSomeEvent()
    { for(int i=0; i<3; i++) if(evnt[i] != null) evnt[i]();
    }
  }
  // Класи, які використовують делегат MyEventHandler.
  class W { public void Whandler() {Console.WriteLine("Подія в W");}}
  class X { public void Xhandler() {Console.WriteLine("Подія в X");}}
  class Y { public void Yhandler() {Console.WriteLine("Подія в Y");}}
  class Z { public void Zhandler() {Console.WriteLine("Подія в Z");}}
  class EventDemo
  { static void Main()
    { MyEvent evt = new MyEvent();
      W w = new W();
      X x = new X();
      Y y = new Y();
      Z z = new Z();
      Console.WriteLine("Додавання у список подій.");
      evt.SomeEvent += x.Xhandler;
      evt.SomeEvent += y.Yhandler;
      evt.SomeEvent += z.Zhandler;
      evt.SomeEvent += w.Whandler; // Має не поміститися у заповнений список
      evt.OnSomeEvent();
      Console.WriteLine("\nВидалення обробника x.Xhandler.");
      evt.SomeEvent -= x.Xhandler;
      evt.OnSomeEvent();
      Console.WriteLine("\nСпроба видалити обробник x.Xhandler ще раз.");
      evt.SomeEvent -= x.Xhandler;
      evt.OnSomeEvent();
      Console.WriteLine("\nДодавання обробника z.Zhandler.");
      evt.SomeEvent += w.Whandler;
      evt.OnSomeEvent();
    }
  }
}

Результат виконання програми такий.

Додавання у список подій.
Список подій заповнено.
Подія в X
Подія в Y
Подія в Z

Видалення обробника x.Xhandler.
Подія в Y
Подія в Z

Спроба видалити обробник x.Xhandler ще раз.
Обробника подій не знайдено.
Подія в Y
Подія в Z

Додавання обробника z.Zhandler.
Подія в W
Подія в Y
Подія в Z

У поданому коді:

Як бачимо, зберігання обробників подій неважко втілити. Це доцільно робити, наприклад, якщо обробники подій необхідно виконувати у певному порядку, відмінному від того, в якому їх введено в ланцюжок подій. Але зазвичай достатньо механізму зберігання обробників подій, що використовує як усталено нерозширена (без аксесорів) форма оператора event.

Подійно-орієнтованого програмування не можливо уникнути при створенні інтерфейсу. У цьому випадку найзручніше використати засоби наочного програму­вання. Наприклад, у середовищі MonoDevelop.

Події можуть бути також визначені як абстрактні (abstract). У цьому випадку конкретна подія має бути реалізована у похідному класі. Але аксесорні форми подій неможливо бути абстрактними. Крім того, подія може бути визначена як герметична (sealed). Подія, може бути віртуальним: її потрібно перевизначити у похідному класі.

Застосування лямбда-виразу може істотно спростити код опрацювання події — див. приклад коду.

using System;
namespace Rextester
{ delegate void MyEventHandler(int n);
  class MyEvent
  { public event MyEventHandler SomeEvent;
    public void OnSomeEvent(int n) 
    { if(SomeEvent != null) SomeEvent(n);
    }
  }
  class LambdaEventDemo
  { static void Main()
    { MyEvent evt = new MyEvent();
      evt.SomeEvent += (n) => Console.WriteLine("n = "+n);
      evt.OnSomeEvent(1);
      evt.OnSomeEvent(2);
    }
  }
}

з таким виведенням.

n = 1
n = 2

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

evt.SomeEvent += delegate(int n) {Console.WriteLine("n = "+n);};

Опрацювання події, породженої діями з клавіатурою чи мишею проілюструємо наступним кодом, у якому переозначено обробники вбудованих подій.

using Gdk;
using Gtk;
using System;
using System.IO;                  // для виведення у консоль
using System.Collections.Generic; // для .GetType().GetProperties() 

class Example : Gtk.Window
{ // Створення вікна
  public Example() : base("Клавіатура й миша")
  { SetDefaultSize(400, 200); 
    SetPosition(WindowPosition.Center);
    DeleteEvent += delegate {Application.Quit();};
    ShowAll();
  }
  private static void WriteProperties (object o) // Друк назв і значень 
  { var ps = new Dictionary<string, string>();   // властивостей об'єкта
    foreach (var p in o.GetType().GetProperties())
    { var v   = p.GetValue(o, new object[] {});
      var val = v == null ? "" : v.ToString();
      ps.Add(p.Name, val);
    }
    foreach (var p in ps) Console.WriteLine(p.Key+" : "+p.Value);
  }
  protected override bool OnKeyPressEvent (EventKey e)
  { Console.WriteLine("\nНатиснуто клавішу з такими властивостями події:");
    WriteProperties(e);
    return true;
  }
  protected override bool OnKeyReleaseEvent (EventKey e)
  { Console.WriteLine("\nВивільнено клавішу з такими властивостями події:");
    WriteProperties(e);
    return true;
  }
  protected override bool OnButtonPressEvent (EventButton e)
  { Console.WriteLine("\nНатиснуто кнопку миші з такими властивостями події:");
    WriteProperties(e);
    return true;
  }
  protected override bool OnMotionNotifyEvent(EventMotion e)
  { Console.WriteLine("\nРух при натиснутій кнопці миші з такими властивостями події:");
    WriteProperties(e);
    return true;
  }
  protected override bool OnButtonReleaseEvent (EventButton e)
  { Console.WriteLine("\nВивільнено кнопку миші у точці з такими властивостями події:");
    WriteProperties(e);
    return true;
  }
  protected override bool OnDeleteEvent(Event e)
  { Application.Quit();
    return true;
  }
  public static void Main()
  { Application.Init();
    new Example();
    Application.Run();
  }
}

Властивості подій, породжені діями з клавіатурою

Властивості подій, породжені діями з мишею

Для використання значення певної властивості події в обробнику події потрібно у коді після назви події (e у поданому вище коді) через крапку вказати назву властивості. Наприклад, e.X i e.Y для координат вказівника миші у вікні.

Таймер (-планувальник)вбудований засіб мови програмування, що задає виклик певного методу через проміжок часу, вказаний розробником.

Таймер задає багатократне виконання певних дій, дозволяючи, на відміну від циклу, виконувати інші дії у проміжках між зверненнями таймера — див. приклад прокоментованого коду

using System;
using System.Timers;
namespace s
{ class Example
  { public static void Main()
    { Timer t = new Timer(); // створити таймер з назвою t

      // призначити метод M обробником події Elapsed -
      // завершення проміжку часу між викликами t 
      t.Elapsed += new ElapsedEventHandler(M);

      t.Interval = 2000; // час у мілісекундах між викликами t
      t.Start();         // запуск таймера
      while (Console.Read() != 'q') 
             Console.WriteLine(" - програма працює");
      t.Close();         // зупинка таймера
      Console.WriteLine(" - програма припиняє роботу");
    }
    public static void M (object source, ElapsedEventArgs e)
    { Console.WriteLine(DateTime.Now);
    }
  }
}

з таким можливим виглядом консолі,

15.08.2022 13:37:32
a - програма працює
s - програма працює
d - програма працює
15.08.2022 13:37:34
r - програма працює
e - програма працює
15.08.2022 13:37:36
w - програма працює
q - програма припиняє роботу

Press any key to continue...

якщо своєчасно натиснути клавіші з написами літер a, s, d, r, e, w, q — саме у такому порядку.

У поданому вище коді коротку назву методу M, що виводить поточні дату й час, використано лише для перенесення наголосу на структури мови програмування. Зазвичай доречніше використати довшу, але змістовнішу назву. Наприклад, OnTimedEvent.

Якщо при виконанні наступної програми

using System;
using System.Timers;
namespace s
{ class Example
  { private static Timer t;
    public static void Main()
    { t = new System.Timers.Timer();
      t.Interval  = 2000;
      t.Elapsed  += M;
      t.AutoReset = true; // багатократний виклик події Elapsed
      t.Enabled   = true; // вмикання таймера
      Console.WriteLine("Натискання клавіші Enter" 
                   +" зупинить виконання програми");
      Console.ReadLine();
    }
    private static void M (Object source, System.Timers.ElapsedEventArgs e)
    { Console.WriteLine(" Дата, час: {0} ", e.SignalTime);
    }
  }
}

натиснути клавішу Enter на 9-ій секунді, отримаємо виведення у консоль, схоже на таке.

Натискання клавіші Enter зупинить виконання програми
 Дата, час: 15.08.2022 16:33:44 
 Дата, час: 15.08.2022 16:33:46 
 Дата, час: 15.08.2022 16:33:48 
 Дата, час: 15.08.2022 16:33:50 


Press any key to continue...

5. Вироблення практичних навичок

Завдання 1. Створити застосунок, який:

Вказівки до виконання.

  1. Створити проект Gtk#. У середовищі MonoDevelop:
    • або натиснути клавіші Ctrl + Shift + N
    • або використати вказівку меню File / New Solution...

    У вікні діалогу Новий проект вибрати .NET / Проект Gtk# 2.0 і натиснути кнопку Далі

    У вікні діалогу Новий проект вказати назву (для поданих далі малюнків s), розташування проекту і натиснути кнопку Створити

  2. Відкрити дизайнер вікон. У вікні програми MonoDevelop у вкладенні Рішення викликати контекстне меню MainWindow.cs натисканням правої кнопки миші й вибрати Відкрити за допомогою / Дизайне вікон

    Пересвідчитися у появі у нижній частині вікна двох кнопок перемикання між режимами редагування коду (Джерело) і наочного редагування (Дизайнер). В останньому режимі помітити у вікні програми прямокутник сірого кольору — форму для розташування об'єктів.



    Розмір форми можна змінити перетягуванням маркера межі.

  3. Викликати панель панель Eлементи керування. У вікні програми MonoDevelop у режимі наочного редагування Дизайнер:

    • або клацнути клавішею миші на написі Eлементи керування з лівого краю вікна — див. малюнок вище;

    • aбо натиснути клавіші Alt + Shift + B;

    • або використати вказвку меню Перегляд / Панелі / Елементи керування — див. малюнок нижче.

    На панелі Eлементи керування, що з'явиться у лівій частні вікна MonoDevelop, побачити переліки нявних контейнерів і власне елементів керування (віджетів).


  4. Встановити контейнер Vbox, перетягнувши елемент Vbox з панелі Eлементи керування на форму.


  5. Встановити у створений контейнер Vbox елементи керування, перетяг­нувши з панелі Eлементи керування:

    • мітку Label — у верхню клітину;
    • поле введення Entry — у середню клітину;
    • кнопку Button — у нихню клітину.

  6. Змінити написи на мітці та кнопці таким чином.



    Відобразити панель Властивості:
    • або клацнути клавішею миші на написі Властивості з лівого краю вікна;
    • aбо натиснути клавіші Alt + Shift + B;
    • або використати вказвку меню Перегляд / Панелі / Властивості.

    Виділити об'єкт — на поданому нижче малюнку label1 — і на вкладенні Властивості в розділі Label Properties (властивості кнопки) натиснути на кнопку із зображенням трикрапки у рядку властивості LabelProp.

    У вікні діалогу Текст у полі введення прибрати напис label1 і натиснути кнопку Гаразд,

    щоб отримати такий вигляд вікна середовища програмування.

    Для кнопки GtkButton змінювати властивість Label у розділі Buttun Properties.

  7. Створити обробник події натискання кнопки, який очищатиме написи мітки й поля. Виділити кнопку з написом Очистити й на панелі Властивості перейти на вкладення Сигнали. У групі Button Signals двічі клацнути на назві події Clicked.

    Піся перемикання на режим редагування коду форми MainWindow.cs побачити наприкінці коду таке

    protected void OnButton1Clicked(object sender, EventArgs e)
    {
    }

    у вікні середовища програмування.

    При попередніх версіях MonoDevelop усередині фігурних можуть бути деякі вказівки, які потрібно видалити.

    Вставити між фігурними дужками такі вказівки.

    entry1.Text="";
    label1.Text="";

  8. Додати посилання на пакунок System.Windows.Forms для виведення повідом­лень. Використати вказівку меню Проект / Редагування посилання...

    У вікні діалогу Редагування посилання на вкладенні Всі після прокручування переліку Збірка виставити мітку в рядку System.Windows.Forms і натиснути кнопку Гаразд.

  9. Запустити проект на виконання:

    • або натиснути клавішу F5;
    • або використати вказівку меню Виконання / Start Debugging

    і перевірити можливість введення даних у поле введення й очищення цього поля після натискання кнопки.

  10. Створити обробник події натискання клавіші, який виводитиме у консоль властивості події натискання клавіші KeyPress. Для цього доповнити наявний код MainWindow.cs до поданого нижче, у якому знаком кометаря // наприкінці рядка і червоним кольором виділено ті рядки, якими потрібно доповнити код.

    using System;
    using Gtk;
    
    public partial class MainWindow : Gtk.Window
    {
        public MainWindow() : base(Gtk.WindowType.Toplevel)
        {
            Build();
            KeyPressEvent += KeyPress;                                 //
        }
        
        [GLib.ConnectBefore]                                           //
        protected void KeyPress(object sender, KeyPressEventArgs args) //
        {   Console.WriteLine("{0,6} {1,6} {2,9} {3,2} {4,16} {5,18} {6,22} {7,9} {8,9}", //
            args.Event.KeyValue, // код клавіші - ціле число 
            args.Event.SendEvent,// 
            args.Event.Time,     // час у мілісекундах
            args.Event.Group,    //
            args.Event.Handle,   //
            args.Event.Key,      // назва клавіші
            args.Event.State,    // стан (розкладка) клавіатури
            args.Event.Type,     // тип події - KeyPress
            args.Event.Window);  // батьківське вікно
            label1.Text = args.Event.Key.ToString();                   //
        }                                                              //
        protected void OnDeleteEvent(object sender, DeleteEventArgs a)
        {
            KeyPressEvent -= KeyPress;                                 //
            Application.Quit();
            a.RetVal = true;
        }
    
        protected void OnButton1Clicked(object sender, EventArgs e)
        {
            entry1.Text = "";
            label1.Text = "";
        }
    }

    У вказівці Console.WriteLine("…", …); між лапками у фігурних дужках вказано формат виведення властивостей з переліку після першої коми: спочатку вказано номер у переліку, (нумерація з нуля), а потім — кількість відведених для цього символів.

    Перелік властивостей подано у випадному списку, який можна побачити після послідовності символів args.Event. при спробі набрати з клавіатури вказівку виведення у консоль — див. наступний малюнок,

    на якому літерами і позначено відповідно властивості (анґлійською properties) і методи (анґлійською methods).

  11. Вибірково перевірити роботу програми, запустивши проект на виконання і натискаючи клавіші при різних розкладках клавіатури і з поєднанням клавіш-модифікаторів та без такого поєднання. Бажано використати розкладки для літер з діакритичнми знаками (наприклад, ľ, š, č, ť, ž, ý, á, í, é, ú, ô) або літерами, що не належать до латиниці чи кирилиці, і звернути увагу на назви клавіш.

  12. Перемістити проект у вказану вчителем теку й повідомити вчителя про завершення роботи.

Завдання 2. Створити застосунок, який:

Вказівки до виконання.

  1. Створити проект Gtk#. У середовищі MonoDevelop:
    • або натиснути клавіші Ctrl + Shift + N
    • або використати вказівку меню File / New Solution...

    У вікні діалогу Новий проект вибрати .NET / Проект Gtk# 2.0 і натиснути кнопку Далі

    У вікні діалогу Новий проект вказати назву (для поданих далі малюнків s), розташування проекту і натиснути кнопку Створити

  2. Відкрити дизайнер вікон. У вікні програми MonoDevelop у вкладенні Рішення викликати контекстне меню MainWindow.cs натисканням правої кнопки миші й вибрати Відкрити за допомогою / Дизайне вікон

    Пересвідчитися у появі у нижній частині вікна двох кнопок перемикання між режимами редагування коду (Джерело) і наочного редагування (Дизайнер). В останньому режимі помітити у вікні програми прямокутник сірого кольору — форму для розташування об'єктів.



    Розмір форми можна змінити перетягуванням маркера межі.

  3. Викликати панель панель Eлементи керування. У вікні програми MonoDevelop у режимі наочного редагування Дизайнер:

    • або клацнути клавішею миші на написі Eлементи керування з лівого краю вікна — див. малюнок вище;

    • aбо натиснути клавіші Alt + Shift + B;

    • або використати вказвку меню Перегляд / Панелі / Елементи керування — див. малюнок нижче.

    На панелі Eлементи керування, що з'явиться у лівій частні вікна MonoDevelop, побачити переліки нявних контейнерів і власне елементів керування (віджетів).

  4. Встановити на формі контейнер EventBox перетягуванням з панелі Eлементи керування. Отримати такмй вигляд вікна середовища програмування.

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

  5. Створити обробник події натискання кнопкм миші. Відобразити панель Властивості:
    • або клацнути клавішею миші на написі Властивості з лівого краю вікна;
    • aбо натиснути клавіші Alt + Shift + B;
    • або використати вказвку меню Перегляд / Панелі / Властивості.

    на панелі Властивості перейти на вкладення Сигнали. У групі Common Widget Signals двічі клацнути на назві події ButtonPressEvent.

    Піся перемикання на режим редагування коду форми MainWindow.cs побачити наприкінці коду таке

    protected void OnEventbox1ButtonPressEvent(object o, ButtonPressEventArgs args)
    {
    }

    у вікні середовища програмування.

    Вставити у код створеного обробника (між фігурними дужками) таку вказівку виведення у консоль всіх властивостей події.

    Console.WriteLine("{0,1}| {1,1} {2,10} {3,14} {4,5} {5,12} {6,8} {7,12} {8,10} {9,4} {10,4} {11,4} {12,4}", //
    args.Event.Axes,
    args.Event.Button,   // зазвичай: "1" - при натисканнв лівої кнопки миші;
                         //           "2" - при натисканні центральної кнопкою;
                         //           "3" - при натисканні правої кнопки.
    args.Event.Device,   //
    args.Event.Handle,   //
    args.Event.SendEvent,//
    args.Event.State,    // стан натискання клавіш-модифікаторів: Shift, Alt, Caps Lock
    args.Event.Time,     // час у мілісекундах
    args.Event.Type,     // назва події: ButtonPress, TwoButtonPress або ThreeButtonPress,
                         // залежно від кількості натискань клавіші протягом певного часу
    args.Event.Window,   // батьківське вікно
    args.Event.X,        // абсциса у вікні застосунку
    args.Event.XRoot,    // абсциса на екрані монітора
    args.Event.Y,        // ордината у вікні застосунку
    args.Event.YRoot);   // ордината на екрані монітора

    Перелік властивостей подано у випадному списку, який можна побачити після послідовності символів args.Event. при спробі набрати вказівку з клавіатури — див. наступні малюнки,

    на яких літерами і позначено відповідно властивості (анґлійською properties) і методи (анґлійською methods).

  6. Перевірити роботу програми щодо натискання кнопок миші.
    Запустити проект на виконання:
    • або натиснути клавішу F5;
    • або використати вказівку меню Виконання / Start Debugging.
    Натискати праву й ліву кнопки миші:
    • при натиснутих і відпущених клавішах-модифікаторах;
    • при розташуванні вказівника миші у різних точках вікна застосунку;
    • при розташуванні вікна застосунку у різних частинах екрану монітора.

    Проглянути виведення застосунку у консоль. Пересвідчитися у можливості породження усіх 3 типів подій: ButtonPress, TwoButtonPress і ThreeButtonPress. Закрити вікно застосунку.

  7. Створити обробник події пересування миші.
    Відобразити панель Властивості:
    • або клацнути клавішею миші на написі Властивості з лівого краю вікна;
    • aбо натиснути клавіші Alt + Shift + B;
    • або використати вказвку меню Перегляд / Панелі / Властивості.

    на панелі Властивості перейти на вкладення Сигнали. У групі Common Widget Signals двічі клацнути на назві події MotionNotifyEvent.

    Піся перемикання на режим редагування коду форми MainWindow.cs побачити наприкінці коду таке

    protected void OnEventbox1MotionNotifyEvent(object o, MotionNotifyEventArgs args)
      {
      }

    у вікні середовища програмування.

    Вставити у код створеного обробника (між фігурними дужками) таку вказівку виведення у консоль всіх властивостей події.

    Console.WriteLine("{0,1}> {1,10} {2,14} {3,5} {4,32} {5,8} {6,12} {7,10} {8,4} {9,4} {10,4} {11,4}", //
    args.Event.Axes,     //
    args.Event.Device,   //
    args.Event.Handle,   //
    args.Event.SendEvent,//
    args.Event.State,    // стан натискання клавіш-модифікаторів: Shift, Alt, Caps Lock
    args.Event.Time,     // час у мілісекундах
    args.Event.Type,     // назва події: MotionNotify
    args.Event.Window,   // батьківське вікно
    args.Event.X,        // абсциса у вікні застосунку
    args.Event.XRoot,    // абсциса на екрані монітора
    args.Event.Y,        // ордината у вікні застосунку
    args.Event.YRoot);   // ордината на екрані монітора

    Перелік властивостей подано у випадному списку, який можна побачити після послідовності символів args.Event. при спробі набрати вказівку з клавіатури — див. наступні малюнки,

    на яких літерами і позначено відповідно властивості (анґлійською properties) і методи (анґлійською methods).

  8. Перевірити роботу програми щодо переміщення миші при натиснутій кнопці миші.
    Запустити проект на виконання:
    • або натиснути клавішу F5;
    • або використати вказівку меню Виконання / Start Debugging.
    При натиснутій кнопці миші (спочатку лівій, а потім правій) пересувати вказівник миші у межах вікна застосунку при натиснутих і відпущених клавішах-модифікаторах. Проглянути виведення застосунку у консоль. Закрити вікно застосунку.

    Примітка. Як усталено подію руху переміщення миші без натискання кнопки не буде надіслано. При потребі її отримати потрібно здійснити певні дії. Наприклад, описані у наступному пункті.

  9. Налаштувати проект на отримання всіх повідомлень про рух миші. У режимі редагування Дизайнер виділити (з використанням випадного списку, розташованого над робочим полем) елемент eventbox1. Відобразити панель Властивості у разі її відсутності:

    • або клацнути клавішею миші на написі Властивості з лівого краю вікна;
    • aбо натиснути клавіші Alt + Shift + B;
    • або використати вказвку меню Перегляд / Панелі / Властивості.

    На вкладенні Властивості панелі Властивості у розділі Common Widget Properties натиснути кнопку з трикрапкою праворуч від напису Events.

    У вікні діалогу Прапорці виставити мітку All pointer motion (Всі переміщення вказівника) й натиснути кнопку з написом Гаразд.


  10. Перевірити роботу програми щодо переміщення миші.
    Запустити проект на виконання:
    • або натиснути клавішу F5;
    • або використати вказівку меню Виконання / Start Debugging.
    Пересувати вказівник миші у межах вікна застосунку при натиснутій і ненатиснутій кнопці миші (спочатку лівій, а потім правій), при натиснутих і відпущених клавішах-модифікаторах. Проглянути виведення застосунку у консоль. Закрити вікно застосунку.

  11. Перемістити проект у вказану вчителем теку й повідомити вчителя про завершення роботи.

6. Підбиття підсумків уроку
Виставлення оцінок.

7. Домашнє завдання

  1. Вивчити матеріал уроку.

  2. Створити програму, яка при натисканні клавіш Shift, Ctrl, Alt виводить у напис літери латиниці: A, B, C відповідно.

  3. Створити програму, яка у файл output.txt записує екранні координати вказівника миші у момент натискання лівої кнопки і припиняє свою роботу із закриванням файлу після натискання клавіші Esc


Текст упорядкував Олександр Рудик.