APLICACIONES MDI[APLICACIONES DE INTERFAZ CON MÚLTIPLES DOCUMENTOS ]Fecha: 03/Sep/2005 (24/08/2005)
|
Joven desarrollador de aplicaciones Web y Servicios Web XML en Visual Basic .NET y Visual C# .NET con bases de datos SQL Server 2000 - 2005. | |
¡ Los peruanos Sí podemos ! |
Hola amigos visitantes de este sitio del Guille, nuevamente me hago presente con esta colaboración con la finalidad de compartir con ustedes cosillas interesantes. Para esta vez he preparado una sencillo ejemplo de aplicación para comprender con mayor facilidad cómo es la funcionalidad de una aplicación MDI, además conoceremos conceptos relacionados a este tema. Empezaré detallando los conceptos respectivos al tema y finalmente usted podrá revisar el código del ejemplo, como también podrá descargarlo.
Debo recordarle que previamente debe conocer muchos conceptos sumamente importantes en la construcción de aplicaciones MDI y SDI. Bueno, si no entiende esto, no corra!...porque a continuación le explicaré estas cosillas. También debe conocer todo respecto a cuadros de diálogos comunes, todo esto le explico a continuación.
Empezemos primero por entender que es una aplicación MDI y una aplicación SDI.
PATRÓN SINGLETÓN CON FORMULARIOS MDI
En dias anteriores estaba creando una aplicación en la cual requería crear una sola instancia de los formularios hijos de una MDI padre. Buscando en la documentación de Microsoft encontré este Pattern llamado Singleton. Acá les muestro una sencilla implementación en formularios MDI para tener solamente una instancia abierta por formulario. Lo primero que hay que hacer es modificar el constructor del formulario hijo, o sea, el formulario que queremos que solo tenga una instancia en la aplicación. En este constructor inicialmente aparece como publico (public).
Código #Region " Windows Form Designer generated code " Public Sub New() MyBase.New() 'This call is required by the Windows Form Designer. InitializeComponent() 'Add any initialization after the InitializeComponent() call End Sub ..... Lo modificaremos y lo haremos privado (private) para evitar llamados a este formulario.
#Region " Windows Form Designer generated code " Private Sub New() MyBase.New() 'This call is required by the Windows Form Designer. InitializeComponent() 'Add any initialization after the InitializeComponent() call End Sub .....Luego lo que haremos será crear una variable global en este mismo formulario hijo para que controle la instancia y la haremos shared para que pueda ser accesada desde el formulario padre.'Variable global Private Shared frmInstance As frmReport = NothingFinalmente crearemos una función shared que será la que finalmente controlara la creación o manejo de la instancia del formulario, logrando obtener solo un formulario abierto para este form1.'Funcion que crea una sola instancia del form1 Public Shared Function Instance() As form1 If frmInstance Is Nothing OrElse frmInstance.IsDisposed = True Then frmInstance = New form1 End If frmInstance.BringToFront() Return frmInstance End Function Ahora en el padre escribiremos el llamado al hijo para crear la instancia, o si ya esta creada, entonces pondrá el formulario hijo en frente para que lo podamos ver.Dim frmHijo as form1 = form1.Instance frmHijo.MdiParent = Me frmHijo.ShowAPLICACIONES DE INTERFAZ CON MÚLTIPLES DOCUMENTOS (MDI)
Estas aplicaciones le permiten mostrar múltiples documentos al mismo tiempo con cada documento que aparece en su ventana propia. Las aplicaciones MDI con frecuencia tienen un elemento del menú de Windows con submenús para cambiar entre ventanas y documentos. El fundamento de una Aplicación con interfaz de múltiples documentos (MDI) es el formulario primario MDI. Este es el formulario que contiene las ventanas secundarias MDI, que son las "sub-ventanas" en donde el usuario interactúa con la aplicación MDI.
Para establecer un formulario como primario MDI, configure la propiedad IsMdiContainer = True.
Para crear un formulario secundario MDI nuevo tiene que configurar la propiedad a MdiParent.Las aplicaciones con interfaz de un único documento (SDI) están formadas por una o más ventanas independientes, cada una de las cuales aparece como ventana independiente en el escritorio de Windows. Microsoft Exchange es un ejemplo de una aplicación SDI, en la que cada mensaje que abra aparece en su propia ventana independiente.
VB .NET
… Protected Sub MDIChildNew_Click( ByVal sender As System.Object, ByVal e As System.EventArgs) Handles _ MenuItem2.Click Dim NewMDIChild As New Form2 'Configurar el Formulario primario de la Ventana secundaria. NewMDIChild.MdiParent = Me 'Mostrar el nuevo formulario. NewMDIChild.Show() End Sub ...C# .NET
... protected void MDIChildNew_Click(object sender, System.EventArgs e) { Form2 newMDIChild = new Form2(); // Set the Parent Form of the Child window. newMDIChild.MdiParent = this; // Display the new form. newMDIChild.Show(); } ...EXPLICANDO EL EJEMPLO
Recuerde que el objetivo de esta aplicación no es la complejidad de esta, sino mas bien, la dinámica de funcionamiento de una aplicación MDI, con un sólo formulario padre y dos formularios hijos. Quedando claro esto, ahora explicaré la funcionalidad del ejemplo: Trabajaremos prácticamente con tres formularios hijos (y un formulario de presentación, que estará activa 5 segundos y luego no lo usaremos más) que simulará una aplicación que nos ayudará en la conversión de divisas y finalmente reportar todas las conversiones realizadas. Además haremos uso de una dataset, la cual será nuestro almacén de registros de las operaciones de conversión. La aplicación expone opciones mediante la cual usted podrá guardar y abrir los registros(en formato XML) con las conversiones realizadas, como también, visualizar el reporte de operaciones. La opciones de menú son las que se aprecian en la siguientes capturas de imágenes.
Cuando corra la aplicación, esta empezará dándole la bienvenida con un formulario denominado Splash, que por cierto es la siguiente:
Formulario Splash Creo que detallar más sobre el ejemplo sería redundar (la aplicación es sencilla), que le parece si revisa el código y así comprenderá mejor acerca de una aplicación MDI. Cualquier duda, puede hacérmelo llegar al correo.
Este es el código para nuestro formulario padre, desde aquí administraremos los demás formularios hijos.
Imports System.Drawing.Drawing2D
Public Class Form1 Inherits System.Windows.Forms.Form Public Shared Sub main() 'cargamos el formulario de presentación. Dim oSplash As New Splash oSplash.ShowDialog() 'luego cargamos el formulario principal Dim oPrincipal As New Form1 oPrincipal.ShowDialog() End Sub Private Sub MenuClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles MenuClose.Click End End Sub Public NroArchivo As Integer = 1 Private Sub MenuAbierto_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles MenuAbierto.Click Try With Me.OpenFileDialog1 .Filter = "Archivo XML|*.xml" .Title = "Abrir archivo XML" .RestoreDirectory = True If (.ShowDialog() = DialogResult.OK) Then MisDatos.Clear() MisDatos.ReadXml(.FileName) MenuReportar_Click(sender, e) End If End With Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub Private Sub MenuHacerCambio_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles MenuHacerCambio.Click Dim frmHijoConvertir As Convertir = Convertir.Instance frmHijoConvertir.MdiParent = Me frmHijoConvertir.Show() frmHijoConvertir.BringToFront() Me.LayoutMdi(MdiLayout.TileHorizontal) 'If nc = 0 Then ' Dim oFrmConversion As New Convertir ' oFrmConversion.MdiParent = Me ' oFrmConversion.Show() ' oFrmConversion.BringToFront() ' nc = 1 'End If End Sub Private Sub MenuReportar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles MenuReportar.Click Dim frmHijoReporte As Reporte = Reporte.Instance frmHijoReporte.MdiParent = Me frmHijoReporte.Show() frmHijoReporte.BringToFront() Me.LayoutMdi(MdiLayout.TileHorizontal) 'If nr = 0 Then ' Dim oFrmreporte As New Reporte ' oFrmreporte.MdiParent = Me ' oFrmreporte.Show() ' oFrmreporte.BringToFront() ' nr = 1 'End If 'Me.LayoutMdi(MdiLayout.TileHorizontal) End Sub Private Sub MenuItem2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles MenuItem2.Click Dim f As Form For Each f In Me.MdiChildren f.Close() Next End Sub Private Sub MenuGuardarComo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles MenuGuardarComo.Click Try With Me.SaveFileDialog1 .Filter = "Archivo XML|*.xml" .Title = "Guardar archivo XML" .FileName = "Archivo XML" & NroArchivo NroArchivo += 1 .RestoreDirectory = True If (.ShowDialog() = DialogResult.OK) Then If .FileName.Length <> Nothing Then MisDatos.WriteXml(.FileName) MsgBox("Datos guardados") Else MsgBox("error, no se guardaron los datos !!!") End If End If End With Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub End Classy este es el código para nuestro formulario de presentación del proyecto. Este formulario nos dará la bienvenida por 5 segundos y desaparecerá fugazmente.
Imports System.Drawing.Drawing2D Public Class Splash Inherits System.Windows.Forms.Form Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) _Handles Timer1.Tick Me.Timer1.Enabled = False Me.Close() End Sub Private Sub Splash_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _Handles MyBase.Load ' Me.BackColor = Color.Silver Dim gp As New GraphicsPath gp.AddEllipse(New Rectangle(New Point(50, 50), New Size(500, 300))) 'gp.AddCurve(New Point() {New Point(50, 199), New Point(299, 50), _ ' New Point(298, 548), New Point(299, 348)}) Dim reg As New Region(gp) Me.Region = reg Me.Timer1.Enabled = True Me.Timer1.Interval = 4000 Me.Timer1.Start() End Sub Private Sub Splash_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) _ Handles MyBase.Paint Dim GradientePanel As New LinearGradientBrush(New RectangleF(0, 0, Me.Width, Me.Height), _ Color.Orange, Color.Olive, LinearGradientMode.ForwardDiagonal) Me.CreateGraphics.DrawEllipse(New Pen(Color.Blue, 4), New Rectangle(New Point(50, 50), _New Size(498, 298))) Me.CreateGraphics.FillRectangle(GradientePanel, New RectangleF(0, 0, Me.Width, Me.Height)) End Sub End ClassEl objeto denominado MisDatos es una dataset la cual será el refugio para registrar las operaciones efectuadas.
Module VariablesGlobales Public MisDatos As New Dataset1 End ModuleLa construcción de nuestra dataset será agregando un nuevo elemento al proyecto denominado esquema XML. Vaya al Menú proyecto, luego Agregar nuevo elemento.... nuestra esquema debe tener el siguiente formato:
También podra hacerlo mediante código con la ayuda de un bloc de notas. El código en XML sería:
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema id="Dataset1" targetNamespace="http://tempuri.org/Dataset1.xsd" elementFormDefault="qualified"
attributeFormDefault="qualified" xmlns="http:"//tempuri.org/Dataset1.xsd" xmlns:mstns="http://tempuri.org/Dataset1.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" >
<xs:element name="Dataset1" msdata:IsDataSet="true" >
<xs:complexType>
<xs:choice maxOccurs="unbounded" >
<xs:element name="MiTabla" >
<xs:complexType>
<xs:sequence>
<xs:element name="CurrencyFrom" type="xs:string" minOccurs="0" />
<xs:element name="CurrencyTo" type="xs:string" minOccurs="0" />
<xs:element name="AmountFrom" type="xs:double" minOccurs="0" />
<xs:element name="AmountTo" type="xs:double" minOccurs="0" />
<xs:element name="Fecha" type="xs:dateTime" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>Finalmente este es el código de lógica para realizar las conversiones:NOTA: Sea cuidadoso al revisar el código.Public Class Convertir Inherits System.Windows.Forms.Form 'CÓDIGO GENERADOR POR EL DISEÑADOR DE WINDOWS Private Shared frmInstanceConvertir As Convertir = Nothing 'Funcion que crea una sola instancia del Form Convertir Public Shared Function Instance() As Convertir If frmInstanceConvertir Is Nothing OrElse frmInstanceConvertir.IsDisposed = True Then frmInstanceConvertir = New Convertir End If frmInstanceConvertir.BringToFront() Return frmInstanceConvertir End Function Private Sub BtnConvertir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles BtnConvertir.Click Try If Not IsNumeric(Me.TxtCantidad.Text) Then Throw New Exception Else Try Dim resul As Double Select Case LstFrom.SelectedIndex Case 0 : resul = CType(Me.TxtCantidad.Text, Double) / Peso Case 1 : resul = CType(Me.TxtCantidad.Text, Double) / Dolar Case 2 : resul = CType(Me.TxtCantidad.Text, Double) / Euro End Select Select Case LstTo.SelectedIndex Case 0 : resul *= Peso resul *= Dolar Case 2 : resul *= Euro End Select 'creamos una fila Dim oRow As DataRow oRow = MisDatos.Tables(0).NewRow oRow(0) = LstFrom.SelectedItem oRow(1) = LstTo.SelectedItem oRow(2) = CType(Me.TxtCantidad.Text, Double) Me.LblResultado.Text = Format(resul, "#,#.00") oRow(3) = CType(Me.LblResultado.Text, Double) oRow(4) = Now.ToShortDateString 'agregamos la fila llenada MisDatos.Tables(0).Rows.Add(oRow) Me.ErrorProvider1.SetError(TxtCantidad, "") Catch ex As Exception MsgBox(ex.Message) End Try End If Catch ex As Exception Me.ErrorProvider1.SetError(TxtCantidad, "Debe ingresar un valor númerico") End Try End Sub Private Sub Convertir_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles MyBase.Load Me.LstTo.SelectedIndex = 1 Me.LstFrom.SelectedIndex = 2 End Sub End ClassAlgo adicional a este artículo, pero muy importante, es el siguiente código para pintar nuestro formulario MDI distinto al color por defecto, ya que por defecto un formulario MDI tiene un color algo oscuro.#Region "PintarMDI" Dim oControlMDI As MdiClient Public Sub FrmLoad(ByVal sender As Object, ByVal e As System.EventArgs) Dim oControl As Control For Each oControl In Me.Controls Try oControlMDI = CType(oControl, MdiClient) oControlMDI.BackColor = Color.AntiqueWhite AddHandler oControlMDI.Paint, AddressOf PintarFondoAreaCliente Catch ex As InvalidCastException End Try Next End Sub Private Sub PintarFondoAreaCliente(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Dim GradientePanel As New LinearGradientBrush(New RectangleF(0, 0, oControlMDI.Width, _ oControlMDI.Height), Color.Blue, Color.White, LinearGradientMode.ForwardDiagonal) e.Graphics.FillRectangle(GradientePanel, New RectangleF(0, 0, oControlMDI.Width, oControlMDI.Height)) End Sub Private Sub TfrmMain_Resize(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles MyBase.Resize If Not (Me.oControlMDI Is Nothing) Then Me.PintarFondoAreaCliente(Me.oControlMDI, New PaintEventArgs(Me.oControlMDI.CreateGraphics, _ New Rectangle(Me.oControlMDI.Location, Me.oControlMDI.Size))) End If End Sub Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles MyBase.Load FrmLoad(sender, e) Me.Size = New Size(800, 600) End Sub #End RegionSinceramente deseo que os haya sido de ayuda para usted. No olvide de darme su voto en PanoramaBox.
Web Developer PERCY REYES PAREDES
Saludos desde Trujillo - Perú
Espacios de nombres usados en el código de este artículo:
System.Drawing.Drawing2D
Fichero con el código de ejemplo: Percynet_ConvertirDivisas - Tamaño 24.6 KB