Skip to content

5. Interfacce grafiche con VB.NET e VS.NET

In questa sede intendiamo illustrare come realizzare interfacce grafiche con VB.NET. Vedremo innanzitutto quali sono le classi di base della piattaforma .NET che ci consentono di realizzare un'interfaccia grafica. In una prima fase non utilizzeremo alcun strumento di generazione automatica. Successivamente utilizzeremo Visual Studio.NET (VS.NET), uno strumento di sviluppo di Microsoft che facilita lo sviluppo di applicazioni con i linguaggi .NET e, in particolare, la creazione di interfacce grafiche. La versione di VS.NET utilizzata è quella in lingua inglese.

5.1. Nozioni di base sulle interfacce grafiche

5.1.1. Una finestra semplice

Consideriamo il seguente codice:


' opzioni
Option Strict On
Option Explicit On 

' spazi dei nomi
Imports System
Imports System.Drawing
Imports System.Windows.Forms

' la classe del modulo
Public Class Form1
    Inherits Form

    ' il produttore
    Public Sub New()
        ' titolo della finestra
        Me.Text = "Mon premier formulaire"
        ' dimensioni della finestra
        Me.Size = New System.Drawing.Size(300, 100)
    End Sub

    ' funzione di test
    Public Shared Sub Main(ByVal args() As String)
        ' viene visualizzato il modulo
        Application.Run(New Form1)
    End Sub
End Class

Il codice precedente viene compilato e poi eseguito

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

dos>frm1

L'esecuzione visualizza la seguente finestra:

Image

Un'interfaccia grafica deriva in genere dalla classe base System.Windows.Forms.Form:

Public Class Form1
    Inherits Form

La classe base Form definisce una finestra di base con pulsanti di chiusura, ingrandimento/riduzione, dimensioni regolabili, ... e gestisce gli eventi su questi oggetti grafici. Qui specializziamo la classe base assegnandole un titolo e specificandone la larghezza (300) e l'altezza (100). Ciò avviene nel suo costruttore:


    Public Sub New()
        ' titolo della finestra
        Me.Text = "Mon premier formulaire"
        ' dimensioni della finestra
        Me.Size = New System.Drawing.Size(300, 100)
    End Sub

Il titolo della finestra è definito dalla proprietà Text e le dimensioni dalla proprietà Size. Size è definito nello spazio dei nomi System.Drawing ed è una struttura. La procedura Main avvia l'applicazione grafica nel modo seguente:


        Application.Run(New Form1)

Viene creato e visualizzato un modulo di tipo Form1; successivamente, l'applicazione si mette in ascolto degli eventi che si verificano sul modulo (clic, movimenti del mouse, ecc.) e ne esegue quelli gestiti dal modulo stesso. In questo caso, il nostro modulo non gestisce altri eventi oltre a quelli gestiti dalla classe base Form (clic sui pulsanti di chiusura, ingrandimento/riduzione, modifica delle dimensioni della finestra, spostamento della finestra, ecc.).

5.1.2. Un modulo con un pulsante

Aggiungiamo ora un pulsante alla nostra finestra:


' opzioni
Option Strict On
Option Explicit On 

' spazi dei nomi
Imports System
Imports System.Drawing
Imports System.Windows.Forms

