Skip to content

5. Графічні інтерфейси з використанням VB.NET та VS.NET

Тут ми пропонуємо показати, як створювати графічні інтерфейси за допомогою VB.NET. Спочатку розглянемо базові класи платформи .NET, які дозволяють нам створювати графічний інтерфейс. На початковому етапі ми не використовуємо жодних інструментів автоматичного генерування. Потім ми скористаємося Visual Studio.NET (VS.NET) — інструментом розробки від Microsoft, що полегшує розробку додатків на мовах .NET, зокрема створення графічних інтерфейсів. Ми використовуємо англійську версію VS.NET.

5.1. Основи графічних інтерфейсів

5.1.1. Просте вікно

Розглянемо такий код:


' опції
Option Strict On
Option Explicit On 

' простори імен
Imports System
Imports System.Drawing
Imports System.Windows.Forms

' клас форми
Public Class Form1
    Inherits Form

    ' виробник
    Public Sub New()
        ' заголовок вікна
        Me.Text = "Mon premier formulaire"
        ' розміри вікна
        Me.Size = New System.Drawing.Size(300, 100)
    End Sub

    ' тестова функція
    Public Shared Sub Main(ByVal args() As String)
        ' відображається форма
        Application.Run(New Form1)
    End Sub
End Class

Попередній код компілюється, а потім виконується

dos>vbc /r:system.dll /r:system.drawing.dll /r:system.windows.forms.dll frm1.vb

dos>frm1

Під час виконання з’являється таке вікно:

Image

Графічний інтерфейс зазвичай походить від базового класу System.Windows.Forms.Form:

Public Class Form1
    Inherits Form

Базовий клас Form визначає базове вікно з кнопками закриття, розгортання/згортання, регульованим розміром тощо та обробляє події для цих графічних об’єктів. Тут ми спеціалізуємо базовий клас, задаючи йому заголовок, ширину (300) та висоту (100). Це робиться у його конструкторі:


    Public Sub New()
        ' заголовок вікна
        Me.Text = "Mon premier formulaire"
        ' розміри вікна
        Me.Size = New System.Drawing.Size(300, 100)
    End Sub

Заголовок вікна задається властивістю Text, а розміри — властивістю Size. Size визначено в просторі імен System.Drawing і є структурою. Процедура Main запускає графічний додаток наступним чином:


        Application.Run(New Form1)

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

5.1.2. Форма з кнопкою

Тепер додамо кнопку до нашого вікна:


' параметри
Option Strict On
Option Explicit On 

' простори імен
Imports System
Imports System.Drawing
Imports System.Windows.Forms

