5. Interfaces gráficas con VB.NET y VS.NET
En este artículo nos proponemos mostrar cómo crear interfaces gráficas con VB.NET. En primer lugar, veremos cuáles son las clases básicas de la plataforma .NET que nos permiten crear una interfaz gráfica. En un primer momento, no utilizaremos ninguna herramienta de generación automática. A continuación, utilizaremos Visual Studio.NET (VS.NET), una herramienta de desarrollo de Microsoft que facilita el desarrollo de aplicaciones con los lenguajes .NET y, en particular, la creación de interfaces gráficas. La versión de VS.NET utilizada es la versión en inglés.
5.1. Fundamentos de las interfaces gráficas
5.1.1. Una ventana sencilla
Consideremos el siguiente código:
' opciones
Option Strict On
Option Explicit On
' espacios de nombres
Imports System
Imports System.Drawing
Imports System.Windows.Forms
' la clase formulario
Public Class Form1
Inherits Form
' el constructor
Public Sub New()
' título de la ventana
Me.Text = "Mon premier formulaire"
' dimensiones de la ventana
Me.Size = New System.Drawing.Size(300, 100)
End Sub
' función de prueba
Public Shared Sub Main(ByVal args() As String)
' se muestra el formulario
Application.Run(New Form1)
End Sub
End Class
El código anterior se compila y luego se ejecuta
La ejecución muestra la siguiente ventana:

