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
W wyniku wykonania wyświetla się następujące okno:

Interfejs graficzny zazwyczaj dziedziczy po klasie bazowej System.Windows.Forms.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:
gdzie EventHandler jest funkcją „delegowaną” o następującej sygnaturze:
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:

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 |
![]() | |
![]() | |
![]() | |
![]() | |
![]() | |
![]() |
Parametr icon może przyjmować wartości spośród następujących stałych:
![]() | idem Stop | ||
to samo Ostrzeżenie | ![]() | ||
to samo jak Asterisk | ![]() | ||
![]() | to samo – ręcznie | ||
![]() |
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
- Uruchom VS.NET i wybierz opcję Fichier/Nouveau/Projet

- podaj parametry swojego projektu
![]() |
- wybierz typ projektu, który chcesz stworzyć, w tym przypadku projekt VB.NET (1)
- wybierz typ aplikacji, którą chcesz skompilować, w tym przypadku aplikację dla systemu Windows (2)
- wskazuj, w którym folderze chcesz umieścić podfolder projektu (3)
- podaj nazwę projektu (4). Będzie to również nazwa folderu, w którym będą znajdować się pliki projektu
- nazwa tego folderu jest podana w polu (5)
- 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:

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

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

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:

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:

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:

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:

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:
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]:

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]:

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ę:
a następnie skompilujmy ponownie:
Tym razem wszystko działa. Uruchommy:

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:
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:

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:

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

Na niektóre z tych właściwości warto zwrócić uwagę:
aby ustawić kolor tła okna | |
do ustawienia koloru rysunków lub tekstu w oknie | |
aby przypisać menu do okna | |
aby nadać tytuł oknu | |
aby określić typ okna | |
aby ustawić czcionkę tekstu w oknie | |
w celu ustawienia nazwy okna |
W tym przypadku ustalamy właściwości Text i Name:
Pola wprowadzania danych i przyciski – 1 | |
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:
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:
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
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
name: cmdAfficher, text: Wyświetl
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:

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

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:
obiekt będący źródłem zdarzenia (w tym przypadku przycisk) | |
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:

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:
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 | |
formularz jest w trakcie zamykania | |
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:

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 | |
aby określić, czy kontrolka ma paski przewijania (Horizontal, Vertical, Both), czy nie (None) | |
jeśli wartość wynosi „true”, naciśnięcie klawisza Enter spowoduje przejście do następnej linii | |
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 | |
lista rozwijana z polem edycji | |
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:
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 | |
element i z listy rozwijanej | |
dodaje obiekt o jako ostatni element listy rozwijanej | |
dodaje tablicę obiektów na końcu listy rozwijanej | |
dodaje obiekt o na pozycji i listy rozwijanej | |
usuwa element i z listy rozwijanej | |
usuwa obiekt o z listy rozwijanej | |
usuwa wszystkie elementy z listy rozwijanej | |
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.

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 | |
mysz właśnie opuściła obszar kontroli | |
mysz porusza się w obszarze kontrolnym | |
Naciśnięcie lewego przycisku myszy | |
Zwolnienie lewego przycisku myszy | |
użytkownik upuszcza obiekt na element sterujący | |
użytkownik wchodzi w obszar kontrolki, przeciągając obiekt | |
użytkownik opuszcza obszar kontrolki, przeciągając obiekt | |
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:

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.



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

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

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:

W naszym przykładzie wykorzystano dwie właściwości:
nazwa elementu sterującego menu | |
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”:

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:

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”:

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:

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:

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:

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”:

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:

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:
typy plików dostępne w rozwijanej liście typów plików w oknie dialogowym | |
numer typu pliku proponowanego domyślnie na powyższej liście. Zaczyna się od 0. | |
folder domyślnie wyświetlany do zapisania pliku | |
nazwa pliku zapasowego podana przez użytkownika | |
metoda wyświetlająca okno dialogowe tworzenia kopii zapasowej. Zwraca wynik typu DialogResult. |
Metoda ShowDialog wyświetla okno dialogowe podobne do poniższego:
![]() |
lista rozwijana utworzona na podstawie właściwości Filter. Domyślny typ pliku jest ustalany przez FilterIndex | |
bieżący katalog, określony przez InitialDirectory, jeśli ta właściwość została wypełniona | |
nazwa pliku wybrana lub wpisana bezpośrednio przez użytkownika. Będzie dostępna we właściwości FileName | |
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:
- Należy określić typy plików, które mają zostać wyświetlone
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
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:
typy plików dostępne w rozwijanej liście typów plików w oknie dialogowym | |
numer typu pliku proponowanego domyślnie na powyższej liście. Zaczyna się od 0. | |
folder wyświetlany domyślnie podczas wyszukiwania pliku do otwarcia | |
nazwa pliku do otwarcia podana przez użytkownika | |
metoda wyświetlająca okno dialogowe zapisu. Zwraca wynik typu DialogResult. |
Metoda ShowDialog wyświetla okno dialogowe podobne do poniższego:
![]() |
lista rozwijana utworzona na podstawie właściwości Filter. Domyślny typ pliku jest ustalany przez metodę FilterIndex | |
bieżący katalog, określony przez InitialDirectory, jeśli ta właściwość została wypełniona | |
nazwa pliku wybrana lub wpisana bezpośrednio przez użytkownika. Będzie dostępna w właściwości FileName | |
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:
- Należy określić typy plików, które mają zostać wyświetlone
- Ustalamy typ pliku, który ma być wyświetlany na początku
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:
- 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:

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

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:

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:

Zegar zatrzymany:

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:

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:

Spośród jej właściwości zwrócimy uwagę jedynie na następujące:
liczba milisekund, po upływie której generowane jest zdarzenie Tick. | |
zdarzenie wygenerowane po upływie Interval milisekund | |
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 |
RadioButton | rdOui | zaznaczone, jeśli jest żonaty | |
RadioButton | rdNon | zaznaczyć, jeśli nie jest żonaty/zamężna | |
NumericUpDown | incEnfants | liczba dzieci podatnika Minimum=0, Maksimum=20, Przyrost=1 | |
TextBox | txtSalaire | roczne wynagrodzenie podatnika w F | |
TextBox | txtImpots | kwota podatku do zapłaty ReadOnly=true | |
Przycisk | btnCalculer | uruchamia obliczenie podatku | |
Przycisk | btnEffacer | przywraca formularz do stanu początkowego podczas ładowania | |
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:

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
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:

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.















































