5. Interfaces gráficas com VB.NET e VS.NET
Propomos aqui mostrar como criar interfaces gráficas com o VB.NET. Começamos por ver quais são as classes de base da plataforma .NET que nos permitem criar uma interface gráfica. Numa primeira fase, não utilizamos nenhuma ferramenta de geração automática. Posteriormente, utilizaremos o Visual Studio.NET (VS.NET), uma ferramenta de desenvolvimento da Microsoft que facilita o desenvolvimento de aplicações com as linguagens .NET e, em particular, a criação de interfaces gráficas. A versão VS.NET utilizada é a versão em inglês.
5.1. Noções básicas sobre interfaces gráficas
5.1.1. Uma janela simples
Consideremos o seguinte código:
' opções
Option Strict On
Option Explicit On
' espaços de nomes
Imports System
Imports System.Drawing
Imports System.Windows.Forms
' a classe do formulário
Public Class Form1
Inherits Form
' o fabricante
Public Sub New()
' título da janela
Me.Text = "Mon premier formulaire"
' dimensões da janela
Me.Size = New System.Drawing.Size(300, 100)
End Sub
' função de teste
Public Shared Sub Main(ByVal args() As String)
' exibe-se o formulário
Application.Run(New Form1)
End Sub
End Class
O código anterior é compilado e, em seguida, executado
A execução apresenta a seguinte janela:

