Skip to content

5. Interfejsy graficzne z wykorzystaniem VB.NET i VS.NET

W niniejszym artykule zamierzamy pokazać, jak tworzyć interfejsy graficzne za pomocą VB.NET. Najpierw przyjrzymy się podstawowym klasom platformy .NET, które umożliwiają nam tworzenie interfejsu graficznego. Na początkowym etapie nie będziemy korzystać z żadnych narzędzi do automatycznego generowania. Następnie skorzystamy z Visual Studio.NET (VS.NET), narzędzia programistycznego firmy Microsoft ułatwiającego tworzenie aplikacji w językach .NET, a w szczególności tworzenie interfejsów graficznych. Używana wersja VS.NET to wersja angielska.

5.1. Podstawy interfejsów graficznych

5.1.1. Proste okno

Rozważmy następujący kod:


' opcje
Option Strict On
Option Explicit On 

' przestrzenie nazw
Imports System
Imports System.Drawing
Imports System.Windows.Forms

' klasa formularza
Public Class Form1
    Inherits Form

    ' producent
    Public Sub New()
        ' nazwa okna
        Me.Text = "Mon premier formulaire"
        ' wymiary okna
        Me.Size = New System.Drawing.Size(300, 100)
    End Sub

    ' funkcja testowa
    Public Shared Sub Main(ByVal args() As String)
        ' wyświetla się formularz
        Application.Run(New Form1)
    End Sub
End Class

Powyższy kod jest kompilowany, a następnie wykonywany

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

dos>frm1

W wyniku wykonania wyświetla się następujące okno:

Image

Interfejs graficzny zazwyczaj dziedziczy po klasie bazowej System.Windows.Forms.Form:

Public Class Form1
    Inherits Form

Klasa bazowa Form definiuje okno bazowe z przyciskami zamykania, powiększania/zmniejszania, regulowaną wielkością itp. oraz obsługuje zdarzenia związane z tymi obiektami graficznymi. W tym przypadku specjalizujemy klasę bazową, ustalając jej tytuł oraz szerokość (300) i wysokość (100). Odbywa się to w jej konstruktorze:


    Public Sub New()
        ' tytuł okna
        Me.Text = "Mon premier formulaire"
        ' wymiary okna
        Me.Size = New System.Drawing.Size(300, 100)
    End Sub

Tytuł okna jest ustalany przez właściwość Text, a wymiary przez właściwość Size. Size jest zdefiniowany w przestrzeni nazw System.Drawing i jest strukturą. Procedura Main uruchamia aplikację graficzną w następujący sposób:


        Application.Run(New Form1)

Tworzony i wyświetlany jest formularz typu Form1, a następnie aplikacja zaczyna nasłuchiwać zdarzeń występujących w formularzu (kliknięcia, ruchy myszą itp.) i uruchamia te, które obsługuje formularz. W tym przypadku nasz formularz nie obsługuje żadnych innych zdarzeń poza tymi, które obsługuje klasa bazowa Form (kliknięcia przycisków zamykania, powiększania/zmniejszania, zmiana rozmiaru okna, przesuwanie okna itp.).

5.1.2. Formularz z przyciskiem

Dodajmy teraz przycisk do naszego okna:


' opcje
Option Strict On
Option Explicit On 

' przestrzenie nazw
Imports System
Imports System.Drawing
Imports System.Windows.Forms

