5. Grafische interfaces met VB.NET en VS.NET
Hier laten we zien hoe je grafische interfaces kunt bouwen met VB.NET. Eerst bekijken we welke basisklassen van het .NET-platform we kunnen gebruiken om een grafische interface te bouwen. In eerste instantie gebruiken we geen tools voor automatische generatie. Vervolgens zullen we Visual Studio.NET (VS.NET) gebruiken, een ontwikkeltool van Microsoft die het ontwikkelen van applicaties met de .NET-talen vergemakkelijkt, en met name het bouwen van grafische interfaces. De gebruikte versie VS.NET is de Engelse versie.
5.1. De basisprincipes van grafische gebruikersinterfaces
5.1.1. Een eenvoudig venster
Laten we eens kijken naar de volgende code:
' opties
Option Strict On
Option Explicit On
' naamruimten
Imports System
Imports System.Drawing
Imports System.Windows.Forms
' de formulierklasse
Public Class Form1
Inherits Form
' de fabrikant
Public Sub New()
' venstertitel
Me.Text = "Mon premier formulaire"
' afmetingen van het venster
Me.Size = New System.Drawing.Size(300, 100)
End Sub
' testfunctie
Public Shared Sub Main(ByVal args() As String)
' het formulier wordt weergegeven
Application.Run(New Form1)
End Sub
End Class
De bovenstaande code wordt gecompileerd en vervolgens uitgevoerd
Tijdens de uitvoering wordt het volgende venster weergegeven:

