El proceso de añadir nuevos controles a nuestras ventanas (o contenedores) en tiempo de ejecución se ha simplificado enormemente. Ya no tendrás que lidiar con arrays de controles; en vez de ello sólo tendrás que llamar al método AddControl
sobre la ventana o ContainerControl
en la que desees añadir el nuevo control. Continúa leyendo y te mostraré cómo hacerlo a través de un ejemplo sencillo.
El nuevo método AddControl acepta cualquier instancia de DesktopUIControl
que quieras añadir en una ventana o ContainerControl, de modo que sólo tendrás que crear una nueva instancia desde código y sobre la marcha para pasarla como parámetro para que el método AddControl haga su magia.
Para que la nueva instancia de un DesktopUIControl sea realmente visible en la ventana o ContainerControl de destino también tendrás que definir algunas propiedades básicas, como por ejemplo los valores de ancho y altura para la nueva instancia del control, así como las propiedades Left y Top que indican su posición relativa sobre la esquina superior izquierda de la ventana o el ContainerControl donde se va a incluir. De modo que un valor Top = 0 y Left = 0 significa que el control se añadirá en la esquina superior izquierda de la ventana.
Para ver cómo funciona todo esto vamos a crear un proyecto Desktop de ejemplo en el que podrás añadir tantas instancias como desees en tiempo de ejecución del control DesktopButton, también podrás eliminar dichas instancias del ContainerControl sobre el que se van a añadir (llamando para ello al método Close
sobre la propia instancia), así como modificar la posición de los controles añadidos a medida que se modifique el tamaño del ContainerControl que los contiene.
1. Crear el ContainerControl Base
Abre Xojo y crea un nuevo proyecto Desktop. A continuación, haz doble clic en el ContainerControl desde la Librería para que se añada al Navegador en el IDE. Utiliza el Panel Inspector para cambiar las siguientes propiedades:
- Name:
BaseContainer
Añade ahora una nueva propiedad a la subclase BaseContainer
en el Navegador (puedes hacerlo desde el menú contextual), definiendo los siguientes valores en el Panel Inspector asociado:
- Name:
Controls()
- Type:
DesktopUIControl
- Scope:
Public
2. Añadir Nuevos Controles a BaseContainer
Vamos a tener que añadir algunos métodos a nuestro BaseContainer, comenzando con el responsable de añadir nuevas instancias DesktopButton
sobre el mismo. Por tanto, añade un nuevo Método a BaseContainer utilizando los siguientes valores en el Panel Inspector asociado:
- Method Name:
AddNewControl
- Scope:
Public
Y escribe el siguiente fragmento de código en el Editor de Código asociado con el método recién añadido:
// Definimos algunos valores estáticos para las nuevas instancias // de boton: valores de ancho y nombre Static cWidth As Integer = 40 Static cInitialName As String = "ControlName" // Coordenadas X e Y iniciales para la instancia del control Var startX As Integer = If(controls.Count = 0, 20, controls(controls.LastIndex).Left + cWidth + 20) Var startY As Integer = If(controls.Count = 0, 20, controls(controls.LastIndex).top) // Necesitamos ajustar las coordenadas X/Y si el control // excede el ancho disponible del BaseContainer // exceeds the available BaseContainer width If startX + cWidth > Me.Width Then startx = 20 starty = starty + controls(controls.LastIndex).height + 20 End If // Creamos la nueva instancia DesktopButton a añadir // ajustando los valores esperados para que sea visible // en el tamaño y posición deseados. Var ncontrol As New DesktopButton Var idxNumber As Integer = controls.LastIndex + 1 nControl.Name = cInitialName + idxNumber.ToString nControl.Caption = idxNumber.ToString nControl.Left = startx nControl.Top = starty nControl.Width = cWidth // En macOS obtenemos la altura del control por omisión // no así en Windows. #If TargetWindows Then nControl.Height = 22 #EndIf // Asignamos el método que llamará la instancia // cuando el usuario pulse el botón // de modo que podamos atraparlo y reenviarlo // a la instancia creada a partir del BaseControl AddHandler nControl.Pressed, AddressOf controlActionCallback // Añadimos el control al Array de controles controls.AddRow nControl // …y también al propio BaseContainer // utilizando para ello la llamada al método AddControl Me.AddControl nControl
Como puedes ver, estamos usando el método AddHandler
para sustituir el Evento disparado originalmente por el control por nuestro propio método; de modo que hemos de crearlo. Añade un nuevo método a BaseContainer utilizando los siguientes valores en el Panel Inspector:
- Name:
ControlActionCallback
- Parameters:
tControl As DesktopUIControl
- Scope:
Public
Y escribiendo la siguiente línea de código en el Editor de Código asociado:
RaiseEvent ControlPressed(tControl)
3. Eliminar Controles de BaseContainer
El tercer y último método que hemos de añadir a nuestra subclase BaseContainer es el responsable de ir eliminando los controles añadidos; de modo que añadiremos un nuevo método a la subclase BaseContainer utilizando los siguientes valores:
- Method Name:
RemoveLastControl
- Scope:
Public
Y escribiendo el siguiente fragmento de código en el Editor de Código asociado para el método:
If controls.LastIndex <> -1 Then Var tControl As DesktopUIControl = controls.pop // We need to remove the callback method from the original // Pressed event on the instance RemoveHandler DesktopButton(tControl).pressed, AddressOf controlActionCallback // Closing the control instance so it is removed from the // containing BaseControl tControl.close End If
4. Reenvío de Eventos
Dado que recibimos el evento Pressed
del DesktopButton en nuestro método ControlActionCallback
, y este realiza a su vez una llamada al Evento ControlPressed
pasando la instancia de control recibida, tendremos que definir dicho Evento en nuestra subclase BaseContainer utilizando para ello los siguientes valores en el Panel Inspector asociado:
- Event Name:
ControlPressed
- Parameters:
tControl As DesktopUIControl
5. Reaccionar al cambio de Tamaño
Queremos que nuestro BaseContainer reaccione a los cambios realizados a su ancho o altura, de modo que tengamos la oportunidad de cambiar la posición de los controles añadidos para que continúen siendo visibles. Por tanto, con el BaseContainer seleccionado en el Navegador, añade el Evento Resizing
y escribe el siguiente fragmento de código en el Editor de Código asociado:
#Pragma DisableBackgroundTasks #Pragma DisableBoundsChecking Var startX As Integer = 20 Var startY As Integer = 20 Var lastIndex As Integer = controls.LastIndex Var tControl As DesktopUIControl For n As Integer = 0 To lastIndex tControl = controls(n) If n <> 0 Then startx = controls(n-1).Left + controls(n-1).Width + 20 If startx > Me.Width - tControl.Width Then startx = 20 if n <> 0 then starty = starty + tControl.Height + 20 End If tControl.Left = startx tControl.top = starty Next n
6. Diseñar la Interfaz de Usuario
Selecciona la ventana Window1
en el Navegador para que se muestre en el Editor de Diseño. A continuación, arrastra un Botón desde la Librería y sitúalo en la parte superior izquierda de la ventana respetando los márgenes indicados por las guías de alineación.
Con el botón añadido seleccionado, cambia los siguientes valores en el Panel Inspector asociado:
- Name:
AddControlButton
- Locking: Left and Top locks closed.
- Caption: “Add Control”
Utiliza los manejadores de tamaño del control para que sea lo suficientemente ancho como para que se muestre correctamente el texto de la propiedad Caption
Añade el Evento Pressed
al botón y escribe la siguiente línea de código en el Editor de Código asociado:
BaseContainer1.AddNewControl
Añade un segundo botón y sitúalo justo debajo del anterior. Utiliza el Panel Inspector asociado para definir los siguientes valores:
- Name:
RemoveControlButton
- Locking: Left and Top locks closed.
- Caption: “Remove Control”
Utiliza los manejadores de cambio de tamaño del control para que sea lo suficientemente ancho como para mostrar correctamente el texto de la propiedad Caption.
Añade el evento Pressed
al botón recién añadido y escribe la siguiente línea de código en el Editor de Código asociado:
BaseContainer1.RemoveLastControl
Añade ahora una Label
desde la Librería y sitúala justo a la derecha del primer botón. Utiliza el Panel Inspector para definir los siguientes valores:
- Locking: Left and Top locks closed.
- Text: “Control Pressed:”
Utiliza los manejadores de cambio de tamaño del control para que sea lo suficientemente ancho como para mostrar el texto de la propiedad Text
.
Añade una segunda Label
justo a la derecha de la anterior, utilizando el Panel Inspector para definir los siguientes valores:
- Name:
ControlPressedName
- Locking: Left and Top locks closed.
- Text: “”
Por último, arrastra el BaseContainer
desde el Navegador y sitúalo bajo el segundo botón. Utiliza los manejadores de cambio de tamaño del control de modo que cubra toda la superficie restante de la ventana. El diseño final debería de tener el siguiente aspecto:
Utiliza el Panel Inspector para definir los siguientes valores:
Locking: left, top, right and bottom clocks closed
Con la instancia de BaseContainer1 seleccionada en el Editor de Diseño, añade el evento ControlPressed
y escribe la siguiente línea de código en el Editor de Código asociado:
ControlPressedName.Text = tControl.name
7. Ejecutar la App
¡Todo listo! Ejecuta la app, pulsa el botón “Add Control” y añade tantos botones como quieras al control BaseControl1
, pulsa el botón “Remove Control” para eliminar controles. Prueba a cambiar el tamaño de la ventana y observarás cómo los controles cambian sus posiciones a medida que sea necesario.
Buenos días, Javier: quería hacerte una sugerencia que, evidentemente, dejo por completo a tu libre albedrío y es que en el curso de programación de Xojo pusieses algún ejemplo de “arrastar y soltar” texto en un campo de texto. He intentado comprender el ejemplo de youtube en inglés (con imagen o fichero), pero creo que el narrador da muchas cosas por supuestas y que un ejemplo en español facilitaría las cosas a muchos usuarios noveles. Muchas gracias y saludos.
Hola Juanjo,
¿Podrías pasarme el enlace al vídeo en inglés al que haces referencia? Así tendría una mejor comprensión de lo que necesitas.
Buenas tardes, Javier:
perdón por la tardanza en contestar. He estado de vacaciones en Armenia con mi pareja y no hemos parado. Te adjunto el enlace, pero, en realidad lo que intento es averiguar cómo funciona el “arrastrar y soltar”, por ejemplo, un texto desde cualquier aplicación externa a cualquier control de texto , sea un textfield o un textarea) sw Xojo, si eso es posible. En el ejemplo en inglés, por lo poco que he entendido, explica cómo arrastrar una imagen o un fichero a un canvas. Muchas gracias y saludos. Enlace ejemplo en inglés: https://youtu.be/jKBl3tLot74