' клас форми
Public Class Form1
    Inherits Form

    ' атрибути
    Private cmdTest As Button

    ' конструктор
    Public Sub New()
        ' заголовок
        Me.Text = "Mon premier formulaire"
        ' розміри
        Me.Size = New System.Drawing.Size(300, 100)
        ' кнопка
        ' створення
        Me.cmdTest = New Button
        ' положення
        cmdTest.Location = New System.Drawing.Point(110, 20)
        ' розмір
        cmdTest.Size = New System.Drawing.Size(80, 30)
        ' назва
        cmdTest.Text = "Test"
        ' менеджер подій
        AddHandler cmdTest.Click, AddressOf cmdTest_Click
        ' додавання кнопки до форми
        Me.Controls.Add(cmdTest)
    End Sub

    ' менеджер подій
    Private Sub cmdTest_Click(ByVal sender As Object, ByVal evt As EventArgs)
        ' натиснуто кнопку — повідомляємо про це
        MessageBox.Show("Clic sur bouton", "Clic sur bouton", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub

    ' тестова функція
    Public Shared Sub Main(ByVal args() As String)
        ' відображення форми
        Application.Run(New Form1)
    End Sub
End Class

Ми додали до форми кнопку:


        ' кнопка
        ' створення
        Me.cmdTest = New Button
        ' позиція
        cmdTest.Location = New System.Drawing.Point(110, 20)
        ' розмір
        cmdTest.Size = New System.Drawing.Size(80, 30)
        ' назва
        cmdTest.Text = "Test"
        ' менеджер подій
        AddHandler cmdTest.Click, AddressOf cmdTest_Click
        ' додавання кнопки до форми
        Me.Controls.Add(cmdTest)

Властивість Location встановлює координати (110,20) верхньої лівої точки кнопки за допомогою структури Point. Ширина та висота кнопки встановлюються на (80,30) за допомогою структури Size. Властивість Text кнопки дозволяє задати її напис. Клас кнопки має подію Click, яка визначається наступним чином:

Public Event Click As EventHandler

де EventHandler — це «делегована» функція з таким сигнатурою:

Public Delegate Sub EventHandler(ByVal sender As Object,ByVal e As EventArgs)

Це означає, що обробник події [Click] для кнопки повинен мати сигнатуру делегату [EventHandler]. У цьому випадку при натисканні кнопки cmdTest буде викликано метод cmdTest_Click. Він визначений наступним чином відповідно до попереднього шаблону EventHandler:


    ' обробник події
    Private Sub cmdTest_Click(ByVal sender As Object, ByVal evt As EventArgs)
        ' було натиснуто кнопку — повідомляємо про це
        MessageBox.Show("Clic sur bouton", "Clic sur bouton", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub

Ми просто виводимо повідомлення:

Image

Клас компілюється та виконується:

dos>vbc /r:system.dll /r:system.drawing.dll /r:system.windows.forms.dll frm2.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4

dos>frm2

Клас MessageBox призначений для виведення повідомлень у вікні. Тут ми використали конструктор

Overloads Public Shared Function Show(ByVal owner As IWin32Window,ByVal text As String,ByVal caption As String,ByVal buttons As MessageBoxButtons,ByVal icon As MessageBoxIcon) As DialogResult
text
повідомлення, яке потрібно відобразити
caption
заголовок вікна
buttons
кнопки, що містяться у вікні
icon
піктограма у вікні

Параметр buttons може приймати значення з наступних констант:

константа
кнопки
   AbortRetryIgnore 
  OK 
    OKCancel 
    RetryCancel 
    YesNo 
    YesNoCancel 

Параметр icon може приймати значення з-поміж таких констант:

Asterisk
Error
те саме, зупинка
Exclamation
те саме Попередження
Hand
Information
так само, як Asterisk
None
Question
Stop
те саме, Hand
Warning

 

Метод Show є статичним методом, який повертає результат типу System.Windows.Forms.DialogResult, що є переліком:


public enum System.Windows.Forms.DialogResult 
{
    Abort = 0x00000003, 
    Cancel = 0x00000002, 
    Ignore = 0x00000005, 
    No = 0x00000007, 
    None = 0x00000000, 
    OK = 0x00000001, 
    Retry = 0x00000004, 
    Yes = 0x00000006, 
}

Щоб дізнатися, яку кнопку натиснув користувач для закриття вікна типу MessageBox, слід написати:

dim res as DialogResult=MessageBox.Show(..)
if res=DialogResult.Yes then
' натиснуто кнопку «Так»
...
end if

5.2. Створення графічного інтерфейсу за допомогою Visual Studio.NET

Ми повернемося до деяких прикладів, розглянутих раніше, і створимо їх за допомогою Visual Studio.NET.

5.2.1. Початкове створення проєкту

  1. Запустіть VS.NET і виберіть опцію Fichier/Nouveau/Projet

Image

  1. введіть параметри вашого проєкту
    1. виберіть тип проекту, який ви хочете створити, у даному випадку проект VB.NET (1)
    2. виберіть тип програми, яку ви хочете створити, у даному випадку — програму для Windows (2)
    3. вкажіть, у якій папці ви хочете розмістити підпапку проекту (3)
    4. вкажіть назву проєкту (4). Це також буде назвою папки, яка міститиме файли проєкту
    5. назва цієї папки вказана у полі (5)
  1. Після цього у папці i4 створюється певна кількість папок і файлів:
підпапки папки «проект1»

З цих файлів цікавий лише один — файл form1.cs, який є вихідним файлом, пов’язаним із формою, створеною за допомогою VS.NET. Ми повернемося до цього пізніше.

5.2.2. Вікна інтерфейсу VS.NET

Інтерфейс VS.NET тепер відображає деякі елементи нашого проєкту i4:

У нас є вікно проектування графічного інтерфейсу:

Вибираючи елементи управління з панелі інструментів (toolbox 2) та розміщуючи їх на поверхні вікна (1), ми можемо створити графічний інтерфейс. Якщо навести курсор миші на «toolbox», вона розширюється і відображає певну кількість елементів управління:

Image

Наразі ми не використовуємо жодного з них. Також на екрані VS.NET ми бачимо вікно «Explorer Solution» (Оглядач рішень):

Image

Спочатку ми майже не будемо користуватися цим вікном. Воно показує всі файли, що складають проект. Нас цікавить лише один із них: вихідний файл нашої програми, у даному випадку Form1.vb. Клацнувши правою кнопкою миші на Form1.vb, ми отримаємо меню, яке дозволяє перейти або до вихідного коду нашого графічного інтерфейсу (Показати код), або до самого графічного інтерфейсу (Конструктор вікон):

Image

До цих двох об’єктів можна отримати доступ безпосередньо з вікна «Solution Explorer»:

 

Відкриті вікна «накопичуються» у головному вікні проектування:

Image

Тут Form1.vb[Design] позначає вікно дизайну, а Form1.vb — вікно коду. Щоб перейти з одного вікна в інше, достатньо натиснути на одну з вкладок. Ще одне важливе вікно, яке відображається на екрані VS.NET, — це вікно властивостей:

Image

Властивості, що відображаються у цьому вікні, належать елементу управління, який наразі виділено у вікні графічного проектування. Доступ до різних вікон проєкту можна отримати за допомогою меню Affichage:

Image

Тут наведено основні вікна, що щойно були описані, а також їхні комбінації клавіш.

5.2.3. Виконання проекту

Хоча ми ще не написали жодного коду, у нас вже є проект, готовий до виконання. Виконайте команду F5 або Déboguer/Démarrer, щоб запустити його. З’явиться таке вікно:

Image

Це вікно можна розгорнути, згорнути, змінити розмір та закрити.

5.2.4. Код, згенерований VS.NET

Давайте розглянемо код (Affichage/Code) нашого додатка:


Public Class Form1
    Inherits System.Windows.Forms.Form

#Область «Код, згенерований Windows Form Designer»

    Public Sub New()
        MyBase.New()

        'Цей виклик необхідний для Windows Form Designer.
        InitializeComponent()

        'Додайте будь-яку ініціалізацію після виклику InitializeComponent()

    End Sub

    'Замінений метод Dispose форми для очищення списку компонентів.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Вимагається конструктором Windows Form
    Private components As System.ComponentModel.IContainer

    'REMARQUE: наступна процедура є обов’язковою для конструктора Windows Form
    'Її можна змінити за допомогою конструктора Windows Form.  
    'Не змінюйте її за допомогою редактора коду.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        components = New System.ComponentModel.Container()
        Me.Text = "Form2"
    End Sub

#Кінець області

End Class

Графічний інтерфейс походить від базового класу System.Windows.Forms.Form:

Public Class Form1
    Inherits System.Windows.Forms.Form

Базовий клас Form визначає базове вікно з кнопками закриття, розгортання/згортання, регулювання розміру тощо та обробляє події для цих графічних об’єктів. Конструктор форми використовує метод InitializeComponent, у якому створюються та ініціалізуються елементи управління форми.


    Public Sub New()
        MyBase.New()

        'Цей виклик є обов’язковим для конструктора Windows Form.
        InitializeComponent()

        'Додайте будь-яку ініціалізацію після виклику InitializeComponent()
    End Sub

Будь-які інші операції в конструкторі можна виконати після виклику функції InitializeComponent. Метод InitializeComponent


Private Sub InitializeComponent()
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(292, 53)
        Me.Name = "Form1"
        Me.Text = "Form1"
    End Sub

визначає заголовок вікна «Form1», його ширину (292) та висоту (53). Заголовок вікна визначається властивістю Text, а розміри — властивістю Size. Size визначено в просторі імен System.Drawing і є структурою. Щоб запустити цю програму, нам потрібно визначити головний модуль проєкту. Для цього ми використовуємо опцію [Projets/Propriétés]:

Image

У [Objet de démarrage] ми вказуємо [Form1] — це форма, яку ми щойно створили. Щоб запустити виконання, використовуємо опцію [Déboguer/Démarrer]:

Image

5.2.5. Компіляція у вікні командного рядка

Тепер спробуємо скомпілювати та запустити цю програму у вікні командного рядка:

dos>dir form1.vb
14/03/2004  11:53               514 Form1.vb

dos>vbc /r:system.dll /r:system.windows.forms.dll form1.vb

vbc : error BC30420: 'Sub Main' est introuvable dans 'Form1'.

Компілятор повідомляє, що не може знайти процедуру [Main]. Дійсно, VS.NET її не згенерувала. Однак ми вже зустрічали її в попередніх прикладах. Вона має такий вигляд:


    Shared Sub Main()
        ' запускається програма
        Application.Run(New Form1) ' où Form1 est le formulaire
    End Sub

Додамо до коду [Form1.vb] попередній код і перекомпілюємо:

dos>vbc /r:system.dll /r:system.windows.forms.dll form2.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4

Form2.vb(41) : error BC30451: Le nom 'Application' n'est pas déclaré.

        Application.Run(New Form2)
        ~~~~~~~~~~~

Цього разу ім'я [Application] невідоме. Це просто означає, що ми не імпортували його простір імен [System.Windows.Forms]. Додамо таку інструкцію:

Imports System.Windows.Forms

а потім перекомпілюємо:

dos>vbc /r:system.dll /r:system.windows.forms.dll form1.vb

Цього разу все пройшло успішно. Запустимо:

dos>dir
14/03/2004  11:53               514 Form1.vb
14/03/2004  12:15             3 584 Form1.exe

dos>form1

Image

Форма типу Form1 створюється та відображається. Можна уникнути додавання процедури [Main], використовуючи опцію /m компілятора, яка дозволяє вказати клас для виконання у випадку, якщо він успадковує System.Windows.Form:

dos>vbc /r:system.dll /r:system.windows.forms.dll /r:system.drawing.dll /m:form2 form2.vb

Опція /m:form2 вказує, що класом, який слід виконати, є клас із назвою [form2].

5.2.6. Обробка подій

Після відображення форми програма починає відстежувати події, що відбуваються у формі (клацання, переміщення миші тощо), і виконує ті з них, які підтримує форма. У даному випадку наша форма не обробляє жодних інших подій, окрім тих, що обробляються базовим класом Form (натискання кнопок закриття, збільшення/зменшення, зміна розміру вікна, переміщення вікна тощо). Згенерована форма використовує атрибут components, який ніде не застосовується. Метод dispose тут також ні до чого. Те саме стосується деяких використовуваних просторів імен (Collections, ComponentModel, Data) та простору імен, визначеного для проєкту projet1. Отже, у цьому прикладі код можна спростити до такого вигляду:


Imports System
Imports System.Drawing
Imports System.Windows.Forms

Public Class Form1
    Inherits System.Windows.Forms.Form

    ' конструктор
    Public Sub New()
        ' створення форми з її компонентами
        InitializeComponent()
    End Sub

    Private Sub InitializeComponent()
        ' розмір вікна
        Me.Size = New System.Drawing.Size(300, 300)
        ' заголовок вікна
        Me.Text = "Form1"
    End Sub

    Shared Sub Main()
        ' запускаємо додаток
        Application.Run(New Form1)
    End Sub
End Class

5.2.7. Висновок

Тепер ми приймемо код, згенерований VS.NET, без змін і обмежимося лише додаванням до нього нашого коду, зокрема для обробки подій, пов'язаних з різними елементами управління форми.

5.3. Вікно з полем введення, кнопкою та написом

5.3.1. Графічне оформлення

У попередньому прикладі ми не розміщували компонентів у вікні. Ми розпочинаємо новий проєкт під назвою interface2. Для цього дотримуємося описаної раніше процедури створення проєкту:

Image

Тепер створимо вікно з кнопкою, написом та полем введення:

Поля такі:

ім’я
тип
роль
1
lblSaisie
Етикетка
назва
2
txtSaisie
TextBox
поле для введення даних
3
btnAfficher
Кнопка
для відображення вмісту поля введення у діалоговому вікні txtSaisie

Щоб створити це вікно, можна вчинити наступним чином: клацніть правою кнопкою миші у вікні поза межами будь-якого компонента та виберіть опцію Properties, щоб отримати доступ до властивостей вікна:

Image

Вікно властивостей з’явиться праворуч:

Image

Слід звернути увагу на деякі з цих властивостей:

BackColor
для встановлення кольору фону вікна
ForeColor
для встановлення кольору малюнків або тексту у вікні
Menu
для прив’язки меню до вікна
Text
щоб надати вікну заголовок
FormBorderStyle
для визначення типу вікна
Font
для визначення шрифту тексту у вікні
Name
для визначення назви вікна

Тут ми встановлюємо властивості Text та Name:

Text
Поля введення та кнопки — 1
Name
frmSaisiesBoutons

За допомогою панелі «Інструменти»

  • виберіть необхідні компоненти
  • перетягніть їх у вікно та задайте їм потрібні розміри
Після вибору компонента в «інструментальному ящику» натисніть клавішу
«Esc», щоб приховати панель інструментів, а потім перетягніть
і налаштуйте розміри компонента. Зробіть це для трьох необхідних компонентів
: Label, TextBox, Button. Щоб вирівняти та
правильно змінити розміри компонентів, скористайтеся меню Format:
Принцип форматування такий:
  1. виберіть різні компоненти, які потрібно відформатувати разом (утримуючи клавішу Ctrl)
  2. виберіть бажаний тип форматування
Опція Align дозволяє вирівнювати компоненти
Опція «Make Same Size» дозволяє зробити так, щоб
компоненти мали однакову висоту або однакову
ширину:
Параметр «Horizontal Spacing» (Горизонтальний інтервал), наприклад, дозволяє
вирівнювати компоненти по горизонталі з
однаковими проміжками між ними. Те саме
стосується опції «Vertical Spacing» для вертикального вирівнювання.
Опція «Center in Form» дозволяє вирівняти по центру
компонент по горизонталі або
по вертикалі у вікні:
Після того як компоненти правильно
розміщені у вікні, зафіксуйте їхні властивості.
Для цього клацніть правою кнопкою миші на компоненті та
виберіть опцію Properties:
  • мітка 1 (Label)
Виберіть компонент, щоб відкрити
відкрити вікно властивостей. У ньому
змініть такі властивості:
name: lblSaisie, text: Введення
  • поле введення 2 (TextBox)
Виберіть компонент, щоб відкрити його
відкрити вікно властивостей. У ньому змініть
наступні властивості:
name: txtSaisie, text: залиште порожнім
  • кнопка 3 (Button):
name: cmdAfficher, text: Показати
  • саме вікно: name: frmSaisies&Кнопки,
text: Введення та кнопки - 1
Ми можемо запустити (Ctrl+F5) наш проєкт
, щоб отримати перше уявлення про вікно
у дії:

Закрийте вікно. Нам залишається написати процедуру, пов’язану з натисканням кнопки Afficher.

5.3.2. Обробка подій форми

Давайте розглянемо код, який було згенеровано графічним конструктором:


...

Public Class frmSaisiesBoutons
  Inherits System.Windows.Forms.Form

  ' компоненти
    Private components As System.ComponentModel.Container = Nothing
    Friend WithEvents btnAfficher As System.Windows.Forms.Button
    Friend WithEvents lblsaisie As System.Windows.Forms.Label
    Friend WithEvents txtsaisie As System.Windows.Forms.TextBox

  ' конструктор
  Public Sub New()
    InitializeComponent()
  End Sub

...

  ' ініціалізація компонентів
    Private Sub InitializeComponent()
...
    End Sub
End Class

Насамперед слід звернути увагу на особливу декларацію компонентів:

  • ключове слово Friend вказує на те, що компонент доступний для всіх класів проекту
  • ключове слово WithEvents вказує, що компонент генерує події. Тепер розглянемо, як обробляти ці події

Відкрийте вікно коду форми (Вигляд/код або F7):

У вікні, показаному вище, є два випадаючі списки (1) і (2). Список (1) — це список компонентів форми:

Image

Список (2) — це перелік подій, пов’язаних із компонентом, обраним у списку (1):

Image

Одне з подій, пов'язаних із компонентом, відображається жирним шрифтом (у цьому випадку — Click). Це подія за замовчуванням для цього компонента. Доступ до обробника цієї конкретної події можна отримати, двічі клацнувши на компоненті у вікні дизайну. VB.net автоматично генерує каркас обробника події у вікні коду та переміщує курсор на нього. Доступ до обробників інших подій здійснюється у вікні коду шляхом вибору компонента у списку (1) та події у (2). VB.net генерує шаблон обробника події або встановлює курсор на ньому, якщо він уже був згенерований:


    Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAfficher.Click
...
    End Sub

За замовчуванням VB.net C_E присвоює ім’я обробнику події E компонента C. Це ім’я можна змінити, якщо це доцільно. Однак це не рекомендується. Розробники VB зазвичай зберігають ім’я, згенероване VB, що забезпечує узгодженість іменування у всіх програмах VB. Прив’язування процедури btnAfficher_Click до події Click компонента btnAfficher здійснюється не за назвою процедури, а за допомогою ключового слова handles:


Handles btnAfficher.Click

У наведеному вище прикладі ключове слово handles вказує, що процедура обробляє подію Click компонента btnAfficher. Попередній обробник подій має два параметри:

sender
об’єкт, що є джерелом події (у цьому випадку — кнопка)
e
об’єкт EventArgs, що містить детальну інформацію про подію, яка відбулася

Ми не будемо використовувати жоден із цих параметрів у цьому випадку. Залишається лише доповнити код. Тут ми хочемо відобразити діалогове вікно з вмістом поля txtSaisie:


    Private Sub btnAfficher_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        ' відображення тексту, введеного у поле введення TxtSaisie
        MessageBox.Show("texte saisi= " + txtsaisie.Text, "Vérification de la saisie", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub

Якщо запустити додаток, отримаємо таке:

Image

5.3.3. Інший спосіб обробки подій

Для кнопки btnAfficher VS.NET згенерував такий код:


Private Sub InitializeComponent()
        ...
        '
        'btnAfficher
        '
        Me.btnAfficher.Location = New System.Drawing.Point(102, 48)
        Me.btnAfficher.Name = "btnAfficher"
        Me.btnAfficher.Size = New System.Drawing.Size(88, 24)
        Me.btnAfficher.TabIndex = 2
        Me.btnAfficher.Text = "Afficher"
...
    End Sub

...

    ' обробник події натискання кнопки cmdAfficher
    Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAfficher.Click
...
    End Sub

Ми можемо прив’язати процедуру btnAfficher_Click до події Click кнопки btnAfficher іншим способом:


Private Sub InitializeComponent()
        ...
        '
        'btnAfficher
        '
        Me.btnAfficher.Location = New System.Drawing.Point(102, 48)
        Me.btnAfficher.Name = "btnAfficher"
        Me.btnAfficher.Size = New System.Drawing.Size(88, 24)
        Me.btnAfficher.TabIndex = 2
        Me.btnAfficher.Text = "Afficher"
        AddHandler btnAfficher.Click, AddressOf btnAfficher_Click
...
    End Sub

...

    ' обробник події кліка на кнопку cmdAfficher
    Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
...
    End Sub

Процедура btnAfficher_Click втратила ключове слово Handles, тим самим втративши прив’язку до події btnAfficher.Click. Тепер ця прив’язка здійснюється за допомогою ключового слова AddHandler:


        AddHandler btnAfficher.Click, AddressOf btnAfficher_Click

Наведений вище код, який буде розміщено в процедурі InitializeComponent форми, пов’язує з подією btnAfficher.Click процедуру з назвою btnAfficher_Click. Крім того, компоненту btnAfficher більше не потрібне ключове слово WithEvents:


    Friend btnAfficher As System.Windows.Forms.Button

У чому полягає різниця між цими двома методами?

  • Ключове слово handles дозволяє пов’язати подію з процедурою лише на етапі проектування. Проектувальник заздалегідь знає, що процедура P має обробляти події E1, E2, ... і пише код

    Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) handles E1, E2, ..., En

Дійсно, процедура може обробляти кілька подій.

  • Ключове слово addhandler дозволяє пов’язати подію з процедурою під час виконання. Це корисно в контексті моделі «виробник-споживач» подій. Об’єкт генерує певну подію, яка може зацікавити інші об’єкти. Останні підписуються на виробника, щоб отримувати цю подію (наприклад, коли температура перевищила критичний поріг). Під час виконання програми виробник події буде виконувати різні інструкції:
Addhandler E, AddressOf P1
Addhandler E, AddressOf P2
...
Addhandler E, AddressOf Pn

де E — подія, що генерується виробником, а Pi — процедури, що належать різним об’єктам-споживачам цієї події. Ми ще повернемося до програми «виробник-споживач» подій у наступному розділі.

5.3.4. Висновок

На основі двох розглянутих проектів можна зробити висновок, що після створення графічного інтерфейсу за допомогою VS.NET робота розробника полягає у написанні обробників подій, які він хоче обробляти для цього графічного інтерфейсу. Надалі ми будемо наводити лише код цих обробників.

5.4. Деякі корисні компоненти

Тепер ми розглянемо різні додатки, що використовують найпоширеніші компоненти, щоб ознайомитися з їхніми основними методами та властивостями. Для кожного додатка ми покажемо графічний інтерфейс та відповідний код, зокрема обробники подій.

5.4.1. Форма Form

Почнемо з огляду найнеобхіднішого компонента — форми, на яку розміщуються інші компоненти. Ми вже розглядали деякі з її основних властивостей. Тут ми зупинимося на кількох важливих подіях форми.

 
форма завантажується
Closing
форма закривається
Closed
форма закрита

Подія Load відбувається ще до того, як форма з’явиться на екрані. Подія Closing відбувається під час закриття форми. Це закриття ще можна зупинити програмним шляхом. Створюємо форму з іменем Form1 без жодних компонентів:

Image

Ми обробляємо три попередні події:


    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' початкове завантаження форми
        MessageBox.Show("Evt Load", "Load")
    End Sub

    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        ' форма закривається
        MessageBox.Show("Evt Closing", "Closing")
        ' запитується підтвердження
        Dim réponse As DialogResult = MessageBox.Show("Voulez-vous vraiment quitter l'application", "Closing", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
        If réponse = DialogResult.No Then
            e.Cancel = True
        End If
    End Sub

    Private Sub Form1_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Closed
        ' форма закривається
        MessageBox.Show("Evt Closed", "Closed")
    End Sub
Ми використовуємо функцію MessageBox, щоб отримувати сповіщення про різні
події. Подія Closing відбудеться, коли користувач
закриє вікно.
Тоді ми запитуємо його, чи дійсно він хоче вийти з програми:
Якщо він відповідає «Ні», ми встановлюємо властивість Cancel події
CancelEventArgs, яке метод отримав як параметр.
Якщо ми встановимо для цього властивості значення False, закриття
вікна скасовується, інакше воно продовжується:

5.4.2. етикетки Label та поля введення TextBox

Ми вже зустрічали ці два компоненти. Label — це текстовий компонент, а TextBox — компонент поля введення. Їхньою основною властивістю є Text, яка позначає або вміст поля введення, або текст мітки. Ця властивість доступна для читання та запису. Подія, яка зазвичай використовується для TextBox, — це TextChanged, яка сигналізує, що користувач змінив поле введення. Ось приклад, у якому використовується подія TextChanged для відстеження змін у полі введення:

тип
назва
роль
1
TextBox
txtSaisie
поле введення
2
Етикетка
lblControle
відображає текст з 1 у режимі реального часу
3
Кнопка
cmdEffacer
для очищення полів 1 і 2
4
Кнопка
cmdQuitter
для виходу з програми

Відповідний код цього додатка — це код обробників подій:


  ' натискання кнопки «Вийти»
    Private Sub cmdQuitter_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles cmdQuitter.Click
        ' натискання кнопки «Вийти» — вихід із програми
        Application.Exit()
    End Sub

    ' зміна поля txtSaisie
    Private Sub txtSaisie_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles txtSaisie.TextChanged
        ' вміст поля TextBox змінився — його копіюють у мітку lblControle
        lblControle.Text = txtSaisie.Text
    End Sub

    ' натиснуто кнопку «Очистити»
    Private Sub cmdEffacer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles cmdEffacer.Click
        ' вміст поля введення очищено
        txtSaisie.Text = ""
    End Sub

    ' була натиснута клавіша
    Private Sub txtSaisie_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) _
    Handles txtSaisie.KeyPress
        ' перевіряється, яка клавіша була натиснута
        Dim touche As Char = e.KeyChar
        If touche = ControlChars.Cr Then
            MessageBox.Show(txtSaisie.Text, "Contrôle", MessageBoxButtons.OK, MessageBoxIcon.Information)
            e.Handled = True
        End If
    End Sub

Зверніть увагу на спосіб завершення роботи програми у процедурі cmdQuitter_Click: Application.Exit(). У наступному прикладі використовується багаторядковий TextBox:

Список елементів управління такий:

тип
назва
роль
1
TextBox
txtMultiLignes
багаторядкове поле введення
2
TextBox
txtAjout
однорядкове поле введення
3
Кнопка
btnAjouter
Додає вміст з 2 до 1

Щоб TextBox став багаторядковим, слід встановити такі властивості елемента управління:

 
для підтримки декількох рядків тексту
ScrollBars=( None, Horizontal, Vertical, Both)
щоб встановити, чи має елемент управління смуги прокрутки (Horizontal, Vertical, Both) чи ні (None)
AcceptReturn=(True, False)
якщо значення дорівнює true, клавіша Enter буде переносити курсор на новий рядок
AcceptTab=(True, False)
якщо значення true, клавіша Tab створюватиме табуляцію в тексті

Корисний код — це той, що обробляє натискання кнопки [Ajouter], та той, що обробляє зміну значення поля введення [txtAjout]:


    ' можливо btnAjouter_Click
    Private Sub btnAjouter_Click1(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnAjouter.Click
        ' додавання вмісту txtAjout до вмісту txtMultilignes
        txtMultilignes.Text &= txtAjout.Text
        txtAjout.Text = ""
    End Sub

    ' або txtAjout_TextChanged
    Private Sub txtAjout_TextChanged1(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles txtAjout.TextChanged
        ' встановлюємо стан кнопки «Додати»
        btnAjouter.Enabled = txtAjout.Text.Trim() <> ""
    End Sub

5.4.3. випадаючі списки ComboBox

Компонент ComboBox — це випадаючий список, доповнений полем введення: користувач може або вибрати елемент у (2), або ввести текст у (1). Існує три типи ComboBox, що визначаються властивістю Style:

 
нерозгортальний список із полем редагування
DropDown
розгортальний список із полем редагування
DropDownList
розгортальний список без поля редагування

За замовчуванням тип ComboBox — це DropDown. Щоб дізнатися про клас ComboBox, введіть ComboBox в індексі довідки (Aide/Index). Клас ComboBox має лише один конструктор:

Public Sub New()
створює порожній об’єкт ComboBox

Елементи ComboBox доступні у властивості Items:

Public ReadOnly Property Items As ComboBox.ObjectCollection

Це індексоване властивість, де Items(i) позначає елемент i комбо-поля. Нехай C — це комбо-поле, а C.Items — його список елементів. Маємо такі властивості:

 
кількість елементів комбо-поля
C.Items(i)
елемент i комбінованого списку
C.Add(object o)
додає об’єкт o як останній елемент комбінації
C.AddRange(object() objets)
додає масив об’єктів у кінець комбінації
C.Insert(int i, object o)
додає об’єкт o на позицію i комбо
C.RemoveAt(int i)
видаляє елемент i з комбо
C.Remove(object o)
видаляє об’єкт o зі списку
C.Clear()
видаляє всі елементи з комбінації
C.IndexOf(object o)
повертає позицію i об'єкта o у комбінованому списку

Може здатися дивним, що комбо-поле може містити об’єкти, хоча зазвичай воно містить символьні рядки. Візуально це саме так і виглядає. Якщо ComboBox містить об’єкт obj, воно відображає рядок obj.ToString(). Нагадаємо, що кожен об’єкт має метод ToString, успадкований від класу object, який повертає символьний рядок, що «представляє» цей об’єкт. Елемент, вибраний у комбінованому списку C, — це C.SelectedItem або C.Items(C.SelectedIndex), де C.SelectedIndex — це номер вибраного елемента, який починається з нуля для першого елемента.

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

Image

Ми наводимо лише відповідний код вікна. У конструкторі форми ми заповнюємо комбінований список:


  Public Sub New()
    ' створення форми
    InitializeComponent()
    ' заповнення комбінованого списку
    cmbNombres.Items.AddRange(New String() {"zéro", "un", "deux", "trois", "quatre"})
        ' вибираємо перший елемент зі списку
    cmbNombres.SelectedIndex = 0
  End Sub

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


    Private Sub cmbNombres_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles cmbNombres.SelectedIndexChanged
        ' вибраний елемент змінився — відображаємо його
        MessageBox.Show("Elément sélectionné : (" & cmbNombres.SelectedItem.ToString & "," & cmbNombres.SelectedIndex & ")", "Combo", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub

5.4.4. компонент ListBox

Ми пропонуємо створити такий інтерфейс:

Компоненти цього вікна такі:

тип
назва
роль/властивості
0
Форма
Form1
форма - BorderStyle=FixedSingle
1
TextBox
txtSaisie
поле для введення даних
2
Кнопка
btnAjouter
кнопка, що дозволяє додати вміст поля введення 1 до списку 3
3
ListBox
listBox1
список 1
4
ListBox
listBox2
список 2
5
Кнопка
btn1TO2
переносить вибрані елементи зі списку 1 до списку 2
6
Кнопка
cmd2T0
виконує зворотну дію
7
Кнопка
btnEffacer1
очистити список 1
8
Кнопка
btnEffacer2
очистити список 2
  • Користувач вводить текст у поле 1. Він додає його до списку 1 за допомогою кнопки Ajouter (2). Поле введення (1) при цьому очищується, і користувач може додати новий елемент.
  • Він може переносити елементи з одного списку в інший, вибравши елемент для перенесення в одному зі списків та натиснувши відповідну кнопку перенесення 5 або 6. Перенесений елемент додається в кінець списку призначення та видаляється зі списку-джерела.
  • Користувач може двічі клацнути на елементі зі списку 1. Цей елемент переноситься у поле введення для редагування та видаляється зі списку 1.

Кнопки вмикаються або вимикаються за такими правилами:

  • кнопка Ajouter підсвічується лише тоді, коли в полі введення є текст, що не є порожнім
  • кнопка 5 для перенесення зі списку 1 до списку 2 підсвічується лише тоді, коли у списку 1 вибрано елемент
  • кнопка 6 для перенесення зі списку 2 до списку 1 підсвічується лише тоді, коли у списку 2 вибрано елемент
  • кнопки 7 і 8 для очищення списків 1 і 2 підсвічуються лише тоді, коли список, який потрібно очистити, містить елементи.

За зазначених умов усі кнопки мають бути вимкнені під час запуску програми. Тому властивість Enabled кнопок слід встановити на значення false. Це можна зробити на етапі проектування, що призведе до генерації відповідного коду в методі InitializeComponent, або зробити це самостійно у конструкторі, як показано нижче:


    Public Sub New()
        ' початкове створення форми
        InitializeComponent()
        ' додаткові ініціалізації
        ' деякі кнопки вимкнено
        btnAjouter.Enabled = False
        btn1TO2.Enabled = False
        btn2TO1.Enabled = False
        btnEffacer1.Enabled = False
        btnEffacer2.Enabled = False
    End Sub

Стан кнопки Ajouter контролюється вмістом поля введення. Подія TextChanged дозволяє відстежувати зміни цього вмісту:


    ' зміна у полі введення тексту
    Private Sub txtSaisie_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles txtSaisie.TextChanged
        ' змінився вміст txtSaisie
        ' кнопка «Додати» активна лише тоді, коли поле введення не порожнє
        btnAjouter.Enabled = txtSaisie.Text.Trim() <> ""
    End Sub

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


    ' зміна вибраного елемента без використання listbox1
    Private Sub listBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles listBox1.SelectedIndexChanged

        ' елемент було вибрано
        ' вмикається кнопка перенесення з 1 до 2
        btn1TO2.Enabled = True
    End Sub

    ' зміна вибраного елемента без використання списку 2
    Private Sub listBox2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles listBox2.SelectedIndexChanged
        ' елемент було вибрано
        ' вмикається кнопка перенесення з 2 до 1
        btn2TO1.Enabled = True
    End Sub

Код, пов’язаний із натисканням кнопки Ajouter, є таким:


    ' натискання кнопки «Додати»
    Private Sub btnAjouter_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnAjouter.Click
        ' додано новий елемент до списку 1
        listBox1.Items.Add(txtSaisie.Text.Trim())
        ' очищення поля введення
        txtSaisie.Text = ""
        ' Список 1 не порожній
        btnEffacer1.Enabled = True
        ' повернення фокусу на поле введення
        txtSaisie.Focus()
    End Sub

Зверніть увагу на метод Focus, який дозволяє встановити «фокус» на елементі управління форми. Код, пов'язаний з натисканням на кнопки Effacer:


    ' натискання кнопки «Очистити1»
    Private Sub btnEffacer1_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnEffacer1.Click
        ' Список 1 очищено
        listBox1.Items.Clear()
        btnEffacer1.Enabled = False
    End Sub

    ' натискання кнопки «Очистити2»
    Private Sub btnEffacer2_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        ' список 2 очищено
        listBox2.Items.Clear()
        btnEffacer2.Enabled = False
    End Sub

Код для перенесення вибраних елементів з одного списку в інший:


    ' натискання кнопки «btn1to2»
    Private Sub btn1TO2_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btn1TO2.Click
        ' перенесення вибраного елемента зі списку 1 до списку 2
        transfert(listBox1, listBox2)
        ' кнопки «Очистити»
        btnEffacer2.Enabled = True
        btnEffacer1.Enabled = listBox1.Items.Count <> 0
        ' кнопки переміщення
        btn1TO2.Enabled = False
        btn2TO1.Enabled = False
    End Sub

    ' натискання кнопки btn2to1
    Private Sub btn2TO1_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btn2TO1.Click
        ' перенесення вибраного елемента зі Списку 2 до Списку 1
        transfert(listBox2, listBox1)
        ' кнопки «Видалити»
        btnEffacer1.Enabled = True
        btnEffacer2.Enabled = listBox2.Items.Count <> 0
        ' кнопки перенесення
        btn1TO2.Enabled = False
        btn2TO1.Enabled = False
    End Sub

    ' перенесення
    Private Sub transfert(ByVal l1 As ListBox, ByVal l2 As ListBox)
        ' перенесення вибраного елемента зі списку 1 до списку l2
        ' вибраний елемент?
        If l1.SelectedIndex = -1 Then Return
        ' додати до l2
        l2.Items.Add(l1.SelectedItem)
        ' видалення зі списку l1
        l1.Items.RemoveAt(l1.SelectedIndex)
    End Sub

Спочатку створюємо метод


    Private Sub transfert(ByVal l1 As ListBox, ByVal l2 As ListBox)

, який переносить у список l2 елемент, вибраний зі списку l1. Це дозволяє нам використовувати лише один метод замість двох для перенесення елемента зі списку listBox1 до списку listBox2 або зі списку listBox2 до списку listBox1. Перед перенесенням переконуємося, що у списку l1 дійсно вибрано елемент:


        ' вибраний елемент?
        If l1.SelectedIndex = -1 Then Return

Властивість SelectedIndex дорівнює -1, якщо наразі жоден елемент не виділено. У процедурах


    Private Sub btnXTOY_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnXTOY.Click

здійснюється перенесення списку X до списку Y та змінюється стан деяких кнопок, щоб відобразити новий стан списків.

5.4.5. прапорці CheckBox, перемикачі ButtonRadio

Ми пропонуємо написати таку програму:

Компоненти вікна такі:

тип
іменник
роль
1
RadioButton
radioButton1
radioButton2
radioButton3
3 перемикачі
2
CheckBox
chechBox1
chechBox2
chechBox3
3 прапорці
3
ListBox
lstValeurs
список

Якщо створити три перемикачі один за одним, вони за замовчуванням стають частиною однієї групи. Тому, коли один з них позначений, інші не позначені. Подія, яка нас цікавить для цих шести елементів управління, — це подія CheckChanged, що вказує на зміну стану прапорця або перемикача. Цей стан у обох випадках представлений булевою властивістю Check, яка при значенні «true» означає, що елемент управління відмічений. Тут ми використали єдиний метод для обробки шести подій CheckChanged — метод affiche:


  ' відображає
    Private Sub affiche(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles checkBox1.CheckedChanged, checkBox2.CheckedChanged, checkBox3.CheckedChanged, _
    radioButton1.CheckedChanged, radioButton2.CheckedChanged, radioButton3.CheckedChanged
        ' відображає стан перемикача або прапорця
        ' чи це прапорець?
        If (TypeOf (sender) Is CheckBox) Then
            Dim chk As CheckBox = CType(sender, CheckBox)
            lstValeurs.Items.Insert(0, chk.Name & "=" & chk.Checked)
        End If
        ' чи це перемикач?
        If (TypeOf (sender) Is RadioButton) Then
            Dim rdb As RadioButton = CType(sender, RadioButton)
            lstValeurs.Items.Insert(0, rdb.Name & "=" & rdb.Checked)
        End If
    End Sub

Синтаксис TypeOf (відправник) Is CheckBox дозволяє перевірити, чи об’єкт sender має тип CheckBox. Це дозволяє нам потім виконати перетворення типу до точного типу sender. Метод affiche записує у список lstValeurs назву компонента, що ініціював подію, та значення його властивості Checked. Під час виконання видно, що натискання на перемикач викликає дві події CheckChanged: одну на старому перемикачі, який переходить у стан «не відмічений», та іншу на новому перемикачі, який переходить у стан «відмічений».

5.4.6. регулятори ScrollBar

Існує кілька типів регуляторів: горизонтальний регулятор (hScrollBar),
вертикальний регулятор (vScrollBar), інкрементатор (NumericUpDown).

Реалізуємо таку програму:

тип
назва
роль
1
hScrollBar
hScrollBar1
горизонтальний регулятор
2
hScrollBar
hScrollBar2
горизонтальний регулятор, що слідує за змінами регулятора 1
3
TextBox
txtValeur
відображає значення горизонтального регулятора
ReadOnly=true, щоб запобігти будь-якому введенню даних
4
NumericUpDown
інкрементатор
дозволяє зафіксувати значення регулятора 2
  • Регулятор ScrollBar дозволяє користувачеві вибрати значення в діапазоні цілих чисел, що символізується «смугою» регулятора, по якій переміщується курсор. Значення регулятора доступне у його властивості Value.
  • Для горизонтального регулятора лівий край відповідає мінімальному значенню діапазону, правий край — максимальному, а курсор — поточно вибраному значенню. Для вертикального регулятора мінімум відповідає верхньому краю, а максимум — нижніму. Ці значення представлені властивостями Minimum та Maximum і за замовчуванням дорівнюють 0 та 100.
  • Клік на крайніх точках повзунка змінює значення на один крок (позитивний або негативний) відповідно до крайньої точки, на яку натиснуто, що називається SmallChange і за замовчуванням дорівнює 1.
  • Клік по обидва боки від повзунка змінює значення на один крок (позитивний або негативний) залежно від того, на який кінець було натиснуто, що позначається як LargeChange і за замовчуванням дорівнює 10.
  • При натисканні на верхній край вертикального повзунка його значення зменшується. Це може здивувати пересічного користувача, який зазвичай очікує, що значення «зросте». Цю проблему можна вирішити, присвоївши від’ємні значення властивостям SmallChange та LargeChange
  • Ці п’ять властивостей (Value, Minimum, Maximum, SmallChange, LargeChange) доступні для читання та запису.
  • Головною подією приводу є та, що сигналізує про зміну значення: подія Scroll.

Поруч із регулятором розташований компонент NumericUpDown: він також має властивості Minimum, Maximum та Value, значення яких за замовчуванням становлять 0, 100, 0. Однак у цьому випадку властивість Value відображається у полі введення, яке є невід’ємною частиною елемента управління. Користувач може самостійно змінювати це значення, якщо властивість ReadOnly елемента управління не встановлено у значення «true». Значення кроку встановлюється властивістю Increment, за замовчуванням 1. Головною подією компонента NumericUpDown є та, що сигналізує про зміну значення: подія ValueChanged. Код нашого додатка виглядає наступним чином:

Форма оформлюється під час її створення:


    ' конструктор
    Public Sub New()
        ' початкове створення форми
        InitializeComponent()
        ' присвоюємо приводу 2 ті самі характеристики, що й приводу 1
        hScrollBar2.Minimum = hScrollBar1.Value
        hScrollBar2.Minimum = hScrollBar1.Minimum
        hScrollBar2.Maximum = hScrollBar1.Maximum
        hScrollBar2.LargeChange = hScrollBar1.LargeChange
        hScrollBar2.SmallChange = hScrollBar1.SmallChange
        ' те саме для інкрементатора
        incrémenteur.Minimum = hScrollBar1.Value
        incrémenteur.Minimum = hScrollBar1.Minimum
        incrémenteur.Maximum = hScrollBar1.Maximum
        incrémenteur.Increment = hScrollBar1.SmallChange
        ' присвоюється TextBox значення приводу 1
        txtValeur.Text = "" & hScrollBar1.Value
    End Sub

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


    ' управління приводом hscrollbar1
    Private Sub hScrollBar1_Scroll(ByVal sender As Object, ByVal e As System.Windows.Forms.ScrollEventArgs) _
    Handles hScrollBar1.Scroll
        ' зміна значення регулятора 1
        ' його значення передається на регулятор 2 та у текстове поле TxtValeur
        hScrollBar2.Value = hScrollBar1.Value
        txtValeur.Text = "" & hScrollBar1.Value
    End Sub

Модуль, що відстежує зміни значень частотного перетворювача 2:


    ' управління регулятором hscrollbar2
    Private Sub hScrollBar2_Scroll(ByVal sender As Object, ByVal e As System.Windows.Forms.ScrollEventArgs) _
    Handles hScrollBar2.Scroll
        ' блокується будь-яка зміна регулятора 2
        ' примушуючи його зберігати значення регулятора 1
        e.NewValue = hScrollBar1.Value
    End Sub

Менеджер, який відстежує зміни параметрів системи управління incrémenteur:


    ' управління інкрементатором
    Private Sub incrémenteur_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles incrémenteur.ValueChanged
        ' фіксація значення регулятора 2
        hScrollBar2.Value = CType(incrémenteur.Value, Integer)
    End Sub

5.5. Події миші

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

 
миша щойно увійшла в область елемента управління
MouseLeave
миша щойно вийшла з області керування
MouseMove
миша рухається в області контролю
MouseDown
Натискання лівої кнопки миші
MouseUp
Відпускання лівої кнопки миші
DragDrop
користувач відпускає об’єкт на елементі управління
DragEnter
користувач входить у область елемента управління, перетягуючи об’єкт
DragLeave
користувач виходить з області елемента управління, перетягуючи об’єкт
DragOver
користувач наводить курсор на область елемента управління, перетягуючи об’єкт

Ось програма, яка допоможе краще зрозуміти, в які моменти відбуваються різні події миші:

тип
назва
роль
1
Етикетка
lblPosition
для відображення положення миші у формі 1, списку 2 або кнопці 3
2
ListBox
lstEvts
для відображення подій миші, відмінних від MouseMove
3
Кнопка
btnEffacer
для очищення вмісту 2

Існують такі обробники подій. Щоб відстежувати переміщення миші по трьох елементах управління, потрібно написати лише один обробник:


    ' можливо form1_mousemove
    Private Sub Form1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
    Handles MyBase.MouseMove, lstEvts.MouseMove, btnEffacer.MouseMove, lstEvts.MouseMove
        ' рух миші — відображення її координат (X, Y)
        lblPosition.Text = "(" & e.X & "," & e.Y & ")"
    End Sub

Слід знати, що кожного разу, коли миша потрапляє в область елемента управління, її система координат змінюється. Її початок координат (0,0) — це лівий верхній кут елемента управління, на якому вона знаходиться. Таким чином, під час виконання, коли ми пересуваємо мишу з форми на кнопку, ми чітко бачимо зміну координат. Щоб краще побачити ці зміни області миші, можна скористатися властивістю Cursor елементів управління:

Image

Цей атрибут дозволяє задати форму курсора миші, коли вона потрапляє в область елемента управління. Так, у нашому прикладі ми встановили для самої форми значення Default, для списку 2 — Hand, а для кнопки 3 — No, як показано на скріншотах нижче.

Image

Image

Image

У методі [InitializeComponent] код, згенерований на основі цих налаштувань, виглядає так:


        Me.lstEvts.Cursor = System.Windows.Forms.Cursors.Hand
        Me.btnEffacer.Cursor = System.Windows.Forms.Cursors.No

Крім того, щоб виявити введення та виведення миші у списку 2, ми обробляємо події MouseEnter та MouseLeave з цього самого списку:


    ' подія lstEvts_MouseEnter
    Private Sub lstEvts_MouseEnter(ByVal sender As System.Object, ByVal e As System.EventArgs) _
    Handles lstEvts.MouseEnter
        affiche("MouseEnter sur liste")
    End Sub

    ' подія lstEvts_MouseLeave
    Private Sub lstEvts_MouseLeave(ByVal sender As System.Object, ByVal e As System.EventArgs) _
    Handles lstEvts.MouseLeave
        affiche("MouseLeave sur liste")
    End Sub
    
' відображає
    Private Sub affiche(ByVal message As String)
        ' повідомлення відображається у верхній частині списку подій
        lstEvts.Items.Insert(0, message)
    End Sub

Image

Для обробки кліків у формі ми обробляємо події MouseDown та MouseUp:


    ' подія Form1_MouseDown
    Private Sub Form1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
    Handles MyBase.MouseDown
        affiche("MouseDown sur formulaire")
    End Sub

    ' подія Form1_MouseUp
    Private Sub Form1_MouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
    Handles MyBase.MouseUp
        affiche("MouseUp sur formulaire")
    End Sub

Image

І нарешті, код обробника кліка на кнопці Effacer:


    ' подія btnEffacer_Click
    Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
    Handles btnEffacer.Click
        ' очищає список подій
        lstEvts.Items.Clear()
    End Sub

5.6. Створення вікна з меню

Тепер розглянемо, як створити вікно з меню. Ми створимо таке вікно:

Елемент управління 1 — це TextBox, доступний лише для читання (ReadOnly=true), з іменем txtStatut. Структура меню така:

Пункти меню є елементами управління, як і інші візуальні компоненти, і мають властивості та події. Наприклад, таблиця властивостей пункту меню A1:

Image

У нашому прикладі використовуються дві властивості:

 
ім’я елемента управління меню
Text
назва пункту меню

Властивості різних пунктів меню в нашому прикладі такі:

Name
Текст
mnuA
опції A
mnuA1
A1
mnuA2
A2
mnuA3
A3
mnuB
варіанти B
mnuB1
B1
mnuSep1
- (роздільник)
mnuB2
B2
mnuB3
B3
mnuB31
B31
mnuB32
B32

Щоб створити меню, виберіть компонент «MainMenu» у панелі «ToolBox»:

Image

У результаті з’являється порожнє меню, яке розміщується у формі з порожніми полями під назвою «Type Here». Достатньо вказати в них різні опції меню:

Image

Щоб вставити роздільник між двома пунктами, як показано вище між пунктами B1 та B2, наведіть курсор на місце, де має бути роздільник у меню, клацніть правою кнопкою миші та виберіть опцію «Insert Separator»:

Image

Якщо запустити додаток за допомогою комбінації клавіш Ctrl+F5, з’явиться форма з меню, яке поки що не виконує жодних дій. Пункти меню обробляються як компоненти: вони мають властивості та події. У [fenêtre de code] виберіть компонент mnuA1, а потім виберіть пов’язані події:

Image

Якщо вище ми генеруємо подію Click, то VS.NET автоматично генерує таку процедуру:


Private Sub mnuA1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuA.Click
....
    End Sub

Ми могли б вчинити так для всіх пунктів меню. У цьому випадку для всіх пунктів можна використовувати одну й ту саму процедуру. Тому перейменовуємо попередню процедуру на affiche і оголошуємо події, які вона обробляє:


    Private Sub affiche(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles mnuA1.Click, mnuA2.Click, mnuB1.Click, mnuB2.Click, mnuB31.Click, mnuB32.Click
        ' відображає у TextBox назву обраного підменю
        txtStatut.Text = (CType(sender, MenuItem)).Text
    End Sub

У цьому методі ми обмежуємося відображенням властивості Text пункту меню у джерелі події. Джерело події sender має тип object. Опції меню мають тип MenuItem, тому тут доводиться виконувати перетворення типу з object у MenuItem. Запустіть програму та виберіть опцію A1, щоб отримати таке повідомлення:

Image

Корисний код цієї програми, окрім коду методу affiche, — це код побудови меню у конструкторі форми (InitializeComponent):


  Private Sub InitializeComponent()
    Me.mainMenu1 = New System.Windows.Forms.MainMenu
    Me.mnuA = New System.Windows.Forms.MenuItem
    Me.mnuA1 = New System.Windows.Forms.MenuItem
    Me.mnuA2 = New System.Windows.Forms.MenuItem
    Me.mnuA3 = New System.Windows.Forms.MenuItem
    Me.mnuB = New System.Windows.Forms.MenuItem
    Me.mnuB1 = New System.Windows.Forms.MenuItem
    Me.mnuB2 = New System.Windows.Forms.MenuItem
    Me.mnuB3 = New System.Windows.Forms.MenuItem
    Me.mnuB31 = New System.Windows.Forms.MenuItem
    Me.mnuB32 = New System.Windows.Forms.MenuItem
    Me.txtStatut = New System.Windows.Forms.TextBox
    Me.mnuSep1 = New System.Windows.Forms.MenuItem
    Me.SuspendLayout()
    ' 
    ' mainMenu1
    ' 
    Me.mainMenu1.MenuItems.AddRange(New System.Windows.Forms.MenuItem() {Me.mnuA, Me.mnuB})

    ' 
    ' mnuA
    ' 
    Me.mnuA.Index = 0
    Me.mnuA.MenuItems.AddRange(New System.Windows.Forms.MenuItem() {Me.mnuA1, Me.mnuA2, Me.mnuA3})
    Me.mnuA.Text = "Options A"
    ' 
    ' mnuA1
    ' 
    Me.mnuA1.Index = 0
    Me.mnuA1.Text = "A1"
        ' 
    ' mnuA2
    ' 
    Me.mnuA2.Index = 1
    Me.mnuA2.Text = "A2"
        ' 
    ' mnuA3
    ' 
    Me.mnuA3.Index = 2
    Me.mnuA3.Text = "A3"
        ' 
    ' mnuB
    ' 
    Me.mnuB.Index = 1
    Me.mnuB.MenuItems.AddRange(New System.Windows.Forms.MenuItem() {Me.mnuB1, Me.mnuSep1, Me.mnuB2, Me.mnuB3})

    Me.mnuB.Text = "Options B"
    ' 
    ' mnuB1
    ' 
    Me.mnuB1.Index = 0
    Me.mnuB1.Text = "B1"
        ' 
    ' mnuB2
    ' 
    Me.mnuB2.Index = 2
    Me.mnuB2.Text = "B2"

    ' 
    ' mnuB3
    ' 
    Me.mnuB3.Index = 3
    Me.mnuB3.MenuItems.AddRange(New System.Windows.Forms.MenuItem() {Me.mnuB31, Me.mnuB32})
    Me.mnuB3.Text = "B3"
        ' 
    ' mnuB31
    ' 
    Me.mnuB31.Index = 0
    Me.mnuB31.Text = "B31"
        ' 
    ' mnuB32
    ' 
    Me.mnuB32.Index = 1
    Me.mnuB32.Text = "B32"
        ' 
    ' txtStatut
    ' 
    Me.txtStatut.Location = New System.Drawing.Point(8, 8)
    Me.txtStatut.Name = "txtStatut"
    Me.txtStatut.ReadOnly = True
    Me.txtStatut.Size = New System.Drawing.Size(112, 20)
    Me.txtStatut.TabIndex = 0
    Me.txtStatut.Text = ""
    ' 
    ' mnuSep1
    ' 
    Me.mnuSep1.Index = 1
    Me.mnuSep1.Text = "-"
    ' 
    ' Form1
    ' 
    Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
    Me.ClientSize = New System.Drawing.Size(136, 42)
    Me.Controls.Add(txtStatut)
    Me.Menu = Me.mainMenu1
    Me.Name = "Form1"
    Me.Text = "Menus"
    Me.ResumeLayout(False)
  End Sub

Зверніть увагу на інструкцію, яка пов’язує меню з формою:


    Me.Menu = Me.mainMenu1

5.7. Невізуальні компоненти

Тепер розглянемо низку невидимих компонентів: їх використовують під час проектування, але під час виконання їх не видно.

5.7.1. Діалогові вікна OpenFileDialog та SaveFileDialog

Ми створимо таку програму:

Елементи управління такі:

тип
назва
роль
1
TextBox багаторядковий
txtTexte
текст, введений користувачем або завантажений із файлу
2
Кнопка
btnSauvegarder
дозволяє зберегти текст з пункту 1 у текстовому файлі
3
Кнопка
btnCharger
дозволяє завантажити вміст текстового файлу в 1
4
Button
btnEffacer
очищає вміст 1

Використовуються два невидимі елементи управління:

Image

Коли їх перетягують із «ToolBox» і розміщують у формі, вони розміщуються в окремій області внизу форми. Компоненти «Dialog» перетягуються з «ToolBox»:

Image

Код кнопки Effacer є простим:


    Private Sub btnEffacer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnEffacer.Click
        ' очищаємо поле введення
        txtTexte.Text = ""
    End Sub

Клас SaveFileDialog визначено так:

Image

Він походить від декількох рівнів класів. З-поміж численних властивостей та методів ми виділимо такі:

string Filter
типи файлів, що пропонуються у випадаючому списку типів файлів діалогового вікна
int FilterIndex
номер типу файлу, запропонованого за замовчуванням у вищезазначеному списку. Починається з 0.
String
InitialDirectory
папка, яка спочатку пропонується для збереження файлу
string FileName
ім'я файлу резервної копії, вказане користувачем
DialogResult.ShowDialog()
метод, який відображає діалогове вікно резервного копіювання. Повертає результат типу DialogResult.

Метод ShowDialog відображає діалогове вікно, подібне до наведеного нижче:

1
випадаючий список, сформований на основі властивості Filter. Тип файлу, запропонований за замовчуванням, визначається методом FilterIndex
2
поточна папка, яка визначається InitialDirectory, якщо це властивість було вказано
3
назва файлу, обрана або введена безпосередньо користувачем. Буде доступна у властивості FileName
4
кнопки «Зберегти»/«Скасувати». Якщо використовується кнопка Enregistrer, функція ShowDialog повертає результат DialogResult.OK

Процедуру збереження можна записати так:


    Private Sub btnSauvegarder_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnSauvegarder.Click
        ' зберігаємо поле введення у текстовий файл
        ' налаштування діалогового вікна savefileDialog1
        saveFileDialog1.InitialDirectory = Application.ExecutablePath
        saveFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"
        saveFileDialog1.FilterIndex = 0
        ' відображається діалогове вікно та отримується його результат
        If saveFileDialog1.ShowDialog() = DialogResult.OK Then
            ' отримуємо ім'я файлу
            Dim nomFichier As String = saveFileDialog1.FileName
            Dim fichier As StreamWriter = Nothing
            Try
                ' відкриваємо файл для запису
                fichier = New StreamWriter(nomFichier)
                ' тут вводиться текст
                fichier.Write(txtTexte.Text)
            Catch ex As Exception
                ' проблема
                MessageBox.Show("Problème à l'écriture du fichier (" + ex.Message + ")", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error)
                Return
            Finally
                ' закриваємо файл
                Try
                    fichier.Close()
                Catch
                End Try
            End Try
        End If
    End Sub
  • Прив’язуємо вихідну папку до папки, що містить виконуваний файл програми:
        saveFileDialog1.InitialDirectory = Application.ExecutablePath
  • Вказуємо типи файлів, які потрібно відобразити
        saveFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"

Зверніть увагу на синтаксис фільтрів: фільтр1|фільтр2|..|фільтрn, де фільтрi = «Текст»|«Шаблон файлу». У цьому випадку користувач матиме можливість вибирати між файлами *.txt та *.*.

  • Вказуємо тип файлу, який потрібно відобразити на початку
        saveFileDialog1.FilterIndex = 0

У цьому випадку користувачеві спочатку будуть показані файли типу *.txt.

  • Відображається діалогове вікно, і його результат отримується

    If saveFileDialog1.ShowDialog() = DialogResult.OK Then
  • Поки діалогове вікно відкрите, користувач не має доступу до головної форми (так зване модальне діалогове вікно). Користувач вказує ім’я файлу для збереження та залишає діалогове вікно, натиснувши кнопку «Зберегти», «Скасувати» або закривши вікно. Результатом методу ShowDialog є DialogResult.OK лише в тому випадку, якщо користувач скористався кнопкою Enregistrer для виходу з діалогового вікна.
  • Після цього ім’я файлу, що створюється, тепер міститься у властивості FileName об’єкта saveFileDialog1. Далі відбувається звичайне створення текстового файлу. У нього записується вміст TextBox: txtTexte.Text, при цьому обробляються винятки, що можуть виникнути.

Клас OpenFileDialog дуже схожий на клас SaveFileDialog і походить з того самого роду класів. З цих властивостей та методів ми звернемо увагу на такі:

string Filter
типи файлів, що пропонуються у випадаючому списку типів файлів діалогового вікна
int FilterIndex
номер типу файлу, запропонованого за замовчуванням у вищезазначеному списку. Починається з 0.
string InitialDirectory
папка, яка спочатку відображається для пошуку файлу, що відкривається
string FileName
ім'я файлу, який потрібно відкрити, вказане користувачем
DialogResult.ShowDialog()
метод, який відображає діалогове вікно збереження. Повертає результат типу DialogResult.

Метод ShowDialog відображає діалогове вікно, подібне до наведеного нижче:

1
випадаючий список, сформований на основі властивості Filter. Тип файлу, що пропонується за замовчуванням, визначається методом FilterIndex
2
поточна папка, задана InitialDirectory, якщо це властивість було вказано
3
назва файлу, обрана або введена безпосередньо користувачем. Буде доступна у властивості FileName
4
кнопки «Відкрити»/«Скасувати». Якщо використовується кнопка Ouvrir, функція ShowDialog повертає результат DialogResult.OK

Процедуру відкриття можна записати так:


Private Sub btnCharger_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnCharger.Click
        ' завантажуємо текстовий файл у поле введення
        ' налаштування діалогового вікна openfileDialog1
        openFileDialog1.InitialDirectory = Application.ExecutablePath
        openFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"
        openFileDialog1.FilterIndex = 0
        ' відображаємо діалогове вікно та отримуємо його результат
        If openFileDialog1.ShowDialog() = DialogResult.OK Then
            ' отримуємо ім'я файлу
            Dim nomFichier As String = openFileDialog1.FileName
            Dim fichier As StreamReader = Nothing
            Try
                ' відкриваємо файл для читання
                fichier = New StreamReader(nomFichier)
                ' зчитується весь файл і заноситься в TextBox
                txtTexte.Text = fichier.ReadToEnd()
            Catch ex As Exception
                ' проблема
                MessageBox.Show("Problème à la lecture du fichier (" + ex.Message + ")", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error)
                Return
            Finally
                ' файл закрито
                Try
                    fichier.Close()
                Catch
                End Try
            End Try
        End If
    End Sub
  • В якості початкової папки задаємо папку, що містить виконуваний файл програми:
            saveFileDialog1.InitialDirectory=Application.ExecutablePath
  • Вказуємо типи файлів, які потрібно відобразити
            saveFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"
  • Вказуємо тип файлу, який має відображатися на початку
            saveFileDialog1.FilterIndex = 0

У цьому випадку користувачеві спочатку будуть показані файли типу *.txt.

  • Відображається діалогове вікно, і отримується його результат

    If openFileDialog1.ShowDialog() = DialogResult.OK Then

Поки діалогове вікно відкрите, користувач не має доступу до головної форми (так зване модальне діалогове вікно). Користувач вказує ім’я файлу, який потрібно відкрити, і виходить із діалогового вікна, натиснувши кнопку «Відкрити», «Скасувати» або закривши вікно. Результатом методу ShowDialog є DialogResult.OK лише в тому випадку, якщо користувач використав кнопку Ouvrir для виходу з діалогового вікна.

  • Після цього ім’я файлу, що створюється, тепер міститься у властивості FileName об’єкта openFileDialog1. Далі відбувається звичайне читання текстового файлу. Зверніть увагу на метод, що дозволяє прочитати файл повністю:
                    txtTexte.Text=fichier.ReadToEnd
  • вміст файлу заноситься в TextBox та txtTexte. Обробляються винятки, які можуть виникнути.

5.7.2. Діалогові вікна FontColor та ColorDialog

Продовжуємо попередній приклад, додавши дві нові кнопки:

тип
назва
роль
6
Кнопка
btnCouleur
для визначення кольору символів у TextBox
7
Кнопка
btnPolice
для встановлення шрифту TextBox

Ми розміщуємо у формі елемент управління ColorDialog та елемент управління FontDialog:

Image

Класи FontDialog та ColorDialog мають метод ShowDialog, аналогічний методу ShowDialog класів OpenFileDialog та SaveFileDialog. Метод ShowDialog класу ColorDialog дозволяє вибрати колір:

Image

Якщо користувач закриває діалогове вікно за допомогою кнопки OK, результатом виклику методу ShowDialog є DialogResult.OK, а вибраний колір зберігається у властивості Color використовуваного об’єкта ColorDialog. Метод ShowDialog класу FontDialog дозволяє вибрати шрифт:

Image

Якщо користувач закриває діалогове вікно за допомогою кнопки OK, результатом методу ShowDialog є DialogResult.OK, а обраний шрифт зберігається у властивості Font використовуваного об’єкта FontDialog. У нас є елементи для обробки кліків на кнопках Couleur та Police:


    Private Sub btnCouleur_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnCouleur.Click
        ' вибір кольору тексту
        If colorDialog1.ShowDialog() = DialogResult.OK Then
            ' змінюємо властивість forecolor у TextBox
            txtTexte.ForeColor = colorDialog1.Color
        End If
    End Sub


    Private Sub btnPolice_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnPolice.Click
        ' вибір шрифту
        If fontDialog1.ShowDialog() = DialogResult.OK Then
            ' змінюємо властивість font для TextBox
            txtTexte.Font = fontDialog1.Font
        End If
    End Sub

5.7.3. Таймер

Тут ми пропонуємо написати такий додаток:

Тип
Назва
Роль
1
TextBox, ReadOnly=true
txtChrono
відображає таймер
2
Кнопка
btnArretMarche
кнопка «Старт/Стоп» хронометра
3
Таймер
timer1
компонент, що генерує подію кожну секунду

Хронометр увімкнено:

Image

Хронометр зупинено:

Image

Щоб щосекунди змінювати вміст TextBox txtChrono, нам потрібен компонент, який генерує подію кожну секунду, яку ми зможемо перехопити, щоб оновити відображення хронометра. Цим компонентом є Timer:

Image

Після встановлення цього компонента у формі (у розділі невидимих компонентів) у конструкторі форми створюється об’єкт типу Timer. Клас System.Windows.Forms.Timer визначено так:

Image

З його властивостей ми розглянемо лише такі:

Interval
кількість мілісекунд, через яку генерується подія Tick.
Tick
подія, що генерується через Interval мілісекунд
Enabled
встановлює таймер у активний (true) або неактивний (false) стан

У нашому прикладі таймер називається timer1, а timer1.Interval встановлено на 1000 мс (1 с). Отже, подія Tick відбуватиметься щосекунди. Натискання кнопки «Стоп/Пуск» обробляється за допомогою такої процедури:


    Private Sub btnArretMarche_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnArretMarche.Click
        ' увімкнути чи вимкнути?
        If btnArretMarche.Text = "Marche" Then
            ' записування часу початку
            début = DateTime.Now
            ' виводимо її на екран
            txtChrono.Text = "00:00:00"
            ' запускаємо таймер
            timer1.Enabled = True
            ' змінити напис на кнопці
            btnArretMarche.Text = "Arrêt"
            ' кінець
            Return
        End If        '
        If btnArretMarche.Text = "Arrêt" Then
            ' зупинка таймера
            timer1.Enabled = False
            ' змінюємо напис на кнопці
            btnArretMarche.Text = "Marche"
            ' кінець
            Return
        End If
    End Sub

    Private Sub timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles timer1.Tick
        ' минула одна секунда
        Dim maintenant As DateTime = DateTime.Now
        Dim durée As TimeSpan = DateTime.op_Subtraction(maintenant, début)
        txtChrono.Text = "" + durée.Hours.ToString("d2") + ":" + durée.Minutes.ToString("d2") + ":" + durée.Seconds.ToString("d2")
    End Sub

Напис на кнопці «Зупинка/Пуск» може бути або «Зупинка», або «Пуск». Тому необхідно перевірити цей напис, щоб визначити, яку дію слід виконати.

  • у разі «Увімкнути» час початку записується у змінну, яка є глобальною змінною об’єкта форми, таймер запускається (Enabled=true), а напис на кнопці змінюється на «Вимкнути».
  • У разі «Зупинка» таймер зупиняється (Enabled=false), а напис на кнопці змінюється на «Увімкнути».

Public Class Timer1
  Inherits System.Windows.Forms.Form
  Private WithEvents timer1 As System.Windows.Forms.Timer
  Private WithEvents btnArretMarche As System.Windows.Forms.Button
  Private components As System.ComponentModel.IContainer
  Private WithEvents txtChrono As System.Windows.Forms.TextBox
  Private WithEvents label1 As System.Windows.Forms.Label

  ' змінні екземпляру
  Private début As DateTime

Атрибут début, наведений вище, відомий у всіх методах класу. Залишається обробити подію Tick на об’єкті timer1, яка відбувається щосекунди:


    Private Sub timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles timer1.Tick
        ' минула одна секунда
        Dim maintenant As DateTime = DateTime.Now
        Dim durée As TimeSpan = DateTime.op_Subtraction(maintenant, début)
        txtChrono.Text = "" + durée.Hours.ToString("d2") + ":" + durée.Minutes.ToString("d2") + ":" + durée.Seconds.ToString("d2")
    End Sub

Обчислюємо час, що минув з моменту запуску хронометра. Отримуємо об’єкт типу TimeSpan, який представляє тривалість у часі. Її потрібно відобразити на хронометрі у форматі hh:mm:ss. Для цього використовуємо властивості Hours, Minutes, Seconds об’єкта TimeSPan, які відповідно представляють години, хвилини та секунди тривалості, яку ми відображаємо у форматі ToString("d2"), щоб отримати двоцифрове відображення.

5.8. Приклад IMPOTS

Повернемося до програми IMPOTS, яку ми вже двічі розглядали. Тепер додамо до неї графічний інтерфейс:

Елементи управління такі

тип
назва
роль
1
RadioButton
rdOui
позначено, якщо одружений
2
RadioButton
rdNon
позначте, якщо не одружений
3
NumericUpDown
incEnfants
кількість дітей платника податків
Мінімальне значення = 0, Максимальне значення = 20, Крок = 1
4
TextBox
txtSalaire
річний дохід платника податків у F
5
TextBox
txtImpots
сума податку до сплати
ReadOnly=true
6
Кнопка
btnCalculer
запускає розрахунок податку
7
Кнопка
btnEffacer
повертає форму до початкового стану під час завантаження
8
Кнопка
btnQuitter
для виходу з програми

Правила роботи

  • кнопка «Розрахувати» залишається неактивною, доки в полі «Заробітна плата» немає даних
  • якщо під час запуску розрахунку виявляється, що зарплата вказана неправильно, з’являється повідомлення про помилку:

Image

Програма наведена нижче. Вона використовує клас impot, створений у розділі про класи. Частина коду, що автоматично генерується VS.NET, тут не наведена.


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
' параметри
Option Explicit On 
Option Strict On

' простори імен
Imports System
Imports System.Drawing
Imports System.Collections
Imports System.ComponentModel
Imports System.Windows.Forms
Imports System.Data

' клас форми
Public Class frmImpots
  Inherits System.Windows.Forms.Form
  Private WithEvents label1 As System.Windows.Forms.Label
  Private WithEvents rdOui As System.Windows.Forms.RadioButton
  Private WithEvents rdNon As System.Windows.Forms.RadioButton
  Private WithEvents label2 As System.Windows.Forms.Label
  Private WithEvents txtSalaire As System.Windows.Forms.TextBox
  Private WithEvents label3 As System.Windows.Forms.Label
  Private WithEvents label4 As System.Windows.Forms.Label
  Private WithEvents groupBox1 As System.Windows.Forms.GroupBox
  Private WithEvents btnCalculer As System.Windows.Forms.Button
  Private WithEvents btnEffacer As System.Windows.Forms.Button
  Private WithEvents btnQuitter As System.Windows.Forms.Button
  Private WithEvents txtImpots As System.Windows.Forms.TextBox
  Private components As System.ComponentModel.Container = Nothing
  Private WithEvents incEnfants As System.Windows.Forms.NumericUpDown

  ' таблиці даних, необхідні для розрахунку податку
  Private limites() As Decimal = {12620D, 13190D, 15640D, 24740D, 31810D, 39970D, 48360D, 55790D, 92970D, 127860D, 151250D, 172040D, 195000D, 0D}
  Private coeffR() As Decimal = {0D, 0.05D, 0.1D, 0.15D, 0.2D, 0.25D, 0.3D, 0.35D, 0.4D, 0.45D, 0.55D, 0.5D, 0.6D, 0.65D}
  Private coeffN() As Decimal = {0D, 631D, 1290.5D, 2072.5D, 3309.5D, 4900D, 6898.5D, 9316.5D, 12106D, 16754.5D, 23147.5D, 30710D, 39312D, 49062D}
   ' об’єкт податку
  Private objImpôt As impot = Nothing


  Public Sub New()
    InitializeComponent()
     ' ініціалізація форми
    btnEffacer_Click(Nothing, Nothing)
    btnCalculer.Enabled = False
     ' створення об’єкта податку
    Try
      objImpôt = New impot(limites, coeffR, coeffN)
    Catch ex As Exception
      MessageBox.Show("Impossible de créer l'objet impôt (" + ex.Message + ")", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error)
       ' поле введення заробітної плати вимкнено
      txtSalaire.Enabled = False
    End Try 'try-catch
  End Sub 

  Protected Overloads Sub Dispose(ByVal disposing As Boolean)
....
  End Sub

  Private Sub InitializeComponent()
    Me.btnQuitter = New System.Windows.Forms.Button
    Me.groupBox1 = New System.Windows.Forms.GroupBox
    Me.btnEffacer = New System.Windows.Forms.Button
    Me.btnCalculer = New System.Windows.Forms.Button
    Me.txtSalaire = New System.Windows.Forms.TextBox
    Me.label1 = New System.Windows.Forms.Label
    Me.label2 = New System.Windows.Forms.Label
    Me.label3 = New System.Windows.Forms.Label
    Me.rdNon = New System.Windows.Forms.RadioButton
    Me.txtImpots = New System.Windows.Forms.TextBox
    Me.label4 = New System.Windows.Forms.Label
    Me.rdOui = New System.Windows.Forms.RadioButton
    Me.incEnfants = New System.Windows.Forms.NumericUpDown
    Me.groupBox1.SuspendLayout()
    CType(Me.incEnfants, System.ComponentModel.ISupportInitialize).BeginInit()
    Me.SuspendLayout()
....
  End Sub 'InitializeComponent

  Public Shared Sub Main()
    Application.Run(New frmImpots)
  End Sub 'Main


  Private Sub btnEffacer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
  Handles btnEffacer.Click
     ' очищення форми
    incEnfants.Value = 0
    txtSalaire.Text = ""
    txtImpots.Text = ""
    rdNon.Checked = True
  End Sub 'btnEffacer_Click


  Private Sub txtSalaire_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
  Handles txtSalaire.TextChanged
     ' стан кнопки «Розрахувати»
    btnCalculer.Enabled = txtSalaire.Text.Trim() <> ""
  End Sub 'txtSalaire_TextChanged


  Private Sub btnQuitter_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
  Handles btnQuitter.Click
     ' завершення роботи програми
    Application.Exit()
  End Sub 'btnQuitter_Click


  Private Sub btnCalculer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
  Handles btnCalculer.Click
     ' Чи правильна заробітна плата?
    Dim intSalaire As Integer = 0
    Try
      ' отримання заробітної плати
      intSalaire = Integer.Parse(txtSalaire.Text)
       ' повинно бути >=0
      If intSalaire < 0 Then
        Throw New Exception("")
      End If
    Catch ex As Exception
      ' повідомлення про помилку
      MessageBox.Show(Me, "Salaire incorrect", "Erreur de saisie", MessageBoxButtons.OK, MessageBoxIcon.Error)
       ' фокус на полі з помилкою
      txtSalaire.Focus()
       ' виділення тексту в полі введення
      txtSalaire.SelectAll()
       ' повернення до візуального інтерфейсу
      Return
    End Try 'try-catch
    ' зарплата правильна — розраховується податок
    txtImpots.Text = "" & CLng(objImpôt.calculer(rdOui.Checked, CInt(incEnfants.Value), intSalaire))
  End Sub 'btnCalculer_Click
End Class

Тут ми використовуємо збірку impots.dll, отриману в результаті компіляції класу impots із розділу 2. Нагадаємо, що цю збірку можна створити в консольному режимі за допомогою команди

dos>vbc /t:library impots.vb

Ця команда створює файл impots.dll, який називається збіркою. Цю збірку можна потім використовувати в різних проектах. Тут, у нашому проекті під назвою VS.NET, ми використовуємо вікно властивостей проекту:

Image

Щоб додати посилання (збірку), клацаємо правою кнопкою миші на ключовому блоці «References» вище, вибираємо опцію [Ajouter une référence] і вказуємо збірку [impots.dll], яку ми заздалегідь помістили в папку проекту:

dos>dir
01/03/2004  14:39                9 250 gui_impots.vb
01/03/2004  14:37                4 096 impots.dll
01/03/2004  14:41               12 288 gui_impots.exe

Після включення збірки [impots.dll] у проект клас [impots] стає відомим проекту. До цього він не був відомий. Інший спосіб — включити вихідний код impots.vb у проект. Для цього у вікні властивостей проєкту клацніть правою кнопкою миші на проєкті, виберіть опцію [Ajouter/Ajouter un élément existant] і вкажіть файл impots.vb.