' classe del modulo
Public Class Form1
    Inherits Form

    ' attributi
    Private cmdTest As Button

    ' il costruttore
    Public Sub New()
        ' il titolo
        Me.Text = "Mon premier formulaire"
        ' le dimensioni
        Me.Size = New System.Drawing.Size(300, 100)
        ' un pulsante
        ' creazione
        Me.cmdTest = New Button
        ' posizione
        cmdTest.Location = New System.Drawing.Point(110, 20)
        ' dimensioni
        cmdTest.Size = New System.Drawing.Size(80, 30)
        ' etichetta
        cmdTest.Text = "Test"
        ' gestore eventi
        AddHandler cmdTest.Click, AddressOf cmdTest_Click
        ' aggiunta pulsante al modulo
        Me.Controls.Add(cmdTest)
    End Sub

    ' gestore eventi
    Private Sub cmdTest_Click(ByVal sender As Object, ByVal evt As EventArgs)
        ' è stato cliccato il pulsante - lo si segnala
        MessageBox.Show("Clic sur bouton", "Clic sur bouton", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub

    ' funzione di test
    Public Shared Sub Main(ByVal args() As String)
        ' visualizzazione del modulo
        Application.Run(New Form1)
    End Sub
End Class

Abbiamo aggiunto un pulsante al modulo:


        ' un pulsante
        ' creazione
        Me.cmdTest = New Button
        ' posizione
        cmdTest.Location = New System.Drawing.Point(110, 20)
        ' dimensione
        cmdTest.Size = New System.Drawing.Size(80, 30)
        ' etichetta
        cmdTest.Text = "Test"
        ' gestore eventi
        AddHandler cmdTest.Click, AddressOf cmdTest_Click
        ' aggiunta pulsante al modulo
        Me.Controls.Add(cmdTest)

La proprietà Location imposta le coordinate (110,20) del punto in alto a sinistra del pulsante utilizzando una struttura Point. La larghezza e l'altezza del pulsante sono impostate a (80,30) tramite una struttura Size. La proprietà Text del pulsante consente di impostare il testo del pulsante. La classe pulsante possiede un evento Click definito come segue:

Public Event Click As EventHandler

dove EventHandler è una funzione «delegata» con la seguente firma:

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

Ciò significa che il gestore dell'evento [Click] sul pulsante dovrà avere la firma del delegato [EventHandler]. In questo caso, quando si fa clic sul pulsante cmdTest, verrà chiamato il metodo cmdTest_Click. Quest’ultimo è definito come segue, in conformità con il modello precedente EventHandler:


    ' gestore eventi
    Private Sub cmdTest_Click(ByVal sender As Object, ByVal evt As EventArgs)
        ' è stato cliccato il pulsante - lo si segnala
        MessageBox.Show("Clic sur bouton", "Clic sur bouton", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub

Ci si limita a visualizzare un messaggio:

Image

La classe viene compilata ed eseguita:

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

La classe MessageBox serve a visualizzare messaggi in una finestra. In questo caso abbiamo utilizzato il costruttore

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
il messaggio da visualizzare
caption
il titolo della finestra
pulsanti
i pulsanti presenti nella finestra
icon
l'icona presente nella finestra

Il parametro buttons può assumere valori tra le seguenti costanti:

costante
pulsanti
   AbortRetryIgnore 
  OK 
    OKCancel 
    RetryCancel 
    YesNo 
    YesNoCancel 

Il parametro icon può assumere valori tra le seguenti costanti:

Asterisk
Error
idem Stop
Exclamation
idem Avviso
Hand
Information
idem Asterisk
None
Question
Stop
idem Hand
Warning

 

Il metodo Show è un metodo statico che restituisce un risultato di tipo System.Windows.Forms.DialogResult, che è un'enumerazione:


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

Per sapere quale pulsante ha premuto l'utente per chiudere la finestra di tipo MessageBox, si scriverà:

dim res as DialogResult=MessageBox.Show(..)
if res=DialogResult.Yes then
' ha premuto il pulsante "Sì"
...
end if

5.2. Creazione di un'interfaccia grafica con Visual Studio.NET

Riprendiamo alcuni degli esempi visti in precedenza, realizzandoli ora con Visual Studio.NET.

5.2.1. Creazione iniziale del progetto

  1. Avviare VS.NET e selezionare l’opzione Fichier/Nouveau/Projet

Image

  1. specificare le caratteristiche del progetto
    1. selezionare il tipo di progetto che si desidera realizzare, in questo caso un progetto VB.NET (1)
    2. selezionare il tipo di applicazione che si desidera creare, in questo caso un'applicazione Windows (2)
    3. indica in quale cartella desideri collocare la sottocartella del progetto (3)
    4. Indica il nome del progetto (4). Questo sarà anche il nome della cartella che conterrà i file del progetto
    5. il nome di questa cartella viene riportato al punto (5)
  1. Vengono quindi creati alcuni file e cartelle all’interno della cartella i4:
sottocartelle della cartella progetto1

Di questi file, solo uno è rilevante: il file form1.cs, che è il file sorgente associato al modulo creato da VS.NET. Ci torneremo più avanti.

5.2.2. Le finestre dell’interfaccia di VS.NET

L’interfaccia di VS.NET mostra ora alcuni elementi del nostro progetto i4:

Abbiamo una finestra di progettazione dell’interfaccia grafica:

Selezionando i controlli dalla barra degli strumenti (toolbox 2) e trascinandoli sull’area della finestra (1), possiamo costruire un’interfaccia grafica. Se passiamo il mouse sulla “toolbox”, questa si ingrandisce e mostra una serie di controlli:

Image

Per il momento non ne utilizziamo nessuno. Sempre nella schermata di VS.NET, troviamo la finestra dell’Esplora soluzioni “Explorer Solution”:

Image

In un primo momento, useremo poco questa finestra. Essa mostra tutti i file che compongono il progetto. Solo uno di essi ci interessa: il file sorgente del nostro programma, in questo caso Form1.vb. Cliccando con il tasto destro su Form1.vb, si apre un menu che consente di accedere sia al codice sorgente della nostra interfaccia grafica (Visualizza codice) sia all’interfaccia grafica stessa (Progettore di viste):

Image

È possibile accedere a queste due entità direttamente dalla finestra «Esplora soluzioni»:

 

Le finestre aperte si “accumulano” nella finestra principale di progettazione:

Image

Qui Form1.vb[Design] indica la finestra di progettazione e Form1.vb la finestra del codice. È sufficiente cliccare su una delle schede per passare da una finestra all'altra. Un’altra finestra importante presente sullo schermo di VS.NET è la finestra delle proprietà:

Image

Le proprietà visualizzate nella finestra sono quelle del controllo attualmente selezionato nella finestra di progettazione grafica. È possibile accedere alle diverse finestre del progetto tramite il menu Affichage:

Image

Qui si trovano le finestre principali appena descritte e le relative scorciatoie da tastiera.

5.2.3. Esecuzione di un progetto

Pur non avendo scritto alcun codice, disponiamo già di un progetto eseguibile. Eseguire F5 o Déboguer/Démarrer per avviarlo. Si otterrà la seguente finestra:

Image

Questa finestra può essere ingrandita, ridotta a icona, ridimensionata e chiusa.

5.2.4. Il codice generato da VS.NET

Diamo un'occhiata al codice (Affichage/Code) della nostra applicazione:


Public Class Form1
    Inherits System.Windows.Forms.Form

#Sezione "Codice generato dal Windows Form Designer"

    Public Sub New()
        MyBase.New()

        'Questa chiamata è richiesta dal Windows Form Designer.
        InitializeComponent()

        'Aggiungere un'inizializzazione qualsiasi dopo la chiamata a InitializeComponent()

    End Sub

    'Il metodo sovrascritto Dispose del modulo per ripulire l'elenco dei componenti.
    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

    'Richiesto dal Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'REMARQUE: la procedura seguente è richiesta dal Designer di Windows Form
    'Può essere modificata utilizzando il Designer di Windows Form.  
    'Non modificarla utilizzando l'editor di codice.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        components = New System.ComponentModel.Container()
        Me.Text = "Form2"
    End Sub

#Fine regione

End Class

Un'interfaccia grafica deriva dalla classe base System.Windows.Forms.Form:

Public Class Form1
    Inherits System.Windows.Forms.Form

La classe base Form definisce una finestra di base con pulsanti di chiusura, ingrandimento/riduzione, dimensioni regolabili, ... e gestisce gli eventi su questi oggetti grafici. Il costruttore del modulo utilizza un metodo InitializeComponent in cui vengono creati e inizializzati i controlli del modulo.


    Public Sub New()
        MyBase.New()

        'Questa chiamata è richiesta dal Windows Form Designer.
        InitializeComponent()

        'Aggiungere un'inizializzazione qualsiasi dopo la chiamata a InitializeComponent()
    End Sub

Qualsiasi altra operazione da eseguire nel generatore può essere effettuata dopo la chiamata a InitializeComponent. Il metodo 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

imposta il titolo della finestra "Form1", la sua larghezza (292) e la sua altezza (53). Il titolo della finestra è definito dalla proprietà Text e le dimensioni dalla proprietà Size. Size è definito nello spazio dei nomi System.Drawing ed è una struttura. Per eseguire questa applicazione, è necessario definire il modulo principale del progetto. A tal fine, si utilizza l'opzione [Projets/Propriétés]:

Image

In [Objet de démarrage], indichiamo [Form1], ovvero il modulo che abbiamo appena creato. Per avviare l'esecuzione, utilizziamo l'opzione [Déboguer/Démarrer]:

Image

5.2.5. Compilazione in una finestra DOS

Ora proviamo a compilare ed eseguire questa applicazione in una finestra 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'.

Il compilatore segnala che non riesce a trovare la procedura [Main]. Infatti, VS.NET non l'ha generata. Tuttavia, l'abbiamo già incontrata negli esempi precedenti. Ha la seguente forma:


    Shared Sub Main()
        ' si avvia l'applicazione
        Application.Run(New Form1) ' où Form1 est le formulaire
    End Sub

Aggiungiamo nel codice di [Form1.vb] il codice precedente e ricompiliamo:

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

In questo caso, il nome [Application] non è riconosciuto. Ciò significa semplicemente che non abbiamo importato il suo spazio dei nomi [System.Windows.Forms]. Aggiungiamo la seguente istruzione:

Imports System.Windows.Forms

quindi ricompiliamo:

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

Questa volta funziona. Eseguiamo:

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

dos>form1

Image

Viene creato e visualizzato un modulo di tipo Form1. È possibile evitare l'aggiunta della procedura [Main] utilizzando l'opzione /m del compilatore, che consente di specificare la classe da eseguire nel caso in cui questa erediti da System.Windows.Form:

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

L'opzione /m:form2 indica che la classe da eseguire è quella denominata [form2].

5.2.6. Gestione degli eventi

Una volta visualizzato il modulo, l’applicazione si mette in ascolto degli eventi che si verificano sul modulo (clic, spostamenti del mouse, ecc.) e fa eseguire quelli gestiti dal modulo stesso. In questo caso, il nostro modulo non gestisce altri eventi oltre a quelli gestiti dalla classe di base Form (clic sui pulsanti di chiusura, ingrandimento/riduzione, modifica delle dimensioni della finestra, spostamento della finestra, ecc.). Il modulo generato utilizza un attributo components che non viene utilizzato da nessuna parte. Anche il metodo dispose non serve a nulla in questo contesto. Lo stesso vale per alcuni spazi dei nomi (Collections, ComponentModel, Data) utilizzati e per quello definito per il progetto projet1. Pertanto, in questo esempio il codice può essere semplificato come segue:


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

Public Class Form1
    Inherits System.Windows.Forms.Form

    ' costruttore
    Public Sub New()
        ' creazione del modulo con i relativi componenti
        InitializeComponent()
    End Sub

    Private Sub InitializeComponent()
        ' dimensioni della finestra
        Me.Size = New System.Drawing.Size(300, 300)
        ' titolo della finestra
        Me.Text = "Form1"
    End Sub

    Shared Sub Main()
        ' si avvia l'app
        Application.Run(New Form1)
    End Sub
End Class

5.2.7. Conclusione

Ora accetteremo così com'è il codice generato da VS.NET e ci limiteremo ad aggiungere il nostro, in particolare per gestire gli eventi relativi ai vari controlli del modulo.

5.3. Finestra con campo di immissione, pulsante ed etichetta

5.3.1. Progettazione grafica

Nell’esempio precedente non avevamo inserito alcun componente nella finestra. Iniziamo un nuovo progetto denominato interface2. A tal fine seguiamo la procedura illustrata in precedenza per creare un progetto:

Image

Ora creiamo una finestra con un pulsante, un'etichetta e un campo di immissione:

I campi sono i seguenti:

nome
tipo
ruolo
1
lblSaisie
Etichetta
una dicitura
2
txtSaisie
TextBox
un campo di immissione
3
btnAfficher
Pulsante
per visualizzare in una finestra di dialogo il contenuto del campo di immissione txtSaisie

Per creare questa finestra, procedere come segue: fare clic con il tasto destro del mouse all'interno della finestra, al di fuori di qualsiasi componente, e selezionare l'opzione Properties per accedere alle proprietà della finestra:

Image

La finestra delle proprietà apparirà quindi sulla destra:

Image

È opportuno prendere nota di alcune di queste proprietà:

BackColor
per impostare il colore di sfondo della finestra
ForeColor
per impostare il colore delle immagini o del testo nella finestra
Menu
per associare un menu alla finestra
Text
per assegnare un titolo alla finestra
FormBorderStyle
per impostare il tipo di finestra
Font
per impostare il carattere dei testi nella finestra
Name
per impostare il nome della finestra

Qui impostiamo le proprietà Text e Name:

Text
Campi di immissione e pulsanti - 1
Name
frmSaisiesBoutons

Utilizzando la barra "Casella degli strumenti"

  • selezionate i componenti di cui avete bisogno
  • trascinateli nella finestra e impostate le dimensioni corrette
Una volta scelto il componente nella "toolbox", utilizzate il tasto
"Esc" per far scomparire la barra degli strumenti, quindi trascinate
e ridimensionate il componente. Ripetete l’operazione per i tre componenti
necessari: Label, TextBox, Button. Per allineare e
ridimensionare correttamente i componenti, utilizzate il menu Format:
Il principio di formattazione è il seguente:
  1. selezionare i diversi componenti da formattare insieme (tenendo premuto il tasto Ctrl)
  2. selezionare il tipo di formattazione desiderato
L'opzione Align consente di allineare i componenti
L'opzione Make Same Size consente di fare in modo che
componenti abbiano la stessa altezza o la stessa
larghezza:
L'opzione "Horizontal Spacing" consente, ad esempio,
di allineare orizzontalmente i componenti con
intervalli di uguale dimensione tra di essi. Lo stesso vale
per l'opzione "Vertical Spacing" per l'allineamento verticale.
L'opzione "Center in Form" consente di centrare
un componente in orizzontale o
verticalmente nella finestra:
Una volta che i componenti sono stati posizionati correttamente
posizionati nella finestra, impostate le loro proprietà.
A tal fine, fare clic con il tasto destro del mouse sul componente e
selezionare l'opzione Properties:
  • l'etichetta 1 (Label)
Selezionate il componente per visualizzarne
la finestra delle proprietà. In essa,
modificare le seguenti proprietà:
nome: lblSaisie, testo: Inserimento
  • il campo di immissione 2 (TextBox)
Selezionare il componente per visualizzarne la
finestra delle proprietà. In essa, modificare
le seguenti proprietà:
nome: txtSaisie, testo: lasciare vuoto
  • il pulsante 3 (Button):
name: cmdAfficher, text: Visualizza
  • la finestra stessa: name: frmSaisies&Pulsanti,
text: Inserimenti e pulsanti - 1
Possiamo eseguire (Ctrl+F5) il nostro progetto
per avere una prima anteprima della finestra
in azione:

Chiudete la finestra. Ora dobbiamo scrivere la procedura associata al clic sul pulsante Afficher.

5.3.2. Gestione degli eventi di un modulo

Diamo un'occhiata al codice generato dal designer grafico:


...

Public Class frmSaisiesBoutons
  Inherits System.Windows.Forms.Form

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

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

...

  ' inizializzazione dei componenti
    Private Sub InitializeComponent()
...
    End Sub
End Class

Si noti innanzitutto la particolare dichiarazione dei componenti:

  • la parola chiave Friend indica che la visibilità del componente si estende a tutte le classi del progetto
  • la parola chiave WithEvents indica che il componente genera eventi. Passiamo ora a vedere come gestire questi eventi

Visualizzate la finestra del codice del modulo (Visualizza/Codice o F7):

La finestra sopra riportata presenta due elenchi a discesa (1) e (2). L’elenco (1) è l’elenco dei componenti del modulo:

Image

L'elenco (2) contiene gli eventi associati al componente selezionato in (1):

Image

Uno degli eventi associati al componente è visualizzato in grassetto (in questo caso Click). Si tratta dell'evento predefinito del componente. È possibile accedere al gestore di questo specifico evento facendo doppio clic sul componente nella finestra di progettazione. VB.net genera quindi automaticamente lo scheletro del gestore dell’evento nella finestra di codice e posiziona l’utente su di esso. L'accesso ai gestori degli altri eventi avviene invece nella finestra del codice, selezionando il componente dall'elenco (1) e l'evento in (2). VB.net genera quindi lo scheletro del gestore dell'evento o si posiziona su di esso se era già stato generato:


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

Per impostazione predefinita, VB.net C_E assegna il nome “E” al gestore dell’evento del componente C. È possibile modificare questo nome se lo si ritiene opportuno. Tuttavia, tale operazione è sconsigliata. Gli sviluppatori di VB mantengono in genere il nome generato da VB, garantendo così la coerenza nella denominazione in tutti i programmi VB. L'associazione della procedura btnAfficher_Click all'evento Click del componente btnAfficher non avviene tramite il nome della procedura, ma tramite la parola chiave handles:


Handles btnAfficher.Click

Nell’esempio sopra riportato, la parola chiave «handles» specifica che la procedura gestisce l’evento «Click» del componente btnAfficher. Il gestore di eventi precedente ha due parametri:

sender
l’oggetto all’origine dell’evento (in questo caso il pulsante)
e
un oggetto EventArgs che descrive in dettaglio l'evento verificatosi

In questo caso non utilizzeremo nessuno di questi parametri. Non ci resta che completare il codice. In questo caso, vogliamo visualizzare una finestra di dialogo contenente il contenuto del campo txtSaisie:


    Private Sub btnAfficher_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        ' viene visualizzato il testo inserito nella casella di immissione TxtSaisie
        MessageBox.Show("texte saisi= " + txtsaisie.Text, "Vérification de la saisie", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub

Se si esegue l’applicazione, si ottiene quanto segue:

Image

5.3.3. Un altro metodo per gestire gli eventi

Per il pulsante btnAfficher, VS.NET ha generato il codice seguente:


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

...

    ' gestione evento clic sul pulsante cmdAfficher
    Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAfficher.Click
...
    End Sub

Possiamo associare la procedura btnAfficher_Click all’evento Click del pulsante btnAfficher in un altro modo:


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

...

    ' gestore di eventi clic sul pulsante cmdAfficher
    Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
...
    End Sub

La procedura btnAfficher_Click ha perso la parola chiave Handles, perdendo così il suo collegamento con l'evento btnAfficher.Click. Questo collegamento viene ora effettuato utilizzando la parola chiave AddHandler:


        AddHandler btnAfficher.Click, AddressOf btnAfficher_Click

Il codice sopra riportato, che verrà inserito nella procedura InitializeComponent del modulo, associa all’evento btnAfficher.Click la procedura denominata btnAfficher_Click. Inoltre, il componente btnAfficher non necessita più della parola chiave WithEvents:


    Friend btnAfficher As System.Windows.Forms.Button

Qual è la differenza tra i due metodi?

  • La parola chiave «handles» consente di associare un evento a una procedura solo in fase di progettazione. Il progettista sa in anticipo che una procedura P deve gestire gli eventi E1, E2, ... e scrive il codice

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

È infatti possibile che una procedura gestisca più eventi.

  • La parola chiave addhandler consente di associare un evento a una procedura al momento dell’esecuzione. Ciò è utile in un contesto di produzione e consumo di eventi. Un oggetto genera un evento specifico che potrebbe interessare altri oggetti. Questi ultimi si iscrivono presso il produttore per ricevere l’evento (ad esempio, una temperatura che ha superato una soglia critica). Durante l’esecuzione dell’applicazione, il produttore dell’evento dovrà eseguire diverse istruzioni:
Addhandler E, AddressOf P1
Addhandler E, AddressOf P2
...
Addhandler E, AddressOf Pn

dove E è l’evento generato dal produttore e Pi le procedure appartenenti ai diversi oggetti consumatori di tale evento. Avremo modo di tornare su un’applicazione produttore-consumatore di eventi in un prossimo capitolo.

5.3.4. Conclusione

Dai due progetti esaminati, possiamo concludere che, una volta realizzata l’interfaccia grafica con VS.NET, il compito dello sviluppatore consiste nello scrivere i gestori degli eventi che desidera gestire per tale interfaccia grafica. D’ora in poi presenteremo solo il codice di questi ultimi.

5.4. Alcuni componenti utili

Presentiamo ora diverse applicazioni che utilizzano i componenti più comuni, al fine di illustrarne i principali metodi e proprietà. Per ciascuna applicazione, presentiamo l’interfaccia grafica e il codice rilevante, in particolare i gestori di eventi.

5.4.1. Modulo Form

Iniziamo presentando il componente indispensabile, il modulo su cui vengono inseriti i componenti. Abbiamo già illustrato alcune delle sue proprietà di base. Ci soffermeremo qui su alcuni eventi importanti di un modulo.

 
il modulo è in fase di caricamento
Closing
il modulo si sta chiudendo
Closed
il modulo è chiuso

L'evento Load si verifica prima ancora che il modulo venga visualizzato. L'evento Closing si verifica quando il modulo sta per essere chiuso. È comunque possibile interrompere questa chiusura tramite programmazione. Creiamo un modulo denominato Form1 senza componenti:

Image

Gestiamo i tre eventi precedenti:


    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' caricamento iniziale del modulo
        MessageBox.Show("Evt Load", "Load")
    End Sub

    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        ' il modulo si sta chiudendo
        MessageBox.Show("Evt Closing", "Closing")
        ' viene richiesta la conferma
        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
        ' il modulo si sta chiudendo
        MessageBox.Show("Evt Closed", "Closed")
    End Sub
Utilizziamo la funzione MessageBox per ricevere una notifica dei diversi
eventi. L'evento Closing si verificherà quando l'utente
chiude la finestra.
A quel punto gli chiediamo se desidera davvero uscire dall’applicazione:
Se risponde No, impostiamo la proprietà Cancel dell’evento
CancelEventArgs che il metodo ha ricevuto come parametro.
Se impostiamo questa proprietà su False, la chiusura
della finestra viene annullata, altrimenti procede:

5.4.2. etichette Label e caselle di immissione TextBox

Abbiamo già incontrato questi due componenti. Label è un componente di testo e TextBox un componente campo di immissione. La loro proprietà principale è Text, che indica il contenuto del campo di immissione o il testo dell’etichetta. Questa proprietà è di tipo lettura/scrittura. L’evento solitamente utilizzato per TextBox è TextChanged, che segnala che l’utente ha modificato il campo di immissione. Ecco un esempio che utilizza l’evento TextChanged per monitorare le modifiche apportate a un campo di immissione:

n.
tipo
nome
ruolo
1
TextBox
txtSaisie
campo di immissione
2
Etichetta
lblControle
visualizza il testo di 1 in tempo reale
3
Pulsante
cmdEffacer
per cancellare i campi 1 e 2
4
Pulsante
cmdQuitter
per uscire dall'applicazione

Il codice rilevante di questa applicazione è quello dei gestori di eventi:


  ' clic sul pulsante Esci
    Private Sub cmdQuitter_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles cmdQuitter.Click
        ' clic sul pulsante "Esci" - si esce dall'applicazione
        Application.Exit()
    End Sub

    ' modifica del campo txtSaisie
    Private Sub txtSaisie_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles txtSaisie.TextChanged
        ' il contenuto di TextBox è cambiato - lo si copia nell'etichetta lblControle
        lblControle.Text = txtSaisie.Text
    End Sub

    ' clic sul pulsante "Cancella"
    Private Sub cmdEffacer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles cmdEffacer.Click
        ' si cancella il contenuto della casella di immissione
        txtSaisie.Text = ""
    End Sub

    ' è stato premuto un tasto
    Private Sub txtSaisie_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) _
    Handles txtSaisie.KeyPress
        ' si verifica quale tasto è stato premuto
        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

Si noti il modo in cui l'applicazione viene chiusa nella procedura cmdQuitter_Click: Application.Exit(). L'esempio seguente utilizza un TextBox su più righe:

L'elenco dei controlli è il seguente:

n.
tipo
nome
ruolo
1
TextBox
txtMultiLignes
campo di immissione multilinea
2
TextBox
txtAjout
campo di immissione a riga singola
3
Pulsante
btnAjouter
Aggiunge il contenuto da 2 a 1

Affinché un TextBox diventi multilinea, è necessario impostare le seguenti proprietà del controllo:

 
per accettare più righe di testo
ScrollBars=( None, Horizontal, Vertical, Both)
per specificare se il controllo deve avere o meno le barre di scorrimento (Horizontal, Vertical, Both) o nessuna (None)
AcceptReturn=(True, False)
se impostato su true, il tasto Invio inserirà un'interruzione di riga
AcceptTab=(True, False)
se impostato su true, il tasto Tab inserirà un tabulatore nel testo

Il codice utile è quello che gestisce il clic sul pulsante [Ajouter] e quello che gestisce la modifica del campo di immissione [txtAjout]:


    ' eventualmente btnAjouter_Click
    Private Sub btnAjouter_Click1(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnAjouter.Click
        ' aggiunta del contenuto di txtAjout a quello di txtMultilignes
        txtMultilignes.Text &= txtAjout.Text
        txtAjout.Text = ""
    End Sub

    ' eventualmente txtAjout_TextChanged
    Private Sub txtAjout_TextChanged1(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles txtAjout.TextChanged
        ' si imposta lo stato del pulsante Aggiungi
        btnAjouter.Enabled = txtAjout.Text.Trim() <> ""
    End Sub

5.4.3. elenchi a discesa ComboBox

Un componente ComboBox è un elenco a discesa abbinato a un campo di immissione: l'utente può scegliere un elemento in (2) oppure digitare del testo in (1). Esistono tre tipi di ComboBox definiti dalla proprietà Style:

 
elenco non a tendina con campo di modifica
DropDown
elenco a discesa con campo di modifica
DropDownList
elenco a discesa senza campo di modifica

Per impostazione predefinita, il tipo di un ComboBox è DropDown. Per scoprire la classe ComboBox, digitare ComboBox nell'indice della guida (Aide/Index). La classe ComboBox ha un unico costruttore:

Public Sub New()
crea un oggetto ComboBox vuoto

Gli elementi di ComboBox sono disponibili nella proprietà Items:

Public ReadOnly Property Items As ComboBox.ObjectCollection

Si tratta di una proprietà indicizzata, dove Items(i) indica l'elemento i del Combo. Supponiamo che C sia un Combo e C.Items il suo elenco di elementi. Abbiamo le seguenti proprietà:

 
numero di elementi del menu a discesa
C.Items(i)
elemento i del menu a discesa
C.Add(object o)
aggiunge l'oggetto o come ultimo elemento del menu a tendina
C.AddRange(object() objets)
aggiunge un array di oggetti alla fine del menu a tendina
C.Insert(int i, object o)
aggiunge l'oggetto o nella posizione i del menu a tendina
C.RemoveAt(int i)
rimuove l'elemento i dal menu a tendina
C.Remove(object o)
rimuove l'oggetto o dal menu a tendina
C.Clear()
elimina tutti gli elementi dal menu a tendina
C.IndexOf(object o)
restituisce la posizione i dell'oggetto o nel menu a discesa

Potrebbe sorprendere che un menu a tendina possa contenere oggetti, mentre solitamente contiene stringhe di caratteri. Dal punto di vista visivo, è proprio così. Se un ComboBox contiene un oggetto obj, visualizza la stringa obj.ToString(). Ricordiamo che ogni oggetto dispone di un metodo ToString ereditato dalla classe object, che restituisce una stringa di caratteri «rappresentativa» dell’oggetto. L'elemento selezionato nel menu a tendina C è C.SelectedItem oppure C.Items(C.SelectedIndex), dove C.SelectedIndex è il numero dell'elemento selezionato, numero che parte da zero per il primo elemento.

Quando si seleziona un elemento dall’elenco a discesa, si verifica l’evento SelectedIndexChanged, che può quindi essere utilizzato per ricevere una notifica del cambiamento di selezione nel menu a discesa. Nell’applicazione seguente, utilizziamo questo evento per visualizzare l’elemento che è stato selezionato nell’elenco.

Image

Presentiamo solo il codice rilevante della finestra. Nel costruttore del modulo popoliamo il menu a discesa:


  Public Sub New()
    ' creazione del modulo
    InitializeComponent()
    ' compilazione del menu a tendina
    cmbNombres.Items.AddRange(New String() {"zéro", "un", "deux", "trois", "quatre"})
        ' si seleziona il primo elemento dell'elenco
    cmbNombres.SelectedIndex = 0
  End Sub

Gestiamo l’evento SelectedIndexChanged del menu a tendina che segnala un nuovo elemento selezionato:


    Private Sub cmbNombres_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles cmbNombres.SelectedIndexChanged
        ' l'elemento selezionato è cambiato - lo visualizziamo
        MessageBox.Show("Elément sélectionné : (" & cmbNombres.SelectedItem.ToString & "," & cmbNombres.SelectedIndex & ")", "Combo", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Sub

5.4.4. componente ListBox

Ci proponiamo di realizzare la seguente interfaccia:

I componenti di questa finestra sono i seguenti:

n.
tipo
nome
ruolo/proprietà
0
Form
Form1
modulo - BorderStyle=FixedSingle
1
TextBox
txtSaisie
campo di inserimento
2
Pulsante
btnAjouter
pulsante che consente di aggiungere il contenuto del campo di immissione 1 all'elenco 3
3
ListBox
listBox1
elenco 1
4
ListBox
listBox2
elenco 2
5
Pulsante
btn1TO2
sposta gli elementi selezionati dall'elenco 1 all'elenco 2
6
Pulsante
cmd2T0
esegue l'operazione inversa
7
Pulsante
btnEffacer1
svuota l'elenco 1
8
Pulsante
btnEffacer2
svuota l'elenco 2
  • L'utente digita del testo nel campo 1. Lo aggiunge all'elenco 1 tramite il pulsante Ajouter (2). Il campo di immissione (1) viene quindi svuotato e l'utente può aggiungere un nuovo elemento.
  • Può trasferire elementi da un elenco all’altro selezionando l’elemento da trasferire in uno degli elenchi e scegliendo il pulsante di trasferimento appropriato 5 o 6. L’elemento trasferito viene aggiunto alla fine dell’elenco di destinazione e rimosso dall’elenco di origine.
  • Può fare doppio clic su un elemento dell’elenco 1. L’elemento viene quindi trasferito nella casella di immissione per essere modificato e rimosso dall’elenco 1.

I pulsanti sono attivi o disattivi secondo le seguenti regole:

  • il pulsante Ajouter è attivo solo se nel campo di immissione è presente del testo
  • il pulsante 5 di trasferimento dall’elenco 1 all’elenco 2 è attivo solo se nell’elenco 1 è presente un elemento selezionato
  • il pulsante 6 per il trasferimento dall’elenco 2 all’elenco 1 è attivo solo se nell’elenco 2 è presente un elemento selezionato
  • i pulsanti 7 e 8 per la cancellazione delle liste 1 e 2 sono attivi solo se la lista da cancellare contiene elementi.

Nelle condizioni precedenti, tutti i pulsanti devono essere spenti all’avvio dell’applicazione. È quindi necessario impostare la proprietà Enabled dei pulsanti su false. È possibile farlo in fase di progettazione, il che genererà il codice corrispondente nel metodo InitializeComponent, oppure farlo manualmente nel costruttore come di seguito:


    Public Sub New()
        ' creazione iniziale del modulo
        InitializeComponent()
        ' inizializzazioni aggiuntive
        ' si disabilitano alcuni pulsanti
        btnAjouter.Enabled = False
        btn1TO2.Enabled = False
        btn2TO1.Enabled = False
        btnEffacer1.Enabled = False
        btnEffacer2.Enabled = False
    End Sub

Lo stato del pulsante Ajouter è controllato dal contenuto del campo di immissione. È l’evento TextChanged che ci permette di monitorare le modifiche di tale contenuto:


    ' modifica nel campo di immissione testo
    Private Sub txtSaisie_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles txtSaisie.TextChanged
        ' il contenuto di txtSaisie è cambiato
        ' il pulsante Aggiungi è attivo solo se il campo di immissione non è vuoto
        btnAjouter.Enabled = txtSaisie.Text.Trim() <> ""
    End Sub

Lo stato dei pulsanti di trasferimento dipende dal fatto che sia stato selezionato o meno un elemento nell'elenco che essi controllano:


    ' modifica dell'elemento selezionato senza listbox1
    Private Sub listBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles listBox1.SelectedIndexChanged

        ' è stato selezionato un elemento
        ' si attiva il pulsante di trasferimento da 1 a 2
        btn1TO2.Enabled = True
    End Sub

    ' modifica dell'elemento selezionato senza listbox2
    Private Sub listBox2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles listBox2.SelectedIndexChanged
        ' È stato selezionato un elemento
        ' si attiva il pulsante di trasferimento da 2 a 1
        btn2TO1.Enabled = True
    End Sub

Il codice associato al clic sul pulsante Ajouter è il seguente:


    ' clic sul pulsante Aggiungi
    Private Sub btnAjouter_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnAjouter.Click
        ' aggiunta di un nuovo elemento  all'elenco 1
        listBox1.Items.Add(txtSaisie.Text.Trim())
        ' cancellazione del dato inserito
        txtSaisie.Text = ""
        ' L'elenco 1 non è vuoto
        btnEffacer1.Enabled = True
        ' il focus torna sulla casella di immissione
        txtSaisie.Focus()
    End Sub

Da notare il metodo Focus che consente di portare il «focus» su un controllo del modulo. Il codice associato al clic sui pulsanti Effacer:


    ' clic sul pulsante Cancella1
    Private Sub btnEffacer1_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnEffacer1.Click
        ' si cancella la lista 1
        listBox1.Items.Clear()
        btnEffacer1.Enabled = False
    End Sub

    ' clic sul pulsante Cancella2
    Private Sub btnEffacer2_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        ' si cancella l'elenco 2
        listBox2.Items.Clear()
        btnEffacer2.Enabled = False
    End Sub

Il codice per trasferire gli elementi selezionati da un elenco all’altro:


    ' clic sul pulsante btn1to2
    Private Sub btn1TO2_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btn1TO2.Click
        ' trasferimento dell'elemento selezionato dall'Elenco 1 all'Elenco 2
        transfert(listBox1, listBox2)
        ' Pulsanti «Cancella»
        btnEffacer2.Enabled = True
        btnEffacer1.Enabled = listBox1.Items.Count <> 0
        ' Pulsanti di trasferimento
        btn1TO2.Enabled = False
        btn2TO1.Enabled = False
    End Sub

    ' clic sul pulsante btn2to1
    Private Sub btn2TO1_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btn2TO1.Click
        ' trasferimento dell'elemento selezionato dall'Elenco 2 all'Elenco 1
        transfert(listBox2, listBox1)
        ' pulsanti Cancella
        btnEffacer1.Enabled = True
        btnEffacer2.Enabled = listBox2.Items.Count <> 0
        ' pulsanti di trasferimento
        btn1TO2.Enabled = False
        btn2TO1.Enabled = False
    End Sub

    ' trasferimento
    Private Sub transfert(ByVal l1 As ListBox, ByVal l2 As ListBox)
        ' trasferimento dell'elemento selezionato dall'elenco 1 all'elenco l2
        ' un elemento selezionato?
        If l1.SelectedIndex = -1 Then Return
        ' aggiunta in l2
        l2.Items.Add(l1.SelectedItem)
        ' eliminazione da l1
        l1.Items.RemoveAt(l1.SelectedIndex)
    End Sub

Per prima cosa, si crea un metodo


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

che trasferisce nell'elenco l2 l'elemento selezionato nell'elenco l1. Questo ci permette di avere un unico metodo invece di due per trasferire un elemento da listBox1 a listBox2 o da listBox2 a listBox1. Prima di effettuare il trasferimento, ci assicuriamo che sia effettivamente selezionato un elemento nell’elenco l1:


        ' un elemento selezionato?
        If l1.SelectedIndex = -1 Then Return

La proprietà SelectedIndex assume il valore -1 se al momento non è selezionato alcun elemento. Nelle procedure


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

si esegue il trasferimento dall'elenco X all'elenco Y e si modifica lo stato di alcuni pulsanti per riflettere il nuovo stato degli elenchi.

5.4.5. caselle di controllo CheckBox, pulsanti di opzione ButtonRadio

Ci proponiamo di scrivere la seguente applicazione:

I componenti della finestra sono i seguenti:

tipo
nome
ruolo
1
RadioButton
radioButton1
radioButton2
radioButton3
3 pulsanti di opzione
2
CheckBox
chechBox1
chechBox2
chechBox3
3 caselle di selezione
3
ListBox
lstValeurs
un elenco

Se si creano i tre pulsanti di opzione uno dopo l'altro, per impostazione predefinita fanno parte dello stesso gruppo. Pertanto, quando uno è selezionato, gli altri non lo sono. L'evento che ci interessa per questi sei controlli è l'evento CheckChanged, che indica che lo stato della casella di controllo o del pulsante di opzione è cambiato. Questo stato è rappresentato in entrambi i casi dalla proprietà booleana Check che, se vera, significa che il controllo è selezionato. In questo caso abbiamo utilizzato un unico metodo per gestire i sei eventi CheckChanged, ovvero il metodo affiche:


  ' visualizza
    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
        ' visualizza lo stato del pulsante di opzione o della casella di controllo
        ' è una casella di controllo?
        If (TypeOf (sender) Is CheckBox) Then
            Dim chk As CheckBox = CType(sender, CheckBox)
            lstValeurs.Items.Insert(0, chk.Name & "=" & chk.Checked)
        End If
        ' È un pulsante di opzione?
        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

La sintassi TypeOf (mittente) Is CheckBox consente di verificare se l’oggetto sender è di tipo CheckBox. Ciò ci permette quindi di effettuare una conversione al tipo esatto di sender. Il metodo affiche scrive nell’elenco lstValeurs il nome del componente all’origine dell’evento e il valore della sua proprietà Checked. All'esecuzione, si osserva che un clic su un pulsante di opzione provoca due eventi CheckChanged: uno sul vecchio pulsante selezionato, che passa a “non selezionato”, e l’altro sul nuovo pulsante, che passa a “selezionato”.

5.4.6. regolatori ScrollBar

Esistono diversi tipi di variatore: il variatore orizzontale (hScrollBar),
il variatore verticale (vScrollBar), l’incrementatore (NumericUpDown).

Realizziamo la seguente applicazione:

n.
tipo
nome
ruolo
1
hScrollBar
hScrollBar1
un variatore orizzontale
2
hScrollBar
hScrollBar2
un variatore orizzontale che segue le variazioni del variatore 1
3
TextBox
txtValeur
visualizza il valore del variatore orizzontale
ReadOnly=true per impedire qualsiasi immissione
4
NumericUpDown
incrementatore
consente di impostare il valore del variatore 2
  • Un variatore ScrollBar consente all'utente di scegliere un valore all'interno di un intervallo di valori interi rappresentato dalla "barra" del variatore su cui si sposta un cursore. Il valore del variatore è disponibile nella sua proprietà Value.
  • Per un variatore orizzontale, l’estremità sinistra rappresenta il valore minimo dell’intervallo, l’estremità destra il valore massimo, mentre il cursore rappresenta il valore attuale selezionato. Per un variatore verticale, il minimo è rappresentato dall’estremità superiore, il massimo dall’estremità inferiore. Questi valori sono rappresentati dalle proprietà Minimum e Maximum e hanno valori predefiniti pari a 0 e 100.
  • Un clic sulle estremità del variatore modifica il valore di un incremento (positivo o negativo) a seconda dell’estremità cliccata, denominata SmallChange, il cui valore predefinito è 1.
  • Un clic su entrambi i lati del cursore fa variare il valore di un incremento (positivo o negativo) a seconda dell’estremità cliccata, denominata LargeChange, che per impostazione predefinita è 10.
  • Quando si clicca sull’estremità superiore di un cursore verticale, il suo valore diminuisce. Ciò può sorprendere l’utente medio, che normalmente si aspetta di vedere il valore «aumentare». Si risolve questo problema assegnando un valore negativo alle proprietà SmallChange e LargeChange
  • Queste cinque proprietà (Value, Minimum, Maximum, SmallChange, LargeChange) sono accessibili sia in lettura che in scrittura.
  • L'evento principale del variatore è quello che segnala una variazione di valore: l'evento Scroll.

Un componente NumericUpDown si trova vicino al variatore: anch’esso presenta le proprietà Minimum, Maximum e Value, con valori predefiniti rispettivamente pari a 0, 100 e 0. In questo caso, però, la proprietà Value viene visualizzata in una casella di immissione che fa parte integrante del controllo. L'utente può modificare autonomamente questo valore, a meno che non si sia impostata la proprietà ReadOnly del controllo su "vero". Il valore dell'incremento è definito dalla proprietà Increment, il cui valore predefinito è 1. L'evento principale del componente NumericUpDown è quello che segnala una modifica del valore: l'evento ValueChanged. Il codice utile della nostra applicazione è il seguente:

Il modulo viene formattato al momento della sua creazione:


    ' costruttore
    Public Sub New()
        ' creazione iniziale del modulo
        InitializeComponent()
        ' si assegnano al variatore 2 le stesse caratteristiche del variatore 1
        hScrollBar2.Minimum = hScrollBar1.Value
        hScrollBar2.Minimum = hScrollBar1.Minimum
        hScrollBar2.Maximum = hScrollBar1.Maximum
        hScrollBar2.LargeChange = hScrollBar1.LargeChange
        hScrollBar2.SmallChange = hScrollBar1.SmallChange
        ' idem per l'incrementatore
        incrémenteur.Minimum = hScrollBar1.Value
        incrémenteur.Minimum = hScrollBar1.Minimum
        incrémenteur.Maximum = hScrollBar1.Maximum
        incrémenteur.Increment = hScrollBar1.SmallChange
        ' si assegna a TextBox il valore del variatore 1
        txtValeur.Text = "" & hScrollBar1.Value
    End Sub

Il gestore che monitora le variazioni di valore del variatore 1:


    ' gestione del variatore hscrollbar1
    Private Sub hScrollBar1_Scroll(ByVal sender As Object, ByVal e As System.Windows.Forms.ScrollEventArgs) _
    Handles hScrollBar1.Scroll
        ' modifica del valore del variatore 1
        ' si trasferisce il suo valore al variatore 2 e alla casella di testo TxtValeur
        hScrollBar2.Value = hScrollBar1.Value
        txtValeur.Text = "" & hScrollBar1.Value
    End Sub

Il gestore che monitora le variazioni di valore del variatore 2:


    ' gestione del variatore hscrollbar2
    Private Sub hScrollBar2_Scroll(ByVal sender As Object, ByVal e As System.Windows.Forms.ScrollEventArgs) _
    Handles hScrollBar2.Scroll
        ' si inibisce qualsiasi modifica del variatore 2
        ' costringendolo a mantenere il valore del variatore 1
        e.NewValue = hScrollBar1.Value
    End Sub

Il gestore che monitora le variazioni del controllo incrémenteur:


    ' gestione dell'incrementatore
    Private Sub incrémenteur_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles incrémenteur.ValueChanged
        ' si imposta il valore del variatore 2
        hScrollBar2.Value = CType(incrémenteur.Value, Integer)
    End Sub

5.5. Eventi del mouse

Quando si disegna in un contenitore, è importante conoscere la posizione del mouse per, ad esempio, visualizzare un punto al clic. Gli spostamenti del mouse generano eventi nel contenitore in cui si muove.

 
il mouse è appena entrato nell’area del controllo
MouseLeave
il mouse ha appena lasciato l'area di controllo
MouseMove
il mouse si sta muovendo nell'area di controllo
MouseDown
Pressione del tasto sinistro del mouse
MouseUp
Rilascio del tasto sinistro del mouse
DragDrop
l'utente rilascia un oggetto sul controllo
DragEnter
l'utente entra nell'area del controllo trascinando un oggetto
DragLeave
l'utente esce dall'area del controllo trascinando un oggetto
DragOver
l'utente passa sopra l'area del controllo trascinando un oggetto

Ecco un programma che permette di comprendere meglio in quali momenti si verificano i diversi eventi del mouse:

n.
tipo
nome
ruolo
1
Etichetta
lblPosition
per visualizzare la posizione del mouse nel modulo 1, nell'elenco 2 o nel pulsante 3
2
ListBox
lstEvts
per visualizzare gli eventi del mouse diversi da MouseMove
3
Pulsante
btnEffacer
per cancellare il contenuto di 2

I gestori di eventi sono i seguenti. Per seguire i movimenti del mouse sui tre controlli, si scrive un solo gestore:


    ' event. 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
        ' movimento del mouse - visualizzazione delle coordinate (X,Y) del mouse
        lblPosition.Text = "(" & e.X & "," & e.Y & ")"
    End Sub

È importante sapere che ogni volta che il mouse entra nell'area di un controllo, il suo sistema di coordinate cambia. Il suo punto di origine (0,0) è l'angolo superiore sinistro del controllo su cui si trova. Pertanto, durante l'esecuzione, quando si sposta il mouse dal modulo al pulsante, si nota chiaramente il cambiamento delle coordinate. Per osservare meglio questi cambiamenti di area del mouse, è possibile utilizzare la proprietà Cursor dei controlli:

Image

Questa proprietà consente di impostare la forma del cursore del mouse quando questo entra nell’area del controllo. Pertanto, nel nostro esempio, abbiamo impostato il cursore su Default per il modulo stesso, su Hand per l’elenco 2 e su No per il pulsante 3, come mostrano le schermate riportate di seguito.

Image

Image

Image

Nel metodo [InitializeComponent], il codice generato da queste impostazioni è il seguente:


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

Inoltre, per rilevare l'entrata e l'uscita del mouse dall'elenco 2, elaboriamo gli eventi MouseEnter e MouseLeave dello stesso elenco:


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

    ' evento 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
    
' visualizza
    Private Sub affiche(ByVal message As String)
        ' il messaggio viene visualizzato in cima all'elenco degli eventi
        lstEvts.Items.Insert(0, message)
    End Sub

Image

Per gestire i clic sul modulo, elaboriamo gli eventi MouseDown e MouseUp:


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

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

Image

Infine, il codice del gestore del clic sul pulsante Effacer:


    ' evento btnEffacer_Click
    Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
    Handles btnEffacer.Click
        ' cancella l'elenco degli eventi
        lstEvts.Items.Clear()
    End Sub

5.6. Creare una finestra con menu

Vediamo ora come creare una finestra con menu. Creeremo la seguente finestra:

Il controllo 1 è un TextBox in sola lettura (ReadOnly=true) e denominato txtStatut. La struttura ad albero del menu è la seguente:

Le opzioni di menu sono controlli come gli altri componenti visivi e dispongono di proprietà ed eventi. Ad esempio, la tabella delle proprietà dell’opzione di menu A1:

Image

Nel nostro esempio vengono utilizzate due proprietà:

 
il nome del controllo menu
Text
il testo dell'opzione di menu

Le proprietà delle diverse opzioni di menu del nostro esempio sono le seguenti:

Nome
Testo
mnuA
Opzioni A
mnuA1
A1
mnuA2
A2
mnuA3
A3
mnuB
opzioni B
mnuB1
B1
mnuSep1
- (separatore)
mnuB2
B2
mnuB3
B3
mnuB31
B31
mnuB32
B32

Per creare un menu, selezionare il componente "MainMenu" nella barra "ToolBox":

Image

Si ottiene così un menu vuoto che viene inserito nel modulo con delle caselle vuote denominate "Type Here". È sufficiente inserire le diverse opzioni del menu:

Image

Per inserire un separatore tra due opzioni, come sopra tra le opzioni B1 e B2, posizionarsi nel punto in cui si desidera inserire il separatore nel menu, fare clic con il tasto destro del mouse e selezionare l’opzione “Insert Separator”:

Image

Se si avvia l’applicazione con Ctrl+F5, si ottiene un modulo con un menu che per il momento non svolge alcuna funzione. Le opzioni del menu sono trattate come componenti: dispongono di proprietà ed eventi. In [fenêtre de code], selezionare il componente mnuA1, quindi selezionare gli eventi associati:

Image

Se sopra si genera l’evento Click, VS.NET genera automaticamente la seguente procedura:


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

Potremmo procedere in questo modo per tutte le opzioni di menu. In questo caso, la stessa procedura può essere utilizzata per tutte le opzioni. Pertanto, rinominiamo la procedura precedente affiche e dichiariamo gli eventi che gestisce:


    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
        ' visualizza in TextBox il nome del sottomenu selezionato
        txtStatut.Text = (CType(sender, MenuItem)).Text
    End Sub

In questo metodo, ci limitiamo a visualizzare la proprietà Text dell'opzione di menu nella fonte dell'evento. La fonte dell'evento sender è di tipo object. Le opzioni di menu sono invece di tipo MenuItem, pertanto in questo caso è necessario effettuare una conversione da object a MenuItem. Eseguite l’applicazione e selezionate l’opzione A1 per ottenere il seguente messaggio:

Image

Il codice utile di questa applicazione, oltre a quello del metodo affiche, è quello relativo alla creazione del menu nel costruttore del modulo (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

Da notare l’istruzione che associa il menu al modulo:


    Me.Menu = Me.mainMenu1

5.7. Componenti non visivi

Ci occupiamo ora di una serie di componenti non visivi: vengono utilizzati in fase di progettazione, ma non sono visibili durante l’esecuzione.

5.7.1. Finestre di dialogo OpenFileDialog e SaveFileDialog

Realizzeremo la seguente applicazione:

I controlli sono i seguenti:

N.
tipo
nome
ruolo
1
TextBox multilinea
txtTexte
testo digitato dall'utente o caricato da un file
2
Pulsante
btnSauvegarder
consente di salvare il testo di 1 in un file di testo
3
Pulsante
btnCharger
consente di caricare il contenuto di un file di testo in 1
4
Pulsante
btnEffacer
cancella il contenuto di 1

Vengono utilizzati due controlli non visivi:

Image

Quando vengono trascinati dal "ToolBox" e rilasciati sul modulo, vengono posizionati in un'area separata nella parte inferiore del modulo. I componenti "Dialog" vengono trascinati dal "ToolBox":

Image

Il codice del pulsante Effacer è semplice:


    Private Sub btnEffacer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnEffacer.Click
        ' si cancella la casella di immissione
        txtTexte.Text = ""
    End Sub

La classe SaveFileDialog è definita come segue:

Image

Deriva da diversi livelli di classe. Tra le numerose proprietà e metodi, ne ricorderemo i seguenti:

string Filter
i tipi di file disponibili nell’elenco a discesa dei tipi di file nella finestra di dialogo
int FilterIndex
il numero del tipo di file proposto per impostazione predefinita nell'elenco sopra riportato. Inizia da 0.
String
InitialDirectory
la cartella inizialmente indicata per il salvataggio del file
string FileName
il nome del file di salvataggio specificato dall'utente
DialogResult.ShowDialog()
metodo che visualizza la finestra di dialogo di salvataggio. Restituisce un risultato di tipo DialogResult.

Il metodo ShowDialog visualizza una finestra di dialogo simile alla seguente:

1
elenco a discesa generato dalla proprietà Filter. Il tipo di file proposto per impostazione predefinita è determinato da FilterIndex
2
cartella corrente, impostata da InitialDirectory se questa proprietà è stata specificata
3
nome del file scelto o digitato direttamente dall’utente. Sarà disponibile nella proprietà FileName
4
pulsanti Salva/Annulla. Se viene utilizzato il pulsante Enregistrer, la funzione ShowDialog restituisce il risultato DialogResult.OK

La procedura di salvataggio può essere scritta come segue:


    Private Sub btnSauvegarder_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnSauvegarder.Click
        ' si salva la casella di immissione in un file di testo
        ' si configura la finestra di dialogo savefileDialog1
        saveFileDialog1.InitialDirectory = Application.ExecutablePath
        saveFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"
        saveFileDialog1.FilterIndex = 0
        ' si visualizza la finestra di dialogo e si recupera il risultato
        If saveFileDialog1.ShowDialog() = DialogResult.OK Then
            ' si recupera il nome del file
            Dim nomFichier As String = saveFileDialog1.FileName
            Dim fichier As StreamWriter = Nothing
            Try
                ' si apre il file in modalità di scrittura
                fichier = New StreamWriter(nomFichier)
                ' qui si inserisce il testo
                fichier.Write(txtTexte.Text)
            Catch ex As Exception
                ' problema
                MessageBox.Show("Problème à l'écriture du fichier (" + ex.Message + ")", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error)
                Return
            Finally
                ' si chiude il file
                Try
                    fichier.Close()
                Catch
                End Try
            End Try
        End If
    End Sub
  • Si associa la cartella iniziale alla cartella che contiene l'eseguibile dell'applicazione:
        saveFileDialog1.InitialDirectory = Application.ExecutablePath
  • Si specificano i tipi di file da visualizzare
        saveFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"

Si noti la sintassi dei filtri filtro1|filtro2|..|filtroi con filtroi= Testo|modello di file. In questo caso l'utente potrà scegliere tra i file *.txt e *.*.

  • Si imposta il tipo di file da visualizzare all’inizio
        saveFileDialog1.FilterIndex = 0

In questo caso, saranno i file di tipo *.txt a essere visualizzati per primi all'utente.

  • Viene visualizzata la finestra di dialogo e ne viene recuperato il risultato

    If saveFileDialog1.ShowDialog() = DialogResult.OK Then
  • Mentre la finestra di dialogo è visualizzata, l'utente non ha più accesso al modulo principale (finestra di dialogo cosiddetta modale). L'utente specifica il nome del file da salvare e chiude la finestra di dialogo tramite il pulsante Salva, il pulsante Annulla oppure chiudendo direttamente la finestra. Il risultato del metodo ShowDialog è DialogResult.OK solo se l’utente ha utilizzato il pulsante Enregistrer per chiudere la finestra di dialogo.
  • A questo punto, il nome del file da creare si trova ora nella proprietà FileName dell’oggetto saveFileDialog1. Si torna quindi alla creazione classica di un file di testo. Vi si scrive il contenuto di TextBox: txtTexte.Text, gestendo al contempo le eccezioni che potrebbero verificarsi.

La classe OpenFileDialog è molto simile alla classe SaveFileDialog e deriva dalla stessa linea di classi. Tra le sue proprietà e metodi, ne ricorderemo i seguenti:

string Filter
i tipi di file proposti nell’elenco a discesa dei tipi di file della finestra di dialogo
int FilterIndex
il numero del tipo di file proposto per impostazione predefinita nell'elenco sopra riportato. Inizia da 0.
string InitialDirectory
la cartella visualizzata inizialmente per la ricerca del file da aprire
string FileName
il nome del file da aprire indicato dall'utente
DialogResult.ShowDialog()
metodo che visualizza la finestra di dialogo di salvataggio. Restituisce un risultato di tipo DialogResult.

Il metodo ShowDialog visualizza una finestra di dialogo simile alla seguente:

1
elenco a discesa generato dalla proprietà Filter. Il tipo di file proposto per impostazione predefinita è determinato da FilterIndex
2
cartella corrente, impostata da InitialDirectory se questa proprietà è stata specificata
3
nome del file scelto o digitato direttamente dall’utente. Sarà disponibile nella proprietà FileName
4
pulsanti Apri/Annulla. Se viene utilizzato il pulsante Ouvrir, la funzione ShowDialog restituisce il risultato DialogResult.OK

La procedura di apertura può essere scritta come segue:


Private Sub btnCharger_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnCharger.Click
        ' si carica un file di testo nella casella di immissione
        ' si configura la finestra di dialogo openfileDialog1
        openFileDialog1.InitialDirectory = Application.ExecutablePath
        openFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"
        openFileDialog1.FilterIndex = 0
        ' si visualizza la finestra di dialogo e si recupera il risultato
        If openFileDialog1.ShowDialog() = DialogResult.OK Then
            ' si recupera il nome del file
            Dim nomFichier As String = openFileDialog1.FileName
            Dim fichier As StreamReader = Nothing
            Try
                ' si apre il file in modalità di lettura
                fichier = New StreamReader(nomFichier)
                ' si legge l'intero file e lo si inserisce in TextBox
                txtTexte.Text = fichier.ReadToEnd()
            Catch ex As Exception
                ' problema
                MessageBox.Show("Problème à la lecture du fichier (" + ex.Message + ")", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error)
                Return
            Finally
                ' si chiude il file
                Try
                    fichier.Close()
                Catch
                End Try
            End Try
        End If
    End Sub
  • Si imposta la cartella iniziale come quella contenente l'eseguibile dell'applicazione:
            saveFileDialog1.InitialDirectory=Application.ExecutablePath
  • Si specificano i tipi di file da presentare
            saveFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"
  • Si imposta il tipo di file da visualizzare all'inizio
            saveFileDialog1.FilterIndex = 0

In questo caso, saranno i file di tipo *.txt a essere visualizzati per primi all'utente.

  • Viene visualizzata la finestra di dialogo e se ne recupera il risultato

    If openFileDialog1.ShowDialog() = DialogResult.OK Then

Mentre la finestra di dialogo è visualizzata, l'utente non ha più accesso al modulo principale (finestra di dialogo cosiddetta modale). L'utente specifica il nome del file da aprire e chiude la finestra di dialogo tramite il pulsante Apri, il pulsante Annulla oppure chiudendo direttamente la finestra. Il risultato del metodo ShowDialog è DialogResult.OK solo se l’utente ha utilizzato il pulsante Ouvrir per chiudere la finestra di dialogo.

  • A questo punto, il nome del file da creare si trova ora nella proprietà FileName dell’oggetto openFileDialog1. Si torna quindi alla classica lettura di un file di testo. Si noti il metodo che consente di leggere l’intero file:
                    txtTexte.Text=fichier.ReadToEnd
  • il contenuto del file viene inserito in TextBox txtTexte. Si gestiscono le eccezioni che potrebbero verificarsi.

5.7.2. Finestre di dialogo FontColor e ColorDialog

Proseguiamo l'esempio precedente presentando due nuovi pulsanti:

N.
tipo
nome
funzione
6
Pulsante
btnCouleur
per impostare il colore dei caratteri di TextBox
7
Pulsante
btnPolice
per impostare il carattere di TextBox

Inseriamo nel modulo un controllo ColorDialog e un controllo FontDialog:

Image

Le classi FontDialog e ColorDialog dispongono di un metodo ShowDialog analogo al metodo ShowDialog delle classi OpenFileDialog e SaveFileDialog. Il metodo ShowDialog della classe ColorDialog consente di scegliere un colore:

Image

Se l’utente chiude la finestra di dialogo con il pulsante OK, il risultato del metodo ShowDialog è DialogResult.OK e il colore selezionato si trova nella proprietà Color dell'oggetto ColorDialog utilizzato. Il metodo ShowDialog della classe FontDialog consente di scegliere un tipo di carattere:

Image

Se l'utente chiude la finestra di dialogo con il pulsante OK, il risultato del metodo ShowDialog è DialogResult.OK e il carattere selezionato si trova nella proprietà Font dell'oggetto FontDialog utilizzato. Abbiamo gli elementi per gestire i clic sui pulsanti Couleur e Police:


    Private Sub btnCouleur_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnCouleur.Click
        ' scelta di un colore per il testo
        If colorDialog1.ShowDialog() = DialogResult.OK Then
            ' si modifica la proprietà forecolor di 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
        ' scelta di un tipo di carattere
        If fontDialog1.ShowDialog() = DialogResult.OK Then
            ' si modifica la proprietà font di TextBox
            txtTexte.Font = fontDialog1.Font
        End If
    End Sub

5.7.3. Timer

Qui ci proponiamo di scrivere la seguente applicazione:

n.
Tipo
Nome
Ruolo
1
TextBox, ReadOnly=true
txtChrono
visualizza un cronometro
2
Pulsante
btnArretMarche
pulsante Start/Stop del cronometro
3
Timer
timer1
componente che emette un evento ogni secondo

Il cronometro è in funzione:

Image

Il cronometro è fermo:

Image

Per modificare ogni secondo il contenuto di TextBox e txtChrono, abbiamo bisogno di un componente che generi un evento ogni secondo, evento che potremo intercettare per aggiornare la visualizzazione del cronometro. Questo componente è il Timer:

Image

Una volta installato questo componente nel modulo (nella sezione dei componenti non visivi), nel costruttore del modulo viene creato un oggetto di tipo Timer. La classe System.Windows.Forms.Timer è definita come segue:

Image

Tra le sue proprietà, ne prenderemo in considerazione solo le seguenti:

Interval
numero di millisecondi al termine dei quali viene generato un evento Tick.
Tick
l'evento generato al termine di Interval millisecondi
Enabled
imposta il timer come attivo (true) o inattivo (false)

Nel nostro esempio il timer si chiama timer1 e timer1.Interval è impostato a 1000 ms (1 s). L'evento Tick si verificherà quindi ogni secondo. Il clic sul pulsante On/Off viene gestito dalla seguente procedura:


    Private Sub btnArretMarche_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles btnArretMarche.Click
        ' Arresto o avvio?
        If btnArretMarche.Text = "Marche" Then
            ' si annota l'ora di inizio
            début = DateTime.Now
            ' lo si visualizza
            txtChrono.Text = "00:00:00"
            ' si avvia il timer
            timer1.Enabled = True
            ' si modifica la dicitura del pulsante
            btnArretMarche.Text = "Arrêt"
            ' fine
            Return
        End If        '
        If btnArretMarche.Text = "Arrêt" Then
            ' arresto del timer
            timer1.Enabled = False
            ' si modifica il testo del pulsante
            btnArretMarche.Text = "Marche"
            ' fine
            Return
        End If
    End Sub

    Private Sub timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles timer1.Tick
        ' è trascorso un secondo
        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

Il testo del pulsante On/Off è “Off” oppure “On”. È quindi necessario verificare il testo per determinare l’azione da eseguire.

  • nel caso di "On", si registra l'ora di inizio in una variabile globale dell'oggetto modulo, si avvia il timer (Enabled=true) e il testo del pulsante passa a "Off".
  • Nel caso di "Arresto", si arresta il timer (Enabled=false) e si imposta l'etichetta del pulsante su "Avvio".

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

  ' variabili di istanza
  Private début As DateTime

L’attributo début sopra indicato è riconosciuto in tutti i metodi della classe. Resta da gestire l’evento Tick sull’oggetto timer1, evento che si verifica ogni secondo:


    Private Sub timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles timer1.Tick
        ' è trascorso un secondo
        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

Si calcola il tempo trascorso dall’ora di avvio del cronometro. Si ottiene un oggetto di tipo TimeSpan che rappresenta un intervallo di tempo. Questo deve essere visualizzato nel cronometro nel formato hh:mm:ss. A tal fine utilizziamo le proprietà Hours, Minutes, Seconds dell’oggetto TimeSPan, che rappresentano rispettivamente le ore, i minuti e i secondi della durata che visualizziamo nel formato ToString("d2") per ottenere una visualizzazione a 2 cifre.

5.8. L'esempio IMPOTS

Riprendiamo l’applicazione IMPOTS già trattata due volte. Ora vi aggiungiamo un’interfaccia grafica:

I controlli sono i seguenti

n.
tipo
nome
ruolo
1
RadioButton
rdOui
spuntare se sposato
2
RadioButton
rdNon
spuntare se non sposato
3
NumericUpDown
incEnfants
numero di figli del contribuente
Minimo=0, Massimo=20, Incremento=1
4
TextBox
txtSalaire
stipendio annuo del contribuente in F
5
TextBox
txtImpots
importo dell'imposta da pagare
ReadOnly=true
6
Pulsante
btnCalculer
avvia il calcolo dell'imposta
7
Pulsante
btnEffacer
ripristina il modulo allo stato iniziale al momento del caricamento
8
Pulsante
btnQuitter
per uscire dall'applicazione

Regole di funzionamento

  • il pulsante «Calcola» rimane disattivato finché il campo dello stipendio è vuoto
  • se, una volta avviato il calcolo, si riscontra che lo stipendio è errato, viene segnalato l’errore:

Image

Il programma è riportato di seguito. Utilizza la classe impot creata nel capitolo dedicato alle classi. Una parte del codice generato automaticamente da VS.NET non è stata qui riprodotta.


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

' spazi dei nomi
Imports System
Imports System.Drawing
Imports System.Collections
Imports System.ComponentModel
Imports System.Windows.Forms
Imports System.Data

' classe modulo
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

  ' tabelle di dati necessarie per il calcolo dell'imposta
  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}
   ' oggetto imposta
  Private objImpôt As impot = Nothing


  Public Sub New()
    InitializeComponent()
     ' inizializzazione del modulo
    btnEffacer_Click(Nothing, Nothing)
    btnCalculer.Enabled = False
     ' creazione di un oggetto imposta
    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)
       ' si disabilita il campo di immissione dello stipendio
      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
     ' azzeramento del modulo
    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
     ' stato del pulsante «Calcola»
    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
     ' fine dell'applicazione
    Application.Exit()
  End Sub 'btnQuitter_Click


  Private Sub btnCalculer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
  Handles btnCalculer.Click
     ' Lo stipendio è corretto?
    Dim intSalaire As Integer = 0
    Try
      ' recupero dello stipendio
      intSalaire = Integer.Parse(txtSalaire.Text)
       ' deve essere >=0
      If intSalaire < 0 Then
        Throw New Exception("")
      End If
    Catch ex As Exception
      ' messaggio di errore
      MessageBox.Show(Me, "Salaire incorrect", "Erreur de saisie", MessageBoxButtons.OK, MessageBoxIcon.Error)
       ' focus sul campo errato
      txtSalaire.Focus()
       ' selezione del testo nel campo di immissione
      txtSalaire.SelectAll()
       ' ritorno all'interfaccia visiva
      Return
    End Try 'try-catch
    ' lo stipendio è corretto - si calcola l'imposta
    txtImpots.Text = "" & CLng(objImpôt.calculer(rdOui.Checked, CInt(incEnfants.Value), intSalaire))
  End Sub 'btnCalculer_Click
End Class

Qui utilizziamo l'assembly impots.dll, risultato della compilazione della classe impots del capitolo 2. Ricordiamo che questo assembly può essere generato in modalità console tramite il comando

dos>vbc /t:library impots.vb

Questo comando genera il file impots.dll denominato «assemblaggio». Tale assemblaggio può essere successivamente utilizzato in diversi progetti. Qui, nel nostro progetto denominato VS.NET, utilizziamo la finestra delle proprietà del progetto:

Image

Per aggiungere un riferimento (un assieme), facciamo clic con il tasto destro del mouse sul gruppo chiave «Riferimenti» sopra indicato, selezioniamo l’opzione [Ajouter une référence] e indichiamo l’assieme [impots.dll] che abbiamo provveduto a inserire nella cartella del progetto:

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

Una volta incluso l’assembly [impots.dll] nel progetto, la classe [impots] diventa nota al progetto. In precedenza non lo era. Un altro metodo consiste nell’includere il file sorgente impots.vb nel progetto. A tal fine, nella finestra delle proprietà del progetto, si fa clic con il tasto destro del mouse sul progetto, si seleziona l’opzione [Ajouter/Ajouter un élément existant] e si indica il file impots.vb.