' klasa formularza
Public Class Form1
    Inherits Form

    ' atrybuty
    Private cmdTest As Button

    ' konstruktor
    Public Sub New()
        ' tytuł
        Me.Text = "Mon premier formulaire"
        ' wymiary
        Me.Size = New System.Drawing.Size(300, 100)
        ' przycisk
        ' tworzenie
        Me.cmdTest = New Button
        ' pozycja
        cmdTest.Location = New System.Drawing.Point(110, 20)
        ' rozmiar
        cmdTest.Size = New System.Drawing.Size(80, 30)
        ' nazwa
        cmdTest.Text = "Test"
        ' menedżer zdarzeń
        AddHandler cmdTest.Click, AddressOf cmdTest_Click
        ' dodanie przycisku do formularza
        Me.Controls.Add(cmdTest)
    End Sub

    ' menedżer zdarzeń
    Private Sub cmdTest_Click(ByVal sender As Object, ByVal evt As EventArgs)
        ' przycisk został kliknięty – zgłaszamy to
        MessageBox.Show("Clic sur bouton", "Clic sur bouton", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub

    ' funkcja testowa
    Public Shared Sub Main(ByVal args() As String)
        ' wyświetlanie formularza
        Application.Run(New Form1)
    End Sub
End Class

Dodaliśmy do formularza przycisk:


        ' przycisk
        ' utworzenie
        Me.cmdTest = New Button
        ' pozycja
        cmdTest.Location = New System.Drawing.Point(110, 20)
        ' rozmiar
        cmdTest.Size = New System.Drawing.Size(80, 30)
        ' nazwa
        cmdTest.Text = "Test"
        ' menedżer zdarzeń
        AddHandler cmdTest.Click, AddressOf cmdTest_Click
        ' dodanie przycisku do formularza
        Me.Controls.Add(cmdTest)

Właściwość Location ustala współrzędne (110,20) lewego górnego rogu przycisku za pomocą struktury Point. Szerokość i wysokość przycisku są ustawione na (80,30) za pomocą struktury Size. Właściwość Text przycisku pozwala ustawić jego etykietę. Klasa przycisku posiada zdarzenie Click zdefiniowane w następujący sposób:

Public Event Click As EventHandler

gdzie EventHandler jest funkcją „delegowaną” o następującej sygnaturze:

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

Oznacza to, że procedurka obsługi zdarzenia [Click] dla przycisku musi mieć sygnaturę delegata [EventHandler]. W tym przypadku po kliknięciu przycisku cmdTest zostanie wywołana metoda cmdTest_Click. Jest ona zdefiniowana w następujący sposób, zgodnie z poprzednim szablonem EventHandler:


    ' menedżer zdarzeń
    Private Sub cmdTest_Click(ByVal sender As Object, ByVal evt As EventArgs)
        ' przycisk został kliknięty – zgłaszamy to
        MessageBox.Show("Clic sur bouton", "Clic sur bouton", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub

Wyświetlany jest po prostu komunikat:

Image

Klasa jest kompilowana i wykonywana:

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

Klasa MessageBox służy do wyświetlania komunikatów w oknie. Wykorzystaliśmy tutaj konstruktor

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
komunikat do wyświetlenia
caption
tytuł okna
przyciski
przyciski znajdujące się w oknie
icon
ikona widoczna w oknie

Parametr buttons może przyjmować wartości spośród następujących stałych:

stała
przyciski
   AbortRetryIgnore 
  OK 
    OKCancel 
    RetryCancel 
    YesNo 
    YesNoCancel 

Parametr icon może przyjmować wartości spośród następujących stałych:

Asterisk
Error
idem Stop
Exclamation
to samo Ostrzeżenie
Hand
Information
to samo jak Asterisk
None
Question
Stop
to samo – ręcznie
Warning

 

Metoda Show jest metodą statyczną, która zwraca wynik typu System.Windows.Forms.DialogResult, który jest wyliczeniem:


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

Aby sprawdzić, który przycisk został naciśnięty przez użytkownika w celu zamknięcia okna typu MessageBox, należy napisać:

dim res as DialogResult=MessageBox.Show(..)
if res=DialogResult.Yes then
' naciśnięto przycisk „Tak”
...
end if

5.2. Tworzenie interfejsu graficznego za pomocą Visual Studio.NET

Wracamy do niektórych z omówionych wcześniej przykładów, tworząc je teraz za pomocą Visual Studio.NET.

5.2.1. Wstępne utworzenie projektu

  1. Uruchom VS.NET i wybierz opcję Fichier/Nouveau/Projet

Image

  1. podaj parametry swojego projektu
    1. wybierz typ projektu, który chcesz stworzyć, w tym przypadku projekt VB.NET (1)
    2. wybierz typ aplikacji, którą chcesz skompilować, w tym przypadku aplikację dla systemu Windows (2)
    3. wskazuj, w którym folderze chcesz umieścić podfolder projektu (3)
    4. podaj nazwę projektu (4). Będzie to również nazwa folderu, w którym będą znajdować się pliki projektu
    5. nazwa tego folderu jest podana w polu (5)
  1. W folderze i4 zostanie utworzonych kilka folderów i plików:
podfoldery folderu „projekt1”

Spośród tych plików interesujący jest tylko jeden – plik form1.cs, który jest plikiem źródłowym powiązanym z formularzem utworzonym przez VS.NET. Wrócimy do tego później.

5.2.2. Okna interfejsu programu VS.NET

Interfejs programu VS.NET wyświetla teraz niektóre elementy naszego projektu i4:

Mamy okno projektowania interfejsu graficznego:

Wybierając elementy sterujące z paska narzędzi (toolbox 2) i umieszczając je na obszarze okna (1), możemy zbudować interfejs graficzny. Jeśli najedziemy myszką na „toolbox”, powiększy się on i wyświetli szereg elementów sterujących:

Image

Na razie nie korzystamy z żadnego z nich. Nadal na ekranie VS.NET znajduje się okno eksploratora rozwiązań „Explorer Solution”:

Image

Na początku nie będziemy zbyt często korzystać z tego okna. Pokazuje ono wszystkie pliki tworzące projekt. Interesuje nas tylko jeden z nich: plik źródłowy naszego programu, w tym przypadku Form1.vb. Klikając prawym przyciskiem myszy na plik Form1.vb, wyświetla się menu umożliwiające dostęp albo do kodu źródłowego naszego interfejsu graficznego (Pokaż kod), albo do samego interfejsu graficznego (Projektant widoków):

Image

Dostęp do tych dwóch elementów można uzyskać bezpośrednio z okna „Solution Explorer”:

 

Otwarte okna „gromadzą się” w głównym oknie projektowym:

Image

W tym przypadku Form1.vb[Design] oznacza okno projektowe, a Form1.vb – okno kodu. Wystarczy kliknąć jedną z zakładek, aby przełączyć się między oknami. Kolejnym ważnym oknem widocznym na ekranie VS.NET jest okno właściwości:

Image

Właściwości wyświetlane w tym oknie dotyczą elementu sterującego aktualnie zaznaczonego w oknie projektowania graficznego. Dostęp do różnych okien projektu można uzyskać za pomocą menu Affichage:

Image

Znajdują się tam główne okna, które właśnie zostały opisane, wraz z ich skrótami klawiszowymi.

5.2.3. Uruchomienie projektu

Mimo że nie napisaliśmy żadnego kodu, mamy już projekt gotowy do uruchomienia. Aby go uruchomić, należy wykonać polecenie F5 lub Déboguer/Démarrer. Pojawi się następujące okno:

Image

Okno to można powiększyć, zminimalizować, zmienić jego rozmiar oraz zamknąć.

5.2.4. Kod wygenerowany przez VS.NET

Przyjrzyjmy się kodowi (Affichage/Code) naszej aplikacji:


Public Class Form1
    Inherits System.Windows.Forms.Form

#Region „Kod wygenerowany przez Windows Form Designer”

    Public Sub New()
        MyBase.New()

        'To wywołanie jest wymagane przez Projektanta Windows Form.
        InitializeComponent()

        'Dodaj dowolną inicjalizację po wywołaniu InitializeComponent()

    End Sub

    'Zastąpiona metoda usuwa formularz w celu wyczyszczenia listy komponentów.
    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

    'Wymagane przez Projektant Windows Form
    Private components As System.ComponentModel.IContainer

    'REMARQUE: następująca procedura jest wymagana przez projektant Windows Form
    'Można ją modyfikować za pomocą projektanta Windows Form.  
    'Nie należy jej modyfikować za pomocą edytora kodu.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        components = New System.ComponentModel.Container()
        Me.Text = "Form2"
    End Sub

#Koniec regionu

End Class

Interfejs graficzny wywodzi się z klasy bazowej System.Windows.Forms.Form:

Public Class Form1
    Inherits System.Windows.Forms.Form

Klasa bazowa Form definiuje okno bazowe z przyciskami zamykania, powiększania/zmniejszania, regulowanym rozmiarem itp. oraz obsługuje zdarzenia związane z tymi obiektami graficznymi. Konstruktor formularza wykorzystuje metodę InitializeComponent, w której tworzone i inicjowane są elementy sterujące formularza.


    Public Sub New()
        MyBase.New()

        'To wywołanie jest wymagane przez projektant Windows Form.
        InitializeComponent()

        'Dodaj dowolną inicjalizację po wywołaniu InitializeComponent()
    End Sub

Wszelkie inne zadania do wykonania w konstruktorze można wykonać po wywołaniu funkcji InitializeComponent. Metoda 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

ustala tytuł okna „Form1”, jego szerokość (292) i wysokość (53). Tytuł okna jest określony przez właściwość Text, a wymiary przez właściwość Size. Size jest zdefiniowany w przestrzeni nazw System.Drawing i jest strukturą. Aby uruchomić tę aplikację, musimy zdefiniować główny moduł projektu. W tym celu używamy opcji [Projets/Propriétés]:

Image

W [Objet de démarrage] wskazujemy [Form1], czyli formularz, który właśnie utworzyliśmy. Aby uruchomić aplikację, używamy opcji [Déboguer/Démarrer]:

Image

5.2.5. Kompilacja w oknie DOS

Teraz spróbujmy skompilować i uruchomić tę aplikację w oknie DOS:

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'.

Kompilator zgłasza, że nie może znaleźć procedury [Main]. Rzeczywiście, procedura VS.NET jej nie wygenerowała. Spotkaliśmy się z nią jednak już w poprzednich przykładach. Ma ona następującą postać:


    Shared Sub Main()
        ' uruchamiamy aplikację
        Application.Run(New Form1) ' où Form1 est le formulaire
    End Sub

Dodajmy powyższy kod do kodu procedury [Form1.vb] i skompilujmy ponownie:

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)
        ~~~~~~~~~~~

Tym razem nazwa [Application] nie jest znana. Oznacza to po prostu, że nie zaimportowaliśmy jej przestrzeni nazw [System.Windows.Forms]. Dodajmy następującą instrukcję:

Imports System.Windows.Forms

a następnie skompilujmy ponownie:

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

Tym razem wszystko działa. Uruchommy:

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

dos>form1

Image

Tworzony i wyświetlany jest formularz typu Form1. Można uniknąć dodawania procedury [Main], korzystając z opcji /m kompilatora, która pozwala określić klasę do wykonania w przypadku, gdy dziedziczy ona po System.Windows.Form:

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

Opcja /m:form2 wskazuje, że klasą, która ma zostać wykonana, jest klasa o nazwie [form2].

5.2.6. Obsługa zdarzeń

Po wyświetleniu formularza aplikacja zaczyna nasłuchiwać zdarzeń występujących w formularzu (kliknięcia, ruchy myszy itp.) i uruchamia te, które obsługuje formularz. W tym przypadku nasz formularz nie obsługuje żadnych innych zdarzeń poza tymi obsługiwanymi przez klasę bazową Form (kliknięcia przycisków zamykania, powiększania/zmniejszania, zmiana rozmiaru okna, przesuwanie okna itp.). Wygenerowany formularz wykorzystuje atrybut components, który nie jest nigdzie używany. Metoda dispose również nie ma tutaj żadnego zastosowania. To samo dotyczy niektórych używanych przestrzeni nazw (Collections, ComponentModel, Data) oraz przestrzeni nazw zdefiniowanej dla projektu projet1. W związku z tym w tym przykładzie kod można uprościć do następującej postaci:


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

Public Class Form1
    Inherits System.Windows.Forms.Form

    ' konstruktor
    Public Sub New()
        ' tworzenie formularza wraz z jego komponentami
        InitializeComponent()
    End Sub

    Private Sub InitializeComponent()
        ' rozmiar okna
        Me.Size = New System.Drawing.Size(300, 300)
        ' tytuł okna
        Me.Text = "Form1"
    End Sub

    Shared Sub Main()
        ' uruchamiamy aplikację
        Application.Run(New Form1)
    End Sub
End Class

5.2.7. Wniosek

Teraz zaakceptujemy kod wygenerowany przez VS.NET w obecnej postaci i ograniczymy się do dodania do niego naszego kodu, w szczególności w celu obsługi zdarzeń związanych z różnymi kontrolkami formularza.

5.3. Okno z polem wprowadzania danych, przyciskiem i etykietą

5.3.1. Projekt graficzny

W poprzednim przykładzie nie umieściliśmy żadnych komponentów w oknie. Rozpoczynamy nowy projekt o nazwie interface2. W tym celu postępujemy zgodnie z procedurą opisaną wcześniej, aby utworzyć projekt:

Image

Teraz zbudujmy okno z przyciskiem, etykietą i polem wprowadzania danych:

Pola są następujące:

nr
nazwa
typ
rola
1
lblSaisie
Etykieta
nazwa
2
txtSaisie
TextBox
pole wprowadzania danych
3
btnAfficher
Przycisk
służący do wyświetlenia zawartości pola wprowadzania danych w oknie dialogowym txtSaisie

Aby utworzyć to okno, można postępować w następujący sposób: kliknąć prawym przyciskiem myszy w oknie poza jakimkolwiek elementem i wybrać opcję Properties, aby uzyskać dostęp do właściwości okna:

Image

Po prawej stronie pojawi się okno właściwości:

Image

Na niektóre z tych właściwości warto zwrócić uwagę:

BackColor
aby ustawić kolor tła okna
ForeColor
do ustawienia koloru rysunków lub tekstu w oknie
Menu
aby przypisać menu do okna
Text
aby nadać tytuł oknu
FormBorderStyle
aby określić typ okna
Font
aby ustawić czcionkę tekstu w oknie
Name
w celu ustawienia nazwy okna

W tym przypadku ustalamy właściwości Text i Name:

Text
Pola wprowadzania danych i przyciski – 1
Name
frmSaisiesBoutons

Za pomocą paska „Zestaw narzędzi”

  • wybierz potrzebne elementy
  • przeciągnij je do okna i nadaj im odpowiednie wymiary
Po wybraniu elementu z „zestawu narzędzi” użyj klawisza
„Esc”, aby ukryć pasek narzędzi, a następnie przeciągnij
i dostosuj rozmiar elementu. Zrób to dla wszystkich trzech
: Label, TextBox, Button. Aby wyrównać i
prawidłowo dopasować rozmiar komponentów, skorzystaj z menu Format:
Zasada formatowania jest następująca:
  1. zaznacz różne elementy, które chcesz sformatować razem (przytrzymując klawisz Ctrl)
  2. wybierz żądany rodzaj formatowania
Opcja Align umożliwia wyrównanie elementów
Opcja „Make Same Size” pozwala ustawić, aby
komponenty miały tę samą wysokość lub tę samą
szerokość:
Opcja „Horizontal Spacing” pozwala na przykład
na poziome wyrównanie komponentów z
o jednakowej wielkości odstępami. To samo
dotyczy opcji „Vertical Spacing”, służącej do wyrównywania w pionie.
Opcja „Center in Form” pozwala wyśrodkować
komponentu w poziomie lub
w pionie w oknie:
Po prawidłowym
umieszczone w oknie, należy ustawić ich właściwości.
W tym celu kliknij prawym przyciskiem myszy na komponent i
wybierz opcję Properties:
  • etykieta 1 (Label)
Zaznacz komponent, aby wyświetlić
otworzyć okno właściwości. W tym oknie
zmień następujące właściwości:
nazwa: lblSaisie, tekst: Pole
  • pole wprowadzania danych 2 (TextBox)
Wybierz komponent, aby wyświetlić jego
okno właściwości. W tym oknie zmień
następujące właściwości:
nazwa: txtSaisie, tekst: pozostaw puste
  • przycisk 3 (Button):
name: cmdAfficher, text: Wyświetl
  • samego okna: name: frmSaisies&Przyciski,
text: Wpisy i przyciski – 1
Możemy uruchomić (Ctrl+F5) nasz projekt,
, aby uzyskać wstępny podgląd okna
w akcji:

Zamknij okno. Pozostaje nam jeszcze napisać procedurę powiązaną z kliknięciem przycisku Afficher.

5.3.2. Obsługa zdarzeń w formularzu

Przyjrzyjmy się kodowi wygenerowanemu przez projektanta graficznego:


...

Public Class frmSaisiesBoutons
  Inherits System.Windows.Forms.Form

  ' komponenty
    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

  ' konstruktor
  Public Sub New()
    InitializeComponent()
  End Sub

...

  ' inicjalizacja komponentów
    Private Sub InitializeComponent()
...
    End Sub
End Class

Na początek warto zwrócić uwagę na specyficzną deklarację komponentów:

  • słowo kluczowe „Friend” oznacza, że widoczność komponentu obejmuje wszystkie klasy w projekcie
  • słowo kluczowe WithEvents oznacza, że komponent generuje zdarzenia. Teraz przyjrzyjmy się, jak obsługiwać te zdarzenia

Wyświetl okno kodu formularza (Widok/kod lub F7):

W powyższym oknie znajdują się dwie listy rozwijane (1) i (2). Lista (1) zawiera listę komponentów formularza:

Image

Lista (2) zawiera listę zdarzeń powiązanych z komponentem wybranym w (1):

Image

Jedno ze zdarzeń powiązanych z komponentem jest wyświetlane pogrubioną czcionką (w tym przypadku „Click”). Jest to domyślne zdarzenie tego komponentu. Dostęp do procedury obsługi tego konkretnego zdarzenia można uzyskać, klikając dwukrotnie komponent w oknie projektowania. VB.net automatycznie generuje wówczas szkielet procedury obsługi zdarzenia w oknie kodu i ustawia kursor myszy na tym szkielecie. Dostęp do procedur obsługi pozostałych zdarzeń odbywa się w oknie kodu poprzez wybranie komponentu z listy (1) oraz zdarzenia z listy (2). VB.net generuje wówczas szkielet procedury obsługi zdarzenia lub ustawia kursor na nim, jeśli został on już wygenerowany:


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

Domyślnie VB.net C_E nadaje nazwę „E” menedżerowi zdarzeń komponentu C. Nazwę tę można zmienić, jeśli jest to dla nas wygodne. Nie jest to jednak zalecane. Programiści VB zazwyczaj zachowują nazwę wygenerowaną przez VB, co zapewnia spójność nazewnictwa we wszystkich programach VB. Powiązanie procedury btnAfficher_Click ze zdarzeniem Click komponentu btnAfficher nie odbywa się poprzez nazwę procedury, lecz za pomocą słowa kluczowego handles:


Handles btnAfficher.Click

W powyższym przykładzie słowo kluczowe „handles” określa, że procedura obsługuje zdarzenie „Click” komponentu btnAfficher. Poprzedni handler zdarzeń ma dwa parametry:

sender
obiekt będący źródłem zdarzenia (w tym przypadku przycisk)
e
obiekt EventArgs, który zawiera szczegóły dotyczące zdarzenia, które miało miejsce

W tym przypadku nie będziemy korzystać z żadnego z tych parametrów. Pozostaje nam tylko uzupełnić kod. Chcemy wyświetlić okno dialogowe zawierające zawartość pola txtSaisie:


    Private Sub btnAfficher_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        ' wyświetlanie tekstu wprowadzonego w polu wprowadzania danych TxtSaisie
        MessageBox.Show("texte saisi= " + txtsaisie.Text, "Vérification de la saisie", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub

Po uruchomieniu aplikacji otrzymujemy następujący wynik:

Image

5.3.3. Inna metoda obsługi zdarzeń

W przypadku przycisku btnAfficher, VS.NET wygenerowało następujący kod:


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

...

    ' obsługa zdarzenia kliknięcia przycisku cmdAfficher
    Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAfficher.Click
...
    End Sub

Możemy powiązać procedurę btnAfficher_Click ze zdarzeniem Click przycisku btnAfficher w inny sposób:


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

...

    ' obsługa zdarzenia kliknięcia przycisku cmdAfficher
    Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
...
    End Sub

Procedura btnAfficher_Click utraciła słowo kluczowe „Handles”, tracąc tym samym powiązanie ze zdarzeniem btnAfficher.Click. Powiązanie to jest teraz realizowane za pomocą słowa kluczowego AddHandler:


        AddHandler btnAfficher.Click, AddressOf btnAfficher_Click

Powyższy kod, który zostanie umieszczony w procedurze InitializeComponent formularza, powiązuje procedurę o nazwie btnAfficher_Click ze zdarzeniem btnAfficher.Click. Ponadto komponent btnAfficher nie wymaga już słowa kluczowego WithEvents:


    Friend btnAfficher As System.Windows.Forms.Button

Jaka jest różnica między tymi dwiema metodami?

  • Słowo kluczowe „handles” pozwala powiązać zdarzenie z procedurą wyłącznie na etapie projektowania. Projektant wie z góry, że procedura P ma obsługiwać zdarzenia E1, E2, ... i pisze kod

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

Procedura może rzeczywiście obsługiwać wiele zdarzeń.

  • Słowo kluczowe `addhandler` pozwala powiązać zdarzenie z procedurą w trakcie wykonywania. Jest to przydatne w modelu „producent-odbiorca” zdarzeń. Obiekt generuje konkretne zdarzenie, które może zainteresować inne obiekty. Obiekty te subskrybują zdarzenie u producenta, aby je otrzymywać (na przykład temperatura przekroczyła próg krytyczny). W trakcie działania aplikacji producent zdarzenia będzie musiał wykonać różne instrukcje:
Addhandler E, AddressOf P1
Addhandler E, AddressOf P2
...
Addhandler E, AddressOf Pn

gdzie E to zdarzenie generowane przez producenta, a Pi to procedury należące do różnych obiektów konsumujących to zdarzenie. W kolejnym rozdziale będziemy mieli okazję powrócić do tematu aplikacji typu producent-konsument zdarzeń.

5.3.4. Wnioski

Na podstawie dwóch omówionych projektów możemy stwierdzić, że po stworzeniu interfejsu graficznego za pomocą VS.NET zadaniem programisty jest napisanie procedur obsługi zdarzeń, które mają być obsługiwane przez ten interfejs. Od tej pory będziemy przedstawiać wyłącznie kod tych procedur.

5.4. Kilka przydatnych komponentów

Przedstawiamy teraz różne aplikacje wykorzystujące najczęściej spotykane komponenty, aby zapoznać się z ich głównymi metodami i właściwościami. Dla każdej aplikacji przedstawiamy interfejs graficzny oraz istotny kod, w szczególności procedury obsługi zdarzeń.

5.4.1. Formularz Form

Zaczynamy od przedstawienia niezbędnego komponentu, jakim jest formularz, na którym umieszcza się inne komponenty. Omówiliśmy już niektóre z jego podstawowych właściwości. W tym miejscu skupimy się na kilku ważnych zdarzeniach związanych z formularzem.

 
formularz jest w trakcie ładowania
Closing
formularz jest w trakcie zamykania
Closed
formularz został zamknięty

Zdarzenie Load ma miejsce jeszcze przed wyświetleniem formularza. Zdarzenie Closing ma miejsce podczas zamykania formularza. Zamknięcie to można jeszcze zatrzymać programowo. Tworzymy formularz o nazwie Form1 bez żadnych komponentów:

Image

Obsługujemy trzy powyższe zdarzenia:


    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' początkowe ładowanie formularza
        MessageBox.Show("Evt Load", "Load")
    End Sub

    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        ' formularz jest właśnie zamykany
        MessageBox.Show("Evt Closing", "Closing")
        ' wymagane jest potwierdzenie
        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
        ' formularz jest w trakcie zamykania
        MessageBox.Show("Evt Closed", "Closed")
    End Sub
Korzystamy z funkcji MessageBox, aby otrzymywać powiadomienia o różnych
zdarzeniach. Zdarzenie Closing nastąpi, gdy użytkownik
zamknie okno.
Następnie pytamy go, czy na pewno chce zamknąć aplikację:
Jeśli odpowie „Nie”, ustawiamy właściwość Cancel zdarzenia
CancelEventArgs, które metoda otrzymała jako parametr.
Jeśli ustawimy tę właściwość na False, zamknięcie
okna zostaje przerwane, w przeciwnym razie jest kontynuowane:

5.4.2. etykiety Label i pola wprowadzania danych TextBox

Z tymi dwoma komponentami mieliśmy już do czynienia. Label jest komponentem tekstowym, a TextBox – komponentem pola wprowadzania danych. Ich główną właściwością jest Text, która określa albo zawartość pola wprowadzania danych, albo tekst etykiety. Ta właściwość jest dostępna do odczytu i zapisu. Zdarzeniem zwykle używanym dla TextBox jest TextChanged, które sygnalizuje, że użytkownik zmienił zawartość pola wprowadzania danych. Oto przykład wykorzystujący zdarzenie TextChanged do śledzenia zmian w polu wprowadzania danych:

nr
typ
nazwa
rola
1
TextBox
txtSaisie
pole wprowadzania danych
2
Etykieta
lblControle
wyświetla tekst z pola 1 w czasie rzeczywistym
3
Przycisk
cmdEffacer
w celu wyczyszczenia pól 1 i 2
4
Przycisk
cmdQuitter
aby zamknąć aplikację

Odpowiedni kod tej aplikacji dotyczy procedur obsługi zdarzeń:


  ' kliknięcie przycisku „Zamknij”
    Private Sub cmdQuitter_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles cmdQuitter.Click
        ' kliknięcie przycisku „Zamknij” – aplikacja zostaje zamknięta
        Application.Exit()
    End Sub

    ' zmiana w polu txtSaisie
    Private Sub txtSaisie_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles txtSaisie.TextChanged
        ' zawartość pola TextBox uległa zmianie – kopiujemy ją do etykiety lblControle
        lblControle.Text = txtSaisie.Text
    End Sub

    ' kliknięcie przycisku „Usuń”
    Private Sub cmdEffacer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles cmdEffacer.Click
        ' usuwamy zawartość pola wprowadzania danych
        txtSaisie.Text = ""
    End Sub

    ' naciśnięto klawisz
    Private Sub txtSaisie_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) _
    Handles txtSaisie.KeyPress
        ' sprawdzamy, który klawisz został naciśnięty
        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

Warto zwrócić uwagę na sposób zamykania aplikacji w procedurze cmdQuitter_Click: Application.Exit(). Poniższy przykład wykorzystuje wielowierszowy TextBox:

Lista elementów sterujących jest następująca:

nr
typ
nazwa
rola
1
TextBox
txtMultiLignes
pole wprowadzania wielowierszowego
2
TextBox
txtAjout
pole wprowadzania danych jednowierszowe
3
Przycisk
btnAjouter
Dodaj zawartość z 2 do 1

Aby pole TextBox stało się wielowierszowe, należy ustawić następujące właściwości kontrolki:

 
aby akceptował wiele wierszy tekstu
ScrollBars=( None, Horizontal, Vertical, Both)
aby określić, czy kontrolka ma paski przewijania (Horizontal, Vertical, Both), czy nie (None)
AcceptReturn=(True, False)
jeśli wartość wynosi „true”, naciśnięcie klawisza Enter spowoduje przejście do następnej linii
AcceptTab=(True, False)
jeśli wartość wynosi „true”, naciśnięcie klawisza Tab spowoduje wstawienie znaku tabulacji w tekście

Przydatny jest kod obsługujący kliknięcie przycisku [Ajouter] oraz kod obsługujący zmianę wartości w polu wprowadzania danych [txtAjout]:


    ' ewentualnie btnAjouter_Click
    Private Sub btnAjouter_Click1(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnAjouter.Click
        ' dodanie zawartości txtAjout do zawartości txtMultilignes
        txtMultilignes.Text &= txtAjout.Text
        txtAjout.Text = ""
    End Sub

    ' ewentualnie txtAjout_TextChanged
    Private Sub txtAjout_TextChanged1(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles txtAjout.TextChanged
        ' ustalamy stan przycisku „Dodaj”
        btnAjouter.Enabled = txtAjout.Text.Trim() <> ""
    End Sub

5.4.3. listy rozwijane ComboBox

Komponent ComboBox to lista rozwijana połączona z polem wprowadzania danych: użytkownik może albo wybrać element z (2), albo wpisać tekst w (1). Istnieją trzy rodzaje ComboBox określone przez właściwość Style:

 
lista bez rozwijania z polem edycji
DropDown
lista rozwijana z polem edycji
DropDownList
lista rozwijana bez pola edycji

Domyślnie typem klasy ComboBox jest DropDown. Aby zapoznać się z klasą ComboBox, wpisz ComboBox w indeksie pomocy (Aide/Index). Klasa ComboBox posiada tylko jeden konstruktor:

Public Sub New()
tworzy pusty obiekt ComboBox

Elementy klasy ComboBox są dostępne we właściwości Items:

Public ReadOnly Property Items As ComboBox.ObjectCollection

Jest to właściwość indeksowana, gdzie Items(i) oznacza element i z listy rozwijanej. Niech C będzie listą rozwijaną, a C.Items jej listą elementów. Mamy następujące właściwości:

 
liczba elementów listy rozwijanej
C.Items(i)
element i z listy rozwijanej
C.Add(object o)
dodaje obiekt o jako ostatni element listy rozwijanej
C.AddRange(object() objets)
dodaje tablicę obiektów na końcu listy rozwijanej
C.Insert(int i, object o)
dodaje obiekt o na pozycji i listy rozwijanej
C.RemoveAt(int i)
usuwa element i z listy rozwijanej
C.Remove(object o)
usuwa obiekt o z listy rozwijanej
C.Clear()
usuwa wszystkie elementy z listy rozwijanej
C.IndexOf(object o)
ustawia pozycję i obiektu o w polu kombi

Można się dziwić, że lista rozwijana może zawierać obiekty, podczas gdy zazwyczaj zawiera ciągi znaków. Pod względem wizualnym tak właśnie będzie. Jeśli ComboBox zawiera obiekt obj, wyświetla ciąg znaków obj.ToString(). Należy pamiętać, że każdy obiekt posiada metodę ToString odziedziczoną po klasie object, która zwraca ciąg znaków „reprezentujący” ten obiekt. Element wybrany w polu kombi C to C.SelectedItem lub C.Items(C.SelectedIndex), gdzie C.SelectedIndex to numer wybranego elementu, przy czym numer ten zaczyna się od zera dla pierwszego elementu.

Podczas wyboru elementu z listy rozwijanej występuje zdarzenie SelectedIndexChanged, które można następnie wykorzystać do otrzymania powiadomienia o zmianie wyboru w liście rozwijanej. W poniższej aplikacji wykorzystujemy to zdarzenie do wyświetlenia elementu, który został wybrany z listy.

Image

Przedstawiamy tylko kod dotyczący tego okna. W konstruktorze formularza wypełniamy listę rozwijaną:


  Public Sub New()
    ' utworzenie formularza
    InitializeComponent()
    ' wypełnianie pola rozwijanego
    cmbNombres.Items.AddRange(New String() {"zéro", "un", "deux", "trois", "quatre"})
        ' wybieramy pierwszy element z listy
    cmbNombres.SelectedIndex = 0
  End Sub

Obsługujemy zdarzenie SelectedIndexChanged listy rozwijanej, które sygnalizuje wybór nowego elementu:


    Private Sub cmbNombres_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles cmbNombres.SelectedIndexChanged
        ' wybrany element uległ zmianie – wyświetlamy go
        MessageBox.Show("Elément sélectionné : (" & cmbNombres.SelectedItem.ToString & "," & cmbNombres.SelectedIndex & ")", "Combo", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub

5.4.4. komponent ListBox

Proponujemy zbudować następujący interfejs:

Elementy tego okna są następujące:

nr
typ
nazwa
rola/właściwości
0
Form
Form1
formularz - BorderStyle=FixedSingle
1
TextBox
txtSaisie
pole wprowadzania danych
2
Przycisk
btnAjouter
przycisk umożliwiający dodanie zawartości pola wprowadzania danych 1 do listy 3
3
ListBox
listBox1
lista 1
4
ListBox
listBox2
lista 2
5
Przycisk
btn1TO2
przenosi zaznaczone elementy z listy 1 do listy 2
6
Przycisk
cmd2T0
wykonuje operację odwrotną
7
Przycisk
btnEffacer1
wyczyść listę 1
8
Przycisk
btnEffacer2
wyczyść listę 2
  • Użytkownik wpisuje tekst w polu 1. Dodaje go do listy 1 za pomocą przycisku Ajouter (2). Pole wprowadzania danych (1) zostaje wówczas wyczyszczone, a użytkownik może dodać nowy element.
  • Może przenosić elementy z jednej listy na drugą, zaznaczając element do przeniesienia na jednej z list i wybierając odpowiedni przycisk przenoszenia 5 lub 6. Przeniesiony element jest dodawany na koniec listy docelowej i usuwany z listy źródłowej.
  • Może dwukrotnie kliknąć element z listy 1. Element ten zostanie wówczas przeniesiony do pola wprowadzania danych w celu edycji i usunięty z listy 1.

Przyciski są podświetlone lub niepodświetlone zgodnie z następującymi zasadami:

  • przycisk Ajouter jest podświetlony tylko wtedy, gdy w polu wprowadzania danych znajduje się tekst inny niż pusty
  • przycisk 5 służący do przenoszenia z listy 1 do listy 2 jest podświetlony tylko wtedy, gdy w liście 1 jest zaznaczony jakiś element
  • przycisk 6 służący do przeniesienia z listy 2 do listy 1 jest podświetlony tylko wtedy, gdy w liście 2 jest zaznaczony element
  • przyciski 7 i 8 służące do czyszczenia list 1 i 2 są podświetlone tylko wtedy, gdy lista, która ma zostać wyczyszczona, zawiera elementy.

W powyższych warunkach wszystkie przyciski muszą być wyłączone w momencie uruchomienia aplikacji. Należy zatem ustawić właściwość Enabled przycisków na wartość false. Można to zrobić na etapie projektowania, co spowoduje wygenerowanie odpowiedniego kodu w metodzie InitializeComponent, lub wykonać to samodzielnie w konstruktorze, jak pokazano poniżej:


    Public Sub New()
        ' początkowe utworzenie formularza
        InitializeComponent()
        ' dodatkowe inicjalizacje
        ' wyłączamy pewną liczbę przycisków
        btnAjouter.Enabled = False
        btn1TO2.Enabled = False
        btn2TO1.Enabled = False
        btnEffacer1.Enabled = False
        btnEffacer2.Enabled = False
    End Sub

Stan przycisku Ajouter jest kontrolowany przez zawartość pola wprowadzania danych. To zdarzenie TextChanged pozwala nam śledzić zmiany tej zawartości:


    ' zmiana w polu wprowadzania tekstu
    Private Sub txtSaisie_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles txtSaisie.TextChanged
        ' zmień treść pola txtSaisie
        ' przycisk „Dodaj” jest podświetlony tylko wtedy, gdy pole nie jest puste
        btnAjouter.Enabled = txtSaisie.Text.Trim() <> ""
    End Sub

Stan przycisków przesyłania zależy od tego, czy w liście, którą kontrolują, został wybrany jakiś element:


    ' zmiana wybranego elementu bez listbox1
    Private Sub listBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles listBox1.SelectedIndexChanged

        ' zaznaczono element
        ' włączamy przycisk przeniesienia z 1 do 2
        btn1TO2.Enabled = True
    End Sub

    ' zmiana wybranego elementu bez listbox2
    Private Sub listBox2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles listBox2.SelectedIndexChanged
        ' zaznaczono element
        ' włączono przycisk przeniesienia z 2 do 1
        btn2TO1.Enabled = True
    End Sub

Kod powiązany z kliknięciem przycisku Ajouter jest następujący:


    ' kliknięcie przycisku „Dodaj”
    Private Sub btnAjouter_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnAjouter.Click
        ' dodano nowy element do listy 1
        listBox1.Items.Add(txtSaisie.Text.Trim())
        ' wyczyszczenie pola wprowadzania danych
        txtSaisie.Text = ""
        ' Lista 1 nie jest pusta
        btnEffacer1.Enabled = True
        ' powrót fokusu do pola wprowadzania danych
        txtSaisie.Focus()
    End Sub

Warto zwrócić uwagę na metodę Focus, która pozwala ustawić „fokus” na elemencie formularza. Kod powiązany z kliknięciem przycisków Effacer:


    ' kliknięcie przycisku „Usuń1”
    Private Sub btnEffacer1_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnEffacer1.Click
        ' lista 1 została wyczyszczona
        listBox1.Items.Clear()
        btnEffacer1.Enabled = False
    End Sub

    ' kliknięcie przycisku „Usuń2”
    Private Sub btnEffacer2_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        ' usuwa się listę 2
        listBox2.Items.Clear()
        btnEffacer2.Enabled = False
    End Sub

Kod służący do przenoszenia zaznaczonych elementów z jednej listy do drugiej:


    ' kliknięcie przycisku „btn1to2”
    Private Sub btn1TO2_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btn1TO2.Click
        ' przeniesienie wybranego elementu z listy 1 do listy 2
        transfert(listBox1, listBox2)
        ' przyciski „Usuń”
        btnEffacer2.Enabled = True
        btnEffacer1.Enabled = listBox1.Items.Count <> 0
        ' przyciski przenoszenia
        btn1TO2.Enabled = False
        btn2TO1.Enabled = False
    End Sub

    ' kliknięcie przycisku btn2to1
    Private Sub btn2TO1_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btn2TO1.Click
        ' przeniesienie wybranego elementu z Listy 2 do Listy 1
        transfert(listBox2, listBox1)
        ' przyciski „Usuń”
        btnEffacer1.Enabled = True
        btnEffacer2.Enabled = listBox2.Items.Count <> 0
        ' przyciski przenoszenia
        btn1TO2.Enabled = False
        btn2TO1.Enabled = False
    End Sub

    ' przeniesienie
    Private Sub transfert(ByVal l1 As ListBox, ByVal l2 As ListBox)
        ' przeniesienie wybranego elementu z listy 1 do listy l2
        ' wybrany element?
        If l1.SelectedIndex = -1 Then Return
        ' dodanie do l2
        l2.Items.Add(l1.SelectedItem)
        ' usunięcie z l1
        l1.Items.RemoveAt(l1.SelectedIndex)
    End Sub

Najpierw tworzymy metodę


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

, która przenosi element wybrany z listy l1 do listy l2. Dzięki temu wystarczy jedna metoda zamiast dwóch, aby przenieść element z listy listBox1 do listy listBox2 lub z listy listBox2 do listy listBox1. Przed przeniesieniem upewniamy się, że na liście l1 rzeczywiście znajduje się zaznaczony element:


        ' wybrany element?
        If l1.SelectedIndex = -1 Then Return

Właściwość SelectedIndex ma wartość -1, jeśli obecnie nie jest zaznaczony żaden element. W procedurach


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

przenosimy listę X do listy Y i zmieniamy stan niektórych przycisków, aby odzwierciedlić nowy stan list.

5.4.5. pola wyboru CheckBox, przyciski opcji ButtonRadio

Proponujemy napisanie następującej aplikacji:

Elementy okna są następujące:

nr
typ
nazwa
rola
1
RadioButton
radioButton1
radioButton2
radioButton3
3 przyciski opcji
2
CheckBox
chechBox1
chechBox2
chechBox3
3 pola wyboru
3
ListBox
lstValeurs
lista

Jeśli utworzymy trzy przyciski opcji jeden po drugim, domyślnie należą one do tej samej grupy. Dlatego też, gdy jeden z nich jest zaznaczony, pozostałe nie są. Zdarzeniem, które nas interesuje w przypadku tych sześciu elementów sterujących, jest zdarzenie CheckChanged wskazujące, że stan pola wyboru lub przycisku opcji uległ zmianie. Stan ten jest w obu przypadkach reprezentowany przez właściwość logiczną Check, której wartość „prawda” oznacza, że element sterujący jest zaznaczony. W tym przypadku zastosowaliśmy jedną metodę do obsługi wszystkich sześciu zdarzeń CheckChanged – metodę affiche:


  ' wyświetla
    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
        ' wyświetla stan przycisku opcji lub pola wyboru
        ' czy to pole wyboru?
        If (TypeOf (sender) Is CheckBox) Then
            Dim chk As CheckBox = CType(sender, CheckBox)
            lstValeurs.Items.Insert(0, chk.Name & "=" & chk.Checked)
        End If
        ' czy to przycisk opcji?
        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

Składnia TypeOf (nadawca) Is CheckBox pozwala sprawdzić, czy obiekt sender jest typu CheckBox. Dzięki temu możemy następnie dokonać konwersji typu na dokładny typ obiektu sender. Metoda affiche zapisuje na liście lstValeurs nazwę komponentu, który wywołał zdarzenie, oraz wartość jego właściwości Checked. Podczas działania widać, że kliknięcie przycisku opcji powoduje dwa zdarzenia CheckChanged: jedno dotyczące starego przycisku zaznaczonego, który przechodzi w stan „niezaznaczony”, a drugie dotyczące nowego przycisku, który przechodzi w stan „zaznaczony”.

5.4.6. regulatory ScrollBar

Istnieje kilka rodzajów suwaków: suwak poziomy (hScrollBar),
regulator pionowy (vScrollBar) oraz inkrementator (NumericUpDown).

Zrealizujmy następującą aplikację:

nr
typ
nazwa
rola
1
hScrollBar
hScrollBar1
przesuwacz poziomy
2
hScrollBar
hScrollBar2
regulacja pozioma, która podąża za zmianami regulacji 1
3
TextBox
txtValeur
wyświetla wartość regulatora poziomego
ReadOnly=true, aby uniemożliwić wprowadzanie danych
4
NumericUpDown
inkrementator
umożliwia ustawienie wartości suwaka 2
  • Regulator ScrollBar umożliwia użytkownikowi wybór wartości z zakresu liczb całkowitych, symbolizowanego przez „pasek” regulatora, po którym porusza się kursor. Wartość regulatora jest dostępna w jego właściwości Value.
  • W przypadku suwaka poziomego lewy koniec reprezentuje minimalną wartość zakresu, prawy koniec – wartość maksymalną, a suwak – aktualnie wybraną wartość. W przypadku suwaka pionowego minimum reprezentuje górny koniec, a maksimum – dolny koniec. Wartości te są reprezentowane przez właściwości Minimum i Maximum, a ich wartości domyślne to 0 i 100.
  • Kliknięcie na skrajne punkty suwaka powoduje zmianę wartości o jeden przyrost (dodatni lub ujemny) w zależności od klikniętego skrajnego punktu o nazwie SmallChange, którego domyślną wartością jest 1.
  • Kliknięcie po obu stronach suwaka powoduje zmianę wartości o jeden przyrost (dodatni lub ujemny) w zależności od klikniętego końca o nazwie LargeChange, którego domyślną wartością jest 10.
  • Po kliknięciu górnego końca suwaka pionowego jego wartość maleje. Może to zaskoczyć przeciętnego użytkownika, który zazwyczaj oczekuje, że wartość będzie „rosła”. Problem ten można rozwiązać, nadając wartości ujemne właściwościom SmallChange i LargeChange
  • Te pięć właściwości (Value, Minimum, Maximum, SmallChange, LargeChange) są dostępne do odczytu i zapisu.
  • Głównym zdarzeniem falownika jest to, które sygnalizuje zmianę wartości: zdarzenie Scroll.

W pobliżu regulatora znajduje się komponent NumericUpDown: posiada on również właściwości Minimum, Maximum i Value, których wartości domyślne to odpowiednio 0, 100, 0. Jednak w tym przypadku właściwość Value jest wyświetlana w polu wprowadzania danych, które stanowi integralną część kontrolki. Użytkownik może samodzielnie zmienić tę wartość, chyba że właściwość ReadOnly kontrolki została ustawiona na wartość „true”. Wartość przyrostu jest ustalana przez właściwość Increment, domyślnie 1. Głównym zdarzeniem komponentu NumericUpDown jest to, które sygnalizuje zmianę wartości: zdarzenie ValueChanged. Kod naszej aplikacji wygląda następująco:

Formularz jest formatowany podczas jego tworzenia:


    ' konstruktor
    Public Sub New()
        ' pierwotne utworzenie formularza
        InitializeComponent()
        ' nadajemy falownikowi 2 takie same parametry jak falownikowi 1
        hScrollBar2.Minimum = hScrollBar1.Value
        hScrollBar2.Minimum = hScrollBar1.Minimum
        hScrollBar2.Maximum = hScrollBar1.Maximum
        hScrollBar2.LargeChange = hScrollBar1.LargeChange
        hScrollBar2.SmallChange = hScrollBar1.SmallChange
        ' to samo dotyczy licznika
        incrémenteur.Minimum = hScrollBar1.Value
        incrémenteur.Minimum = hScrollBar1.Minimum
        incrémenteur.Maximum = hScrollBar1.Maximum
        incrémenteur.Increment = hScrollBar1.SmallChange
        ' przypisuje się TextBox wartość napędu 1
        txtValeur.Text = "" & hScrollBar1.Value
    End Sub

Procedura monitorująca zmiany wartości napędu 1:


    ' zarządzanie falownikiem hscrollbar1
    Private Sub hScrollBar1_Scroll(ByVal sender As Object, ByVal e As System.Windows.Forms.ScrollEventArgs) _
    Handles hScrollBar1.Scroll
        ' zmiana wartości regulatora 1
        ' przenosimy tę wartość na regulator 2 i na pole tekstowe TxtValeur
        hScrollBar2.Value = hScrollBar1.Value
        txtValeur.Text = "" & hScrollBar1.Value
    End Sub

Moduł monitorujący zmiany wartości napędu 2:


    ' obsługa suwaka hscrollbar2
    Private Sub hScrollBar2_Scroll(ByVal sender As Object, ByVal e As System.Windows.Forms.ScrollEventArgs) _
    Handles hScrollBar2.Scroll
        ' blokuje się wszelkie zmiany suwaka 2
        ' wymuszając na nim zachowanie wartości regulatora 1
        e.NewValue = hScrollBar1.Value
    End Sub

Moduł monitorujący zmiany w sterowaniu incrémenteur:


    ' zarządzanie licznikiem
    Private Sub incrémenteur_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles incrémenteur.ValueChanged
        ' ustalanie wartości regulatora 2
        hScrollBar2.Value = CType(incrémenteur.Value, Integer)
    End Sub

5.5. Zdarzenia myszy

Podczas rysowania w kontenerze ważne jest, aby znać pozycję myszy, na przykład w celu wyświetlenia punktu po kliknięciu. Przesunięcia myszy powodują wygenerowanie zdarzeń w kontenerze, w którym się porusza.

 
mysz właśnie weszła w obszar kontrolki
MouseLeave
mysz właśnie opuściła obszar kontroli
MouseMove
mysz porusza się w obszarze kontrolnym
MouseDown
Naciśnięcie lewego przycisku myszy
MouseUp
Zwolnienie lewego przycisku myszy
DragDrop
użytkownik upuszcza obiekt na element sterujący
DragEnter
użytkownik wchodzi w obszar kontrolki, przeciągając obiekt
DragLeave
użytkownik opuszcza obszar kontrolki, przeciągając obiekt
DragOver
użytkownik najeżdża kursorem na obszar kontrolki, przeciągając obiekt

Oto program pozwalający lepiej zrozumieć, w jakich momentach występują różne zdarzenia myszy:

nr
typ
nazwa
rola
1
Etykieta
lblPosition
aby wyświetlić położenie myszy w formularzu 1, liście 2 lub przycisku 3
2
ListBox
lstEvts
aby wyświetlić zdarzenia myszy inne niż MouseMove
3
Przycisk
btnEffacer
aby wyczyścić zawartość pola 2

Oto listy procedur obsługi zdarzeń. Aby śledzić ruchy myszy na trzech kontrolkach, wystarczy napisać jedną procedurę obsługi:


    ' ewentualnie 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
        ' ruch myszy – wyświetlanie jej współrzędnych (X, Y)
        lblPosition.Text = "(" & e.X & "," & e.Y & ")"
    End Sub

Należy pamiętać, że za każdym razem, gdy mysz wchodzi w obszar elementu sterującego, zmienia się jej układ współrzędnych. Jej punkt początkowy (0,0) to lewy górny róg elementu sterującego, na którym się znajduje. Tak więc podczas wykonywania kodu, gdy przesuwamy mysz z formularza na przycisk, wyraźnie widać zmianę współrzędnych. Aby lepiej dostrzec te zmiany obszaru działania myszy, można skorzystać z właściwości Cursor elementów sterujących:

Image

Właściwość ta pozwala ustawić kształt kursora myszy, gdy mysz wchodzi w obszar kontrolki. W naszym przykładzie ustawiliśmy kursor na „Default” dla samego formularza, „Hand” dla listy 2 oraz „No” dla przycisku 3, jak pokazują poniższe zrzuty ekranu.

Image

Image

Image

W metodzie [InitializeComponent] kod wygenerowany na podstawie tych wyborów wygląda następująco:


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

Ponadto, aby wykrywać wejścia i wyjścia myszy na liście 2, przetwarzamy zdarzenia MouseEnter i MouseLeave z tej samej listy:


    ' ewent. 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

    ' zdarzenie 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
    
' wyświetla
    Private Sub affiche(ByVal message As String)
        ' wyświetla się komunikat na górze listy zdarzeń
        lstEvts.Items.Insert(0, message)
    End Sub

Image

Aby obsłużyć kliknięcia w formularzu, przetwarzamy zdarzenia MouseDown i MouseUp:


    ' zdarzenie 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

    ' zdarzenie 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

Na koniec kod obsługi kliknięcia przycisku Effacer:


    ' zdarzenie btnEffacer_Click
    Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
    Handles btnEffacer.Click
        ' usuwa listę zdarzeń
        lstEvts.Items.Clear()
    End Sub

5.6. Tworzenie okna z menu

Zobaczmy teraz, jak utworzyć okno z menu. Utworzymy następujące okno:

Element sterujący 1 to TextBox tylko do odczytu (ReadOnly=true) o nazwie txtStatut. Struktura drzewa menu jest następująca:

Opcje menu są elementami sterującymi, podobnie jak inne komponenty wizualne, i posiadają właściwości oraz zdarzenia. Na przykład tabela właściwości opcji menu A1:

Image

W naszym przykładzie wykorzystano dwie właściwości:

 
nazwa elementu sterującego menu
Text
nazwa opcji menu

Właściwości poszczególnych opcji menu w naszym przykładzie są następujące:

Nazwa
Text
mnuA
opcje A
mnuA1
A1
mnuA2
A2
mnuA3
A3
mnuB
opcje B
mnuB1
B1
mnuSep1
- (separator)
mnuB2
B2
mnuB3
B3
mnuB31
B31
mnuB32
B32

Aby utworzyć menu, należy wybrać komponent „MainMenu” z paska „ToolBox”:

Image

W ten sposób otrzymujemy puste menu, które pojawia się w formularzu z pustymi polami o nazwie „Type Here”. Wystarczy wpisać w nich różne opcje menu:

Image

Aby wstawić separator między dwiema opcjami, tak jak powyżej między opcjami B1 i B2, należy ustawić kursor w miejscu, w którym ma znajdować się separator w menu, kliknąć prawym przyciskiem myszy i wybrać opcję „Insert Separator”:

Image

Jeśli uruchomimy aplikację za pomocą skrótu Ctrl+F5, otrzymamy formularz z menu, które na razie nie wykonuje żadnej czynności. Opcje menu są traktowane jak komponenty: mają właściwości i zdarzenia. W [fenêtre de code] zaznacz komponent mnuA1, a następnie wybierz powiązane zdarzenia:

Image

Jeśli powyżej wygenerujemy zdarzenie Click, to VS.NET automatycznie wygeneruje następującą procedurę:


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

Moglibyśmy postępować w ten sposób dla wszystkich opcji menu. W tym przypadku ta sama procedura może być wykorzystana dla wszystkich opcji. Dlatego zmieniamy nazwę poprzedniej procedury na affiche i deklarujemy zdarzenia, które ona obsługuje:


    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
        ' wyświetla w TextBox nazwę wybranego podmenu
        txtStatut.Text = (CType(sender, MenuItem)).Text
    End Sub

W tej metodzie ograniczamy się do wyświetlenia właściwości Text opcji menu w źródle zdarzenia. Źródło zdarzenia sender jest typu object. Opcje menu są typu MenuItem, dlatego w tym przypadku konieczne jest przeprowadzenie konwersji typu z object na MenuItem. Uruchom aplikację i wybierz opcję A1, aby uzyskać następujący komunikat:

Image

Przydatnym kodem tej aplikacji, oprócz kodu metody affiche, jest kod służący do tworzenia menu w kreatorze formularza (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

Warto zwrócić uwagę na instrukcję, która powiązuje menu z formularzem:


    Me.Menu = Me.mainMenu1

5.7. Komponenty niewidoczne

Zajmiemy się teraz kilkoma komponentami niewidocznymi: są one wykorzystywane podczas projektowania, ale nie są widoczne podczas działania programu.

5.7.1. Okna dialogowe OpenFileDialog i SaveFileDialog

Stworzymy następującą aplikację:

Elementy sterujące są następujące:

Nr
typ
nazwa
rola
1
TextBox wielowierszowy
txtTexte
tekst wpisany przez użytkownika lub załadowany z pliku
2
Przycisk
btnSauvegarder
umożliwia zapisanie tekstu z pola 1 w pliku tekstowym
3
Przycisk
btnCharger
umożliwia wczytanie zawartości pliku tekstowego do pola 1
4
Przycisk
btnEffacer
usuwa zawartość 1

Wykorzystywane są dwa elementy sterujące niewizualne:

Image

Po przeciągnięciu z „ToolBox” i upuszczeniu na formularzu są one umieszczane w oddzielnej strefie na dole formularza. Komponenty „Dialog” są pobierane z „ToolBox”:

Image

Kod przycisku Effacer jest prosty:


    Private Sub btnEffacer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnEffacer.Click
        ' kasuje się pole wprowadzania danych
        txtTexte.Text = ""
    End Sub

Klasa SaveFileDialog jest zdefiniowana w następujący sposób:

Image

Wywodzi się ona z kilku poziomów klas. Spośród tych licznych właściwości i metod zwrócimy uwagę na następujące:

string Filter
typy plików dostępne w rozwijanej liście typów plików w oknie dialogowym
int FilterIndex
numer typu pliku proponowanego domyślnie na powyższej liście. Zaczyna się od 0.
String
InitialDirectory
folder domyślnie wyświetlany do zapisania pliku
string FileName
nazwa pliku zapasowego podana przez użytkownika
DialogResult.ShowDialog()
metoda wyświetlająca okno dialogowe tworzenia kopii zapasowej. Zwraca wynik typu DialogResult.

Metoda ShowDialog wyświetla okno dialogowe podobne do poniższego:

1
lista rozwijana utworzona na podstawie właściwości Filter. Domyślny typ pliku jest ustalany przez FilterIndex
2
bieżący katalog, określony przez InitialDirectory, jeśli ta właściwość została wypełniona
3
nazwa pliku wybrana lub wpisana bezpośrednio przez użytkownika. Będzie dostępna we właściwości FileName
4
przyciski Zapisz/Anuluj. Jeśli używany jest przycisk Enregistrer, funkcja ShowDialog zwraca wynik DialogResult.OK

Procedura zapisywania może wyglądać następująco:


    Private Sub btnSauvegarder_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnSauvegarder.Click
        ' zapisujemy pole wprowadzania danych w pliku tekstowym
        ' konfiguruje się okno dialogowe savefileDialog1
        saveFileDialog1.InitialDirectory = Application.ExecutablePath
        saveFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"
        saveFileDialog1.FilterIndex = 0
        ' wyświetla się okno dialogowe i pobierany jest jego wynik
        If saveFileDialog1.ShowDialog() = DialogResult.OK Then
            ' pobieramy nazwę pliku
            Dim nomFichier As String = saveFileDialog1.FileName
            Dim fichier As StreamWriter = Nothing
            Try
                ' otwieramy plik w trybie zapisu
                fichier = New StreamWriter(nomFichier)
                ' wpisujemy tam tekst
                fichier.Write(txtTexte.Text)
            Catch ex As Exception
                ' problem
                MessageBox.Show("Problème à l'écriture du fichier (" + ex.Message + ")", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error)
                Return
            Finally
                ' zamykamy plik
                Try
                    fichier.Close()
                Catch
                End Try
            End Try
        End If
    End Sub
  • Przypisujemy folder początkowy do folderu zawierającego plik wykonywalny aplikacji:
        saveFileDialog1.InitialDirectory = Application.ExecutablePath
  • Należy określić typy plików, które mają zostać wyświetlone
        saveFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"

Należy zwrócić uwagę na składnię filtrów: filtr1|filtre2|..|filtren avec filtrei= Texte|szablon pliku. W tym przypadku użytkownik będzie miał do wyboru pliki *.txt oraz *.*.

  • Ustalamy typ pliku, który ma być wyświetlany na początku
        saveFileDialog1.FilterIndex = 0

W tym przypadku użytkownikowi zostaną najpierw wyświetlone pliki typu *.txt.

  • Wyświetlane jest okno dialogowe, a jego wynik jest pobierany

    If saveFileDialog1.ShowDialog() = DialogResult.OK Then
  • Podczas wyświetlania okna dialogowego użytkownik nie ma już dostępu do głównego formularza (okno dialogowe jest tzw. modalne). Użytkownik określa nazwę pliku do zapisania i opuszcza okno, klikając przycisk „Zapisz”, „Anuluj” lub po prostu zamykając okno. Wynikiem metody ShowDialog jest DialogResult.OK tylko wtedy, gdy użytkownik użył przycisku Enregistrer, aby zamknąć okno dialogowe.
  • Po wykonaniu tej czynności nazwa pliku, który ma zostać utworzony, znajduje się teraz we właściwości FileName obiektu saveFileDialog1. W tym momencie powracamy do klasycznego tworzenia pliku tekstowego. Zapisujemy w nim zawartość obiektu TextBox: txtTexte.Text, jednocześnie obsługując wyjątki, które mogą wystąpić.

Klasa OpenFileDialog jest bardzo zbliżona do klasy SaveFileDialog i wywodzi się z tej samej linii klas. Spośród jej właściwości i metod zwrócimy uwagę na następujące:

string Filter
typy plików dostępne w rozwijanej liście typów plików w oknie dialogowym
int FilterIndex
numer typu pliku proponowanego domyślnie na powyższej liście. Zaczyna się od 0.
string InitialDirectory
folder wyświetlany domyślnie podczas wyszukiwania pliku do otwarcia
string FileName
nazwa pliku do otwarcia podana przez użytkownika
DialogResult.ShowDialog()
metoda wyświetlająca okno dialogowe zapisu. Zwraca wynik typu DialogResult.

Metoda ShowDialog wyświetla okno dialogowe podobne do poniższego:

1
lista rozwijana utworzona na podstawie właściwości Filter. Domyślny typ pliku jest ustalany przez metodę FilterIndex
2
bieżący katalog, określony przez InitialDirectory, jeśli ta właściwość została wypełniona
3
nazwa pliku wybrana lub wpisana bezpośrednio przez użytkownika. Będzie dostępna w właściwości FileName
4
przyciski Otwórz/Anuluj. Jeśli używany jest przycisk Ouvrir, funkcja ShowDialog zwraca wynik DialogResult.OK

Procedurę otwierania można zapisać w następujący sposób:


Private Sub btnCharger_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnCharger.Click
        ' wczytuje się plik tekstowy do pola wprowadzania danych
        ' konfiguruje się okno dialogowe openfileDialog1
        openFileDialog1.InitialDirectory = Application.ExecutablePath
        openFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"
        openFileDialog1.FilterIndex = 0
        ' wyświetla się okno dialogowe i pobierany jest jego wynik
        If openFileDialog1.ShowDialog() = DialogResult.OK Then
            ' pobieramy nazwę pliku
            Dim nomFichier As String = openFileDialog1.FileName
            Dim fichier As StreamReader = Nothing
            Try
                ' otwieramy plik w trybie odczytu
                fichier = New StreamReader(nomFichier)
                ' odczytujemy cały plik i umieszczamy go w TextBox
                txtTexte.Text = fichier.ReadToEnd()
            Catch ex As Exception
                ' problem
                MessageBox.Show("Problème à la lecture du fichier (" + ex.Message + ")", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error)
                Return
            Finally
                ' zamykamy plik
                Try
                    fichier.Close()
                Catch
                End Try
            End Try
        End If
    End Sub
  • Jako katalog początkowy ustalamy katalog zawierający plik wykonywalny aplikacji:
            saveFileDialog1.InitialDirectory=Application.ExecutablePath
  • Należy określić typy plików, które mają zostać wyświetlone
            saveFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"
  • Ustalamy typ pliku, który ma być wyświetlany na początku
            saveFileDialog1.FilterIndex = 0

W tym przypadku pliki typu *.txt będą wyświetlane użytkownikowi jako pierwsze.

  • Wyświetla się okno dialogowe, a jego wynik jest pobierany

    If openFileDialog1.ShowDialog() = DialogResult.OK Then

Podczas wyświetlania okna dialogowego użytkownik nie ma już dostępu do głównego formularza (okno dialogowe jest tzw. modalne). Użytkownik określa nazwę pliku do otwarcia i opuszcza okno, klikając przycisk „Otwórz”, „Anuluj” lub po prostu zamykając okno. Wynikiem metody ShowDialog jest DialogResult.OK tylko wtedy, gdy użytkownik użył przycisku Ouvrir, aby zamknąć okno dialogowe.

  • Po wykonaniu tej czynności nazwa pliku, który ma zostać utworzony, znajduje się teraz we właściwości FileName obiektu openFileDialog1. Następnie powraca się do klasycznego odczytu pliku tekstowego. Należy zwrócić uwagę na metodę, która pozwala odczytać cały plik:
                    txtTexte.Text=fichier.ReadToEnd
  • zawartość pliku jest umieszczana w obiektach TextBox i txtTexte. Obsługujemy wyjątki, które mogą wystąpić.

5.7.2. Okna dialogowe FontColor i ColorDialog

Kontynuujemy poprzedni przykład, przedstawiając dwa nowe przyciski:

Nr
typ
nazwa
rola
6
Przycisk
btnCouleur
do ustawienia koloru znaków w TextBox
7
Przycisk
btnPolice
w celu ustawienia czcionki dla TextBox

Umieszczamy w formularzu kontrolkę ColorDialog oraz kontrolkę FontDialog:

Image

Klasy FontDialog i ColorDialog posiadają metodę ShowDialog analogiczną do metody ShowDialog klas OpenFileDialog i SaveFileDialog. Metoda ShowDialog klasy ColorDialog umożliwia wybór koloru:

Image

Jeśli użytkownik zamknie okno dialogowe za pomocą przycisku OK, wynikiem działania metody ShowDialog jest DialogResult.OK, a wybrany kolor znajduje się we właściwości Color używanego obiektu ColorDialog. Metoda ShowDialog klasy FontDialog umożliwia wybór czcionki:

Image

Jeśli użytkownik zamknie okno dialogowe za pomocą przycisku OK, wynikiem działania metody ShowDialog jest DialogResult.OK, a wybrana czcionka znajduje się we właściwości Font używanego obiektu FontDialog. Mamy elementy do obsługi kliknięć na przyciskach Couleur i Police:


    Private Sub btnCouleur_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnCouleur.Click
        ' wybór koloru tekstu
        If colorDialog1.ShowDialog() = DialogResult.OK Then
            ' zmienia się właściwość „forecolor” w pliku 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
        ' wybór czcionki
        If fontDialog1.ShowDialog() = DialogResult.OK Then
            ' zmiana właściwości font obiektu TextBox
            txtTexte.Font = fontDialog1.Font
        End If
    End Sub

5.7.3. Timer

W tym miejscu proponujemy napisać następującą aplikację:

nr
Typ
Nazwa
Rola
1
TextBox, ReadOnly=true
txtChrono
wyświetla licznik czasu
2
Przycisk
btnArretMarche
przycisk Start/Stop stopera
3
Timer
timer1
komponent generujący tutaj zdarzenie co sekundę

Czasomierz działa:

Image

Zegar zatrzymany:

Image

Aby co sekundę zmieniać zawartość elementów TextBox i txtChrono, potrzebujemy komponentu, który generuje zdarzenie co sekundę – zdarzenie, które będziemy mogli przechwycić w celu aktualizacji wyświetlacza stopera. Tym komponentem jest Timer:

Image

Po zainstalowaniu tego komponentu w formularzu (w sekcji komponentów niewizualnych) w konstruktorze formularza tworzony jest obiekt typu Timer. Klasa System.Windows.Forms.Timer jest zdefiniowana w następujący sposób:

Image

Spośród jej właściwości zwrócimy uwagę jedynie na następujące:

Interval
liczba milisekund, po upływie której generowane jest zdarzenie Tick.
Tick
zdarzenie wygenerowane po upływie Interval milisekund
Enabled
ustawia timer jako aktywny (true) lub nieaktywny (false)

W naszym przykładzie timer nosi nazwę timer1, a timer1.Interval jest ustawiony na 1000 ms (1 s). Zdarzenie Tick będzie więc występować co sekundę. Kliknięcie przycisku „Stop/Start” jest obsługiwane przez następującą procedurę:


    Private Sub btnArretMarche_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnArretMarche.Click
        ' wyłączyć czy włączyć?
        If btnArretMarche.Text = "Marche" Then
            ' odnotowujemy godzinę rozpoczęcia
            début = DateTime.Now
            ' wyświetlanie
            txtChrono.Text = "00:00:00"
            ' uruchamia się licznik czasu
            timer1.Enabled = True
            ' zmieniamy nazwę przycisku
            btnArretMarche.Text = "Arrêt"
            ' koniec
            Return
        End If        '
        If btnArretMarche.Text = "Arrêt" Then
            ' zatrzymanie licznika czasu
            timer1.Enabled = False
            ' zmiana nazwy przycisku
            btnArretMarche.Text = "Marche"
            ' koniec
            Return
        End If
    End Sub

    Private Sub timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles timer1.Tick
        ' minęła sekunda
        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

Napis na przycisku „Wyłącz/Włącz” to albo „Wyłącz”, albo „Włącz”. Musimy więc sprawdzić ten napis, aby wiedzieć, co należy zrobić.

  • w przypadku „Włącz”, zapisujemy czas rozpoczęcia w zmiennej, która jest zmienną globalną obiektu formularza, uruchamiamy licznik czasu (Enabled=true), a tekst przycisku zmienia się na „Wyłącz”.
  • W przypadku „Wyłącz” zatrzymujemy licznik czasu (Enabled=false) i zmieniamy napis na przycisku na „Włącz”.

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

  ' zmienne instancji
  Private début As DateTime

Powyższy atrybut début jest rozpoznawany we wszystkich metodach klasy. Pozostaje nam jeszcze obsłużyć zdarzenie Tick na obiekcie timer1, które występuje co sekundę:


    Private Sub timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles timer1.Tick
        ' minęła sekunda
        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

Obliczamy czas, który upłynął od momentu uruchomienia stopera. Otrzymujemy obiekt typu TimeSpan, który reprezentuje upływ czasu. Czas ten musi zostać wyświetlony na stoperze w formacie hh:mm:ss. W tym celu wykorzystujemy właściwości Hours, Minutes, Seconds obiektu TimeSPan, które reprezentują odpowiednio godziny, minuty i sekundy wyświetlanego czasu w formacie ToString("d2"), aby uzyskać wyświetlanie z dwoma cyframi.

5.8. Przykład IMPOTS

Wracamy do aplikacji IMPOTS, którą omówiliśmy już dwukrotnie. Dodajemy do niej teraz interfejs graficzny:

Elementy sterujące są następujące

nr
typ
nazwa
rola
1
RadioButton
rdOui
zaznaczone, jeśli jest żonaty
2
RadioButton
rdNon
zaznaczyć, jeśli nie jest żonaty/zamężna
3
NumericUpDown
incEnfants
liczba dzieci podatnika
Minimum=0, Maksimum=20, Przyrost=1
4
TextBox
txtSalaire
roczne wynagrodzenie podatnika w F
5
TextBox
txtImpots
kwota podatku do zapłaty
ReadOnly=true
6
Przycisk
btnCalculer
uruchamia obliczenie podatku
7
Przycisk
btnEffacer
przywraca formularz do stanu początkowego podczas ładowania
8
Przycisk
btnQuitter
służy do zamknięcia aplikacji

Zasady działania

  • przycisk „Oblicz” pozostaje nieaktywny, dopóki w polu wynagrodzenia nie ma żadnych danych
  • jeśli po uruchomieniu obliczeń okaże się, że wynagrodzenie jest nieprawidłowe, wyświetlany jest komunikat o błędzie:

Image

Poniżej przedstawiono program. Wykorzystuje on klasę impot utworzoną w rozdziale poświęconym klasom. Część kodu wygenerowanego automatycznie przez VS.NET nie została tutaj zamieszczona.


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
' opcje
Option Explicit On 
Option Strict On

' przestrzenie nazw
Imports System
Imports System.Drawing
Imports System.Collections
Imports System.ComponentModel
Imports System.Windows.Forms
Imports System.Data

' klasa formularza
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

  ' tabele danych niezbędne do obliczenia podatku
  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}
   ' obiekt podatku
  Private objImpôt As impot = Nothing


  Public Sub New()
    InitializeComponent()
     ' inicjalizacja formularza
    btnEffacer_Click(Nothing, Nothing)
    btnCalculer.Enabled = False
     ' utworzenie obiektu podatku
    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)
       ' wyłączamy pole wprowadzania wynagrodzenia
      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
     ' wyzerowanie formularza
    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
     ' stan przycisku „Oblicz”
    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
     ' zakończenie działania aplikacji
    Application.Exit()
  End Sub 'btnQuitter_Click


  Private Sub btnCalculer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
  Handles btnCalculer.Click
     ' czy wynagrodzenie jest prawidłowe?
    Dim intSalaire As Integer = 0
    Try
      ' pobieranie wynagrodzenia
      intSalaire = Integer.Parse(txtSalaire.Text)
       ' musi wynosić >=0
      If intSalaire < 0 Then
        Throw New Exception("")
      End If
    Catch ex As Exception
      ' komunikat o błędzie
      MessageBox.Show(Me, "Salaire incorrect", "Erreur de saisie", MessageBoxButtons.OK, MessageBoxIcon.Error)
       ' fokus na błędnym polu
      txtSalaire.Focus()
       ' zaznaczenie tekstu w polu wprowadzania danych
      txtSalaire.SelectAll()
       ' powrót do interfejsu graficznego
      Return
    End Try 'try-catch
    ' wynagrodzenie jest prawidłowe – obliczamy podatek
    txtImpots.Text = "" & CLng(objImpôt.calculer(rdOui.Checked, CInt(incEnfants.Value), intSalaire))
  End Sub 'btnCalculer_Click
End Class

W tym miejscu wykorzystujemy plik assemblera impots.dll, będący wynikiem kompilacji klasy „impots” z rozdziału 2. Przypomnijmy, że plik ten można wygenerować w trybie konsoli za pomocą polecenia

dos>vbc /t:library impots.vb

Polecenie to generuje plik o nazwie impots.dll, zwany zestawem. Zestaw ten można następnie wykorzystać w różnych projektach. W naszym projekcie, w pliku VS.NET, korzystamy z okna właściwości projektu:

Image

Aby dodać odniesienie (zespół), klikamy prawym przyciskiem myszy na kluczową grupę „References” powyżej, wybieramy opcję [Ajouter une référence] i wskazujemy zespół [impots.dll], który wcześniej umieściliśmy w folderze projektu:

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

Po dołączeniu zestawu [impots.dll] do projektu klasa [impots] staje się znana projektowi. Wcześniej nie była. Inną metodą jest dołączenie pliku źródłowego impots.vb do projektu. W tym celu w oknie właściwości projektu należy kliknąć prawym przyciskiem myszy na projekcie, wybrać opcję [Ajouter/Ajouter un élément existant] i wskazać plik impots.vb.