Uma interface gráfica deriva, geralmente, da classe base System.Windows.Forms.Form:
A classe base Form define uma janela básica com botões para fechar, ampliar/reduzir, tamanho ajustável, etc., e gere os eventos nestes objetos gráficos. Aqui, especializamos a classe base, definindo-lhe um título e as suas largura (300) e altura (100). Isto é feito no seu construtor:
Public Sub New()
' título da janela
Me.Text = "Mon premier formulaire"
' dimensões da janela
Me.Size = New System.Drawing.Size(300, 100)
End Sub
O título da janela é definido pela propriedade Text e as dimensões pela propriedade Size. Size está definido no espaço de nomes System.Drawing e é uma estrutura. O procedimento Main inicia a aplicação gráfica da seguinte forma:
Application.Run(New Form1)
É criado e apresentado um formulário do tipo Form1; em seguida, a aplicação fica à espera dos eventos que ocorrem no formulário (cliques, movimentos do rato, etc.) e executa aqueles que o formulário suporta. Neste caso, o nosso formulário não gere outros eventos além dos geridos pela classe base Form (cliques nos botões de fecho, maximizar/minimizar, alteração do tamanho da janela, deslocamento da janela, etc.).
5.1.2. Um formulário com um botão
Vamos agora adicionar um botão à nossa janela:
' opções
Option Strict On
Option Explicit On
' espaços de nomes
Imports System
Imports System.Drawing
Imports System.Windows.Forms
' a classe do formulário
Public Class Form1
Inherits Form
' atributos
Private cmdTest As Button
' o construtor
Public Sub New()
' o título
Me.Text = "Mon premier formulaire"
' as dimensões
Me.Size = New System.Drawing.Size(300, 100)
' um botão
' criação
Me.cmdTest = New Button
' posição
cmdTest.Location = New System.Drawing.Point(110, 20)
' tamanho
cmdTest.Size = New System.Drawing.Size(80, 30)
' rótulo
cmdTest.Text = "Test"
' gestor de eventos
AddHandler cmdTest.Click, AddressOf cmdTest_Click
' adição de botão ao formulário
Me.Controls.Add(cmdTest)
End Sub
' gestor de eventos
Private Sub cmdTest_Click(ByVal sender As Object, ByVal evt As EventArgs)
' houve um clique no botão - é indicado
MessageBox.Show("Clic sur bouton", "Clic sur bouton", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
' função de teste
Public Shared Sub Main(ByVal args() As String)
' exibe-se o formulário
Application.Run(New Form1)
End Sub
End Class
Adicionámos um botão ao formulário:
' um botão
' criação
Me.cmdTest = New Button
' posição
cmdTest.Location = New System.Drawing.Point(110, 20)
' tamanho
cmdTest.Size = New System.Drawing.Size(80, 30)
' designação
cmdTest.Text = "Test"
' gestor de eventos
AddHandler cmdTest.Click, AddressOf cmdTest_Click
' adição de botão ao formulário
Me.Controls.Add(cmdTest)
A propriedade Location define as coordenadas (110,20) do ponto superior esquerdo do botão utilizando uma estrutura Point. A largura e a altura do botão são definidas como (80,30) através de uma estrutura Size. A propriedade Text do botão permite definir o texto do botão. A classe «botão» possui um evento Click definido da seguinte forma:
onde EventHandler é uma função «delegada» com a seguinte assinatura:
Isto significa que o gestor do evento [Click] no botão deverá ter a assinatura do delegado [EventHandler]. Neste caso, ao clicar no botão cmdTest, será chamado o método cmdTest_Click. Este está definido da seguinte forma, de acordo com o modelo anterior EventHandler:
' gestor de eventos
Private Sub cmdTest_Click(ByVal sender As Object, ByVal evt As EventArgs)
' houve um clique no botão - é indicado
MessageBox.Show("Clic sur bouton", "Clic sur bouton", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
Limita-se a apresentar uma mensagem:

A classe é compilada e executada:
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
A classe MessageBox serve para apresentar mensagens numa janela. Aqui, utilizámos o construtor
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 | a mensagem a apresentar |
legenda | o título da janela |
botões | os botões presentes na janela |
icon | o ícone presente na janela |
O parâmetro buttons pode assumir valores entre as seguintes constantes:
constante | botões |
![]() | |
![]() | |
![]() | |
![]() | |
![]() | |
![]() |
O parâmetro icon pode assumir valores entre as seguintes constantes:
![]() | idem Stop | ||
idem Aviso | ![]() | ||
idem Asterisk | ![]() | ||
![]() | idem Hand | ||
![]() |
O método Show é um método estático que devolve um resultado do tipo System.Windows.Forms.DialogResult, que é uma enumeração:
public enum System.Windows.Forms.DialogResult
{
Abort = 0x00000003,
Cancel = 0x00000002,
Ignore = 0x00000005,
No = 0x00000007,
None = 0x00000000,
OK = 0x00000001,
Retry = 0x00000004,
Yes = 0x00000006,
}
Para saber em que botão o utilizador clicou para fechar a janela do tipo MessageBox, escrever-se-á:
dim res as DialogResult=MessageBox.Show(..)
if res=DialogResult.Yes then
' ele clicou no botão «Sim»
...
end if
5.2. Criar uma interface gráfica com o Visual Studio.NET
Retomamos alguns dos exemplos vistos anteriormente, construindo-os agora com o Visual Studio.NET.
5.2.1. Criação inicial do projeto
- Inicie o VS.NET e selecione a opção Fichier/Nouveau/Projet

- e introduza as características do seu projeto
![]() |
- Selecione o tipo de projeto que pretende criar; neste caso, um projeto VB.NET (1)
- selecione o tipo de aplicação que pretende criar, neste caso uma aplicação Windows (2)
- indique em que pasta pretende colocar a subpasta do projeto (3)
- Indique o nome do projeto (4). Este será também o nome da pasta que conterá os ficheiros do projeto
- O nome desta pasta é indicado em (5)
- São então criadas várias pastas e ficheiros na pasta i4:
subpastas da pasta «projeto1» ![]() |
Destes ficheiros, apenas um é relevante: o ficheiro form1.cs, que é o ficheiro de origem associado ao formulário criado pelo VS.NET. Voltaremos a este assunto mais tarde.
5.2.2. As janelas da interface do VS.NET
A interface do VS.NET apresenta agora alguns elementos do nosso projeto i4:
Temos uma janela de conceção da interface gráfica:
![]() |
Ao selecionar controlos na barra de ferramentas (toolbox 2) e arrastá-los para a área da janela (1), podemos construir uma interface gráfica. Se passarmos o rato sobre a «toolbox», esta amplia-se e exibe vários controlos:

Por enquanto, não utilizamos nenhum deles. Ainda no ecrã de VS.NET, encontramos a janela do explorador de soluções «Explorer Solution»:

Numa primeira fase, não utilizaremos muito esta janela. Ela mostra todos os ficheiros que compõem o projeto. Apenas um deles nos interessa: o ficheiro-fonte do nosso programa, neste caso Form1.vb. Ao clicar com o botão direito do rato em Form1.vb, surge um menu que permite aceder ao código-fonte da nossa interface gráfica (Mostrar o código) ou à própria interface gráfica (Criador de vistas):

É possível aceder a estas duas entidades diretamente a partir da janela «Solution Explorer»:
![]() | ![]() |
As janelas abertas «acumulam-se» na janela principal de conceção:

Aqui, Form1.vb[Design] designa a janela de design e Form1.vb a janela de código. Basta clicar numa das separadores para alternar entre as janelas. Outra janela importante presente no ecrã do VS.NET é a janela de propriedades:

As propriedades apresentadas na janela são as do controlo atualmente selecionado na janela de design gráfico. É possível aceder a diferentes janelas do projeto através do menu Affichage:

Aqui encontram-se as janelas principais que acabaram de ser descritas, bem como os respetivos atalhos de teclado.
5.2.3. Execução de um projeto
Apesar de ainda não termos escrito qualquer código, já temos um projeto executável. Execute F5 ou Déboguer/Démarrer para o executar. Obtemos a seguinte janela:

Esta janela pode ser maximizada, minimizada, redimensionada e fechada.
5.2.4. O código gerado pelo VS.NET
Vejamos o código (Affichage/Code) da nossa aplicação:
Public Class Form1
Inherits System.Windows.Forms.Form
#Região «Código gerado pelo Windows Form Designer»
Public Sub New()
MyBase.New()
'Esta chamada é exigida pelo Windows Form Designer.
InitializeComponent()
'Adicione uma inicialização qualquer após a chamada InitializeComponent()
End Sub
'O método substituído Dispose do formulário para limpar a lista de componentes.
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
'Exigido pelo Windows Form Designer
Private components As System.ComponentModel.IContainer
'REMARQUE: o procedimento seguinte é exigido pelo Windows Form Designer
'Pode ser alterado utilizando o Windows Form Designer.
'Não a altere utilizando o editor de código.
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
components = New System.ComponentModel.Container()
Me.Text = "Form2"
End Sub
#Fim da região
End Class
Uma interface gráfica deriva da classe base System.Windows.Forms.Form:
A classe base Form define uma janela básica com botões para fechar, ampliar/reduzir, tamanho ajustável, etc., e gere os eventos nestes objetos gráficos. O construtor do formulário utiliza um método InitializeComponent no qual os controlos do formulário são criados e inicializados.
Public Sub New()
MyBase.New()
'Esta chamada é exigida pelo Windows Form Designer.
InitializeComponent()
'Adicione uma inicialização qualquer após a chamada InitializeComponent()
End Sub
Qualquer outro trabalho a realizar no construtor pode ser efetuado após a chamada à função InitializeComponent. O método 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
define o título da janela «Form1», a sua largura (292) e a sua altura (53). O título da janela é definido pela propriedade Text e as dimensões pela propriedade Size. Size está definido no espaço de nomes System.Drawing e é uma estrutura. Para executar esta aplicação, é necessário definir o módulo principal do projeto. Para tal, utilizamos a opção [Projets/Propriétés]:

Em [Objet de démarrage], indicamos [Form1], que é o formulário que acabámos de criar. Para iniciar a execução, utilizamos a opção [Déboguer/Démarrer]:

5.2.5. Compilação numa janela do DOS
Agora, vamos tentar compilar e executar esta aplicação numa janela do 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'.
O compilador indica que não encontra a procedimento [Main]. De facto, o VS.NET não a gerou. No entanto, já a encontrámos nos exemplos anteriores. Tem a seguinte forma:
Shared Sub Main()
' inicia-se a aplicação
Application.Run(New Form1) ' où Form1 est le formulaire
End Sub
Vamos adicionar o código anterior ao código de [Form1.vb] e recompilar:
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)
~~~~~~~~~~~
Desta vez, o nome [Application] não é conhecido. Isso significa simplesmente que não importámos o seu espaço de nomes [System.Windows.Forms]. Vamos adicionar a seguinte instrução:
e, em seguida, recompilemos:
Desta vez, correu bem. Vamos executar:

É criado e apresentado um formulário do tipo Form1. É possível evitar a adição do procedimento [Main] utilizando a opção /m do compilador, que permite especificar a classe a executar, caso esta herde de System.Windows.Form:
A opção /m:form2 indica que a classe a executar é a classe com o nome [form2].
5.2.6. Gestão de eventos
Assim que o formulário é apresentado, a aplicação fica à espera dos eventos que ocorrem no formulário (cliques, movimentos do rato, etc.) e executa aqueles que o formulário gere. Neste caso, o nosso formulário não gere outros eventos além dos geridos pela classe base Form (cliques nos botões de fecho, ampliar/reduzir, alteração do tamanho da janela, deslocamento da janela, etc.). O formulário gerado utiliza um atributo components que não é utilizado em lado nenhum. O método dispose também não tem qualquer utilidade aqui. O mesmo se aplica a alguns espaços de nomes (Collections, ComponentModel, Data) utilizados e ao definido para o projeto projet1. Assim, neste exemplo, o código pode ser simplificado para o seguinte:
Imports System
Imports System.Drawing
Imports System.Windows.Forms
Public Class Form1
Inherits System.Windows.Forms.Form
' construtor
Public Sub New()
' construção do formulário com os seus componentes
InitializeComponent()
End Sub
Private Sub InitializeComponent()
' tamanho da janela
Me.Size = New System.Drawing.Size(300, 300)
' título da janela
Me.Text = "Form1"
End Sub
Shared Sub Main()
' inicia-se a aplicação
Application.Run(New Form1)
End Sub
End Class
5.2.7. Conclusão
Vamos agora aceitar tal como está o código gerado pelo VS.NET e limitar-nos-emos a adicionar o nosso, nomeadamente para gerir os eventos relacionados com os diferentes controlos do formulário.
5.3. Janela com campo de introdução de dados, botão e legenda
5.3.1. Conceção gráfica
No exemplo anterior, não tínhamos colocado quaisquer componentes na janela. Começamos um novo projeto denominado interface2. Para tal, seguimos o procedimento explicado anteriormente para criar um projeto:

Vamos agora criar uma janela com um botão, um rótulo e um campo de entrada:
![]() |
Os campos são os seguintes:
n.º | nome | tipo | função |
1 | lblSaisie | Rótulo | uma descrição |
2 | txtSaisie | TextBox | um campo de introdução de dados |
3 | btnAfficher | Botão | para apresentar numa caixa de diálogo o conteúdo do campo de entrada txtSaisie |
Pode-se proceder da seguinte forma para criar esta janela: clique com o botão direito do rato na janela, fora de qualquer componente, e selecione a opção Properties para aceder às propriedades da janela:

A janela de propriedades aparece então à direita:

Algumas destas propriedades merecem destaque:
para definir a cor de fundo da janela | |
para definir a cor dos desenhos ou do texto na janela | |
para associar um menu à janela | |
para atribuir um título à janela | |
para definir o tipo de janela | |
para definir o tipo de letra do texto na janela | |
para definir o nome da janela |
Aqui, definimos as propriedades Text e Name:
Campos de introdução de dados e botões - 1 | |
frmSaisiesBoutons |
Utilizando a barra «Caixa de ferramentas»
- selecione os componentes de que necessita
- arraste-os para a janela e defina as dimensões corretas
![]() | ![]() |
Depois de escolher o componente na «caixa de ferramentas», utilize a tecla «Esc» para ocultar a barra de ferramentas e, em seguida, arraste e ajuste as dimensões do componente. Repita este procedimento para os três componentes necessários: Label, TextBox, Button. Para alinhar e dimensionar corretamente os componentes, utilize o menu Format: | ![]() |
O princípio da formatação é o seguinte:
A opção Align permite-lhe alinhar componentes | ![]() |
A opção «Make Same Size» permite que componentes tenham a mesma altura ou a mesma largura: | ![]() |
A opção «Horizontal Spacing» permite, por exemplo, alinhar horizontalmente os componentes com intervalos de igual tamanho entre eles. O mesmo se aplica para a opção «Espaçamento vertical», que permite o alinhamento vertical. A opção «Center in Form» permite centrar um componente horizontalmente ou verticalmente na janela: | ![]() |
Depois de os componentes estarem corretamente colocados na janela, defina as suas propriedades. Para tal, clique com o botão direito do rato no componente e selecione a opção Properties:
Selecione o componente para aceder a janela de propriedades. Nesta janela, altere as seguintes propriedades: nome: lblSaisie, texto: Introdução
Selecione o componente para aceder à sua janela de propriedades. Nesta janela, altere as seguintes propriedades: nome: txtSaisie, texto: não preencher
name: cmdAfficher, text: Mostrar
text: Entradas e botões - 1 | ![]() |
Podemos executar (Ctrl+F5) o nosso projeto para ter uma primeira visão geral da janela em ação: | ![]() |
Feche a janela. Resta-nos escrever o procedimento associado a um clique no botão Afficher.
5.3.2. Gestão de eventos de um formulário
Vejamos o código que foi gerado pelo designer gráfico:
...
Public Class frmSaisiesBoutons
Inherits System.Windows.Forms.Form
' componentes
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
' construtor
Public Sub New()
InitializeComponent()
End Sub
...
' inicialização dos componentes
Private Sub InitializeComponent()
...
End Sub
End Class
Em primeiro lugar, é de salientar a declaração específica dos componentes:
- a palavra-chave «Friend» indica que a visibilidade do componente se estende a todas as classes do projeto
- a palavra-chave WithEvents indica que o componente gera eventos. Vamos agora analisar como gerir esses eventos
Abre a janela de código do formulário (Exibir/código ou F7):
![]() |
A janela acima apresenta duas listas suspensas (1) e (2). A lista (1) é a lista de componentes do formulário:

A lista (2) é a lista de eventos associados ao componente selecionado em (1):

Um dos eventos associados ao componente é apresentado a negrito (neste caso, «Click»). Trata-se do evento predefinido do componente. O acesso ao gestor deste evento específico pode ser feito clicando duas vezes no componente na janela de design. O VB.net gera então automaticamente o esqueleto do gestor de eventos na janela de código e posiciona o utilizador sobre ele. O acesso aos gestores dos outros eventos é feito na janela de código, selecionando o componente na lista (1) e o evento em (2). O VB.net gera então o esboço do gestor de eventos ou posiciona-se sobre ele, caso já tenha sido gerado:
Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAfficher.Click
...
End Sub
Por predefinição, o VB.net C_E atribui o nome «E» ao gestor de eventos do componente C. É possível alterar este nome, se assim o desejarmos. No entanto, tal não é recomendado. Os programadores do VB costumam manter o nome gerado pelo VB, o que garante a coerência na nomenclatura em todos os programas VB. A associação do procedimento btnAfficher_Click ao evento Click do componente btnAfficher não é feita através do nome do procedimento, mas sim através da palavra-chave «handles»:
Handles btnAfficher.Click
No exemplo acima, a palavra-chave «handles» especifica que a procedimento gere o evento «Click» do componente btnAfficher. O gestor de eventos anterior tem dois parâmetros:
o objeto que originou o evento (neste caso, o botão) | |
um objeto EventArgs que detalha o evento que ocorreu |
Não utilizaremos nenhum destes parâmetros aqui. Resta-nos apenas completar o código. Neste caso, pretendemos apresentar uma caixa de diálogo com o conteúdo do campo txtSaisie:
Private Sub btnAfficher_Click(ByVal sender As Object, ByVal e As System.EventArgs)
' exibe-se o texto que foi introduzido na caixa de introdução de dados TxtSaisie
MessageBox.Show("texte saisi= " + txtsaisie.Text, "Vérification de la saisie", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
Se executarmos a aplicação, obtemos o seguinte:

5.3.3. Outro método para gerir os eventos
Para o botão btnAfficher, o VS.NET gerou o seguinte código:
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
...
' gestor de eventos de clique no botão cmdAfficher
Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAfficher.Click
...
End Sub
Podemos associar o procedimento btnAfficher_Click ao evento «Click» do botão btnAfficher de outra forma:
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
...
' gestor de eventos de clique no botão cmdAfficher
Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
...
End Sub
O procedimento btnAfficher_Click perdeu a palavra-chave «Handles», perdendo assim a sua associação ao evento btnAfficher.Click. Esta associação é agora feita através da palavra-chave AddHandler:
AddHandler btnAfficher.Click, AddressOf btnAfficher_Click
O código acima, que será inserido no procedimento InitializeComponent do formulário, associa ao evento btnAfficher.Click o procedimento com o nome btnAfficher_Click. Além disso, o componente btnAfficher já não necessita da palavra-chave WithEvents:
Friend btnAfficher As System.Windows.Forms.Button
Qual é a diferença entre os dois métodos?
- A palavra-chave «handles» só permite associar um evento a um procedimento na fase de conceção. O programador sabe antecipadamente que um procedimento P deve gerir os eventos E1, E2, ... e escreve o código
Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) handles E1, E2, ..., En
De facto, é possível que uma procedimento trate vários eventos.
- A palavra-chave `addhandler` permite associar um evento a um procedimento no momento da execução. Isto é útil num contexto de produtor-consumidor de eventos. Um objeto produz um evento específico que pode ser do interesse de outros objetos. Estes subscrevem-se junto do produtor para receber o evento (uma temperatura que tenha ultrapassado um limiar crítico, por exemplo). Durante a execução da aplicação, o produtor do evento terá de executar diferentes instruções:
onde E é o evento produzido pelo produtor e Pi são os procedimentos pertencentes aos diferentes objetos consumidores desse evento. Teremos oportunidade de voltar a abordar uma aplicação produtor-consumidor de eventos num próximo capítulo.
5.3.4. Conclusão
A partir dos dois projetos analisados, podemos concluir que, uma vez construída a interface gráfica com o VS.NET, o trabalho do programador consiste em escrever os gestores de eventos que pretende gerir para essa interface gráfica. A partir de agora, apresentaremos apenas o código desses gestores.
5.4. Alguns componentes úteis
Apresentamos agora várias aplicações que utilizam os componentes mais comuns, a fim de explorar os seus principais métodos e propriedades. Para cada aplicação, apresentamos a interface gráfica e o código relevante, nomeadamente os gestores de eventos.
5.4.1. Formulário Form
Começamos por apresentar o componente indispensável: o formulário, no qual se colocam os componentes. Já apresentámos algumas das suas propriedades básicas. Aqui, vamos debruçar-nos sobre alguns eventos importantes de um formulário.
O formulário está a ser carregado | |
o formulário está a ser fechado | |
O formulário está fechado |
O evento Load ocorre antes mesmo de o formulário ser apresentado. O evento Closing ocorre quando o formulário está a ser fechado. Ainda é possível interromper este encerramento por meio de programação. Criamos um formulário com o nome Form1 sem componentes:

Processamos os três eventos anteriores:
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
' carregamento inicial do formulário
MessageBox.Show("Evt Load", "Load")
End Sub
Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
' o formulário está a fechar-se
MessageBox.Show("Evt Closing", "Closing")
' é solicitada a confirmação
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
' o formulário está a fechar
MessageBox.Show("Evt Closed", "Closed")
End Sub
Utilizamos a função MessageBox para sermos notificados dos diferentes eventos. O evento «Closing» ocorrerá quando o utilizador fechar a janela. | ![]() |
Perguntamos-lhe então se pretende mesmo sair da aplicação: | ![]() |
Se ele responder «Não», definimos a propriedade Cancel do evento CancelEventArgs que o método recebeu como parâmetro. Se definirmos esta propriedade como False, o encerramento da janela é cancelada; caso contrário, prossegue: | ![]() |
5.4.2. rótulos Label e caixas de entrada TextBox
Já nos deparámos com estes dois componentes. Label é um componente de texto e TextBox um componente de campo de introdução de dados. A sua principal propriedade é Text, que designa quer o conteúdo do campo de introdução de dados, quer o texto do rótulo. Esta propriedade é de leitura/gravação. O evento normalmente utilizado para o TextBox é o TextChanged, que sinaliza que o utilizador alterou o campo de introdução de dados. Eis um exemplo que utiliza o evento TextChanged para acompanhar as alterações num campo de introdução de dados:
![]() |
n.º | tipo | nome | função |
1 | TextBox | txtSaisie | campo de introdução |
2 | Rótulo | lblControle | exibe o texto de 1 em tempo real |
3 | Botão | cmdEffacer | para apagar os campos 1 e 2 |
4 | Botão | cmdQuitter | para sair da aplicação |
O código relevante desta aplicação é o dos gestores de eventos:
' clique no botão «Sair»
Private Sub cmdQuitter_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles cmdQuitter.Click
' clique no botão «Sair» — sai-se da aplicação
Application.Exit()
End Sub
' alteração no campo txtSaisie
Private Sub txtSaisie_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles txtSaisie.TextChanged
' o conteúdo de TextBox foi alterado — é copiado para o rótulo lblControle
lblControle.Text = txtSaisie.Text
End Sub
' clique no botão «Apagar»
Private Sub cmdEffacer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles cmdEffacer.Click
' o conteúdo da caixa de introdução de dados é apagado
txtSaisie.Text = ""
End Sub
' foi premida uma tecla
Private Sub txtSaisie_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) _
Handles txtSaisie.KeyPress
' verifica-se qual a tecla que foi premida
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
Note-se a forma de encerrar a aplicação no procedimento cmdQuitter_Click: Application.Exit(). O exemplo seguinte utiliza um TextBox de várias linhas:
![]() |
A lista de controlos é a seguinte:
n.º | tipo | nome | função |
1 | TextBox | txtMultiLignes | campo de introdução de texto com várias linhas |
2 | TextBox | txtAjout | campo de introdução de texto de uma linha |
3 | Botão | btnAjouter | Adiciona o conteúdo de 2 a 1 |
Para que um TextBox passe a ser multilinha, definem-se as seguintes propriedades do controlo:
para aceitar várias linhas de texto | |
para definir se o controlo deve ter barras de deslocamento (Horizontal, Vertical, Both) ou não (None) | |
se for igual a «true», a tecla Enter irá passar para a linha seguinte | |
se for igual a «true», a tecla Tab irá inserir uma tabulação no texto |
O código relevante é aquele que processa o clique no botão [Ajouter] e aquele que processa a alteração no campo de introdução de dados [txtAjout]:
' eventualmente btnAjouter_Click
Private Sub btnAjouter_Click1(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnAjouter.Click
' adicionar o conteúdo de txtAjout ao de 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
' define-se o estado do botão «Adicionar»
btnAjouter.Enabled = txtAjout.Text.Trim() <> ""
End Sub
5.4.3. listas suspensas ComboBox
![]() | ![]() |
Um componente ComboBox é uma lista suspensa acompanhada de um campo de introdução de texto: o utilizador pode escolher um elemento em (2) ou introduzir texto em (1). Existem três tipos de ComboBox definidos pela propriedade Style:
lista não suspensa com campo de edição | |
lista suspensa com área de edição | |
lista suspensa sem campo de edição |
Por predefinição, o tipo de um ComboBox é DropDown. Para consultar a classe ComboBox, digite ComboBox no índice da ajuda (Aide/Index). A classe ComboBox tem um único construtor:
Public Sub New() | cria um objeto ComboBox vazio |
Os elementos do ComboBox estão disponíveis na propriedade Items:
Trata-se de uma propriedade indexada, em que Items(i) designa o elemento i do Combo. Seja C um combo e C.Items a sua lista de elementos. Temos as seguintes propriedades:
número de elementos do combo | |
elemento i do combo | |
adiciona o objeto o como último elemento da lista suspensa | |
adiciona uma matriz de objetos ao final da lista suspensa | |
adiciona o objeto o na posição i da lista suspensa | |
remove o elemento i da lista suspensa | |
remove o objeto o da lista suspensa | |
elimina todos os elementos da lista suspensa | |
retorna a posição i do objeto o na lista suspensa |
Pode parecer surpreendente que uma lista de seleção possa conter objetos, quando normalmente contém cadeias de caracteres. Visualmente, é isso que acontece. Se um ComboBox contiver um objeto obj, exibe a cadeia obj.ToString(). Recorde-se que todo o objeto possui um método ToString herdado da classe object, que devolve uma cadeia de caracteres «representativa» do objeto. O elemento selecionado na lista suspensa C é C.SelectedItem ou C.Items(C.SelectedIndex), em que C.SelectedIndex é o número do elemento selecionado, começando por zero para o primeiro elemento.
Ao selecionar um elemento na lista suspensa, ocorre o evento SelectedIndexChanged, que pode então ser utilizado para ser notificado da alteração da seleção na lista suspensa. Na aplicação seguinte, utilizamos este evento para apresentar o elemento que foi selecionado na lista.

Apresentamos apenas o código relevante da janela. No construtor do formulário, preenchemos a lista suspensa:
Public Sub New()
' criação do formulário
InitializeComponent()
' preenchimento da lista suspensa
cmbNombres.Items.AddRange(New String() {"zéro", "un", "deux", "trois", "quatre"})
' selecionamos o primeiro elemento da lista
cmbNombres.SelectedIndex = 0
End Sub
Tratamos o evento SelectedIndexChanged da lista suspensa, que sinaliza um novo elemento selecionado:
Private Sub cmbNombres_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles cmbNombres.SelectedIndexChanged
' o elemento selecionado mudou — exibimo-lo
MessageBox.Show("Elément sélectionné : (" & cmbNombres.SelectedItem.ToString & "," & cmbNombres.SelectedIndex & ")", "Combo", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
5.4.4. componente ListBox
Propomos construir a seguinte interface:
![]() |
Os componentes desta janela são os seguintes:
n.º | tipo | nome | função/propriedades |
0 | Form | Form1 | formulário - BorderStyle=FixedSingle |
1 | TextBox | txtSaisie | campo de introdução de dados |
2 | Botão | btnAjouter | botão que permite adicionar o conteúdo do campo de introdução 1 à lista 3 |
3 | ListBox | listBox1 | lista 1 |
4 | ListBox | listBox2 | lista 2 |
5 | Botão | btn1TO2 | transfere os elementos selecionados da lista 1 para a lista 2 |
6 | Botão | cmd2T0 | faz o inverso |
7 | Botão | btnEffacer1 | esvazia a lista 1 |
8 | Botão | btnEffacer2 | Esvaziar a lista 2 |
- O utilizador introduz texto no campo 1. Adiciona-o à lista 1 através do botão Ajouter (2). O campo de introdução (1) é então esvaziado e o utilizador pode adicionar um novo elemento.
- Pode transferir elementos de uma lista para outra, selecionando o elemento a transferir numa das listas e escolhendo o botão de transferência adequado, 5 ou 6. O elemento transferido é adicionado ao final da lista de destino e removido da lista de origem.
- Pode clicar duas vezes num elemento da lista 1. Esse elemento é então transferido para a caixa de introdução de dados para edição e removido da lista 1.
Os botões ficam ativos ou inativos de acordo com as seguintes regras:
- o botão Ajouter só fica ativo se houver texto no campo de introdução
- o botão 5 de transferência da lista 1 para a lista 2 só fica aceso se houver um elemento selecionado na lista 1
- o botão 6 de transferência da lista 2 para a lista 1 só fica aceso se houver um elemento selecionado na lista 2
- os botões 7 e 8 para apagar as listas 1 e 2 só ficam acesos se a lista a apagar contiver elementos.
Nas condições anteriores, todos os botões devem estar desativados no arranque da aplicação. É a propriedade Enabled dos botões que deve, então, ser definida como false. Isto pode ser feito na fase de conceção, o que terá como efeito a geração do código correspondente no método InitializeComponent, ou pode ser feito manualmente no construtor, como se segue:
Public Sub New()
' criação inicial do formulário
InitializeComponent()
' inicializações complementares
' inibem-se alguns botões
btnAjouter.Enabled = False
btn1TO2.Enabled = False
btn2TO1.Enabled = False
btnEffacer1.Enabled = False
btnEffacer2.Enabled = False
End Sub
O estado do botão Ajouter é controlado pelo conteúdo do campo de introdução de dados. É o evento TextChanged que nos permite acompanhar as alterações desse conteúdo:
' alteração no campo de introdução de texto
Private Sub txtSaisie_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles txtSaisie.TextChanged
' o conteúdo de txtSaisie foi alterado
' o botão «Adicionar» só fica ativo se o campo de introdução de texto não estiver vazio
btnAjouter.Enabled = txtSaisie.Text.Trim() <> ""
End Sub
O estado dos botões de transferência depende do facto de ter sido ou não selecionado um elemento na lista que controlam:
' alteração do elemento selecionado sem a caixa de lista 1
Private Sub listBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles listBox1.SelectedIndexChanged
' foi selecionado um elemento
' o botão de transferência de 1 para 2 fica ativo
btn1TO2.Enabled = True
End Sub
' alteração do elemento selecionado sem a caixa de lista 2
Private Sub listBox2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles listBox2.SelectedIndexChanged
' foi selecionado um elemento
' ativa-se o botão de transferência de 2 para 1
btn2TO1.Enabled = True
End Sub
O código associado ao clique no botão Ajouter é o seguinte:
' clique no botão «Adicionar»
Private Sub btnAjouter_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnAjouter.Click
' adição de um novo elemento à lista 1
listBox1.Items.Add(txtSaisie.Text.Trim())
' limpar o campo de introdução
txtSaisie.Text = ""
' A Lista 1 não está vazia
btnEffacer1.Enabled = True
' foco volta para a caixa de introdução de dados
txtSaisie.Focus()
End Sub
De salientar o método Focus, que permite colocar o «foco» num controlo do formulário. O código associado ao clique nos botões Effacer:
' clique no botão Apagar1
Private Sub btnEffacer1_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnEffacer1.Click
' a Lista 1 é apagada
listBox1.Items.Clear()
btnEffacer1.Enabled = False
End Sub
' clique no botão Apagar2
Private Sub btnEffacer2_Click(ByVal sender As Object, ByVal e As System.EventArgs)
' a lista 2 é apagada
listBox2.Items.Clear()
btnEffacer2.Enabled = False
End Sub
O código para transferir os elementos selecionados de uma lista para a outra:
' clique no botão «btn1to2»
Private Sub btn1TO2_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btn1TO2.Click
' transferência do elemento selecionado da Lista 1 para a Lista 2
transfert(listBox1, listBox2)
' Botões «Apagar»
btnEffacer2.Enabled = True
btnEffacer1.Enabled = listBox1.Items.Count <> 0
' Botões de transferência
btn1TO2.Enabled = False
btn2TO1.Enabled = False
End Sub
' clique no botão btn2to1
Private Sub btn2TO1_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btn2TO1.Click
' transferência do elemento selecionado da Lista 2 para a Lista 1
transfert(listBox2, listBox1)
' botões «Apagar»
btnEffacer1.Enabled = True
btnEffacer2.Enabled = listBox2.Items.Count <> 0
' botões de transferência
btn1TO2.Enabled = False
btn2TO1.Enabled = False
End Sub
' transferência
Private Sub transfert(ByVal l1 As ListBox, ByVal l2 As ListBox)
' transferência do elemento selecionado da Lista 1 para a Lista 2
' um elemento selecionado?
If l1.SelectedIndex = -1 Then Return
' adicionar à l2
l2.Items.Add(l1.SelectedItem)
' eliminação na l1
l1.Items.RemoveAt(l1.SelectedIndex)
End Sub
Em primeiro lugar, criamos um método
Private Sub transfert(ByVal l1 As ListBox, ByVal l2 As ListBox)
que transfere para a lista l2 o elemento selecionado na lista l1. Isto permite-nos ter um único método, em vez de dois, para transferir um elemento de listBox1 para listBox2 ou de listBox2 para listBox1. Antes de efetuar a transferência, certificamo-nos de que existe efetivamente um elemento selecionado na lista l1:
' um elemento selecionado?
If l1.SelectedIndex = -1 Then Return
A propriedade SelectedIndex tem o valor -1 se não houver nenhum elemento selecionado no momento. Nos procedimentos
Private Sub btnXTOY_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnXTOY.Click
é efetuada a transferência da lista X para a lista Y e é alterado o estado de determinados botões para refletir o novo estado das listas.
5.4.5. caixas de seleção CheckBox, botões de opção ButtonRadio
Propomos escrever a seguinte aplicação:
![]() |
Os componentes da janela são os seguintes:
n.º | tipo | nome | função |
1 | RadioButton | radioButton1 radioButton2 radioButton3 | 3 botões de opção |
2 | CheckBox | chechBox1 chechBox2 chechBox3 | 3 caixas de seleção |
3 | ListBox | lstValeurs | uma lista |
Se criarmos os três botões de opção um a seguir ao outro, estes fazem parte, por predefinição, do mesmo grupo. Assim, quando um está marcado, os outros não estão. O evento que nos interessa para estes seis controlos é o evento CheckChanged, que indica que o estado da caixa de seleção ou do botão de opção mudou. Este estado é representado, em ambos os casos, pela propriedade booleana Check, cujo valor «verdadeiro» significa que o controlo está marcado. Aqui, utilizámos um único método para tratar os seis eventos CheckChanged, o método affiche:
' exibe
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
' exibe o estado do botão de opção ou da caixa de seleção
' é uma caixa de seleção?
If (TypeOf (sender) Is CheckBox) Then
Dim chk As CheckBox = CType(sender, CheckBox)
lstValeurs.Items.Insert(0, chk.Name & "=" & chk.Checked)
End If
' é um botão de opção?
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
A sintaxe TypeOf (remetente) Is CheckBox permite verificar se o objeto sender é do tipo CheckBox. Isto permite-nos, em seguida, efetuar uma conversão de tipo para o tipo exato de sender. O método affiche insere na lista lstValeurs o nome do componente que originou o evento e o valor da sua propriedade Checked. Durante a execução, verifica-se que um clique num botão de opção provoca dois eventos CheckChanged: um no antigo botão marcado, que passa para «desmarcado», e outro no novo botão, que passa para «marcado».
5.4.6. reguladores ScrollBar
Existem vários tipos de controlos deslizantes: o control deslizante horizontal (hScrollBar), o variador vertical (vScrollBar) e o incrementador (NumericUpDown). | ![]() |
Vamos criar a seguinte aplicação:
![]() |
n.º | tipo | nome | função |
1 | hScrollBar | hScrollBar1 | um variador horizontal |
2 | hScrollBar | hScrollBar2 | um variador horizontal que acompanha as variações do variador 1 |
3 | TextBox | txtValeur | exibe o valor do variador horizontal ReadOnly=true para impedir qualquer introdução de dados |
4 | NumericUpDown | incrementador | permite fixar o valor do regulador 2 |
- Um regulador ScrollBar permite ao utilizador selecionar um valor dentro de um intervalo de valores inteiros, simbolizado pela «faixa» do regulador, sobre a qual se desloca um cursor. O valor do regulador está disponível na sua propriedade Value.
- Num regulador horizontal, a extremidade esquerda representa o valor mínimo do intervalo, a extremidade direita o valor máximo e o cursor o valor atual selecionado. Num regulador vertical, o mínimo é representado pela extremidade superior e o máximo pela extremidade inferior. Estes valores são representados pelas propriedades Minimum e Maximum e têm, por predefinição, os valores 0 e 100.
- Um clique nas extremidades do regulador altera o valor num incremento (positivo ou negativo), dependendo da extremidade clicada, designada por SmallChange, cujo valor predefinido é 1.
- Um clique em qualquer um dos lados do cursor faz com que o valor varie num incremento (positivo ou negativo), dependendo da extremidade clicada, designada por LargeChange, cujo valor predefinido é 10.
- Quando se clica na extremidade superior de um regulador vertical, o seu valor diminui. Isto pode surpreender o utilizador comum, que normalmente espera ver o valor «subir». Este problema é resolvido atribuindo um valor negativo às propriedades SmallChange e LargeChange
- Estas cinco propriedades (Value, Minimum, Maximum, SmallChange, LargeChange) estão acessíveis para leitura e escrita.
- O evento principal do variador é aquele que sinaliza uma alteração de valor: o evento Scroll.
Um componente NumericUpDown encontra-se próximo do variador: também possui as propriedades Minimum, Maximum e Value, com valores por predefinição de 0, 100 e 0, respetivamente. Mas, neste caso, a propriedade Value é apresentada numa caixa de entrada que faz parte integrante do controlo. O utilizador pode alterar este valor por si próprio, a menos que a propriedade ReadOnly do controlo tenha sido definida como «verdadeiro». O valor do incremento é definido pela propriedade Increment, cujo valor predefinido é 1. O evento principal do componente NumericUpDown é aquele que sinaliza uma alteração de valor: o evento ValueChanged. O código útil da nossa aplicação é o seguinte:
O formulário é formatado durante a sua construção:
' construtor
Public Sub New()
' criação inicial do formulário
InitializeComponent()
' atribuem-se ao variador 2 as mesmas características que ao variador 1
hScrollBar2.Minimum = hScrollBar1.Value
hScrollBar2.Minimum = hScrollBar1.Minimum
hScrollBar2.Maximum = hScrollBar1.Maximum
hScrollBar2.LargeChange = hScrollBar1.LargeChange
hScrollBar2.SmallChange = hScrollBar1.SmallChange
' o mesmo se aplica ao incrementador
incrémenteur.Minimum = hScrollBar1.Value
incrémenteur.Minimum = hScrollBar1.Minimum
incrémenteur.Maximum = hScrollBar1.Maximum
incrémenteur.Increment = hScrollBar1.SmallChange
' atribui-se ao TextBox o valor do variador 1
txtValeur.Text = "" & hScrollBar1.Value
End Sub
O gestor que acompanha as variações de valor do variador 1:
' gestão do variador hscrollbar1
Private Sub hScrollBar1_Scroll(ByVal sender As Object, ByVal e As System.Windows.Forms.ScrollEventArgs) _
Handles hScrollBar1.Scroll
' alteração do valor do variador 1
' o seu valor é refletido no variador 2 e na caixa de texto TxtValeur
hScrollBar2.Value = hScrollBar1.Value
txtValeur.Text = "" & hScrollBar1.Value
End Sub
O gestor que acompanha as variações de valor do variador 2:
' gestão do variador hscrollbar2
Private Sub hScrollBar2_Scroll(ByVal sender As Object, ByVal e As System.Windows.Forms.ScrollEventArgs) _
Handles hScrollBar2.Scroll
' inibe-se qualquer alteração do variador 2
' forçando-o a manter o valor do variador 1
e.NewValue = hScrollBar1.Value
End Sub
O gestor que acompanha as variações do controlo incrémenteur:
' gestão do incrementador
Private Sub incrémenteur_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles incrémenteur.ValueChanged
' fixa-se o valor do variador 2
hScrollBar2.Value = CType(incrémenteur.Value, Integer)
End Sub
5.5. Eventos do rato
Quando se desenha num contentor, é importante saber a posição do rato para, por exemplo, exibir um ponto ao clicar. Os movimentos do rato provocam eventos no contentor em que se desloca.
![]() | ![]() |
o rato acabou de entrar na área do controlo | |
o rato acabou de sair da área de controlo | |
o rato está a mover-se na área de controlo | |
Clicou no botão esquerdo do rato | |
Soltar o botão esquerdo do rato | |
O utilizador solta um objeto no controlo | |
O utilizador entra na área do controlo ao arrastar um objeto | |
o utilizador sai da área do controlo ao arrastar um objeto | |
o utilizador passa por cima da área do controlo ao arrastar um objeto |
Eis um programa que permite compreender melhor em que momentos ocorrem os diferentes eventos do rato:
![]() |
n.º | tipo | nome | função |
1 | Etiqueta | lblPosition | para exibir a posição do rato no formulário 1, na lista 2 ou no botão 3 |
2 | ListBox | lstEvts | para apresentar os eventos do rato que não sejam MouseMove |
3 | Botão | btnEffacer | para apagar o conteúdo de 2 |
Os gestores de eventos são os seguintes. Para acompanhar os movimentos do rato nos três controlos, basta escrever um único gestor:
' eventualmente 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 do rato - exibe-se as coordenadas (X, Y) do mesmo
lblPosition.Text = "(" & e.X & "," & e.Y & ")"
End Sub
É importante saber que, sempre que o rato entra na área de um controlo, o seu sistema de coordenadas muda. A sua origem (0,0) é o canto superior esquerdo do controlo em que se encontra. Assim, durante a execução, quando se passa o rato do formulário para o botão, observa-se claramente a mudança de coordenadas. Para observar melhor estas mudanças no domínio do rato, pode-se utilizar a propriedade Cursor dos controlos:

Esta propriedade permite definir a forma do cursor do rato quando este entra na área do controlo. Assim, no nosso exemplo, definimos o cursor como «Default» para o próprio formulário, «Hand» para a lista 2 e «No» para o botão 3, tal como mostram as capturas de ecrã abaixo.



No método [InitializeComponent], o código gerado por estas opções é o seguinte:
Me.lstEvts.Cursor = System.Windows.Forms.Cursors.Hand
Me.btnEffacer.Cursor = System.Windows.Forms.Cursors.No
Além disso, para detetar as entradas e saídas do rato na lista 2, processamos os eventos MouseEnter e MouseLeave dessa mesma lista:
' eventualmente 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
' exibe
Private Sub affiche(ByVal message As String)
' a mensagem é exibida no topo da lista de eventos
lstEvts.Items.Insert(0, message)
End Sub

Para processar os cliques no formulário, processamos os eventos 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

Por fim, o código do gestor de cliques no botão Effacer:
' evento btnEffacer_Click
Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles btnEffacer.Click
' apaga a lista de eventos
lstEvts.Items.Clear()
End Sub
5.6. Criar uma janela com menu
Vamos agora ver como criar uma janela com menu. Vamos criar a seguinte janela:
![]() |
O controlo 1 é um TextBox de leitura única (ReadOnly=true) e com o nome txtStatut. A estrutura do menu é a seguinte:
![]() | ![]() |
As opções de menu são controlos, tal como os outros componentes visuais, e possuem propriedades e eventos. Por exemplo, a tabela de propriedades da opção de menu A1:

No nosso exemplo, são utilizadas duas propriedades:
o nome do controlo de menu | |
o texto da opção do menu |
As propriedades das diferentes opções de menu do nosso exemplo são as seguintes:
Name | Texto |
mnuA | opções A |
mnuA1 | A1 |
mnuA2 | A2 |
mnuA3 | A3 |
mnuB | opções B |
mnuB1 | B1 |
mnuSep1 | - (separador) |
mnuB2 | B2 |
mnuB3 | B3 |
mnuB31 | B31 |
mnuB32 | B32 |
Para criar um menu, selecione o componente «MainMenu» na barra «ToolBox»:

Fica-se então com um menu vazio que é inserido no formulário com campos em branco intitulados «Type Here». Basta indicar aí as diferentes opções do menu:

Para inserir um separador entre duas opções, como acima entre as opções B1 e B2, posicione-se no local do separador no menu, clique com o botão direito do rato e selecione a opção «Insert Separator»:

Se iniciarmos a aplicação com Ctrl+F5, obtemos um formulário com um menu que, por enquanto, não faz nada. As opções do menu são tratadas como componentes: têm propriedades e eventos. Em [fenêtre de code], selecione o componente mnuA1 e, em seguida, selecione os eventos associados:

Se, no exemplo acima, gerarmos o evento Click, o VS.NET gera automaticamente o seguinte procedimento:
Private Sub mnuA1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuA.Click
....
End Sub
Poderíamos proceder desta forma para todas as opções do menu. Aqui, o mesmo procedimento pode ser utilizado para todas as opções. Por isso, renomeamos o procedimento anterior para affiche e declaramos os eventos que ele gere:
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
' exibe no TextBox o nome do submenu selecionado
txtStatut.Text = (CType(sender, MenuItem)).Text
End Sub
Neste método, limitamo-nos a apresentar a propriedade Text da opção do menu na origem do evento. A origem do evento sender é do tipo object. As opções de menu são do tipo MenuItem, pelo que, neste caso, é necessário efetuar uma conversão de tipo de object para MenuItem. Execute a aplicação e selecione a opção A1 para obter a seguinte mensagem:

O código relevante desta aplicação, para além do do método affiche, é o da construção do menu no construtor do formulário (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
Deve-se destacar a instrução que associa o menu ao formulário:
Me.Menu = Me.mainMenu1
5.7. Componentes não visuais
Vamos agora debruçar-nos sobre alguns componentes não visuais: estes são utilizados durante a conceção, mas não são visíveis durante a execução.
5.7.1. Caixas de diálogo OpenFileDialog e SaveFileDialog
Vamos construir a seguinte aplicação:
![]() |
Os controlos são os seguintes:
N.º | tipo | nome | função |
1 | TextBox multilinhas | txtTexte | texto digitado pelo utilizador ou carregado a partir de um ficheiro |
2 | Botão | btnSauvegarder | permite guardar o texto de 1 num ficheiro de texto |
3 | Botão | btnCharger | permite carregar o conteúdo de um ficheiro de texto em 1 |
4 | Botão | btnEffacer | apaga o conteúdo de 1 |
São utilizados dois controlos não visuais:

Quando são selecionados no «ToolBox» e colocados no formulário, são posicionados numa área separada na parte inferior do formulário. Os componentes «Dialog» são selecionados no «ToolBox»:

O código do botão Effacer é simples:
Private Sub btnEffacer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnEffacer.Click
' limpa-se a caixa de entrada
txtTexte.Text = ""
End Sub
A classe SaveFileDialog é definida da seguinte forma:

Deriva de vários níveis de classe. Das suas numerosas propriedades e métodos, destacamos os seguintes:
os tipos de ficheiros apresentados na lista suspensa de tipos de ficheiros da caixa de diálogo | |
o número do tipo de ficheiro proposto por predefinição na lista acima. Começa em 0. | |
a pasta apresentada inicialmente para guardar o ficheiro | |
o nome do ficheiro de cópia de segurança indicado pelo utilizador | |
método que apresenta a caixa de diálogo de gravação. Devolve um resultado do tipo DialogResult. |
O método ShowDialog apresenta uma caixa de diálogo semelhante à seguinte:
![]() |
lista suspensa criada a partir da propriedade Filter. O tipo de ficheiro proposto por predefinição é definido por FilterIndex | |
pasta atual, definida por InitialDirectory, caso esta propriedade tenha sido preenchida | |
nome do ficheiro selecionado ou introduzido diretamente pelo utilizador. Estará disponível na propriedade FileName | |
Botões «Guardar»/«Anular». Se for utilizado o botão Enregistrer, a função ShowDialog devolve o resultado DialogResult.OK |
O procedimento de gravação pode ser escrito da seguinte forma:
Private Sub btnSauvegarder_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnSauvegarder.Click
' guarda-se o campo de entrada num ficheiro de texto
' configura-se a caixa de diálogo savefileDialog1
saveFileDialog1.InitialDirectory = Application.ExecutablePath
saveFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"
saveFileDialog1.FilterIndex = 0
' exibe-se a caixa de diálogo e recupera-se o seu resultado
If saveFileDialog1.ShowDialog() = DialogResult.OK Then
' recupera-se o nome do ficheiro
Dim nomFichier As String = saveFileDialog1.FileName
Dim fichier As StreamWriter = Nothing
Try
' abre-se o ficheiro para gravação
fichier = New StreamWriter(nomFichier)
' escreve-se o texto aqui
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
' fecha-se o ficheiro
Try
fichier.Close()
Catch
End Try
End Try
End If
End Sub
- Associa-se a pasta inicial à pasta que contém o executável da aplicação:
- Definem-se os tipos de ficheiros a apresentar
Note-se a sintaxe dos filtros: filtro1|filtro2|..|filtroi, em que filtroi = Texto|modelo de ficheiro. Aqui, o utilizador poderá escolher entre ficheiros *.txt e *.*.
- Definimos o tipo de ficheiro a apresentar no início
Aqui, serão apresentados em primeiro lugar ao utilizador os ficheiros do tipo *.txt.
- A caixa de diálogo é apresentada e o seu resultado é recuperado
If saveFileDialog1.ShowDialog() = DialogResult.OK Then
- Enquanto a caixa de diálogo está visível, o utilizador já não tem acesso ao formulário principal (caixa de diálogo dita «modal»). O utilizador define o nome do ficheiro a guardar e sai da caixa de diálogo, quer através do botão «Guardar», quer através do botão «Cancelar», quer fechando a caixa de diálogo. O resultado do método ShowDialog é DialogResult.OK apenas se o utilizador tiver utilizado o botão Enregistrer para sair da caixa de diálogo.
- Feito isto, o nome do ficheiro a criar encontra-se agora na propriedade FileName do objeto saveFileDialog1. Passamos então à criação clássica de um ficheiro de texto. Nele, escreve-se o conteúdo de TextBox: txtTexte.Text, ao mesmo tempo que se gerem as exceções que possam ocorrer.
A classe OpenFileDialog é muito semelhante à classe SaveFileDialog e deriva da mesma linhagem de classes. Destas propriedades e métodos, destacamos os seguintes:
os tipos de ficheiros propostos na lista suspensa de tipos de ficheiros da caixa de diálogo | |
o número do tipo de ficheiro proposto por predefinição na lista acima. Começa em 0. | |
a pasta apresentada inicialmente para a pesquisa do ficheiro a abrir | |
o nome do ficheiro a abrir indicado pelo utilizador | |
método que apresenta a caixa de diálogo de gravação. Devolve um resultado do tipo DialogResult. |
O método ShowDialog apresenta uma caixa de diálogo semelhante à seguinte:
![]() |
lista suspensa criada a partir da propriedade Filter. O tipo de ficheiro proposto por predefinição é definido por FilterIndex | |
pasta atual, definida por InitialDirectory caso esta propriedade tenha sido preenchida | |
nome do ficheiro selecionado ou introduzido diretamente pelo utilizador. Estará disponível na propriedade FileName | |
Botões Abrir/Cancelar. Se for utilizado o botão Ouvrir, a função ShowDialog devolve o resultado DialogResult.OK |
O procedimento de abertura pode ser escrito da seguinte forma:
Private Sub btnCharger_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnCharger.Click
' carregar um ficheiro de texto na caixa de introdução
' configura-se a caixa de diálogo openfileDialog1
openFileDialog1.InitialDirectory = Application.ExecutablePath
openFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"
openFileDialog1.FilterIndex = 0
' exibe-se a caixa de diálogo e recupera-se o seu resultado
If openFileDialog1.ShowDialog() = DialogResult.OK Then
' recupera-se o nome do ficheiro
Dim nomFichier As String = openFileDialog1.FileName
Dim fichier As StreamReader = Nothing
Try
' abre-se o ficheiro em modo de leitura
fichier = New StreamReader(nomFichier)
' lê-se todo o ficheiro e coloca-se no 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
' fecha-se o ficheiro
Try
fichier.Close()
Catch
End Try
End Try
End If
End Sub
- Define-se a pasta inicial como a pasta que contém o executável da aplicação:
- Definem-se os tipos de ficheiros a apresentar
- Define-se o tipo de ficheiro a apresentar no início
Neste caso, serão apresentados em primeiro lugar ao utilizador os ficheiros do tipo *.txt.
- A caixa de diálogo é apresentada e o seu resultado é recuperado
If openFileDialog1.ShowDialog() = DialogResult.OK Then
Enquanto a caixa de diálogo está visível, o utilizador já não tem acesso ao formulário principal (caixa de diálogo dita «modal»). O utilizador define o nome do ficheiro a abrir e sai da caixa de diálogo, quer através do botão «Abrir», quer através do botão «Cancelar», quer fechando a caixa de diálogo. O resultado do método ShowDialog é DialogResult.OK apenas se o utilizador tiver utilizado o botão Ouvrir para sair da caixa de diálogo.
- Feito isto, o nome do ficheiro a criar encontra-se agora na propriedade FileName do objeto openFileDialog1. Passa-se então à leitura clássica de um ficheiro de texto. De notar o método que permite ler a totalidade de um ficheiro:
- o conteúdo do ficheiro é colocado no TextBox txtTexte. Gerimos as exceções que possam ocorrer.
5.7.2. Caixas de diálogo FontColor e ColorDialog
Continuamos o exemplo anterior, apresentando dois novos botões:
![]() |
N.º | tipo | nome | função |
6 | Botão | btnCouleur | para definir a cor dos caracteres do TextBox |
7 | Botão | btnPolice | para definir o tipo de letra do TextBox |
Inserimos no formulário um controlo ColorDialog e um controlo FontDialog:

As classes FontDialog e ColorDialog têm um método ShowDialog análogo ao método ShowDialog das classes OpenFileDialog e SaveFileDialog. O método ShowDialog da classe ColorDialog permite selecionar uma cor:

Se o utilizador sair da caixa de diálogo através do botão OK, o resultado do método ShowDialog é DialogResult.OK e a cor selecionada encontra-se na propriedade Color do objeto ColorDialog utilizado. O método ShowDialog da classe FontDialog permite selecionar um tipo de letra:

Se o utilizador sair da caixa de diálogo através do botão OK, o resultado do método ShowDialog é DialogResult.OK e o tipo de letra selecionado encontra-se na propriedade Font do objeto FontDialog utilizado. Temos os elementos para tratar os cliques nos botões Couleur e Police:
Private Sub btnCouleur_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnCouleur.Click
' escolha de uma cor de texto
If colorDialog1.ShowDialog() = DialogResult.OK Then
' altera-se a propriedade «forecolor» do 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
' escolha de um tipo de letra
If fontDialog1.ShowDialog() = DialogResult.OK Then
' alterar a propriedade «font» do TextBox
txtTexte.Font = fontDialog1.Font
End If
End Sub
5.7.3. Temporizador
Propomos aqui escrever a seguinte aplicação:
![]() |
n.º | Tipo | Nome | Função |
1 | TextBox, ReadOnly=true | txtChrono | exibe um cronómetro |
2 | Botão | btnArretMarche | botão de parar/iniciar o cronómetro |
3 | Temporizador | timer1 | componente que emite aqui um evento a cada segundo |
O cronómetro em funcionamento:

O cronómetro parado:

Para alterar a cada segundo o conteúdo do TextBox e do txtChrono, precisamos de um componente que gere um evento a cada segundo, evento esse que poderemos interceptar para atualizar a exibição do cronómetro. Esse componente é o Timer:

Depois de instalar este componente no formulário (na secção dos componentes não visuais), é criado um objeto do tipo Timer no construtor do formulário. A classe System.Windows.Forms.Timer é definida da seguinte forma:

Das suas propriedades, destacamos apenas as seguintes:
número de milissegundos após o qual é emitido um evento Tick. | |
o evento gerado ao fim de Interval milissegundos | |
torna o temporizador ativo (true) ou inativo (false) |
No nosso exemplo, o temporizador chama-se timer1 e timer1.Interval está definido para 1000 ms (1 s). O evento Tick ocorrerá, portanto, a cada segundo. O clique no botão Parar/Iniciar é processado pelo seguinte procedimento:
Private Sub btnArretMarche_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnArretMarche.Click
' parar ou continuar?
If btnArretMarche.Text = "Marche" Then
' regista-se a hora de início
début = DateTime.Now
' exibe-se
txtChrono.Text = "00:00:00"
' inicia-se o temporizador
timer1.Enabled = True
' alterar o texto do botão
btnArretMarche.Text = "Arrêt"
' fim
Return
End If '
If btnArretMarche.Text = "Arrêt" Then
' paragem do temporizador
timer1.Enabled = False
' alterar o texto do botão
btnArretMarche.Text = "Marche"
' fim
Return
End If
End Sub
Private Sub timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles timer1.Tick
' passou um segundo
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
O texto do botão Parar/Ligar é «Parar» ou «Ligar». Por isso, é necessário verificar esse texto para saber o que fazer.
- No caso de «Ligar», regista-se a hora de início numa variável que é uma variável global do objeto formulário, o temporizador é iniciado (Enabled=true) e o texto do botão passa a «Desligar».
- No caso de «Parar», o temporizador é parado (Enabled=false) e o texto do botão passa a «Ligar».
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
' variáveis de instância
Private début As DateTime
O atributo début acima é reconhecido em todos os métodos da classe. Resta-nos tratar o evento Tick no objeto timer1, evento que ocorre a cada segundo:
Private Sub timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles timer1.Tick
' passou um segundo
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
Calcula-se o tempo decorrido desde o momento em que o cronómetro foi iniciado. Obtenha-se um objeto do tipo TimeSpan que representa um intervalo de tempo. Este deve ser exibido no cronómetro no formato hh:mm:ss. Para tal, utilizamos as propriedades Hours, Minutes, Seconds do objeto TimeSPan, que representam, respetivamente, as horas, minutos e segundos da duração que apresentamos no formato ToString("d2") para obter uma exibição com 2 dígitos.
5.8. O exemplo IMPOTS
Retomamos a aplicação IMPOTS, já abordada duas vezes. Acrescentamos agora uma interface gráfica:
![]() |
Os controlos são os seguintes
n.º | tipo | nome | função |
RadioButton | rdOui | marcado se for casado | |
RadioButton | rdNon | marcar se não for casado | |
NumericUpDown | incEnfants | número de filhos do contribuinte Mínimo=0, Máximo=20, Incremento=1 | |
TextBox | txtSalaire | salário anual do contribuinte em F | |
TextBox | txtImpots | montante do imposto a pagar ReadOnly=true | |
Botão | btnCalculer | inicia o cálculo do imposto | |
Botão | btnEffacer | repor o formulário ao seu estado inicial ao carregar | |
Botão | btnQuitter | para sair da aplicação |
Regras de funcionamento
- o botão «Calcular» permanece desativado enquanto não houver nada no campo do salário
- se, quando o cálculo for iniciado, se verificar que o salário está incorreto, o erro é assinalado:

O programa é apresentado abaixo. Utiliza a classe impot criada no capítulo sobre classes. Uma parte do código gerado automaticamente pela VS.NET não foi aqui reproduzida.
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
' opções
Option Explicit On
Option Strict On
' espaços de nomes
Imports System
Imports System.Drawing
Imports System.Collections
Imports System.ComponentModel
Imports System.Windows.Forms
Imports System.Data
' classe de formulário
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
' tabelas de dados necessárias para o cálculo do imposto
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}
' objeto de imposto
Private objImpôt As impot = Nothing
Public Sub New()
InitializeComponent()
' inicialização do formulário
btnEffacer_Click(Nothing, Nothing)
btnCalculer.Enabled = False
' criação de um objeto de imposto
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)
' inibe-se o campo de introdução do salário
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
' Limpar o formulário
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
' estado do botão «Calcular»
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
' fim da aplicação
Application.Exit()
End Sub 'btnQuitter_Click
Private Sub btnCalculer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnCalculer.Click
' O salário está correto?
Dim intSalaire As Integer = 0
Try
' recuperação do salário
intSalaire = Integer.Parse(txtSalaire.Text)
' deve ser >=0
If intSalaire < 0 Then
Throw New Exception("")
End If
Catch ex As Exception
' mensagem de erro
MessageBox.Show(Me, "Salaire incorrect", "Erreur de saisie", MessageBoxButtons.OK, MessageBoxIcon.Error)
' foco no campo com erro
txtSalaire.Focus()
' seleção do texto do campo de introdução
txtSalaire.SelectAll()
' regresso à interface visual
Return
End Try 'try-catch
' o salário está correto — calcula-se o imposto
txtImpots.Text = "" & CLng(objImpôt.calculer(rdOui.Checked, CInt(incEnfants.Value), intSalaire))
End Sub 'btnCalculer_Click
End Class
Utilizamos aqui o programa em assembler impots.dll, resultado da compilação da classe «impots» do capítulo 2. Recorde-se que este programa em assembler pode ser gerado no modo de consola através do comando
Este comando gera o ficheiro impots.dll, denominado «assemblagem». Esta assemblagem pode, posteriormente, ser utilizada em diferentes projetos. Aqui, no nosso projeto com o nome VS.NET, utilizamos a janela de propriedades do projeto:

Para adicionar uma referência (um conjunto), clicamos com o botão direito do rato no conjunto-chave «Referências» acima, selecionamos a opção [Ajouter une référence] e indicamos o conjunto [impots.dll], que nos certificámos de colocar na pasta do projeto:
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
Assim que o conjunto [impots.dll] for incluído no projeto, a classe [impots] passa a ser reconhecida pelo projeto. Anteriormente, não era o caso. Outro método consiste em incluir o código-fonte impots.vb no projeto. Para tal, na janela de propriedades do projeto, clica-se com o botão direito do rato no projeto, seleciona-se a opção [Ajouter/Ajouter un élément existant] e indica-se o ficheiro impots.vb.















