Een grafische interface is doorgaans afgeleid van de basisklasse System.Windows.Forms.Form:
De basisklasse Form definieert een basisvenster met knoppen voor sluiten, vergroten/verkleinen, een aanpasbare grootte, ... en beheert de gebeurtenissen op deze grafische objecten. Hier specialiseren we de basisklasse door er een titel en de breedte (300) en hoogte (100) aan toe te wijzen. Dit gebeurt in de constructor:
Public Sub New()
' venstertitel
Me.Text = "Mon premier formulaire"
' afmetingen van het venster
Me.Size = New System.Drawing.Size(300, 100)
End Sub
De titel van het venster wordt bepaald door de eigenschap Text en de afmetingen door de eigenschap Size. Size is gedefinieerd in de naamruimte System.Drawing en is een structuur. De procedure Main start de grafische toepassing als volgt:
Application.Run(New Form1)
Er wordt een formulier van het type Form1 aangemaakt en weergegeven, waarna de applicatie luistert naar gebeurtenissen die op het formulier plaatsvinden (muisklikken, muisbewegingen, ...) en de gebeurtenissen uitvoert die door het formulier worden ondersteund. In dit geval verwerkt ons formulier geen andere gebeurtenissen dan die welke worden verwerkt door de basisklasse Form (klikken op knoppen voor sluiten, vergroten/verkleinen, het venster vergroten of verkleinen, het venster verplaatsen, enz.).
5.1.2. Een formulier met een knop
Laten we nu een knop aan ons venster toevoegen:
' opties
Option Strict On
Option Explicit On
' naamruimten
Imports System
Imports System.Drawing
Imports System.Windows.Forms
' de formulierklasse
Public Class Form1
Inherits Form
' attributen
Private cmdTest As Button
' de constructor
Public Sub New()
' de titel
Me.Text = "Mon premier formulaire"
' de afmetingen
Me.Size = New System.Drawing.Size(300, 100)
' een knop
' aanmaken
Me.cmdTest = New Button
' positie
cmdTest.Location = New System.Drawing.Point(110, 20)
' grootte
cmdTest.Size = New System.Drawing.Size(80, 30)
' tekst
cmdTest.Text = "Test"
' gebeurtenisbeheerder
AddHandler cmdTest.Click, AddressOf cmdTest_Click
' knop aan formulier toevoegen
Me.Controls.Add(cmdTest)
End Sub
' gebeurtenisbeheerder
Private Sub cmdTest_Click(ByVal sender As Object, ByVal evt As EventArgs)
' er is op de knop geklikt – dit wordt gemeld
MessageBox.Show("Clic sur bouton", "Clic sur bouton", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
' testfunctie
Public Shared Sub Main(ByVal args() As String)
' het formulier wordt weergegeven
Application.Run(New Form1)
End Sub
End Class
We hebben een knop aan het formulier toegevoegd:
' een knop
' aanmaken
Me.cmdTest = New Button
' positie
cmdTest.Location = New System.Drawing.Point(110, 20)
' grootte
cmdTest.Size = New System.Drawing.Size(80, 30)
' tekst
cmdTest.Text = "Test"
' gebeurtenisbeheerder
AddHandler cmdTest.Click, AddressOf cmdTest_Click
' knop aan formulier toevoegen
Me.Controls.Add(cmdTest)
De eigenschap Location stelt de coördinaten (110,20) van de linkerbovenhoek van de knop in met behulp van een structuur Point. De breedte en hoogte van de knop worden ingesteld op (80,30) met behulp van een structuur Size. Met de eigenschap Text van de knop kan de tekst van de knop worden ingesteld. De klasse ‘knop’ heeft een Click-gebeurtenis die als volgt is gedefinieerd:
waarbij EventHandler een „gedelegeerde” functie is met de volgende signatuur:
Dit betekent dat de gebeurtenishandler [Click] voor de knop de handtekening van de gedelegeerde functie [EventHandler] moet hebben. Wanneer hier op de knop cmdTest wordt geklikt, wordt de methode cmdTest_Click aangeroepen. Deze is als volgt gedefinieerd, in overeenstemming met het voorgaande sjabloon EventHandler:
' gebeurtenisbeheerder
Private Sub cmdTest_Click(ByVal sender As Object, ByVal evt As EventArgs)
' er is op de knop geklikt – dit wordt gemeld
MessageBox.Show("Clic sur bouton", "Clic sur bouton", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
Er wordt alleen een bericht weergegeven:

De klasse wordt gecompileerd en uitgevoerd:
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
De klasse MessageBox wordt gebruikt om berichten in een venster weer te geven. We hebben hier de constructor gebruikt
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 | het weer te geven bericht |
caption | de titel van het venster |
buttons | de knoppen in het venster |
icon | het pictogram in het venster |
De parameter buttons kan de volgende constantewaarden aannemen:
constante | knoppen |
![]() | |
![]() | |
![]() | |
![]() | |
![]() | |
![]() |
De parameter icon kan een van de volgende constante waarden aannemen:
![]() | idem Stop | ||
idem Waarschuwing | ![]() | ||
idem Asterisk | ![]() | ||
![]() | idem Hand | ||
![]() |
De methode Show is een statische methode die een resultaat van het type System.Windows.Forms.DialogResult retourneert, wat een opsomming is:
public enum System.Windows.Forms.DialogResult
{
Abort = 0x00000003,
Cancel = 0x00000002,
Ignore = 0x00000005,
No = 0x00000007,
None = 0x00000000,
OK = 0x00000001,
Retry = 0x00000004,
Yes = 0x00000006,
}
Om te weten op welke knop de gebruiker heeft gedrukt om het venster van het type MessageBox te sluiten, schrijven we:
dim res as DialogResult=MessageBox.Show(..)
if res=DialogResult.Yes then
' er is op de knop 'Ja' gedrukt
...
end if
5.2. Een grafische interface bouwen met Visual Studio.NET
We nemen enkele van de eerder besproken voorbeelden opnieuw onder de loep en bouwen ze nu met Visual Studio.NET.
5.2.1. Het project aanmaken
- Start VS.NET en selecteer de optie Fichier/Nouveau/Projet

- Voer de specificaties van uw project in
![]() |
- selecteer het type project dat u wilt bouwen, in dit geval een VB.NET-project (1)
- selecteer het type applicatie dat u wilt bouwen, in dit geval een Windows-applicatie (2)
- geef aan in welke map u de submap van het project wilt plaatsen (3)
- Geef de naam van het project op (4). Dit wordt ook de naam van de map waarin de projectbestanden worden opgeslagen
- De naam van deze map wordt weergegeven in (5)
- Er worden vervolgens een aantal mappen en bestanden aangemaakt in de map i4:
submappen van de map project1 ![]() |
Van deze bestanden is er slechts één van belang, namelijk het bestand form1.cs. Dit is het bronbestand dat hoort bij het formulier dat is aangemaakt door VS.NET. We komen hier later op terug.
5.2.2. De vensters van de interface van VS.NET
De interface van VS.NET toont nu bepaalde elementen van ons project i4:
We hebben een ontwerpvenster voor de grafische interface:
![]() |
Door besturingselementen uit de werkbalk (toolbox 2) te selecteren en deze op het vensteroppervlak (1) te plaatsen, kunnen we een grafische interface bouwen. Als we de muis over de "toolbox" bewegen, wordt deze vergroot en verschijnen er een aantal besturingselementen:

Voorlopig gebruiken we er nog geen. Nog steeds op het scherm van VS.NET vinden we het venster van de oplossingsverkenner "Explorer Solution":

In eerste instantie zullen we dit venster nog niet veel gebruiken. Het toont alle bestanden waaruit het project bestaat. Slechts één daarvan is voor ons van belang: het bronbestand van ons programma, in dit geval Form1.vb. Door met de rechtermuisknop op Form1.vb te klikken, verschijnt er een menu waarmee we toegang krijgen tot de broncode van onze grafische interface (Code weergeven) of tot de grafische interface zelf (View Designer):

Je kunt deze twee entiteiten rechtstreeks openen vanuit het venster ‘Solution Explorer’:
![]() | ![]() |
De geopende vensters ‘stapelen’ zich op in het hoofdontwerpvenster:

Hier verwijst Form1.vb[Design] naar het ontwerpvenster en Form1.vb naar het codevenster. U hoeft alleen maar op een van de tabbladen te klikken om van het ene venster naar het andere te schakelen. Een ander belangrijk venster dat op het scherm van VS.NET te zien is, is het eigenschappenvenster:

De eigenschappen die in het venster worden weergegeven, zijn die van het besturingselement dat momenteel is geselecteerd in het grafische ontwerpvenster. Via het menu Affichage krijgt men toegang tot verschillende vensters van het project:

Hier vindt u de zojuist beschreven hoofdvensters en de bijbehorende sneltoetsen.
5.2.3. Een project uitvoeren
Hoewel we nog geen code hebben geschreven, hebben we al een uitvoerbaar project. Voer F5 of Déboguer/Démarrer uit om het project uit te voeren. We krijgen dan het volgende venster te zien:

Dit venster kan worden vergroot, geminimaliseerd, in grootte worden aangepast en gesloten.
5.2.4. De door VS.NET gegenereerde code
Laten we eens kijken naar de code (Affichage/Code) van onze applicatie:
Public Class Form1
Inherits System.Windows.Forms.Form
#Regio "Code gegenereerd door de Windows Form Designer"
Public Sub New()
MyBase.New()
'Deze aanroep is vereist door de Windows Form Designer.
InitializeComponent()
'Voeg een willekeurige initialisatie toe na de aanroep InitializeComponent()
End Sub
'De vervangen methode verwijdert het formulier om de lijst met componenten op te schonen.
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
'Vereist door de Windows Form Designer
Private components As System.ComponentModel.IContainer
'REMARQUE: de volgende procedure is vereist door de Windows Form Designer
'Deze kan worden gewijzigd met behulp van de Windows Form Designer.
'Wijzig deze niet met behulp van de code-editor.
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
components = New System.ComponentModel.Container()
Me.Text = "Form2"
End Sub
#Einde regio
End Class
Een grafische interface is afgeleid van de basisklasse System.Windows.Forms.Form:
De basisklasse Form definieert een basisvenster met knoppen voor sluiten, vergroten/verkleinen, een aanpasbare grootte, ... en beheert de gebeurtenissen op deze grafische objecten. De constructor van het formulier maakt gebruik van een methode InitializeComponent waarin de besturingselementen van het formulier worden aangemaakt en geïnitialiseerd.
Public Sub New()
MyBase.New()
'Deze aanroep is vereist door de Windows Form Designer.
InitializeComponent()
'Voeg een willekeurige initialisatie toe na de aanroep InitializeComponent()
End Sub
Alle andere taken in de constructor kunnen worden uitgevoerd na het aanroepen van InitializeComponent. De methode 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
stelt de titel van het venster "Form1", de breedte (292) en de hoogte (53) vast. De titel van het venster wordt bepaald door de eigenschap Text en de afmetingen door de eigenschap Size. Size is gedefinieerd in de naamruimte System.Drawing en is een structuur. Om deze toepassing uit te voeren, moeten we de hoofdmodule van het project definiëren. Hiervoor gebruiken we de optie [Projets/Propriétés]:

In [Objet de démarrage] geven we [Form1] op, het formulier dat we zojuist hebben aangemaakt. Om de uitvoering te starten, gebruiken we de optie [Déboguer/Démarrer]:

5.2.5. Compileren in een DOS-venster
Laten we nu eens proberen deze toepassing te compileren en uit te voeren in een DOS-venster:
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'.
De compiler geeft aan dat hij de procedure [Main] niet kan vinden. Dit komt doordat VS.NET deze niet heeft gegenereerd. We zijn deze echter al tegengekomen in de voorgaande voorbeelden. Ze heeft de volgende vorm:
Shared Sub Main()
' de app wordt gestart
Application.Run(New Form1) ' où Form1 est le formulaire
End Sub
Laten we de bovenstaande code toevoegen aan de code van [Form1.vb] en opnieuw compileren:
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)
~~~~~~~~~~~
Deze keer is de naam [Application] niet bekend. Dit betekent simpelweg dat we de naamruimte [System.Windows.Forms] niet hebben geïmporteerd. Laten we de volgende instructie toevoegen:
en vervolgens opnieuw compileren:
Deze keer lukt het wel. Laten we het volgende uitvoeren:

Er wordt een formulier van het type Form1 aangemaakt en weergegeven. Het toevoegen van de procedure [Main] kan worden vermeden door de optie /m van de compiler te gebruiken, waarmee de uit te voeren klasse kan worden gespecificeerd in het geval dat deze afstamt van System.Windows.Form:
De optie /m:form2 geeft aan dat de uit te voeren klasse de klasse met de naam [form2] is.
5.2.6. Gebeurtenisafhandeling
Zodra het formulier wordt weergegeven, luistert de toepassing naar gebeurtenissen die op het formulier plaatsvinden (klikken, muisbewegingen, ...) en laat ze uitvoeren die door het formulier worden afgehandeld. In dit geval ondersteunt ons formulier geen andere gebeurtenissen dan die welke worden ondersteund door de basisklasse Form (klikken op knoppen voor sluiten, vergroten/verkleinen, wijzigen van de venstergrootte, verplaatsen van het venster, ...). Het gegenereerde formulier maakt gebruik van een attribuut components dat nergens wordt gebruikt. De methode dispose heeft hier eveneens geen functie. Hetzelfde geldt voor bepaalde gebruikte naamruimten (Collections, ComponentModel, Data) en voor de naamruimte die voor het project is gedefinieerd: projet1. Daarom kan de code in dit voorbeeld worden vereenvoudigd tot het volgende:
Imports System
Imports System.Drawing
Imports System.Windows.Forms
Public Class Form1
Inherits System.Windows.Forms.Form
' constructor
Public Sub New()
' het formulier wordt opgebouwd met zijn componenten
InitializeComponent()
End Sub
Private Sub InitializeComponent()
' venstergrootte
Me.Size = New System.Drawing.Size(300, 300)
' venstertitel
Me.Text = "Form1"
End Sub
Shared Sub Main()
' de app wordt gestart
Application.Run(New Form1)
End Sub
End Class
5.2.7. Conclusie
We nemen nu de door VS.NET gegenereerde code zoals deze is en voegen er alleen onze eigen code aan toe, met name om de gebeurtenissen te beheren die verband houden met de verschillende controlevelden van het formulier.
5.3. Venster met invoerveld, knop en tekstlabel
5.3.1. Grafisch ontwerp
In het vorige voorbeeld hadden we nog geen componenten in het venster geplaatst. We beginnen een nieuw project met de naam interface2. Hiervoor volgen we de eerder beschreven procedure om een project aan te maken:

Laten we nu een venster maken met een knop, een label en een invoerveld:
![]() |
De velden zijn als volgt:
nr. | naam | type | rol |
1 | lblSaisie | Label | een omschrijving |
2 | txtSaisie | TextBox | een invoerveld |
3 | btnAfficher | Knop | om de inhoud van het invoerveld txtSaisie in een dialoogvenster weer te geven |
U kunt als volgt te werk gaan om dit venster te maken: klik met de rechtermuisknop in het venster buiten een component en kies de optie Properties om toegang te krijgen tot de eigenschappen van het venster:

Het eigenschappenvenster verschijnt dan aan de rechterkant:

Enkele van deze eigenschappen zijn het vermelden waard:
om de achtergrondkleur van het venster in te stellen | |
om de kleur van de afbeeldingen of tekst in het venster in te stellen | |
om een menu aan het venster te koppelen | |
om het venster een titel te geven | |
om het type venster vast te stellen | |
om het lettertype van de tekst in het venster in te stellen | |
om de naam van het venster vast te leggen |
Hier stellen we de eigenschappen Text en Name in:
Invoervelden & knoppen - 1 | |
frmSaisiesBoutons |
Met behulp van de balk "Werkgereedschap"
- selecteer je de componenten die je nodig hebt
- plaats ze in het venster en geef ze de juiste afmetingen
![]() | ![]() |
Zodra u het onderdeel in de "toolbox" hebt gekozen, gebruikt u de toets "Esc" om de werkbalk te verbergen, en plaats vervolgens en pas de afmetingen van de component aan. Doe dit voor de drie : Label, TextBox, Button. Om de componenten uit te lijnen en de componenten op de juiste manier te dimensioneren, gebruik je het menu Format: | ![]() |
Het principe van de opmaak is als volgt:
Met de optie Align kunt u componenten uitlijnen | ![]() |
Met de optie Make Same Size kunt u ervoor zorgen dat componenten dezelfde hoogte of dezelfde breedte krijgen: | ![]() |
Met de optie 'Horizontal Spacing' kun je bijvoorbeeld componenten horizontaal uit te lijnen met afstanden van gelijke grootte. Hetzelfde geldt geldt voor de optie ‘Vertical Spacing’ om componenten verticaal uit te lijnen. Met de optie 'Center in Form' kun je een component horizontaal of verticaal in het venster te centreren: | ![]() |
Zodra de componenten correct in het venster zijn geplaatst, stelt u hun eigenschappen in. Klik hiervoor met de rechtermuisknop op de component en kies de optie Properties:
Selecteer de component om het eigenschappenvenster te openen. Wijzig daarin de volgende eigenschappen aan: naam: lblSaisie, tekst: Invoer
Selecteer de component om het eigenschappenvenster te openen. Wijzig daarin de volgende eigenschappen: naam: txtSaisie, tekst: laat leeg
name: cmdAfficher, text: Weergeven
text: Invoervelden & knoppen - 1 | ![]() |
We kunnen ons project uitvoeren (Ctrl-F5) om een eerste indruk te krijgen van het venster in actie: | ![]() |
Sluit het venster. Nu moeten we nog de procedure schrijven die wordt geactiveerd wanneer op de knop wordt geklikt: Afficher.
5.3.2. Beheer van gebeurtenissen in een formulier
Laten we eens kijken naar de code die door de grafische ontwerper is gegenereerd:
...
Public Class frmSaisiesBoutons
Inherits System.Windows.Forms.Form
' componenten
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
' constructor
Public Sub New()
InitializeComponent()
End Sub
...
' initialisatie van de componenten
Private Sub InitializeComponent()
...
End Sub
End Class
Allereerst valt de specifieke declaratie van de componenten op:
- het sleutelwoord `Friend` geeft aan dat de component zichtbaar is voor alle klassen in het project
- het sleutelwoord WithEvents geeft aan dat de component gebeurtenissen genereert. We gaan nu kijken hoe we deze gebeurtenissen kunnen beheren
Open het codevenster van het formulier (Weergave/code of F7):
![]() |
Het bovenstaande venster bevat twee vervolgkeuzelijsten (1) en (2). Lijst (1) is de lijst met formuliercomponenten:

Lijst (2) is de lijst met gebeurtenissen die gekoppeld zijn aan de in (1) geselecteerde component:

Een van de gebeurtenissen die aan de component is gekoppeld, wordt vetgedrukt weergegeven (hier: Click). Dit is de standaardgebeurtenis van de component. U kunt de handler voor deze specifieke gebeurtenis openen door te dubbelklikken op de component in het ontwerpvenster. VB.net genereert dan automatisch het skelet van de gebeurtenishandler in het codevenster en plaatst de gebruiker daarop. De handlers van de andere gebeurtenissen zijn te openen in het codevenster door de component in de lijst (1) en de gebeurtenis in (2) te selecteren. VB.net genereert dan het skelet van de gebeurtenishandler of plaatst de cursor erop als deze al was gegenereerd:
Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAfficher.Click
...
End Sub
Standaard noemt VB.net C_E de gebeurtenishandler E van component C. Deze naam kan naar wens worden gewijzigd. Dit wordt echter afgeraden. Ontwikkelaars van VB behouden doorgaans de door VB gegenereerde naam, wat zorgt voor een consistente naamgeving in alle VB-programma's. De koppeling van de procedure btnAfficher_Click aan de Click-gebeurtenis van de component btnAfficher gebeurt niet via de naam van de procedure, maar via het sleutelwoord handles:
Handles btnAfficher.Click
Hierboven geeft het sleutelwoord **handles aan dat de procedure de Click-gebeurtenis van de component btnAfficher** afhandelt. De voorgaande gebeurtenishandler heeft twee parameters:
het object dat de gebeurtenis veroorzaakt (in dit geval de knop) | |
een object EventArgs dat de details van de gebeurtenis bevat |
We zullen hier geen van deze parameters gebruiken. We hoeven nu alleen nog maar de code aan te vullen. Hier willen we een dialoogvenster weergeven met daarin de inhoud van het veld txtSaisie:
Private Sub btnAfficher_Click(ByVal sender As Object, ByVal e As System.EventArgs)
' de tekst weergeven die in het invoerveld is ingevoerd TxtSaisie
MessageBox.Show("texte saisi= " + txtsaisie.Text, "Vérification de la saisie", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
Als we de applicatie uitvoeren, krijgen we het volgende te zien:

5.3.3. Een andere methode om gebeurtenissen te beheren
Voor de knop btnAfficher heeft VS.NET de volgende code gegenereerd:
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
...
' behandeling van een eventuele klik op de knop cmdAfficher
Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAfficher.Click
...
End Sub
We kunnen de procedure btnAfficher_Click op een andere manier koppelen aan de Click-gebeurtenis van de knop btnAfficher:
Private Sub InitializeComponent()
...
'
'btnAfficher
'
Me.btnAfficher.Location = New System.Drawing.Point(102, 48)
Me.btnAfficher.Name = "btnAfficher"
Me.btnAfficher.Size = New System.Drawing.Size(88, 24)
Me.btnAfficher.TabIndex = 2
Me.btnAfficher.Text = "Afficher"
AddHandler btnAfficher.Click, AddressOf btnAfficher_Click
...
End Sub
...
' gebeurtenisbeheerder bij klik op knop cmdAfficher
Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
...
End Sub
De procedure btnAfficher_Click heeft het trefwoord Handles verloren en daarmee ook de koppeling met de gebeurtenis btnAfficher.Click. Deze koppeling wordt nu gemaakt met behulp van het trefwoord AddHandler:
AddHandler btnAfficher.Click, AddressOf btnAfficher_Click
De bovenstaande code, die in de procedure InitializeComponent van het formulier wordt geplaatst, koppelt de procedure met de naam btnAfficher_Click aan de gebeurtenis btnAfficher.Click. Bovendien heeft de component btnAfficher het trefwoord WithEvents niet meer nodig:
Friend btnAfficher As System.Windows.Forms.Button
Wat is het verschil tussen beide methoden?
- Met het sleutelwoord `handles` kan een gebeurtenis alleen tijdens het ontwerpen aan een procedure worden gekoppeld. De ontwerper weet van tevoren dat een procedure P de gebeurtenissen E1, E2, ... moet afhandelen en schrijft de code
Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) handles E1, E2, ..., En
Het is inderdaad mogelijk dat een procedure meerdere gebeurtenissen afhandelt.
- Met het sleutelwoord `addhandler` kan tijdens de uitvoering een gebeurtenis aan een procedure worden gekoppeld. Dit is nuttig in een ‘producent-consument’-context voor gebeurtenissen. Een object genereert een specifieke gebeurtenis die voor andere objecten van belang kan zijn. Deze objecten abonneren zich bij de producent om de gebeurtenis te ontvangen (bijvoorbeeld een temperatuur die een kritieke drempel heeft overschreden). Tijdens de uitvoering van de applicatie zal de producent van de gebeurtenis verschillende instructies moeten uitvoeren:
waarbij E de door de producent geproduceerde gebeurtenis is en Pi de procedures die behoren tot de verschillende objecten die deze gebeurtenis verbruiken. In een volgend hoofdstuk zullen we nog terugkomen op een producent-consument-toepassing voor gebeurtenissen.
5.3.4. Conclusie
Uit de twee bestudeerde projecten kunnen we concluderen dat, zodra de grafische interface is gebouwd met VS.NET, het werk van de ontwikkelaar bestaat uit het schrijven van de gebeurtenishandlers die hij voor deze grafische interface wil beheren. We zullen voortaan alleen nog de code hiervan presenteren.
5.4. Enkele nuttige componenten
We presenteren nu diverse applicaties waarin de meest gangbare componenten worden gebruikt, om de belangrijkste methoden en eigenschappen ervan te ontdekken. Voor elke applicatie presenteren we de grafische interface en de relevante code, met name de gebeurtenishandlers.
5.4.1. Formulier
We beginnen met de onmisbare component: het formulier waarop componenten worden geplaatst. We hebben al enkele basis-eigenschappen ervan besproken. Hier gaan we dieper in op enkele belangrijke gebeurtenissen van een formulier.
het formulier wordt geladen | |
het formulier wordt gesloten | |
het formulier is gesloten |
De gebeurtenis Load vindt plaats nog voordat het formulier wordt weergegeven. De gebeurtenis Closing vindt plaats wanneer het formulier wordt gesloten. Dit sluiten kan nog programmatisch worden tegengehouden. We maken een formulier met de naam Form1 zonder componenten:

We verwerken de drie voorgaande gebeurtenissen:
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
' het formulier wordt voor het eerst geladen
MessageBox.Show("Evt Load", "Load")
End Sub
Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
' het formulier wordt gesloten
MessageBox.Show("Evt Closing", "Closing")
' er wordt om bevestiging gevraagd
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
' het formulier wordt gesloten
MessageBox.Show("Evt Closed", "Closed")
End Sub
We gebruiken de functie MessageBox om op de hoogte te worden gesteld van de verschillende gebeurtenissen. De gebeurtenis Closing vindt plaats wanneer de gebruiker het venster sluit. | ![]() |
We vragen hem dan of hij de applicatie echt wil afsluiten: | ![]() |
Als hij ‘Nee’ antwoordt, stellen we de eigenschap Cancel van de gebeurtenis CancelEventArgs die de methode als parameter heeft ontvangen. Als we deze eigenschap instellen op False, wordt het sluiten van het venster wordt afgebroken, anders gaat het door: | ![]() |
5.4.2. Label- en invoervakken TextBox
We zijn deze twee componenten al tegengekomen. Label is een tekstcomponent en TextBox een invoerveldcomponent. Hun belangrijkste eigenschap is Text, die ofwel de inhoud van het invoerveld ofwel de tekst van het label aangeeft. Deze eigenschap is lees- en schrijfbaar. De gebeurtenis die doorgaans voor TextBox wordt gebruikt, is TextChanged, die aangeeft dat de gebruiker het invoerveld heeft gewijzigd. Hier volgt een voorbeeld waarin de gebeurtenis TextChanged wordt gebruikt om de wijzigingen in een invoerveld bij te houden:
![]() |
nr. | type | naam | rol |
1 | TextBox | txtSaisie | invoerveld |
2 | Label | lblControle | geeft de tekst van 1 in realtime weer |
3 | Knop | cmdEffacer | om de velden 1 en 2 te wissen |
4 | Knop | cmdQuitter | om de applicatie te verlaten |
De relevante code voor deze applicatie is die van de gebeurtenishandlers:
' klik op de knop 'Afsluiten'
Private Sub cmdQuitter_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles cmdQuitter.Click
' klik op de knop 'Afsluiten' – de applicatie wordt afgesloten
Application.Exit()
End Sub
' wijziging in veld txtSaisie
Private Sub txtSaisie_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles txtSaisie.TextChanged
' de inhoud van TextBox is gewijzigd – deze wordt gekopieerd naar het label lblControle
lblControle.Text = txtSaisie.Text
End Sub
' klik op de knop 'Wissen'
Private Sub cmdEffacer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles cmdEffacer.Click
' de inhoud van het invoerveld wordt gewist
txtSaisie.Text = ""
End Sub
' er is een toets ingedrukt
Private Sub txtSaisie_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) _
Handles txtSaisie.KeyPress
' er wordt gekeken welke toets is ingedrukt
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
Let op de manier waarop de applicatie wordt afgesloten in de procedure cmdQuitter_Click: Application.Exit(). Het volgende voorbeeld maakt gebruik van een TextBox met meerdere regels:
![]() |
De lijst met besturingselementen is als volgt:
nr. | type | naam | rol |
1 | TextBox | txtMultiLignes | meerregelig invoerveld |
2 | TextBox | txtAjout | invoerveld met één regel |
3 | Knop | btnAjouter | Voegt de inhoud van 2 naar 1 toe |
Om een TextBox om te zetten naar een meerregelig veld, stelt u de volgende eigenschappen van het besturingselement in:
om meerdere regels tekst toe te staan | |
om aan te geven of het besturingselement scrollbalken moet hebben (Horizontal, Vertical, Both) of niet (None) | |
indien gelijk aan true, zorgt de Enter-toets ervoor dat er een nieuwe regel wordt ingevoegd | |
indien gelijk aan true, zal de Tab-toets een tabstop in de tekst genereren |
De relevante code is die welke de klik op de knop [Ajouter] verwerkt en die welke de wijziging van het invoerveld [txtAjout] verwerkt:
' eventueel btnAjouter_Click
Private Sub btnAjouter_Click1(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnAjouter.Click
' de inhoud van txtAjout wordt toegevoegd aan die van txtMultilignes
txtMultilignes.Text &= txtAjout.Text
txtAjout.Text = ""
End Sub
' evt txtAjout_TextChanged
Private Sub txtAjout_TextChanged1(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles txtAjout.TextChanged
' de status van de knop ‘Toevoegen’ wordt vastgelegd
btnAjouter.Enabled = txtAjout.Text.Trim() <> ""
End Sub
5.4.3. keuzelijsten ComboBox
![]() | ![]() |
Een ComboBox-component is een keuzelijst in combinatie met een invoerveld: de gebruiker kan ofwel een item selecteren in (2) of tekst invoeren in (1). Er zijn drie soorten ComboBox, bepaald door de eigenschap Style:
niet-uitklapbare lijst met bewerkingsveld | |
uitklapbare lijst met invoerveld | |
uitklaplijst zonder invoerveld |
Standaard is het type van een ComboBox DropDown. Om de klasse ComboBox te bekijken, typ je ComboBox in de helpindex (Aide/Index). De klasse ComboBox heeft één constructor:
Public Sub New() | maakt een leeg ComboBox-object aan |
De elementen van ComboBox zijn beschikbaar in de eigenschap Items:
Dit is een geïndexeerde eigenschap, waarbij Items(i) verwijst naar het i-de element van de combobox. Stel dat C een combobox is en C.Items de lijst met elementen. We hebben de volgende eigenschappen:
aantal elementen van de combobox | |
element i van de combobox | |
voegt het object o toe als laatste element van de combobox | |
voegt een array met objecten toe aan het einde van de combo | |
voegt het object o toe op positie i van de combobox | |
verwijdert element i uit de combobox | |
verwijdert het object o uit de combobox | |
verwijdert alle elementen uit de combo | |
geeft de positie i van het object o in de keuzelijst weer |
Het is misschien verrassend dat een keuzelijst objecten kan bevatten, terwijl deze gewoonlijk tekenreeksen bevat. Visueel gezien is dit inderdaad het geval. Als een ComboBox een object obj bevat, wordt de tekenreeks obj.ToString weergegeven(). We herinneren ons dat elk object een methode ToString heeft die is geërfd van de klasse object en die een tekenreeks retourneert die ‘representatief’ is voor het object. Het geselecteerde element in de keuzelijst C is C.SelectedItem of C.Items(C.SelectedIndex), waarbij C.SelectedIndex het nummer is van het geselecteerde element, dit nummer begint bij nul voor het eerste element.
Bij het selecteren van een item in de keuzelijst vindt de gebeurtenis SelectedIndexChanged plaats, die vervolgens kan worden gebruikt om een melding te krijgen over de wijziging in de selectie in de keuzelijst. In de volgende toepassing gebruiken we deze gebeurtenis om het item weer te geven dat in de lijst is geselecteerd.

We tonen alleen de relevante code van het venster. In de formulierconstructor vullen we de keuzelijst in:
Public Sub New()
' formulier aanmaken
InitializeComponent()
' combo invullen
cmbNombres.Items.AddRange(New String() {"zéro", "un", "deux", "trois", "quatre"})
' we selecteren het eerste element uit de lijst
cmbNombres.SelectedIndex = 0
End Sub
We verwerken de gebeurtenis SelectedIndexChanged van de keuzelijst die aangeeft dat er een nieuw item is geselecteerd:
Private Sub cmbNombres_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles cmbNombres.SelectedIndexChanged
' het geselecteerde element is gewijzigd – we geven het weer
MessageBox.Show("Elément sélectionné : (" & cmbNombres.SelectedItem.ToString & "," & cmbNombres.SelectedIndex & ")", "Combo", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
5.4.4. component ListBox
We stellen voor om de volgende interface te bouwen:
![]() |
De componenten van dit venster zijn de volgende:
nr. | type | naam | rol/eigenschappen |
0 | Form | Form1 | formulier - BorderStyle=FixedSingle |
1 | TextBox | txtSaisie | invoerveld |
2 | Knop | btnAjouter | knop waarmee de inhoud van invoerveld 1 aan lijst 3 kan worden toegevoegd |
3 | ListBox | listBox1 | lijst 1 |
4 | ListBox | listBox2 | lijst 2 |
5 | Knop | btn1TO2 | verplaatst de geselecteerde items van lijst 1 naar lijst 2 |
6 | Knop | cmd2T0 | doet het omgekeerde |
7 | Knop | btnEffacer1 | de lijst leegmaken 1 |
8 | Knop | btnEffacer2 | lijst 2 leegmaken |
- De gebruiker typt tekst in veld 1. Hij voegt deze toe aan lijst 1 met de knop Ajouter (2). Het invoerveld (1) wordt vervolgens leeggemaakt en de gebruiker kan een nieuw item toevoegen.
- Hij kan items van de ene lijst naar de andere verplaatsen door het te verplaatsen item in een van de lijsten te selecteren en de juiste verplaatsknop 5 of 6 te kiezen. Het verplaatste item wordt aan het einde van de doellijst toegevoegd en uit de bronlijst verwijderd.
- Hij kan dubbelklikken op een item in lijst 1. Dit item wordt dan naar het invoerveld verplaatst om te worden bewerkt en uit lijst 1 verwijderd.
De knoppen zijn ingeschakeld of uitgeschakeld volgens de volgende regels:
- de knop Ajouter is alleen actief als er tekst in het invoerveld staat
- de knop 5 voor het overzetten van lijst 1 naar lijst 2 is alleen actief als er een item is geselecteerd in lijst 1
- de knop 6 voor het overzetten van lijst 2 naar lijst 1 is alleen actief als er een item is geselecteerd in lijst 2
- de knoppen 7 en 8 voor het wissen van lijst 1 en lijst 2 zijn alleen verlicht als de te wissen lijst items bevat.
Onder de bovenstaande voorwaarden moeten alle knoppen bij het opstarten van de applicatie uitgeschakeld zijn. De eigenschap Enabled van de knoppen moet dan worden ingesteld op false. Dit kan tijdens het ontwerpen worden gedaan, waardoor de bijbehorende code in de methode InitializeComponent wordt gegenereerd, of we kunnen dit zelf in de constructor doen, zoals hieronder:
Public Sub New()
' het formulier wordt voor het eerst aangemaakt
InitializeComponent()
' aanvullende initialisaties
' een aantal knoppen worden uitgeschakeld
btnAjouter.Enabled = False
btn1TO2.Enabled = False
btn2TO1.Enabled = False
btnEffacer1.Enabled = False
btnEffacer2.Enabled = False
End Sub
De status van de knop Ajouter wordt bepaald door de inhoud van het invoerveld. Met de gebeurtenis TextChanged kunnen we de wijzigingen in deze inhoud volgen:
' wijziging in tekstinvoerveld
Private Sub txtSaisie_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles txtSaisie.TextChanged
' de inhoud van txtSaisie is gewijzigd
' de knop Toevoegen is alleen actief als het veld niet leeg is
btnAjouter.Enabled = txtSaisie.Text.Trim() <> ""
End Sub
De status van de overdrachtsknoppen hangt af van het feit of er al dan niet een item is geselecteerd in de lijst die ze beheren:
' wijziging van het geselecteerde element zonder listbox1
Private Sub listBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles listBox1.SelectedIndexChanged
' er is een element geselecteerd
' de knop voor overdracht van 1 naar 2 wordt geactiveerd
btn1TO2.Enabled = True
End Sub
' wijziging van het geselecteerde element zonder listbox2
Private Sub listBox2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles listBox2.SelectedIndexChanged
' er is een element geselecteerd
' de knop voor overdracht van 2 naar 1 wordt geactiveerd
btn2TO1.Enabled = True
End Sub
De code die hoort bij het klikken op de knop Ajouter is als volgt:
' klik op de knop Toevoegen
Private Sub btnAjouter_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnAjouter.Click
' een nieuw element toegevoegd aan lijst 1
listBox1.Items.Add(txtSaisie.Text.Trim())
' de invoer wordt gewist
txtSaisie.Text = ""
' Lijst 1 is niet leeg
btnEffacer1.Enabled = True
' focus terug naar het invoerveld
txtSaisie.Focus()
End Sub
Let op de methode Focus, waarmee de „focus” op een formulierveld kan worden geplaatst. De code die hoort bij het klikken op de knoppen Effacer:
' klik op knop Wissen1
Private Sub btnEffacer1_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnEffacer1.Click
' lijst 1 wordt gewist
listBox1.Items.Clear()
btnEffacer1.Enabled = False
End Sub
' klik op knop Wissen2
Private Sub btnEffacer2_Click(ByVal sender As Object, ByVal e As System.EventArgs)
' lijst 2 wordt gewist
listBox2.Items.Clear()
btnEffacer2.Enabled = False
End Sub
De code om de geselecteerde elementen van de ene lijst naar de andere over te zetten:
' klik op knop knop1naar2
Private Sub btn1TO2_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btn1TO2.Click
' het geselecteerde item wordt overgebracht van lijst 1 naar lijst 2
transfert(listBox1, listBox2)
' Knoppen 'Wissen'
btnEffacer2.Enabled = True
btnEffacer1.Enabled = listBox1.Items.Count <> 0
' overzetknoppen
btn1TO2.Enabled = False
btn2TO1.Enabled = False
End Sub
' klik op knop btn2to1
Private Sub btn2TO1_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btn2TO1.Click
' het geselecteerde item verplaatsen van Lijst 2 naar Lijst 1
transfert(listBox2, listBox1)
' knoppen Wissen
btnEffacer1.Enabled = True
btnEffacer2.Enabled = listBox2.Items.Count <> 0
' overzetknoppen
btn1TO2.Enabled = False
btn2TO1.Enabled = False
End Sub
' overzetten
Private Sub transfert(ByVal l1 As ListBox, ByVal l2 As ListBox)
' het geselecteerde item overbrengen van lijst 1 naar lijst l2
' een geselecteerd element?
If l1.SelectedIndex = -1 Then Return
' toevoegen aan l2
l2.Items.Add(l1.SelectedItem)
' verwijderen uit l1
l1.Items.RemoveAt(l1.SelectedIndex)
End Sub
Allereerst maken we een methode aan
Private Sub transfert(ByVal l1 As ListBox, ByVal l2 As ListBox)
die het geselecteerde element uit de lijst l1 overbrengt naar de lijst l2. Zo hebben we slechts één methode nodig in plaats van twee om een element van listBox1 naar listBox2 of van listBox2 naar listBox1 over te zetten. Voordat we de overdracht uitvoeren, controleren we of er daadwerkelijk een element is geselecteerd in de lijst l1:
' een geselecteerd element?
If l1.SelectedIndex = -1 Then Return
De eigenschap SelectedIndex heeft de waarde -1 als er momenteel geen item is geselecteerd. In de procedures
Private Sub btnXTOY_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnXTOY.Click
wordt de lijst X overgezet naar lijst Y en wordt de status van bepaalde knoppen aangepast om de nieuwe status van de lijsten weer te geven.
5.4.5. selectievakjes CheckBox, keuzerondjes ButtonRadio
We stellen voor om de volgende applicatie te schrijven:
![]() |
De componenten van het venster zijn als volgt:
nr. | type | naam | rol |
1 | RadioButton | radioButton1 radioButton2 radioButton3 | 3 keuzerondjes |
2 | CheckBox | chechBox1 chechBox2 chechBox3 | 3 selectievakjes |
3 | ListBox | lstValeurs | een lijst |
Als we de drie keuzerondjes achter elkaar plaatsen, maken ze standaard deel uit van dezelfde groep. Wanneer er dus één is aangevinkt, zijn de andere dat niet. De gebeurtenis die voor deze zes besturingselementen van belang is, is de gebeurtenis CheckChanged, die aangeeft dat de status van het selectievakje of het keuzerondje is gewijzigd. Deze status wordt in beide gevallen weergegeven door de booleaanse eigenschap Check, die, indien waar, aangeeft dat het besturingselement is aangevinkt. We hebben hier één enkele methode gebruikt om de zes gebeurtenissen CheckChanged te verwerken, namelijk de methode affiche:
' weergeeft
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
' geeft de status van de keuzeknop of het selectievakje weer
' is dit een selectievakje?
If (TypeOf (sender) Is CheckBox) Then
Dim chk As CheckBox = CType(sender, CheckBox)
lstValeurs.Items.Insert(0, chk.Name & "=" & chk.Checked)
End If
' is dit een keuzerondje?
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
Met de syntaxis TypeOf (sender) Is CheckBox kan worden gecontroleerd of het object sender van het type CheckBox is. Hierdoor kunnen we vervolgens een typeconversie uitvoeren naar het exacte type van sender. De methode affiche schrijft in de lijst lstValeurs de naam van de component die de gebeurtenis heeft veroorzaakt en de waarde van de eigenschap Checked. Tijdens de uitvoering zien we dat een klik op een keuzeknop twee gebeurtenissen CheckChanged veroorzaakt: één op de oude aangevinkte knop, die nu „niet aangevinkt” wordt, en één op de nieuwe knop, die nu „aangevinkt” wordt.
5.4.6. schakelaars ScrollBar
Er zijn verschillende soorten variatoren: de horizontale variator (hScrollBar), de verticale variator (vScrollBar) en de incrementeerder (NumericUpDown). | ![]() |
Laten we de volgende toepassing maken:
![]() |
nr. | type | naam | rol |
1 | hScrollBar | hScrollBar1 | een horizontale variator |
2 | hScrollBar | hScrollBar2 | een horizontale variator die de variaties van variator 1 volgt |
3 | TextBox | txtValeur | geeft de waarde van de horizontale regelaar weer ReadOnly=true om invoer te voorkomen |
4 | NumericUpDown | incrementator | maakt het mogelijk de waarde van regelaar 2 vast te zetten |
- Met een schuifregelaar van het type ScrollBar kan de gebruiker een waarde kiezen binnen een bereik van gehele getallen, gesymboliseerd door de "strook" van de schuifregelaar waarover een cursor beweegt. De waarde van de schuifregelaar is beschikbaar in de eigenschap Value.
- Bij een horizontale schuifregelaar vertegenwoordigt het linkeruiteinde de minimumwaarde van het bereik, het rechteruiteinde de maximumwaarde en de schuifknop de huidige geselecteerde waarde. Bij een verticale schuifregelaar wordt het minimum vertegenwoordigd door het bovenste uiteinde en het maximum door het onderste uiteinde. Deze waarden worden weergegeven door de eigenschappen Minimum en Maximum en zijn standaard ingesteld op 0 en 100.
- Een klik op de uiteinden van de schuifregelaar verandert de waarde met één stap (positief of negatief), afhankelijk van het aangeklikte uiteinde, genaamd SmallChange, dat standaard 1 is.
- Een klik aan weerszijden van de schuifregelaar verandert de waarde met één stap (positief of negatief), afhankelijk van het aangeklikte uiteinde, genaamd LargeChange, dat standaard 10 is.
- Wanneer je op het bovenste uiteinde van een verticale schuifbalk klikt, neemt de waarde af. Dit kan de gemiddelde gebruiker verrassen, die normaal gesproken verwacht dat de waarde „stijgt“. Dit probleem los je op door de eigenschappen SmallChange en LargeChange een negatieve waarde te geven.
- Deze vijf eigenschappen (Value, Minimum, Maximum, SmallChange, LargeChange) zijn zowel lees- als schrijfbaar.
- De belangrijkste gebeurtenis van de regelaar is die welke een waardeverandering signaleert: de Scroll-gebeurtenis.
Een component NumericUpDown bevindt zich in de buurt van de regelaar: ook deze heeft de eigenschappen Minimum, Maximum en Value, standaard ingesteld op 0, 100, 0. Maar hier wordt de eigenschap Value weergegeven in een invoerveld dat integraal deel uitmaakt van het besturingselement. De gebruiker kan deze waarde zelf wijzigen, tenzij de eigenschap ReadOnly van het besturingselement op ‘waar’ is ingesteld. De waarde van de stapgrootte wordt bepaald door de eigenschap Increment, standaard 1. De belangrijkste gebeurtenis van de component NumericUpDown is degene die een waardeverandering signaleert: de gebeurtenis ValueChanged. De relevante code van onze toepassing is als volgt:
Het formulier wordt tijdens de opbouw opgemaakt:
' constructor
Public Sub New()
' eerste aanmaak van het formulier
InitializeComponent()
' we geven regelaar 2 dezelfde kenmerken als regelaar 1
hScrollBar2.Minimum = hScrollBar1.Value
hScrollBar2.Minimum = hScrollBar1.Minimum
hScrollBar2.Maximum = hScrollBar1.Maximum
hScrollBar2.LargeChange = hScrollBar1.LargeChange
hScrollBar2.SmallChange = hScrollBar1.SmallChange
' idem voor de incrementator
incrémenteur.Minimum = hScrollBar1.Value
incrémenteur.Minimum = hScrollBar1.Minimum
incrémenteur.Maximum = hScrollBar1.Maximum
incrémenteur.Increment = hScrollBar1.SmallChange
' aan TextBox wordt de waarde van regelaar 1 toegewezen
txtValeur.Text = "" & hScrollBar1.Value
End Sub
De handler die de waardeveranderingen van regelaar 1 bijhoudt:
' beheer van regelaar hscrollbar1
Private Sub hScrollBar1_Scroll(ByVal sender As Object, ByVal e As System.Windows.Forms.ScrollEventArgs) _
Handles hScrollBar1.Scroll
' wijziging van de waarde van regelaar 1
' de waarde wordt doorgegeven aan regelaar 2 en aan het tekstvak TxtValeur
hScrollBar2.Value = hScrollBar1.Value
txtValeur.Text = "" & hScrollBar1.Value
End Sub
De handler die de waardeveranderingen van regelaar 2 volgt:
' beheer van de schuifbalk hscrollbar2
Private Sub hScrollBar2_Scroll(ByVal sender As Object, ByVal e As System.Windows.Forms.ScrollEventArgs) _
Handles hScrollBar2.Scroll
' elke wijziging van regelaar 2 wordt geblokkeerd
' door deze te dwingen de waarde van variator 1 te behouden
e.NewValue = hScrollBar1.Value
End Sub
De manager die de veranderingen in de besturing incrémenteur bijhoudt:
' beheer van de incrementator
Private Sub incrémenteur_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles incrémenteur.ValueChanged
' de waarde van variator 2 wordt vastgezet
hScrollBar2.Value = CType(incrémenteur.Value, Integer)
End Sub
5.5. Muisgebeurtenissen
Wanneer je in een container tekent, is het belangrijk om de positie van de muis te kennen, bijvoorbeeld om bij een klik een punt weer te geven. De bewegingen van de muis veroorzaken gebeurtenissen in de container waarin de muis zich verplaatst.
![]() | ![]() |
de muis is zojuist het gebied van het besturingselement binnengekomen | |
de muis heeft zojuist het besturingsgebied verlaten | |
de muis beweegt binnen het besturingsgebied | |
De linkermuisknop is ingedrukt | |
De linkermuisknop loslaten | |
de gebruiker laat een object op het besturingselement los | |
de gebruiker komt in het gebied van het besturingselement door een object te slepen | |
de gebruiker verlaat het gebied van het besturingselement door een object te slepen | |
de gebruiker beweegt met een object over het besturingsgebied |
Hier is een programma waarmee je beter kunt begrijpen wanneer de verschillende muisgebeurtenissen plaatsvinden:
![]() |
nr. | type | naam | rol |
1 | Label | lblPosition | om de positie van de muis in formulier 1, lijst 2 of knop 3 weer te geven |
2 | ListBox | lstEvts | om andere muisgebeurtenissen weer te geven dan MouseMove |
3 | Knop | btnEffacer | om de inhoud van 2 te wissen |
De gebeurtenishandlers zijn als volgt. Om de muisbewegingen op de drie besturingselementen te volgen, schrijven we slechts één handler:
' evt. 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
' muisbeweging – de coördinaten (X,Y) van de muis worden weergegeven
lblPosition.Text = "(" & e.X & "," & e.Y & ")"
End Sub
Het is belangrijk om te weten dat telkens wanneer de muis het gebied van een besturingselement binnenkomt, het coördinatensysteem verandert. Het beginpunt (0,0) is de linkerbovenhoek van het besturingselement waarop de muis zich bevindt. Tijdens de uitvoering, wanneer de muis van het formulier naar de knop wordt verplaatst, is de verandering in coördinaten dus duidelijk zichtbaar. Om deze veranderingen in het muisgebied beter te kunnen zien, kun je de eigenschap Cursor van de besturingselementen gebruiken:

Met deze eigenschap kun je de vorm van de muiscursor instellen wanneer deze het bereik van het besturingselement binnenkomt. In ons voorbeeld hebben we de cursor ingesteld op Default voor het formulier zelf, op Hand voor lijst 2 en op No voor knop 3, zoals te zien is op de onderstaande schermafbeeldingen.



In de methode [InitializeComponent] is de code die door deze keuzes wordt gegenereerd als volgt:
Me.lstEvts.Cursor = System.Windows.Forms.Cursors.Hand
Me.btnEffacer.Cursor = System.Windows.Forms.Cursors.No
Om bovendien de muisbewegingen (in en uit) op lijst 2 te detecteren, verwerken we de gebeurtenissen MouseEnter en MouseLeave uit diezelfde lijst:
' event 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
' gebeurtenis 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
' geeft weer
Private Sub affiche(ByVal message As String)
' het bericht wordt bovenaan de lijst met gebeurtenissen weergegeven
lstEvts.Items.Insert(0, message)
End Sub

Om klikken op het formulier te verwerken, verwerken we de gebeurtenissen MouseDown en MouseUp:
' gebeurtenis 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
' gebeurtenis 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

Tot slot de code voor de klikhandler op de knop Effacer:
' gebeurtenis btnEffacer_Click
Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles btnEffacer.Click
' wist de lijst met gebeurtenissen
lstEvts.Items.Clear()
End Sub
5.6. Een venster met een menu maken
Laten we nu eens kijken hoe we een venster met een menu kunnen maken. We gaan het volgende venster maken:
![]() |
Besturingselement 1 is een alleen-lezen TextBox (ReadOnly=true) met de naam txtStatut. De menustructuur is als volgt:
![]() | ![]() |
Menuopties zijn besturingselementen, net als andere visuele componenten, en beschikken over eigenschappen en gebeurtenissen. Bijvoorbeeld de eigenschappenlijst van de menuoptie A1:

In ons voorbeeld worden twee eigenschappen gebruikt:
de naam van het menubesturingselement | |
de tekst van de menuoptie |
De eigenschappen van de verschillende menuopties in ons voorbeeld zijn als volgt:
Naam | Tekst |
mnuA | opties A |
mnuA1 | A1 |
mnuA2 | A2 |
mnuA3 | A3 |
mnuB | opties B |
mnuB1 | B1 |
mnuSep1 | - (scheidingsteken) |
mnuB2 | B2 |
mnuB3 | B3 |
mnuB31 | B31 |
mnuB32 | B32 |
Om een menu aan te maken, selecteert u de component "MainMenu" in de balk "ToolBox":

Je krijgt dan een leeg menu dat in het formulier wordt geplaatst met lege velden met de titel "Type Here". Je hoeft alleen maar de verschillende menuopties in te vullen:

Om een scheidingsteken in te voegen tussen twee opties, zoals hierboven tussen de opties B1 en B2, ga je naar de plaats waar het scheidingsteken in het menu moet komen, klik je met de rechtermuisknop en kies je de optie Insert Separator:

Als je de applicatie start met Ctrl-F5, krijg je een formulier te zien met een menu dat voorlopig nog niets doet. De menuopties worden behandeld als componenten: ze hebben eigenschappen en gebeurtenissen. Selecteer in [fenêtre de code] de component mnuA1 en selecteer vervolgens de bijbehorende gebeurtenissen:

Als hierboven de gebeurtenis Click wordt gegenereerd, genereert VS.NET automatisch de volgende procedure:
Private Sub mnuA1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuA.Click
....
End Sub
We zouden op deze manier voor alle menuopties te werk kunnen gaan. Hier kan voor alle opties dezelfde procedure worden gebruikt. Daarom hernoemen we de vorige procedure naar affiche en definiëren we de gebeurtenissen die deze procedure afhandelt:
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
' geeft in TextBox de naam van het geselecteerde submenu weer
txtStatut.Text = (CType(sender, MenuItem)).Text
End Sub
Bij deze methode geven we alleen de eigenschap Text van de menuoptie weer bij de bron van de gebeurtenis. De bron van de gebeurtenis sender is van het type object. De menuopties zijn van het type MenuItem, dus moeten we hier een typeconversie uitvoeren van object naar MenuItem. Start de toepassing en selecteer de optie A1 om het volgende bericht te krijgen:

De relevante code van deze applicatie is, naast die van de methode affiche, de code voor het opbouwen van het menu in de formulierbouwer (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
Let op de instructie die het menu aan het formulier koppelt:
Me.Menu = Me.mainMenu1
5.7. Niet-visuele componenten
We richten ons nu op een aantal niet-visuele componenten: deze worden gebruikt tijdens het ontwerpen, maar zijn niet zichtbaar tijdens de uitvoering.
5.7.1. Dialoogvensters OpenFileDialog en SaveFileDialog
We gaan de volgende applicatie bouwen:
![]() |
De besturingselementen zijn als volgt:
Nr. | type | naam | rol |
1 | TextBox meerdere regels | txtTexte | door de gebruiker ingevoerde tekst of tekst die uit een bestand is geladen |
2 | Knop | btnSauvegarder | hiermee kan de tekst uit 1 in een tekstbestand worden opgeslagen |
3 | Knop | btnCharger | hiermee kun je de inhoud van een tekstbestand in 1 laden |
4 | Knop | btnEffacer | wist de inhoud van 1 |
Er worden twee niet-visuele besturingselementen gebruikt:

Wanneer ze uit de "ToolBox" worden gehaald en op het formulier worden geplaatst, worden ze in een apart gebied onderaan het formulier geplaatst. De "Dialog"-componenten worden uit de "ToolBox" gehaald:

De code van de knop Effacer is eenvoudig:
Private Sub btnEffacer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnEffacer.Click
' het invoerveld wordt gewist
txtTexte.Text = ""
End Sub
De klasse SaveFileDialog is als volgt gedefinieerd:

Deze is afgeleid van meerdere klasseniveaus. Van de vele eigenschappen en methoden zullen we de volgende onthouden:
de bestandstypen die worden aangeboden in de vervolgkeuzelijst met bestandstypen in het dialoogvenster | |
het nummer van het bestandstype dat standaard in de bovenstaande lijst wordt aangeboden. Begint bij 0. | |
de map die aanvankelijk wordt weergegeven voor het opslaan van het bestand | |
de door de gebruiker opgegeven naam van het back-upbestand | |
methode die het dialoogvenster voor het opslaan weergeeft. Levert een resultaat van het type DialogResult op. |
De methode ShowDialog toont een dialoogvenster dat er ongeveer zo uitziet:
![]() |
uitklaplijst samengesteld op basis van de eigenschap Filter. Het standaard voorgestelde bestandstype wordt bepaald door FilterIndex | |
huidige map, vastgelegd door InitialDirectory indien deze eigenschap is ingevuld | |
de bestandsnaam die is gekozen of rechtstreeks door de gebruiker is ingevoerd. Deze is beschikbaar in de eigenschap FileName | |
knoppen Opslaan/Annuleren. Als de knop Enregistrer wordt gebruikt, levert de functie ShowDialog het resultaat DialogResult.OK op |
De opslagprocedure kan als volgt worden geschreven:
Private Sub btnSauvegarder_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnSauvegarder.Click
' het invoerveld wordt opgeslagen in een tekstbestand
' het dialoogvenster wordt geconfigureerd savefileDialog1
saveFileDialog1.InitialDirectory = Application.ExecutablePath
saveFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"
saveFileDialog1.FilterIndex = 0
' het dialoogvenster wordt weergegeven en het resultaat wordt opgehaald
If saveFileDialog1.ShowDialog() = DialogResult.OK Then
' de bestandsnaam wordt opgehaald
Dim nomFichier As String = saveFileDialog1.FileName
Dim fichier As StreamWriter = Nothing
Try
' het bestand wordt geopend in schrijfmodus
fichier = New StreamWriter(nomFichier)
' hier wordt de tekst ingevoerd
fichier.Write(txtTexte.Text)
Catch ex As Exception
' probleem
MessageBox.Show("Problème à l'écriture du fichier (" + ex.Message + ")", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
Finally
' het bestand wordt gesloten
Try
fichier.Close()
Catch
End Try
End Try
End If
End Sub
- We koppelen het oorspronkelijke dossier aan het dossier dat het uitvoerbare bestand van de toepassing bevat:
- We stellen de weer te geven bestandstypen in
Let op de syntaxis van de filters: filter1|filter2|..|filtren, waarbij filteri = Tekst|bestandssjabloon. Hier heeft de gebruiker de keuze tussen *.txt-bestanden en *.*-bestanden.
- We stellen het bestandstype vast dat als eerste moet worden weergegeven
Hier worden de bestanden van het type *.txt als eerste aan de gebruiker getoond.
- Het dialoogvenster wordt weergegeven en het resultaat wordt opgehaald
If saveFileDialog1.ShowDialog() = DialogResult.OK Then
- Terwijl het dialoogvenster wordt weergegeven, heeft de gebruiker geen toegang meer tot het hoofdformulier (dit wordt een modaal dialoogvenster genoemd). De gebruiker stelt de naam van het op te slaan bestand in en verlaat het dialoogvenster door op de knop Opslaan of Annuleren te klikken, of door het venster te sluiten. Het resultaat van de methode ShowDialog is alleen DialogResult.OK als de gebruiker de knop Enregistrer heeft gebruikt om het dialoogvenster te verlaten.
- Zodra dit is gebeurd, staat de naam van het aan te maken bestand nu in de eigenschap FileName van het object saveFileDialog1. Vervolgens keert men terug naar het klassieke aanmaken van een tekstbestand. Hierin wordt de inhoud van TextBox: txtTexte.Text geschreven, waarbij eventuele uitzonderingen worden afgehandeld.
De klasse OpenFileDialog lijkt sterk op de klasse SaveFileDialog en is afgeleid van dezelfde reeks klassen. Van deze eigenschappen en methoden onthouden we de volgende:
de bestandstypen die worden aangeboden in de vervolgkeuzelijst met bestandstypen in het dialoogvenster | |
het nummer van het bestandstype dat standaard in de bovenstaande lijst wordt aangeboden. Begint bij 0. | |
de map die in eerste instantie wordt weergegeven voor het zoeken naar het te openen bestand | |
de door de gebruiker opgegeven naam van het te openen bestand | |
methode die het dialoogvenster voor het opslaan weergeeft. Levert een resultaat van het type DialogResult op. |
De methode ShowDialog geeft een dialoogvenster weer dat er ongeveer zo uitziet:
![]() |
een vervolgkeuzelijst die is samengesteld op basis van de eigenschap Filter. Het standaard voorgestelde bestandstype wordt bepaald door FilterIndex | |
huidige map, vastgelegd door InitialDirectory indien deze eigenschap is ingevuld | |
de bestandsnaam die is gekozen of rechtstreeks door de gebruiker is ingevoerd. Deze is beschikbaar in de eigenschap FileName | |
knoppen Openen/Annuleren. Als de knop Ouvrir wordt gebruikt, levert de functie ShowDialog het resultaat DialogResult.OK op |
De procedure voor het openen kan als volgt worden geschreven:
Private Sub btnCharger_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnCharger.Click
' een tekstbestand in het invoerveld laden
' het dialoogvenster wordt geconfigureerd openfileDialog1
openFileDialog1.InitialDirectory = Application.ExecutablePath
openFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"
openFileDialog1.FilterIndex = 0
' het dialoogvenster wordt weergegeven en het resultaat wordt opgehaald
If openFileDialog1.ShowDialog() = DialogResult.OK Then
' de bestandsnaam wordt opgehaald
Dim nomFichier As String = openFileDialog1.FileName
Dim fichier As StreamReader = Nothing
Try
' het bestand wordt geopend in leesmodus
fichier = New StreamReader(nomFichier)
' het hele bestand wordt gelezen en opgeslagen in het TextBox
txtTexte.Text = fichier.ReadToEnd()
Catch ex As Exception
' probleem
MessageBox.Show("Problème à la lecture du fichier (" + ex.Message + ")", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
Finally
' het bestand wordt gesloten
Try
fichier.Close()
Catch
End Try
End Try
End If
End Sub
- De startmap wordt ingesteld op de map die het uitvoerbare bestand van de applicatie bevat:
- We stellen de weer te geven bestandstypen in
- We stellen het bestandstype in dat als eerste moet worden weergegeven
Hier worden bestanden van het type *.txt als eerste aan de gebruiker getoond.
- Het dialoogvenster wordt weergegeven en het resultaat wordt opgehaald
If openFileDialog1.ShowDialog() = DialogResult.OK Then
Terwijl het dialoogvenster wordt weergegeven, heeft de gebruiker geen toegang meer tot het hoofdformulier (dit wordt een modaal dialoogvenster genoemd). De gebruiker geeft de naam op van het te openen bestand en verlaat het dialoogvenster door op de knop Openen of Annuleren te klikken, of door het venster te sluiten. Het resultaat van de methode ShowDialog is alleen DialogResult.OK als de gebruiker de knop Ouvrir heeft gebruikt om het dialoogvenster te sluiten.
- Zodra dit is gebeurd, staat de naam van het aan te maken bestand nu in de eigenschap FileName van het object openFileDialog1. We keren dan terug naar het klassieke lezen van een tekstbestand. Let op de methode waarmee het volledige bestand kan worden gelezen:
- de inhoud van het bestand wordt opgeslagen in de TextBox en txtTexte. Eventuele uitzonderingen worden afgehandeld.
5.7.2. Dialoogvensters FontColor en ColorDialog
We gaan verder met het vorige voorbeeld en introduceren twee nieuwe knoppen:
![]() |
Nr. | type | naam | functie |
6 | Knop | btnCouleur | om de kleur van de tekens van TextBox vast te stellen |
7 | Knop | btnPolice | om het lettertype van TextBox in te stellen |
We plaatsen een ColorDialog-besturingselement en een FontDialog-besturingselement op het formulier:

De klassen FontDialog en ColorDialog hebben een methode ShowDialog die vergelijkbaar is met de methode ShowDialog van de klassen OpenFileDialog en SaveFileDialog. Met de methode ShowDialog van de klasse ColorDialog kan een kleur worden gekozen:

Als de gebruiker het dialoogvenster verlaat met de knop OK, is het resultaat van de methode ShowDialog DialogResult.OK en staat de gekozen kleur in de eigenschap Color van het gebruikte object ColorDialog. Met de methode ShowDialog van de klasse FontDialog kan een lettertype worden gekozen:

Als de gebruiker het dialoogvenster sluit met de knop OK, is het resultaat van de methode ShowDialog DialogResult.OK en staat het gekozen lettertype in de eigenschap Font van het gebruikte object FontDialog. We hebben de elementen om klikken op de knoppen Couleur en Police te verwerken:
Private Sub btnCouleur_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnCouleur.Click
' tekstkleur kiezen
If colorDialog1.ShowDialog() = DialogResult.OK Then
' de eigenschap 'forecolor' van TextBox wordt gewijzigd
txtTexte.ForeColor = colorDialog1.Color
End If
End Sub
Private Sub btnPolice_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnPolice.Click
' een lettertype kiezen
If fontDialog1.ShowDialog() = DialogResult.OK Then
' de eigenschap `font` van TextBox wijzigen
txtTexte.Font = fontDialog1.Font
End If
End Sub
5.7.3. Timer
We stellen hier voor om de volgende applicatie te schrijven:
![]() |
nr. | Type | Naam | Rol |
1 | TextBox, ReadOnly=true | txtChrono | toont een stopwatch |
2 | Knop | btnArretMarche | knop Stop/Start van de stopwatch |
3 | Timer | timer1 | component die hier elke seconde een gebeurtenis uitzendt |
De stopwatch loopt:

De stopwatch is gestopt:

Om de inhoud van TextBox en txtChrono elke seconde te wijzigen, hebben we een component nodig die elke seconde een gebeurtenis genereert. Deze gebeurtenis kunnen we vervolgens opvangen om de weergave van de stopwatch bij te werken. Die component is de Timer:

Zodra deze component op het formulier is geïnstalleerd (in het gedeelte met niet-visuele componenten), wordt er een object van het type Timer aangemaakt in de formulierbouwer. De klasse System.Windows.Forms.Timer is als volgt gedefinieerd:

Van de eigenschappen ervan zullen we alleen de volgende onthouden:
aantal milliseconden waarna een gebeurtenis Tick wordt gegenereerd. | |
de gebeurtenis die plaatsvindt na Interval milliseconden | |
maakt de timer actief (true) of inactief (false) |
In ons voorbeeld heet de timer timer1 en is timer1.Interval ingesteld op 1000 ms (1 s). De gebeurtenis Tick zal dus elke seconde plaatsvinden. Het klikken op de knop Stop/Start wordt verwerkt door de volgende procedure:
Private Sub btnArretMarche_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnArretMarche.Click
' uit of aan?
If btnArretMarche.Text = "Marche" Then
' de starttijd noteren
début = DateTime.Now
' we geven deze weer
txtChrono.Text = "00:00:00"
' de timer wordt gestart
timer1.Enabled = True
' de tekst van de knop wordt gewijzigd
btnArretMarche.Text = "Arrêt"
' einde
Return
End If '
If btnArretMarche.Text = "Arrêt" Then
' de timer stoppen
timer1.Enabled = False
' de tekst van de knop wordt gewijzigd
btnArretMarche.Text = "Marche"
' einde
Return
End If
End Sub
Private Sub timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles timer1.Tick
' er is één seconde verstreken
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
De tekst op de knop Stop/Start is ofwel „Stop“ ofwel „Start“. We moeten dus een controle uitvoeren op deze tekst om te bepalen wat er moet gebeuren.
- In het geval van „Aan” wordt het starttijdstip opgeslagen in een variabele die een globale variabele van het formulierobject is, wordt de timer gestart (Enabled=true) en verandert de tekst van de knop in „Uit”.
- In het geval van "Stop" wordt de timer gestopt (Enabled=false) en wordt de tekst op de knop gewijzigd in "Start".
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
' instantievariabelen
Private début As DateTime
Het bovenstaande attribuut début is bekend in alle methoden van de klasse. We moeten nu nog de gebeurtenis Tick op het object timer1 afhandelen, een gebeurtenis die elke seconde plaatsvindt:
Private Sub timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles timer1.Tick
' er is één seconde verstreken
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
We berekenen de tijd die is verstreken sinds het starten van de chronometer. We krijgen een object van het type TimeSpan dat een tijdsduur vertegenwoordigt. Deze moet in de stopwatch worden weergegeven in de vorm hh:mm:ss. Hiervoor gebruiken we de eigenschappen Hours, Minutes, Seconds van het object TimeSPan, die respectievelijk de uren, minuten en seconden van de tijdsduur vertegenwoordigen. We geven deze weer in het formaat ToString("d2") om een weergave met twee cijfers te krijgen.
5.8. Het voorbeeld IMPOTS
We pakken de applicatie IMPOTS er weer bij, die we al twee keer hebben behandeld. We voegen er nu een grafische interface aan toe:
![]() |
De besturingselementen zijn als volgt
nr. | type | naam | rol |
RadioButton | rdOui | aangevinkt indien gehuwd | |
RadioButton | rdNon | aangevinkt indien niet gehuwd | |
NumericUpDown | incEnfants | aantal kinderen van de belastingplichtige Minimum=0, Maximum=20, Stap=1 | |
TextBox | txtSalaire | jaarsalaris van de belastingplichtige in F | |
TextBox | txtImpots | te betalen belastingbedrag ReadOnly=true | |
Knop | btnCalculer | start de belastingberekening | |
Knop | btnEffacer | zet het formulier bij het laden terug naar de oorspronkelijke staat | |
Knop | btnQuitter | om de applicatie te verlaten |
Werkingsregels
- de knop 'Berekenen' blijft uitgeschakeld zolang er niets in het salarisveld staat
- als bij het starten van de berekening blijkt dat het salaris onjuist is, wordt de fout gemeld:

Het programma staat hieronder. Het maakt gebruik van de klasse impot die in het hoofdstuk over klassen is aangemaakt. Een deel van de code die automatisch door VS.NET wordt gegenereerd, is hier niet weergegeven.
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
' opties
Option Explicit On
Option Strict On
' naamruimten
Imports System
Imports System.Drawing
Imports System.Collections
Imports System.ComponentModel
Imports System.Windows.Forms
Imports System.Data
' formulierklasse
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
' gegevenstabellen die nodig zijn voor de berekening van de belasting
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}
' belastingobject
Private objImpôt As impot = Nothing
Public Sub New()
InitializeComponent()
' initialisatie van het formulier
btnEffacer_Click(Nothing, Nothing)
btnCalculer.Enabled = False
' aanmaken van een belastingobject
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)
' het invoerveld voor het salaris wordt uitgeschakeld
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
' formulier leegmaken
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
' status van de knop 'Berekenen'
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
' einde van de toepassing
Application.Exit()
End Sub 'btnQuitter_Click
Private Sub btnCalculer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnCalculer.Click
' Is het salaris correct?
Dim intSalaire As Integer = 0
Try
' het salaris ophalen
intSalaire = Integer.Parse(txtSalaire.Text)
' moet >=0 zijn
If intSalaire < 0 Then
Throw New Exception("")
End If
Catch ex As Exception
' foutmelding
MessageBox.Show(Me, "Salaire incorrect", "Erreur de saisie", MessageBoxButtons.OK, MessageBoxIcon.Error)
' focus op foutief veld
txtSalaire.Focus()
' tekst in invoerveld selecteren
txtSalaire.SelectAll()
' terug naar de visuele interface
Return
End Try 'try-catch
' het salaris is correct – de belasting wordt berekend
txtImpots.Text = "" & CLng(objImpôt.calculer(rdOui.Checked, CInt(incEnfants.Value), intSalaire))
End Sub 'btnCalculer_Click
End Class
We gebruiken hier de assemblage impots.dll, het resultaat van de compilatie van de klasse impots uit hoofdstuk 2. Ter herinnering: deze assemblage kan in de consolemodus worden gegenereerd met het commando
Dit commando genereert het bestand impots.dll, ook wel ‘assemblage’ genoemd. Deze assemblage kan vervolgens in verschillende projecten worden gebruikt. Hier, in ons project onder VS.NET, gebruiken we het venster met de projecteigenschappen:

Om een verwijzing (een assemblage) toe te voegen, klikken we met de rechtermuisknop op de sleutelgroep ‘References’ hierboven, kiezen we de optie [Ajouter une référence] en selecteren we de assemblage [impots.dll] die we zorgvuldig in de projectmap hebben geplaatst:
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
Zodra de assembly [impots.dll] in het project is opgenomen, wordt de klasse [impots] bekend bij het project. Voorheen was dat niet het geval. Een andere methode is om de broncode impots.vb in het project op te nemen. Hiervoor klikt men in het venster met de projecteigenschappen met de rechtermuisknop op het project, kiest men de optie [Ajouter/Ajouter un élément existant] en selecteert men het bestand impots.vb.















