Una interfaz gráfica suele derivarse de la clase base System.Windows.Forms.Form:
La clase base Form define una ventana básica con botones de cierre, maximizar/minimizar, tamaño ajustable, etc., y gestiona los eventos de estos objetos gráficos. Aquí especializamos la clase base asignándole un título y su anchura (300) y altura (100). Esto se hace en su constructor:
Public Sub New()
' título de la ventana
Me.Text = "Mon premier formulaire"
' dimensiones de la ventana
Me.Size = New System.Drawing.Size(300, 100)
End Sub
El título de la ventana se establece mediante la propiedad Text y las dimensiones mediante la propiedad Size. Size se define en el espacio de nombres System.Drawing y es una estructura. El procedimiento Main inicia la aplicación gráfica de la siguiente manera:
Application.Run(New Form1)
Se crea y se muestra un formulario de tipo Form1; a continuación, la aplicación se pone a la escucha de los eventos que se producen en el formulario (clics, movimientos del ratón, etc.) y ejecuta aquellos que el formulario gestiona. En este caso, nuestro formulario no gestiona ningún evento más allá de los que gestiona la clase base Form (clics en los botones de cierre, maximizar/minimizar, cambio de tamaño de la ventana, desplazamiento de la ventana, etc.).
5.1.2. Un formulario con un botón
Añadamos ahora un botón a nuestra ventana:
' opciones
Option Strict On
Option Explicit On
' espacios de nombres
Imports System
Imports System.Drawing
Imports System.Windows.Forms
' la clase del formulario
Public Class Form1
Inherits Form
' atributos
Private cmdTest As Button
' el constructor
Public Sub New()
' el título
Me.Text = "Mon premier formulaire"
' las dimensiones
Me.Size = New System.Drawing.Size(300, 100)
' un botón
' creación
Me.cmdTest = New Button
' posición
cmdTest.Location = New System.Drawing.Point(110, 20)
' tamaño
cmdTest.Size = New System.Drawing.Size(80, 30)
' etiqueta
cmdTest.Text = "Test"
' gestor de eventos
AddHandler cmdTest.Click, AddressOf cmdTest_Click
' Añadir botón al formulario
Me.Controls.Add(cmdTest)
End Sub
' gestor de eventos
Private Sub cmdTest_Click(ByVal sender As Object, ByVal evt As EventArgs)
' se ha hecho clic en el botón - se notifica
MessageBox.Show("Clic sur bouton", "Clic sur bouton", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
' función de prueba
Public Shared Sub Main(ByVal args() As String)
' se muestra el formulario
Application.Run(New Form1)
End Sub
End Class
Hemos añadido un botón al formulario:
' un botón
' creación
Me.cmdTest = New Button
' posición
cmdTest.Location = New System.Drawing.Point(110, 20)
' tamaño
cmdTest.Size = New System.Drawing.Size(80, 30)
' etiqueta
cmdTest.Text = "Test"
' gestor de eventos
AddHandler cmdTest.Click, AddressOf cmdTest_Click
' Añadir botón al formulario
Me.Controls.Add(cmdTest)
La propiedad Location establece las coordenadas (110,20) del punto superior izquierdo del botón mediante una estructura Point. El ancho y la altura del botón se fijan en (80,30) mediante una estructura Size. La propiedad Text del botón permite establecer el texto del botón. La clase botón tiene un evento Click definido de la siguiente manera:
donde EventHandler es una función «delegada» con la siguiente firma:
Esto significa que el controlador del evento [Click] del botón deberá tener la firma del delegado [EventHandler]. En este caso, al hacer clic en el botón cmdTest, se llamará al método cmdTest_Click. Este se define de la siguiente manera, de acuerdo con el modelo EventHandler anterior:
' gestor de eventos
Private Sub cmdTest_Click(ByVal sender As Object, ByVal evt As EventArgs)
' se ha hecho clic en el botón - se notifica
MessageBox.Show("Clic sur bouton", "Clic sur bouton", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
Nos limitamos a mostrar un mensaje:

La clase se compila y se ejecuta:
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 clase MessageBox sirve para mostrar mensajes en una ventana. Aquí hemos utilizado el constructor
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 | el mensaje que se va a mostrar |
caption | el título de la ventana |
botones | los botones presentes en la ventana |
icono | el icono presente en la ventana |
El parámetro buttons puede tomar sus valores entre las siguientes constantes:
constante | botones |
![]() | |
![]() | |
![]() | |
![]() | |
![]() | |
![]() |
El parámetro icon puede tomar sus valores entre las siguientes constantes:
![]() | ídem Stop | ||
ídem Advertencia | ![]() | ||
ídem Asterisk | ![]() | ||
![]() | ídem Hand | ||
![]() |
El método Show es un método estático que devuelve un resultado de tipo System.Windows.Forms.DialogResult, que es una enumeración:
public enum System.Windows.Forms.DialogResult
{
Abort = 0x00000003,
Cancel = 0x00000002,
Ignore = 0x00000005,
No = 0x00000007,
None = 0x00000000,
OK = 0x00000001,
Retry = 0x00000004,
Yes = 0x00000006,
}
Para saber qué botón ha pulsado el usuario para cerrar la ventana de tipo MessageBox, escribiremos:
dim res as DialogResult=MessageBox.Show(..)
if res=DialogResult.Yes then
' pulsó el botón «Sí»
...
end if
5.2. Crear una interfaz gráfica con Visual Studio.NET
Retomamos algunos de los ejemplos vistos anteriormente y los creamos ahora con Visual Studio.NET.
5.2.1. Creación inicial del proyecto
- Inicie VS.NET y seleccione la opción Fichier/Nouveau/Projet

- Introduzca las características de su proyecto
![]() |
- seleccione el tipo de proyecto que desea crear, en este caso un proyecto VB.NET (1)
- seleccione el tipo de aplicación que desea crear, en este caso una aplicación de Windows (2)
- Indique en qué carpeta desea colocar la subcarpeta del proyecto (3)
- Indique el nombre del proyecto (4). Este será también el nombre de la carpeta que contendrá los archivos del proyecto
- El nombre de esta carpeta se muestra en (5)
- A continuación, se crean varias carpetas y archivos dentro de la carpeta i4:
subcarpetas de la carpeta proyecto1 ![]() |
De estos archivos, solo uno es relevante: el archivo form1.cs, que es el archivo fuente asociado al formulario creado por VS.NET. Volveremos sobre ello más adelante.
5.2.2. Las ventanas de la interfaz de VS.NET
La interfaz de VS.NET muestra ahora algunos elementos de nuestro proyecto i4:
Tenemos una ventana de diseño de la interfaz gráfica:
![]() |
Al seleccionar controles de la barra de herramientas (toolbox 2) y soltarlos en la superficie de la ventana (1), podemos construir una interfaz gráfica. Si pasamos el ratón por encima de la «toolbox», esta se amplía y muestra una serie de controles:

Por el momento, no utilizamos ninguno. Siguiendo en la pantalla de VS.NET, encontramos la ventana del explorador de soluciones «Explorer Solution»:

En un primer momento, apenas utilizaremos esta ventana. Muestra todos los archivos que componen el proyecto. Solo nos interesa uno de ellos: el archivo fuente de nuestro programa, en este caso Form1.vb. Al hacer clic con el botón derecho del ratón sobre Form1.vb, aparece un menú que permite acceder al código fuente de nuestra interfaz gráfica (Mostrar código) o a la propia interfaz gráfica (Diseñador de vistas):

Se puede acceder a estas dos entidades directamente desde la ventana «Explorador de soluciones»:
![]() | ![]() |
Las ventanas abiertas «se acumulan» en la ventana principal de diseño:

Aquí, Form1.vb[Design] designa la ventana de diseño y Form1.vb la ventana de código. Basta con hacer clic en una de las pestañas para pasar de una ventana a otra. Otra ventana importante que aparece en la pantalla de VS.NET es la ventana de propiedades:

Las propiedades que se muestran en la ventana son las del control actualmente seleccionado en la ventana de diseño gráfico. Se puede acceder a diferentes ventanas del proyecto mediante el menú Affichage:

En él se encuentran las ventanas principales que acabamos de describir, así como sus atajos de teclado.
5.2.3. Ejecución de un proyecto
Aunque no hayamos escrito ningún código, tenemos un proyecto ejecutable. Ejecútelo con F5 o Déboguer/Démarrer. Aparecerá la siguiente ventana:

Esta ventana se puede ampliar, minimizar, redimensionar y cerrar.
5.2.4. El código generado por VS.NET
Veamos el código (Affichage/Code) de nuestra aplicación:
Public Class Form1
Inherits System.Windows.Forms.Form
#Región «Código generado por el Diseñador de formularios de Windows»
Public Sub New()
MyBase.New()
'Esta llamada es requerida por el Diseñador de Windows Form.
InitializeComponent()
'Añada cualquier inicialización después de la llamada InitializeComponent()
End Sub
'El método sustituido Dispose del formulario para limpiar la 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
'Requerido por el Diseñador de Windows Form
Private components As System.ComponentModel.IContainer
'REMARQUE: el Diseñador de Windows Form requiere el siguiente procedimiento
'Se puede modificar utilizando el Diseñador de formularios de Windows.
'No lo modifique utilizando el editor de código.
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
components = New System.ComponentModel.Container()
Me.Text = "Form2"
End Sub
#Fin de región
End Class
Una interfaz gráfica deriva de la clase base System.Windows.Forms.Form:
La clase base Form define una ventana básica con botones de cierre, maximizar/minimizar, tamaño ajustable, etc., y gestiona los eventos de estos objetos gráficos. El constructor del formulario utiliza un método InitializeComponent en el que se crean e inicializan los controles del formulario.
Public Sub New()
MyBase.New()
'El Diseñador de formularios de Windows requiere esta llamada.
InitializeComponent()
'Añada cualquier inicialización después de la llamada InitializeComponent()
End Sub
Cualquier otro trabajo que haya que realizar en el constructor se puede hacer tras llamar a InitializeComponent. El 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
establece el título de la ventana «Form1», su anchura (292) y su altura (53). El título de la ventana se establece mediante la propiedad Text y las dimensiones mediante la propiedad Size. Size se define en el espacio de nombres System.Drawing y es una estructura. Para ejecutar esta aplicación, debemos definir el módulo principal del proyecto. Para ello, utilizamos la opción [Projets/Propriétés]:

En [Objet de démarrage], indicamos [Form1], que es el formulario que acabamos de crear. Para iniciar la ejecución, utilizamos la opción [Déboguer/Démarrer]:

5.2.5. Compilación en una ventana de DOS
Ahora, intentemos compilar y ejecutar esta aplicación en una ventana de 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'.
El compilador indica que no encuentra el procedimiento [Main]. De hecho, VS.NET no lo ha generado. Sin embargo, ya lo hemos visto en los ejemplos anteriores. Tiene la siguiente forma:
Shared Sub Main()
' se inicia la aplicación
Application.Run(New Form1) ' où Form1 est le formulaire
End Sub
Añadamos al código de [Form1.vb] el código anterior y volvamos a compilar:
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)
~~~~~~~~~~~
En esta ocasión, el nombre [Application] no es conocido. Esto simplemente significa que no hemos importado su espacio de nombres [System.Windows.Forms]. Añadamos la siguiente instrucción:
y volvamos a compilar:
Esta vez funciona. Ejecutemos:

Se crea y se muestra un formulario de tipo Form1. Se puede evitar añadir el procedimiento [Main] utilizando la opción /m del compilador, que permite especificar la clase que se debe ejecutar en caso de que esta herede de System.Windows.Form:
La opción /m:form2 indica que la clase que se va a ejecutar es la clase con el nombre [form2].
5.2.6. Gestión de eventos
Una vez mostrado el formulario, la aplicación se pone a la escucha de los eventos que se producen en el formulario (clics, movimientos del ratón, etc.) y ejecuta aquellos que el formulario gestiona. En este caso, nuestro formulario no gestiona ningún evento que no sean los gestionados por la clase base Form (clics en los botones de cierre, maximizar/minimizar, cambio de tamaño de la ventana, desplazamiento de la ventana, etc.). El formulario generado utiliza un atributo components que no se utiliza en ningún sitio. El método dispose tampoco sirve para nada aquí. Lo mismo ocurre con algunos espacios de nombres (Collections, ComponentModel, Data) utilizados y con el definido para el proyecto projet1. Por lo tanto, en este ejemplo, el código se puede simplificar de la siguiente manera:
Imports System
Imports System.Drawing
Imports System.Windows.Forms
Public Class Form1
Inherits System.Windows.Forms.Form
' constructor
Public Sub New()
' construcción del formulario con sus componentes
InitializeComponent()
End Sub
Private Sub InitializeComponent()
' tamaño de la ventana
Me.Size = New System.Drawing.Size(300, 300)
' título de la ventana
Me.Text = "Form1"
End Sub
Shared Sub Main()
' se inicia la aplicación
Application.Run(New Form1)
End Sub
End Class
5.2.7. Conclusión
Ahora aceptaremos tal cual el código generado por VS.NET y nos limitaremos a añadir el nuestro, en particular para gestionar los eventos relacionados con los diferentes controles del formulario.
5.3. Ventana con campo de entrada, botón y etiqueta
5.3.1. Diseño gráfico
En el ejemplo anterior, no habíamos colocado ningún componente en la ventana. Comenzamos un nuevo proyecto llamado interface2. Para ello, seguimos el procedimiento explicado anteriormente para crear un proyecto:

Ahora vamos a crear una ventana con un botón, una etiqueta y un campo de entrada:
![]() |
Los campos son los siguientes:
n.º | nombre | tipo | función |
1 | lblSaisie | Etiqueta | una descripción |
2 | txtSaisie | TextBox | un campo de entrada |
3 | btnAfficher | Botón | para mostrar en un cuadro de diálogo el contenido del campo de entrada txtSaisie |
Para crear esta ventana, puede proceder de la siguiente manera: haga clic con el botón derecho del ratón en la ventana, fuera de cualquier componente, y seleccione la opción Properties para acceder a las propiedades de la ventana:

A continuación, aparecerá la ventana de propiedades a la derecha:

Cabe destacar algunas de estas propiedades:
para establecer el color de fondo de la ventana | |
para establecer el color de los dibujos o del texto de la ventana | |
para asociar un menú a la ventana | |
para asignar un título a la ventana | |
para establecer el tipo de ventana | |
para establecer la fuente de los caracteres en la ventana | |
para establecer el nombre de la ventana |
Aquí fijamos las propiedades Text y Name:
Entradas y botones - 1 | |
frmSaisiesBoutons |
Con la barra «Caja de herramientas»
- seleccione los componentes que necesite
- colóquelos en la ventana y asigne las dimensiones adecuadas
![]() | ![]() |
Una vez elegido el componente en la «caja de herramientas», utiliza la tecla «Esc» para ocultar la barra de herramientas y, a continuación, arrastre y ajuste el tamaño del componente. Haga lo mismo con los tres componentes Requeridos: Label, TextBox, Button. Para alinear y ajustar correctamente el tamaño de los componentes, utilice el menú Format: | ![]() |
El principio del formato es el siguiente:
La opción Align le permite alinear componentes | ![]() |
La opción Make Same Size permite que componentes tengan la misma altura o el mismo ancho: | ![]() |
La opción «Horizontal Spacing» permite, por ejemplo, alinear horizontalmente los componentes con espacios entre ellos del mismo tamaño. Lo mismo con la opción «Espaciado vertical» para alinear verticalmente. La opción «Center in Form» permite centrar un componente horizontalmente o verticalmente en la ventana: | ![]() |
Una vez que los componentes estén correctamente colocados en la ventana, fije sus propiedades. Para ello, haz clic con el botón derecho del ratón sobre el componente y seleccione la opción Properties:
Seleccione el componente para acceder a su ventana de propiedades. En ella, modifique las siguientes propiedades: nombre: lblSaisie, texto: Introducción
Seleccione el componente para acceder a su ventana de propiedades. En ella, modifique las siguientes propiedades: nombre: txtSaisie, texto: no introduzca nada
nombre: cmdAfficher, texto: Mostrar
texto: Entradas y botones - 1 | ![]() |
Podemos ejecutar (Ctrl+F5) nuestro proyecto para tener una primera vista previa de la ventana en acción: | ![]() |
Cierra la ventana. Ahora nos queda escribir el procedimiento asociado al clic en el botón Afficher.
5.3.2. Gestión de eventos de un formulario
Veamos el código que ha generado el diseñador 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
' constructor
Public Sub New()
InitializeComponent()
End Sub
...
' inicialización de los componentes
Private Sub InitializeComponent()
...
End Sub
End Class
En primer lugar, cabe destacar la declaración específica de los componentes:
- la palabra clave Friend indica que la visibilidad del componente se extiende a todas las clases del proyecto
- la palabra clave WithEvents indica que el componente genera eventos. Ahora nos centraremos en cómo gestionar estos eventos
Muestre la ventana de código del formulario (Ver/Código o F7):
![]() |
La ventana anterior presenta dos listas desplegables (1) y (2). La lista (1) es la lista de componentes del formulario:

La lista (2) es la lista de eventos asociados al componente seleccionado en (1):

Uno de los eventos asociados al componente se muestra en negrita (en este caso, Click). Se trata del evento predeterminado del componente. Se puede acceder al controlador de este evento concreto haciendo doble clic sobre el componente en la ventana de diseño. VB.net genera entonces automáticamente el esqueleto del controlador de eventos en la ventana de código y sitúa al usuario sobre él. El acceso a los gestores de los demás eventos se realiza en la ventana de código, seleccionando el componente en la lista (1) y el evento en (2). VB.net genera entonces el esqueleto del gestor de eventos o se sitúa sobre él si ya estaba generado:
Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAfficher.Click
...
End Sub
Por defecto, VB.net C_E nombra el gestor del evento E del componente C. Se puede cambiar este nombre si nos conviene. Sin embargo, no es recomendable. Los desarrolladores de VB suelen mantener el nombre generado por VB, lo que garantiza la coherencia en la nomenclatura de todos los programas VB. La asociación del procedimiento btnAfficher_Click al evento Click del componente btnAfficher no se realiza mediante el nombre del procedimiento, sino mediante la palabra clave handles:
Handles btnAfficher.Click
En el ejemplo anterior, la palabra clave handles especifica que el procedimiento gestiona el evento Click del componente btnAfficher. El gestor de eventos anterior tiene dos parámetros:
el objeto que origina el evento (en este caso, el botón) | |
un objeto EventArgs que detalla el evento que se ha producido |
No utilizaremos ninguno de estos parámetros aquí. Solo nos queda completar el código. En este caso, queremos mostrar un cuadro de diálogo con el contenido del campo txtSaisie:
Private Sub btnAfficher_Click(ByVal sender As Object, ByVal e As System.EventArgs)
' se muestra el texto introducido en el cuadro de entrada TxtSaisie
MessageBox.Show("texte saisi= " + txtsaisie.Text, "Vérification de la saisie", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
Si ejecutamos la aplicación, obtenemos lo siguiente:

5.3.3. Otro método para gestionar los eventos
Para el botón btnAfficher, VS.NET ha generado el siguiente 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 al hacer clic en el botón cmdAfficher
Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAfficher.Click
...
End Sub
Podemos asociar el procedimiento btnAfficher_Click al evento Click del botón btnAfficher de otra manera:
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 al hacer clic en el botón cmdAfficher
Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
...
End Sub
El procedimiento btnAfficher_Click ha perdido la palabra clave Handles, perdiendo así su asociación con el evento btnAfficher.Click. Esta asociación se realiza ahora mediante la palabra clave AddHandler:
AddHandler btnAfficher.Click, AddressOf btnAfficher_Click
El código anterior, que se colocará en el procedimiento InitializeComponent del formulario, asocia al evento btnAfficher.Click el procedimiento denominado btnAfficher_Click. Por otra parte, el componente btnAfficher ya no necesita la palabra clave WithEvents:
Friend btnAfficher As System.Windows.Forms.Button
¿Cuál es la diferencia entre ambos métodos?
- La palabra clave handles solo permite asociar un evento a un procedimiento en el momento del diseño. El diseñador sabe de antemano que un procedimiento P debe gestionar los eventos E1, E2, ... y escribe el código
Private Sub btnAfficher_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) handles E1, E2, ..., En
De hecho, es posible que un procedimiento gestione varios eventos.
- La palabra clave addhandler permite asociar un evento a un procedimiento en el momento de la ejecución. Esto resulta útil en un contexto de productor-consumidor de eventos. Un objeto produce un evento concreto que puede interesar a otros objetos. Estos se suscriben al productor para recibir el evento (una temperatura que ha superado un umbral crítico, por ejemplo). Durante la ejecución de la aplicación, el productor del evento tendrá que ejecutar diferentes instrucciones:
donde E es el evento generado por el productor y Pi son los procedimientos que pertenecen a los diferentes objetos consumidores de dicho evento. Tendremos ocasión de volver sobre una aplicación de productor-consumidor de eventos en un próximo capítulo.
5.3.4. Conclusión
A partir de los dos proyectos estudiados, podemos concluir que, una vez construida la interfaz gráfica con VS.NET, el trabajo del desarrollador consiste en escribir los controladores de eventos que desea gestionar para dicha interfaz gráfica. A partir de ahora solo presentaremos el código de estos.
5.4. Algunos componentes útiles
A continuación, presentamos diversas aplicaciones que utilizan los componentes más habituales con el fin de descubrir sus principales métodos y propiedades. Para cada aplicación, presentamos la interfaz gráfica y el código relevante, en particular los controladores de eventos.
5.4.1. Formulario
Comenzamos presentando el componente indispensable: el formulario en el que se colocan los componentes. Ya hemos presentado algunas de sus propiedades básicas. Aquí nos detendremos en algunos eventos importantes de un formulario.
El formulario se está cargando | |
El formulario se está cerrando | |
El formulario está cerrado |
El evento Load se produce incluso antes de que se muestre el formulario. El evento Closing se produce cuando el formulario se está cerrando. Este cierre aún se puede detener mediante programación. Creamos un formulario con el nombre Form1 sin componentes:

Procesamos los tres eventos anteriores:
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
' carga inicial del formulario
MessageBox.Show("Evt Load", "Load")
End Sub
Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
' el formulario se está cerrando
MessageBox.Show("Evt Closing", "Closing")
' se solicita confirmación
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
' el formulario se está cerrando
MessageBox.Show("Evt Closed", "Closed")
End Sub
Utilizamos la función MessageBox para recibir notificaciones de los diferentes eventos. El evento Closing se producirá cuando el usuario cierre la ventana. | ![]() |
A continuación, le preguntamos si realmente desea salir de la aplicación: | ![]() |
Si responde «No», establecemos la propiedad Cancel del evento CancelEventArgs que el método ha recibido como parámetro. Si establecemos esta propiedad en False, se cancela el cierre de la ventana se cancela; de lo contrario, continúa: | ![]() |
5.4.2. Etiquetas Label y cuadros de entrada TextBox
Ya nos hemos encontrado con estos dos componentes. Label es un componente de texto y TextBox un componente de campo de entrada. Su propiedad principal es Text, que designa bien el contenido del campo de entrada o bien el texto de la etiqueta. Esta propiedad es de lectura/escritura. El evento que se suele utilizar para TextBox es TextChanged, que indica que el usuario ha modificado el campo de entrada. A continuación se muestra un ejemplo que utiliza el evento TextChanged para seguir los cambios en un campo de entrada:
![]() |
n.º | tipo | nombre | función |
1 | TextBox | txtSaisie | campo de entrada |
2 | Etiqueta | lblControle | muestra el texto de 1 en tiempo real |
3 | Botón | cmdEffacer | para borrar los campos 1 y 2 |
4 | Botón | cmdQuitter | para salir de la aplicación |
El código relevante de esta aplicación es el de los gestores de eventos:
' clic en el botón Salir
Private Sub cmdQuitter_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles cmdQuitter.Click
' clic en el botón Salir - se sale de la aplicación
Application.Exit()
End Sub
' modificación del campo txtSaisie
Private Sub txtSaisie_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles txtSaisie.TextChanged
' el contenido de TextBox ha cambiado - se copia en la etiqueta lblControle
lblControle.Text = txtSaisie.Text
End Sub
' clic en el botón «Borrar»
Private Sub cmdEffacer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles cmdEffacer.Click
' se borra el contenido del cuadro de entrada
txtSaisie.Text = ""
End Sub
' se ha pulsado una tecla
Private Sub txtSaisie_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) _
Handles txtSaisie.KeyPress
' se comprueba qué tecla se ha pulsado
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
Cabe destacar la forma de cerrar la aplicación en el procedimiento cmdQuitter_Click: Application.Exit(). El siguiente ejemplo utiliza un TextBox de varias líneas:
![]() |
La lista de controles es la siguiente:
n.º | tipo | nombre | función |
1 | TextBox | txtMultiLignes | campo de entrada de varias líneas |
2 | TextBox | txtAjout | campo de entrada de una sola línea |
3 | Botón | btnAjouter | Añade el contenido de 2 a 1 |
Para que un TextBox se convierta en multilínea, se configuran las siguientes propiedades del control:
para aceptar varias líneas de texto | |
para indicar si el control debe tener barras de desplazamiento (Horizontal, Vertical, Both) o no (None) | |
si es igual a true, la tecla Intro pasará a la línea siguiente | |
si es igual a true, la tecla Tab generará un salto de tabulación en el texto |
El código útil es el que gestiona el clic en el botón [Ajouter] y el que gestiona la modificación del campo de entrada [txtAjout]:
' evt btnAjouter_Click
Private Sub btnAjouter_Click1(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnAjouter.Click
' se añade el contenido de txtAjout al 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
' se establece el estado del botón Añadir
btnAjouter.Enabled = txtAjout.Text.Trim() <> ""
End Sub
5.4.3. listas desplegables ComboBox
![]() | ![]() |
Un componente ComboBox es una lista desplegable acompañada de un campo de entrada: el usuario puede elegir un elemento en (2) o escribir texto en (1). Existen tres tipos de ComboBox determinados por la propiedad Style:
lista no desplegable con cuadro de edición | |
lista desplegable con cuadro de edición | |
lista desplegable sin área de edición |
Por defecto, el tipo de un ComboBox es DropDown. Para obtener información sobre la clase ComboBox, escriba ComboBox en el índice de la ayuda (Aide/Index). La clase ComboBox tiene un único constructor:
Public Sub New() | crea un objeto ComboBox vacío |
Los elementos de ComboBox están disponibles en la propiedad Items:
Es una propiedad indexada, donde Items(i) designa el elemento i del combo. Sea C un combo y C.Items su lista de elementos. Tenemos las siguientes propiedades:
número de elementos del combo | |
elemento i del combo | |
añade el objeto o como último elemento del combo | |
añade una matriz de objetos al final del combo | |
añade el objeto o en la posición i del combo | |
elimina el elemento i del combo | |
elimina el objeto o del combo | |
elimina todos los elementos del combo | |
devuelve la posición i del objeto o en el combo |
Puede sorprender que un combo pueda contener objetos cuando normalmente contiene cadenas de caracteres. A nivel visual, así será. Si un ComboBox contiene un objeto obj, muestra la cadena obj.ToString(). Recordemos que todo objeto tiene un método ToString heredado de la clase object y que devuelve una cadena de caracteres «representativa» del objeto. El elemento seleccionado en el combo C es C.SelectedItem o C.Items(C.SelectedIndex), donde C.SelectedIndex es el número del elemento seleccionado, n.º que comienza en cero para el primer elemento.
Al seleccionar un elemento en la lista desplegable se produce el evento SelectedIndexChanged, que puede utilizarse para recibir una notificación del cambio de selección en el cuadro combinado. En la siguiente aplicación, utilizamos este evento para mostrar el elemento que se ha seleccionado en la lista.

Solo mostramos el código relevante de la ventana. En el constructor del formulario rellenamos el cuadro combinado:
Public Sub New()
' creación del formulario
InitializeComponent()
' rellenar el cuadro combinado
cmbNombres.Items.AddRange(New String() {"zéro", "un", "deux", "trois", "quatre"})
' seleccionamos el primer elemento de la lista
cmbNombres.SelectedIndex = 0
End Sub
Procesamos el evento SelectedIndexChanged del cuadro combinado que indica que se ha seleccionado un nuevo elemento:
Private Sub cmbNombres_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles cmbNombres.SelectedIndexChanged
' el elemento seleccionado ha cambiado; lo mostramos
MessageBox.Show("Elément sélectionné : (" & cmbNombres.SelectedItem.ToString & "," & cmbNombres.SelectedIndex & ")", "Combo", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
5.4.4. componente ListBox
Nos proponemos crear la siguiente interfaz:
![]() |
Los componentes de esta ventana son los siguientes:
n.º | tipo | nombre | función/propiedades |
0 | Form | Form1 | formulario - BorderStyle=FixedSingle |
1 | TextBox | txtSaisie | campo de entrada |
2 | Botón | btnAjouter | botón que permite añadir el contenido del campo de entrada 1 a la lista 3 |
3 | ListBox | listBox1 | lista 1 |
4 | ListBox | listBox2 | lista 2 |
5 | Botón | btn1TO2 | traslada los elementos seleccionados de la lista 1 a la lista 2 |
6 | Botón | cmd2T0 | Hace lo contrario |
7 | Botón | btnEffacer1 | vacía la lista 1 |
8 | Botón | btnEffacer2 | vacía la lista 2 |
- El usuario escribe texto en el campo 1. Lo añade a la lista 1 con el botón Ajouter (2). A continuación, se vacía el campo de entrada (1) y el usuario puede añadir un nuevo elemento.
- Puede transferir elementos de una lista a otra seleccionando el elemento que desea transferir en una de las listas y eligiendo el botón de transferencia adecuado 5 o 6. El elemento transferido se añade al final de la lista de destino y se elimina de la lista de origen.
- Puede hacer doble clic en un elemento de la lista 1. Este elemento se transfiere entonces al cuadro de entrada para su modificación y se elimina de la lista 1.
Los botones están activados o desactivados según las siguientes reglas:
- el botón Ajouter solo está activado si hay texto en el campo de entrada
- el botón 5 de transferencia de la lista 1 a la lista 2 solo está activado si hay un elemento seleccionado en la lista 1
- el botón 6 de transferencia de la lista 2 a la lista 1 solo está activado si hay un elemento seleccionado en la lista 2
- los botones 7 y 8 para borrar las listas 1 y 2 solo están activados si la lista que se va a borrar contiene elementos.
En las condiciones anteriores, todos los botones deben estar apagados al iniciar la aplicación. Para ello, hay que establecer la propiedad Enabled de los botones en false. Esto se puede hacer en el momento del diseño, lo que generará el código correspondiente en el método InitializeComponent, o bien hacerlo nosotros mismos en el constructor, como se muestra a continuación:
Public Sub New()
' creación inicial del formulario
InitializeComponent()
' inicializaciones adicionales
' se desactivan algunos botones
btnAjouter.Enabled = False
btn1TO2.Enabled = False
btn2TO1.Enabled = False
btnEffacer1.Enabled = False
btnEffacer2.Enabled = False
End Sub
El estado del botón Ajouter se controla mediante el contenido del campo de entrada. El evento TextChanged nos permite seguir los cambios de dicho contenido:
' cambio en el campo de entrada de texto
Private Sub txtSaisie_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles txtSaisie.TextChanged
' el contenido de txtSaisie ha cambiado
' el botón Añadir solo está activo si el campo de entrada no está vacío
btnAjouter.Enabled = txtSaisie.Text.Trim() <> ""
End Sub
El estado de los botones de transferencia depende de si se ha seleccionado o no un elemento en la lista que controlan:
' cambio del elemento seleccionado sin listbox1
Private Sub listBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles listBox1.SelectedIndexChanged
' se ha seleccionado un elemento
' se activa el botón de transferencia de 1 a 2
btn1TO2.Enabled = True
End Sub
' cambio del elemento seleccionado sin cuadro de lista 2
Private Sub listBox2_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles listBox2.SelectedIndexChanged
' se ha seleccionado un elemento
' se activa el botón de transferencia de 2 a 1
btn2TO1.Enabled = True
End Sub
El código asociado al clic en el botón Ajouter es el siguiente:
' clic en el botón Añadir
Private Sub btnAjouter_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnAjouter.Click
' se añade un nuevo elemento a la lista 1
listBox1.Items.Add(txtSaisie.Text.Trim())
' borrado de la entrada
txtSaisie.Text = ""
' La lista 1 no está vacía
btnEffacer1.Enabled = True
' el foco vuelve al cuadro de entrada
txtSaisie.Focus()
End Sub
Cabe destacar el método Focus, que permite poner el «foco» en un control del formulario. El código asociado al clic en los botones Effacer:
' clic en el botón Borrar1
Private Sub btnEffacer1_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnEffacer1.Click
' se borra la lista 1
listBox1.Items.Clear()
btnEffacer1.Enabled = False
End Sub
' clic en el botón Borrar2
Private Sub btnEffacer2_Click(ByVal sender As Object, ByVal e As System.EventArgs)
' se borra la lista 2
listBox2.Items.Clear()
btnEffacer2.Enabled = False
End Sub
El código para transferir los elementos seleccionados de una lista a otra:
' clic en el botón btn1to2
Private Sub btn1TO2_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btn1TO2.Click
' se transfiere el elemento seleccionado de la Lista 1 a la Lista 2
transfert(listBox1, listBox2)
' Botones «Borrar»
btnEffacer2.Enabled = True
btnEffacer1.Enabled = listBox1.Items.Count <> 0
' Botones de transferencia
btn1TO2.Enabled = False
btn2TO1.Enabled = False
End Sub
' clic en el botón btn2to1
Private Sub btn2TO1_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btn2TO1.Click
' transferencia del elemento seleccionado de la Lista 2 a la Lista 1
transfert(listBox2, listBox1)
' botones Borrar
btnEffacer1.Enabled = True
btnEffacer2.Enabled = listBox2.Items.Count <> 0
' botones de transferencia
btn1TO2.Enabled = False
btn2TO1.Enabled = False
End Sub
' transferencia
Private Sub transfert(ByVal l1 As ListBox, ByVal l2 As ListBox)
' transferencia del elemento seleccionado de la Lista 1 a la Lista 2
' ¿Un elemento seleccionado?
If l1.SelectedIndex = -1 Then Return
' añadir a l2
l2.Items.Add(l1.SelectedItem)
' eliminación en l1
l1.Items.RemoveAt(l1.SelectedIndex)
End Sub
En primer lugar, creamos un método
Private Sub transfert(ByVal l1 As ListBox, ByVal l2 As ListBox)
que transfiere a la lista l2 el elemento seleccionado en la lista l1. Esto nos permite disponer de un único método, en lugar de dos, para transferir un elemento de listBox1 a listBox2 o de listBox2 a listBox1. Antes de realizar la transferencia, nos aseguramos de que haya un elemento seleccionado en la lista l1:
' ¿un elemento seleccionado?
If l1.SelectedIndex = -1 Then Return
La propiedad SelectedIndex tiene el valor -1 si no hay ningún elemento seleccionado actualmente. En los procedimientos
Private Sub btnXTOY_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnXTOY.Click
se realiza la transferencia de la lista X a la lista Y y se cambia el estado de algunos botones para reflejar el nuevo estado de las listas.
5.4.5. casillas de selección CheckBox, botones de radio ButtonRadio
Nos proponemos escribir la siguiente aplicación:
![]() |
Los componentes de la ventana son los siguientes:
n.º | tipo | nombre | función |
1 | RadioButton | radioButton1 radioButton2 radioButton3 | 3 botones de radio |
2 | CheckBox | chechBox1 chechBox2 chechBox3 | 3 casillas de selección |
3 | ListBox | lstValeurs | una lista |
Si creamos los tres botones de radio uno tras otro, por defecto forman parte del mismo grupo. Por lo tanto, cuando uno está marcado, los demás no lo están. El evento que nos interesa para estos seis controles es el evento CheckChanged, que indica que el estado de la casilla de verificación o del botón de radio ha cambiado. Este estado se representa en ambos casos mediante la propiedad booleana Check, que, si es verdadera, significa que el control está marcado. Aquí hemos utilizado un único método para gestionar los seis eventos CheckChanged, el método affiche:
' muestra
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
' muestra el estado del botón de radio o de la casilla de verificación
' ¿Es una casilla de verificación?
If (TypeOf (sender) Is CheckBox) Then
Dim chk As CheckBox = CType(sender, CheckBox)
lstValeurs.Items.Insert(0, chk.Name & "=" & chk.Checked)
End If
' ¿Es un botón de radio?
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 sintaxis TypeOf (remitente) Is CheckBox permite verificar si el objeto sender es de tipo CheckBox. Esto nos permite, a continuación, realizar una conversión de tipo al tipo exacto de sender. El método affiche escribe en la lista lstValeurs el nombre del componente que origina el evento y el valor de su propiedad Checked. Al ejecutarlo, se observa que al hacer clic en un botón de radio se producen dos eventos CheckChanged: uno en el antiguo botón marcado, que pasa a «desmarcado», y otro en el nuevo botón, que pasa a «marcado».
5.4.6. controladores ScrollBar
Existen varios tipos de control deslizante: el control deslizante horizontal (hScrollBar), el variador vertical (vScrollBar) y el incrementador (NumericUpDown). | ![]() |
Realicemos la siguiente aplicación:
![]() |
n.º | tipo | nombre | función |
1 | hScrollBar | hScrollBar1 | un variador horizontal |
2 | hScrollBar | hScrollBar2 | un variador horizontal que sigue las variaciones del variador 1 |
3 | TextBox | txtValeur | muestra el valor del regulador horizontal ReadOnly=true para impedir cualquier entrada |
4 | NumericUpDown | incrementador | permite fijar el valor del control deslizante 2 |
- Un control deslizante ScrollBar permite al usuario seleccionar un valor dentro de un rango de valores enteros, representado por la «banda» del control deslizante sobre la que se desplaza un cursor. El valor del control deslizante está disponible en su propiedad Value.
- En un control deslizante horizontal, el extremo izquierdo representa el valor mínimo del rango, el extremo derecho el valor máximo y el cursor el valor actual seleccionado. En un control deslizante vertical, el mínimo está representado por el extremo superior y el máximo por el extremo inferior. Estos valores están representados por las propiedades Minimum y Maximum y tienen por defecto los valores 0 y 100.
- Al hacer clic en los extremos del control deslizante, el valor varía en un incremento (positivo o negativo) según el extremo en el que se haya hecho clic, denominado SmallChange, cuyo valor por defecto es 1.
- Al hacer clic a ambos lados del cursor, el valor varía en un incremento (positivo o negativo) según el extremo en el que se haya hecho clic, denominado LargeChange, cuyo valor por defecto es 10.
- Al hacer clic en el extremo superior de un control deslizante vertical, su valor disminuye. Esto puede sorprender al usuario medio, que normalmente espera que el valor «aumente». Este problema se soluciona asignando un valor negativo a las propiedades SmallChange y LargeChange
- Estas cinco propiedades (Value, Minimum, Maximum, SmallChange, LargeChange) son accesibles en lectura y escritura.
- El evento principal del variador es el que señala un cambio de valor: el evento Scroll.
Un componente NumericUpDown se encuentra cerca del variador: también tiene las propiedades Minimum, Maximum y Value, con valores predeterminados de 0, 100 y 0, respectivamente. Pero aquí, la propiedad Value se muestra en un cuadro de entrada que forma parte integrante del control. El usuario puede modificar este valor por sí mismo, salvo que se haya establecido la propiedad ReadOnly del control en verdadero. El valor del incremento viene determinado por la propiedad Increment, cuyo valor por defecto es 1. El evento principal del componente NumericUpDown es el que señala un cambio de valor: el evento ValueChanged. El código útil de nuestra aplicación es el siguiente:
El formulario se formatea durante su construcción:
' constructor
Public Sub New()
' creación inicial del formulario
InitializeComponent()
' se le dan al variador 2 las mismas características que al variador 1
hScrollBar2.Minimum = hScrollBar1.Value
hScrollBar2.Minimum = hScrollBar1.Minimum
hScrollBar2.Maximum = hScrollBar1.Maximum
hScrollBar2.LargeChange = hScrollBar1.LargeChange
hScrollBar2.SmallChange = hScrollBar1.SmallChange
' lo mismo para el incrementador
incrémenteur.Minimum = hScrollBar1.Value
incrémenteur.Minimum = hScrollBar1.Minimum
incrémenteur.Maximum = hScrollBar1.Maximum
incrémenteur.Increment = hScrollBar1.SmallChange
' se asigna a TextBox el valor del variador 1
txtValeur.Text = "" & hScrollBar1.Value
End Sub
El gestor que sigue las variaciones de valor del variador 1:
' gestión del variador hscrollbar1
Private Sub hScrollBar1_Scroll(ByVal sender As Object, ByVal e As System.Windows.Forms.ScrollEventArgs) _
Handles hScrollBar1.Scroll
' cambio de valor del variador 1
' se aplica su valor al variador 2 y al cuadro de texto TxtValeur
hScrollBar2.Value = hScrollBar1.Value
txtValeur.Text = "" & hScrollBar1.Value
End Sub
El gestor que sigue las variaciones de valor del variador 2:
' gestión del variador hscrollbar2
Private Sub hScrollBar2_Scroll(ByVal sender As Object, ByVal e As System.Windows.Forms.ScrollEventArgs) _
Handles hScrollBar2.Scroll
' se inhibe cualquier cambio en el regulador 2
' obligándolo a mantener el valor del variador 1
e.NewValue = hScrollBar1.Value
End Sub
El gestor que supervisa las variaciones del control incrémenteur:
' gestión del incrementador
Private Sub incrémenteur_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles incrémenteur.ValueChanged
' se fija el valor del variador 2
hScrollBar2.Value = CType(incrémenteur.Value, Integer)
End Sub
5.5. Eventos del ratón
Cuando se dibuja en un contenedor, es importante conocer la posición del ratón para, por ejemplo, mostrar un punto al hacer clic. Los movimientos del ratón provocan eventos en el contenedor por el que se desplaza.
![]() | ![]() |
el ratón acaba de entrar en el área del control | |
el ratón acaba de salir del área del control | |
el ratón se mueve dentro del área de control | |
Pulsación del botón izquierdo del ratón | |
Suelta el botón izquierdo del ratón | |
El usuario suelta un objeto sobre el control | |
El usuario entra en el área del control arrastrando un objeto | |
el usuario sale del área del control arrastrando un objeto | |
El usuario pasa por encima del área del control al arrastrar un objeto |
A continuación se muestra un programa que permite comprender mejor en qué momentos se producen los diferentes eventos del ratón:
![]() |
n.º | tipo | nombre | función |
1 | Etiqueta | lblPosition | para mostrar la posición del ratón en el formulario 1, la lista 2 o el botón 3 |
2 | ListBox | lstEvts | para mostrar los eventos del ratón distintos de MouseMove |
3 | Botón | btnEffacer | para borrar el contenido de 2 |
Los controladores de eventos son los siguientes. Para seguir los movimientos del ratón en los tres controles, solo se escribe un único controlador:
' evt form1_mousemove
Private Sub Form1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) _
Handles MyBase.MouseMove, lstEvts.MouseMove, btnEffacer.MouseMove, lstEvts.MouseMove
' movimiento del ratón: se muestran las coordenadas (X, Y) del mismo
lblPosition.Text = "(" & e.X & "," & e.Y & ")"
End Sub
Hay que tener en cuenta que cada vez que el ratón entra en el área de un control, su sistema de coordenadas cambia. Su origen (0,0) es la esquina superior izquierda del control en el que se encuentra. Así, al ejecutar el código, cuando se pasa el ratón del formulario al botón, se ve claramente el cambio de coordenadas. Para ver mejor estos cambios de área del ratón, se puede utilizar la propiedad Cursor de los controles:

Esta propiedad permite establecer la forma del cursor del ratón cuando este entra en el ámbito del control. Así, en nuestro ejemplo, hemos establecido el cursor en Default para el propio formulario, en Hand para la lista 2 y en No para el botón 3, tal y como muestran las capturas de pantalla siguientes.



En el método [InitializeComponent], el código generado por estas opciones es el siguiente:
Me.lstEvts.Cursor = System.Windows.Forms.Cursors.Hand
Me.btnEffacer.Cursor = System.Windows.Forms.Cursors.No
Por otra parte, para detectar las entradas y salidas del ratón en la lista 2, procesamos los eventos MouseEnter y MouseLeave de esta misma lista:
' 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
' muestra
Private Sub affiche(ByVal message As String)
' se muestra el mensaje en la parte superior de la lista de eventos
lstEvts.Items.Insert(0, message)
End Sub

Para gestionar los clics en el formulario, procesamos los eventos MouseDown y 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 último, el código del gestor de clics en el botón Effacer:
' evento btnEffacer_Click
Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles btnEffacer.Click
' borra la lista de eventos
lstEvts.Items.Clear()
End Sub
5.6. Crear una ventana con menú
Veamos ahora cómo crear una ventana con menú. Vamos a crear la siguiente ventana:
![]() |
El control 1 es un TextBox de solo lectura (ReadOnly=true) y se llama txtStatut. La estructura del menú es la siguiente:
![]() | ![]() |
Las opciones de menú son controles como los demás componentes visuales y tienen propiedades y eventos. Por ejemplo, la tabla de propiedades de la opción de menú A1:

En nuestro ejemplo se utilizan dos propiedades:
el nombre del control de menú | |
el texto de la opción de menú |
Las propiedades de las diferentes opciones de menú de nuestro ejemplo son las siguientes:
Name | Texto |
mnuA | opciones A |
mnuA1 | A1 |
mnuA2 | A2 |
mnuA3 | A3 |
mnuB | opciones B |
mnuB1 | B1 |
mnuSep1 | - (separador) |
mnuB2 | B2 |
mnuB3 | B3 |
mnuB31 | B31 |
mnuB32 | B32 |
Para crear un menú, se selecciona el componente «MainMenu» en la barra «ToolBox»:

De este modo, se crea un menú vacío que se inserta en el formulario con casillas vacías tituladas «Type Here». Solo hay que indicar en ellas las diferentes opciones del menú:

Para insertar un separador entre dos opciones, como se ha hecho anteriormente entre las opciones B1 y B2, colóquese en la ubicación del separador en el menú, haga clic con el botón derecho y seleccione la opción Insert Separator:

Si se inicia la aplicación con Ctrl+F5, aparece un formulario con un menú que, por el momento, no realiza ninguna acción. Las opciones del menú se tratan como componentes: tienen propiedades y eventos. En [fenêtre de code], seleccione el componente mnuA1 y, a continuación, seleccione los eventos asociados:

Si en el ejemplo anterior se genera el evento Click, VS.NET genera automáticamente el siguiente procedimiento:
Private Sub mnuA1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuA.Click
....
End Sub
Podríamos proceder así para todas las opciones del menú. En este caso, se puede utilizar el mismo procedimiento para todas las opciones. Por lo tanto, renombramos el procedimiento anterior como affiche y declaramos los eventos que gestiona:
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
' muestra en TextBox el nombre del submenú seleccionado
txtStatut.Text = (CType(sender, MenuItem)).Text
End Sub
En este método, nos limitamos a mostrar la propiedad Text de la opción de menú en el origen del evento. El origen del evento sender es de tipo object. Las opciones de menú son de tipo MenuItem, por lo que aquí nos vemos obligados a realizar una conversión de tipo de object a MenuItem. Ejecute la aplicación y seleccione la opción A1 para obtener el siguiente mensaje:

El código útil de esta aplicación, además del del método affiche, es el de la construcción del menú en el generador de formularios (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
Cabe destacar la instrucción que asocia el menú al formulario:
Me.Menu = Me.mainMenu1
5.7. Componentes no visuales
Ahora nos centramos en una serie de componentes no visuales: se utilizan durante el diseño, pero no se ven durante la ejecución.
5.7.1. Cuadros de diálogo OpenFileDialog y SaveFileDialog
Vamos a crear la siguiente aplicación:
![]() |
Los controles son los siguientes:
N.º | tipo | nombre | función |
1 | TextBox multilíneas | txtTexte | texto escrito por el usuario o cargado desde un archivo |
2 | Botón | btnSauvegarder | permite guardar el texto de 1 en un archivo de texto |
3 | Botón | btnCharger | permite cargar el contenido de un archivo de texto en 1 |
4 | Botón | btnEffacer | borra el contenido de 1 |
Se utilizan dos controles no visuales:

Cuando se seleccionan en el «ToolBox» y se colocan en el formulario, se sitúan en una zona separada en la parte inferior del formulario. Los componentes «Dialog» se seleccionan en el «ToolBox»:

El código del botón Effacer es sencillo:
Private Sub btnEffacer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnEffacer.Click
' se borra el cuadro de entrada
txtTexte.Text = ""
End Sub
La clase SaveFileDialog se define de la siguiente manera:

Deriva de varios niveles de clase. De estas numerosas propiedades y métodos, destacaremos los siguientes:
los tipos de archivo que aparecen en la lista desplegable de tipos de archivo del cuadro de diálogo | |
el número del tipo de archivo propuesto por defecto en la lista anterior. Empieza por 0. | |
la carpeta que se muestra inicialmente para guardar el archivo | |
el nombre del archivo de copia de seguridad indicado por el usuario | |
método que muestra el cuadro de diálogo de copia de seguridad. Devuelve un resultado de tipo DialogResult. |
El método ShowDialog muestra un cuadro de diálogo similar al siguiente:
![]() |
Lista desplegable generada a partir de la propiedad Filter. El tipo de archivo predeterminado viene fijado por FilterIndex | |
carpeta actual, fijado por InitialDirectory si se ha rellenado esta propiedad | |
nombre del archivo elegido o introducido directamente por el usuario. Estará disponible en la propiedad FileName | |
Botones Guardar/Cancelar. Si se utiliza el botón Enregistrer, la función ShowDialog devuelve el resultado DialogResult.OK |
El procedimiento de guardado se puede escribir así:
Private Sub btnSauvegarder_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnSauvegarder.Click
' se guarda el cuadro de entrada en un archivo de texto
' se configura el cuadro de diálogo savefileDialog1
saveFileDialog1.InitialDirectory = Application.ExecutablePath
saveFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"
saveFileDialog1.FilterIndex = 0
' se muestra el cuadro de diálogo y se recupera su resultado
If saveFileDialog1.ShowDialog() = DialogResult.OK Then
' se recupera el nombre del archivo
Dim nomFichier As String = saveFileDialog1.FileName
Dim fichier As StreamWriter = Nothing
Try
' se abre el archivo en modo de escritura
fichier = New StreamWriter(nomFichier)
' se escribe el texto en él
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
' se cierra el archivo
Try
fichier.Close()
Catch
End Try
End Try
End If
End Sub
- Se establece la carpeta inicial como la carpeta que contiene el ejecutable de la aplicación:
- Se establecen los tipos de archivos que se van a presentar
Cabe destacar la sintaxis de los filtros filtro1|filtro2|..|filtro con filtroi= Texto|plantilla de archivo. Aquí el usuario podrá elegir entre los archivos *.txt y *.*.
- Se establece el tipo de archivo que se mostrará al principio
Aquí, los archivos de tipo *.txt serán los primeros en mostrarse al usuario.
- Se muestra el cuadro de diálogo y se recupera su resultado
If saveFileDialog1.ShowDialog() = DialogResult.OK Then
- Mientras se muestra el cuadro de diálogo, el usuario ya no tiene acceso al formulario principal (cuadro de diálogo denominado modal). El usuario establece el nombre del archivo que desea guardar y sale del cuadro de diálogo, ya sea mediante el botón Guardar, el botón Cancelar o cerrando el cuadro de diálogo. El resultado del método ShowDialog es DialogResult.OK únicamente si el usuario ha utilizado el botón Enregistrer para salir del cuadro de diálogo.
- Una vez hecho esto, el nombre del archivo que se va a crear se encuentra ahora en la propiedad FileName del objeto saveFileDialog1. A continuación, se vuelve a la creación clásica de un archivo de texto. En él se escribe el contenido de TextBox: txtTexte.Text, gestionando al mismo tiempo las excepciones que puedan producirse.
La clase OpenFileDialog es muy similar a la clase SaveFileDialog y deriva de la misma línea de clases. De estas propiedades y métodos, destacaremos los siguientes:
los tipos de archivo propuestos en la lista desplegable de tipos de archivo del cuadro de diálogo | |
el número del tipo de archivo propuesto por defecto en la lista anterior. Empieza por 0. | |
la carpeta que se muestra inicialmente para buscar el archivo que se va a abrir | |
el nombre del archivo que se va a abrir indicado por el usuario | |
método que muestra el cuadro de diálogo de guardado. Devuelve un resultado de tipo DialogResult. |
El método ShowDialog muestra un cuadro de diálogo similar al siguiente:
![]() |
lista desplegable creada a partir de la propiedad Filter. El tipo de archivo propuesto por defecto viene determinado por FilterIndex | |
carpeta actual, fijada por InitialDirectory si se ha rellenado esta propiedad | |
nombre del archivo elegido o introducido directamente por el usuario. Estará disponible en la propiedad FileName | |
Botones Abrir/Cancelar. Si se utiliza el botón Ouvrir, la función ShowDialog devuelve el resultado DialogResult.OK |
El procedimiento de apertura se puede escribir así:
Private Sub btnCharger_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnCharger.Click
' se carga un archivo de texto en el cuadro de entrada
' se configura el cuadro de diálogo openfileDialog1
openFileDialog1.InitialDirectory = Application.ExecutablePath
openFileDialog1.Filter = "Fichiers texte (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"
openFileDialog1.FilterIndex = 0
' se muestra el cuadro de diálogo y se recupera su resultado
If openFileDialog1.ShowDialog() = DialogResult.OK Then
' se recupera el nombre del archivo
Dim nomFichier As String = openFileDialog1.FileName
Dim fichier As StreamReader = Nothing
Try
' se abre el archivo en modo de lectura
fichier = New StreamReader(nomFichier)
' se lee todo el archivo y se guarda en el 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
' se cierra el archivo
Try
fichier.Close()
Catch
End Try
End Try
End If
End Sub
- Se establece la carpeta inicial como la carpeta que contiene el ejecutable de la aplicación:
- Se establecen los tipos de archivos que se van a presentar
- Se establece el tipo de archivo que se mostrará al principio
En este caso, los archivos de tipo *.txt serán los primeros en mostrarse al usuario.
- Se muestra el cuadro de diálogo y se recupera su resultado
If openFileDialog1.ShowDialog() = DialogResult.OK Then
Mientras se muestra el cuadro de diálogo, el usuario ya no tiene acceso al formulario principal (cuadro de diálogo denominado modal). El usuario especifica el nombre del archivo que desea abrir y sale del cuadro de diálogo pulsando el botón Abrir, el botón Cancelar o cerrando el cuadro de diálogo. El resultado del método ShowDialog es DialogResult.OK únicamente si el usuario ha utilizado el botón Ouvrir para salir del cuadro de diálogo.
- Una vez hecho esto, el nombre del archivo que se va a crear se encuentra ahora en la propiedad FileName del objeto openFileDialog1. A continuación, se vuelve a la lectura clásica de un archivo de texto. Cabe destacar el método que permite leer la totalidad de un archivo:
- el contenido del archivo se coloca en TextBox txtTexte. Se gestionan las excepciones que puedan producirse.
5.7.2. Cuadros de diálogo FontColor y ColorDialog
Continuamos con el ejemplo anterior presentando dos nuevos botones:
![]() |
N.º | tipo | nombre | función |
6 | Botón | btnCouleur | para establecer el color de los caracteres de TextBox |
7 | Botón | btnPolice | para establecer la fuente de los caracteres de TextBox |
Colocamos en el formulario un control ColorDialog y un control FontDialog:

Las clases FontDialog y ColorDialog tienen un método ShowDialog análogo al método ShowDialog de las clases OpenFileDialog y SaveFileDialog. El método ShowDialog de la clase ColorDialog permite seleccionar un color:

Si el usuario sale del cuadro de diálogo con el botón OK, el resultado del método ShowDialog es DialogResult.OK y el color seleccionado se encuentra en la propiedad Color del objeto ColorDialog utilizado. El método ShowDialog de la clase FontDialog permite seleccionar una fuente:

Si el usuario sale del cuadro de diálogo con el botón OK, el resultado del método ShowDialog es DialogResult.OK y la fuente seleccionada se encuentra en la propiedad Font del objeto FontDialog utilizado. Tenemos los elementos para gestionar los clics en los botones Couleur y Police:
Private Sub btnCouleur_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnCouleur.Click
' selección de un color de texto
If colorDialog1.ShowDialog() = DialogResult.OK Then
' se cambia la propiedad forecolor de 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
' selección de una fuente
If fontDialog1.ShowDialog() = DialogResult.OK Then
' se cambia la propiedad font de TextBox
txtTexte.Font = fontDialog1.Font
End If
End Sub
5.7.3. Temporizador
Aquí nos proponemos escribir la siguiente aplicación:
![]() |
n.º | Tipo | Nombre | Función |
1 | TextBox, ReadOnly=true | txtChrono | muestra un cronómetro |
2 | Botón | btnArretMarche | botón de inicio/parada del cronómetro |
3 | Temporizador | timer1 | componente que emite aquí un evento cada segundo |
El cronómetro en marcha:

El cronómetro parado:

Para cambiar cada segundo el contenido de TextBox y txtChrono, necesitamos un componente que genere un evento cada segundo, evento que podremos interceptar para actualizar la visualización del cronómetro. Este componente es el Timer:

Una vez instalado este componente en el formulario (en la sección de componentes no visuales), se crea un objeto de tipo Timer en el constructor del formulario. La clase System.Windows.Forms.Timer se define de la siguiente manera:

De sus propiedades, solo destacaremos las siguientes:
número de milisegundos tras los cuales se emite un evento Tick. | |
el evento producido al final de Interval milisegundos | |
activa (true) o desactiva (false) el temporizador |
En nuestro ejemplo, el temporizador se llama timer1 y timer1.Interval se establece en 1000 ms (1 s). Por lo tanto, el evento Tick se producirá cada segundo. El clic en el botón Parar/Iniciar se gestiona mediante el siguiente procedimiento:
Private Sub btnArretMarche_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnArretMarche.Click
' ¿parar o continuar?
If btnArretMarche.Text = "Marche" Then
' se anota la hora de inicio
début = DateTime.Now
' se muestra
txtChrono.Text = "00:00:00"
' se inicia el temporizador
timer1.Enabled = True
' cambiar el texto del botón
btnArretMarche.Text = "Arrêt"
' fin
Return
End If '
If btnArretMarche.Text = "Arrêt" Then
' parada del temporizador
timer1.Enabled = False
' se cambia el texto del botón
btnArretMarche.Text = "Marche"
' fin
Return
End If
End Sub
Private Sub timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles timer1.Tick
' ha transcurrido un 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
El texto del botón Parar/Iniciar es «Parar» o «Iniciar». Por lo tanto, es necesario realizar una comprobación de este texto para saber qué hacer.
- En el caso de «Marcha», se anota la hora de inicio en una variable que es una variable global del objeto formulario, se inicia el temporizador (Enabled=true) y el texto del botón cambia a «Parada».
- En el caso de «Parada», se detiene el temporizador (Enabled=false) y se cambia el texto del botón a «Marcha».
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
' variables de instancia
Private début As DateTime
El atributo début anterior es conocido en todos los métodos de la clase. Nos queda por tratar el evento Tick en el objeto timer1, evento que se produce cada segundo:
Private Sub timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles timer1.Tick
' ha transcurrido un 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
Se calcula el tiempo transcurrido desde el momento en que se puso en marcha el cronómetro. Se obtiene un objeto de tipo TimeSpan que representa una duración en el tiempo. Esta debe mostrarse en el cronómetro en formato hh:mm:ss. Para ello utilizamos las propiedades Hours, Minutes, Seconds del objeto TimeSPan, que representan respectivamente las horas, los minutos y los segundos de la duración que mostramos en el formato ToString("d2") para obtener una visualización de 2 dígitos.
5.8. El ejemplo IMPOTS
Retomamos la aplicación IMPOTS, que ya hemos tratado dos veces. Ahora le añadimos una interfaz gráfica:
![]() |
Los controles son los siguientes
n.º | tipo | nombre | función |
RadioButton | rdOui | marcado si está casado | |
RadioButton | rdNon | marcado si no está casado | |
NumericUpDown | incEnfants | Número de hijos del contribuyente Mínimo=0, Máximo=20, Incremento=1 | |
TextBox | txtSalaire | salario anual del contribuyente en F | |
TextBox | txtImpots | Importe del impuesto a pagar ReadOnly=true | |
Botón | btnCalculer | inicia el cálculo del impuesto | |
Botón | btnEffacer | restablece el formulario a su estado inicial al cargarse | |
Botón | btnQuitter | para salir de la aplicación |
Reglas de funcionamiento
- El botón «Calcular» permanece desactivado mientras no haya nada en el campo del salario
- si, al iniciar el cálculo, resulta que el salario es incorrecto, se señala el error:

El programa se muestra a continuación. Utiliza la clase impot creada en el capítulo sobre clases. Una parte del código generado automáticamente por VS.NET no se ha reproducido aquí.
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
' opciones
Option Explicit On
Option Strict On
' espacios de nombres
Imports System
Imports System.Drawing
Imports System.Collections
Imports System.ComponentModel
Imports System.Windows.Forms
Imports System.Data
' clase de formulario
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
' tablas de datos necesarias para el cálculo del impuesto
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 impuesto
Private objImpôt As impot = Nothing
Public Sub New()
InitializeComponent()
' inicialización del formulario
btnEffacer_Click(Nothing, Nothing)
btnCalculer.Enabled = False
' creación de un objeto fiscal
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)
' se desactiva el campo de introducción del salario
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
' borrado del formulario
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 del botón «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
' fin de la aplicación
Application.Exit()
End Sub 'btnQuitter_Click
Private Sub btnCalculer_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnCalculer.Click
' ¿Es correcto el salario?
Dim intSalaire As Integer = 0
Try
' Recuperación del salario
intSalaire = Integer.Parse(txtSalaire.Text)
' debe ser >=0
If intSalaire < 0 Then
Throw New Exception("")
End If
Catch ex As Exception
' mensaje de error
MessageBox.Show(Me, "Salaire incorrect", "Erreur de saisie", MessageBoxButtons.OK, MessageBoxIcon.Error)
' foco en campo erróneo
txtSalaire.Focus()
' selección del texto del campo de entrada
txtSalaire.SelectAll()
' volver a la interfaz visual
Return
End Try 'try-catch
' el salario es correcto: se calcula el impuesto
txtImpots.Text = "" & CLng(objImpôt.calculer(rdOui.Checked, CInt(incEnfants.Value), intSalaire))
End Sub 'btnCalculer_Click
End Class
Aquí utilizamos el ensamblado impots.dll, resultado de la compilación de la clase impots del capítulo 2. Recordemos que este ensamblado se puede generar en modo consola mediante el comando
Este comando genera el archivo impots.dll, denominado ensamblado. Este ensamblado se puede utilizar posteriormente en diferentes proyectos. Aquí, en nuestro proyecto bajo VS.NET, utilizamos la ventana de propiedades del proyecto:

Para añadir una referencia (un ensamblaje), hacemos clic con el botón derecho del ratón en el conjunto clave References situado arriba, seleccionamos la opción [Ajouter une référence] y designamos el ensamblaje [impots.dll] que nos hemos encargado de colocar en la carpeta del proyecto:
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 vez incluido el ensamblado [impots.dll] en el proyecto, la clase [impots] pasa a ser conocida por el proyecto. Antes no lo era. Otro método consiste en incluir el código fuente impots.vb en el proyecto. Para ello, en la ventana de propiedades del proyecto, se hace clic con el botón derecho del ratón sobre el proyecto, se selecciona la opción [Ajouter/Ajouter un élément existant] y se indica el archivo impots.vb.















































