Siglo XXI. Es posible compartir contactos con otras personas directamente desde el móvil pero, admitámoslo, las tarjetas de visita aun son realmente comunes como un modo de compartir información personal de contacto.
De hecho y desde hace ya algunos años, es bastante habitual que este tipo de tarjetas incorporen un código QR que se corresponden con los propios datos de contacto de modo que, al escanearlo, se pueda añadir directamente a la Agenda del dispositivo u ordenador.
En este tutorial crearemos una app que te permitirá hacer precisamente eso: generar códigos QR con la información embebida en formato vCard. Como “extra” también será posible exportar el archivo en formato vCard, en cuyo caso también incluirá (si se desea) la fotografía correspondiente a la persona o bien el logotipo de empresa.
Como de costumbre, y antes de empezar con los pasos propiamente dichos, descarga Xojo desde https://www.xojo.com/download e instálalo en tu ordenador tal y como harías como cualquier otra aplicación en tu sistema operativo de elección (macOS, Windows o Linux).
Una vez instalado Xojo, ejecútalo y selecciona Desktop en la ventana Choose a Project. Al hacerlo verás que puedes introducir el nombre deseado para la aplicación, así como el nombre de la empresa, etc. Puedes dejar los valores presentados por omisión o bien cambiarlos por aquellos de tu elección.
Diseñar la Interfaz de Usuario
Sin duda, se trata del proceso que probablemente nos lleve más tiempo (más pasos requeridos). En este proceso veremos como podemos utilizar en nuestro favor el control ContainerControl para compartimentar diferentes aspectos de la UI y también la lógica asociada a cada uno de estos componentes. ¡Comencemos!
Contendor de Datos Personales
Haz clic sobre el botón Library para acceder a la librería que muestra todos los controles de interfaz de usuario incluidos de serie en Xojo para los proyectos de Escritorio.
Ubica el control Container y arrástralo sobre el Navegador de proyecto. Se trata del área vertical en la izquierda de la ventana del IDE, donde se muestran todos los elementos añadidos al proyecto.
Cuando sueltes el control sobre el Navegador de Proyecto verás que este se añadido como un nuevo componente y se mostrará el Panel Inspector asociado en el área derecha de la ventana del IDE. Cambia los siguientes valores en dicho panel inspector:
- Name: PersonalInfoContainer
- Width: 374
- Height: 302
Con el control PersonalInfoContainer seleccionado en el Navegador accederás al Editor de Diseño correspondiente a dicho control. Vuelve a pulsar sobre el icono Library para acceder nuevamente a los controles disponibles. En esta ocasión, ubica el control GroupBox y haz doble cloc sobre el para que se añada automáticamente al editor de diseño correspondiente al container. Utiliza los siguientes valores en el Panel Inspector asociado:
- Left: 0
- Top: 0
- Width: 374
- Height: 302
- Locking: Bloquea los cuatro candados
- Caption: Personal Information
A continuación añadiremos tanto las etiquetas como los campos de texto sobre el control GroupBox1 para que el usuario pueda introducir los datos a partir de los cuales se crearán tanto la vCard como el QR con dicha información.
Añade desde la librería controles Label y TextField de modo que la interfaz de usuario tenga un aspecto similar al siguiente:
Selecciona todas las etiquetas Label y cambia el siguiente atributo en el panel Inspector (el cambio se aplicará a todos los elementos seleccionados):
- Text Alignment: Right
A continuación introduce los siguientes valores para cada una de las Label, seleccionándolas en este caso una a una desde la superior hasta la situada en la parte inferior:
Label1
- Name: NameLB
- Text: Name:
Label2
- Name: SurnameLB
- Text: Surname:
Label3
- Name: CompanyLB
- Text: Company:
Label4
- Name: TitleLB
- Text: Title:
Label5
- Name: PhoneLB
- Text: Phone:
Label6
- Name: MobileLB
- Text: Mobile:
Label7
- Name: EmailLB
- Text: Email:
Label8
- Name: WebLB
- Text: Web:
A continuación selecciona cada uno de los Textfield, también uno a uno comenzando con el situado en la parte superior, e introduce los siguientes valores en el panel inspector asociado con cada uno de ellos:
TextField1
- Name: NameTF
- Locking: Bloquea los candados izquierdo, superior y derecho.
TextField2
- Name: SurnameTF
- Locking: Bloquea los candados izquierdo, superior y derecho.
TextField3
- Name: CompanyTF
- Locking: Bloquea los candados izquierdo, superior y derecho.
TextField4
- Name: TitleTF
- Locking: Bloquea los candados izquierdo, superior y derecho.
TextField5
- Name: PhoneTF
- Locking: Bloquea los candados izquierdo, superior y derecho.
TextField6
- Name: MobileTF
- Locking: Bloquea los candados izquierdo, superior y derecho.
TextField7
- Name: EmailTF
- Locking: Bloquea los candados izquierdo, superior y derecho.
TextField8
- Name: WebTF
- Locking: Bloquea los candados izquierdo, superior y derecho.
Cuando termines, la interfaz de usuario del container PersonalInfoContainer tendrá el siguiente aspecto:
Contendor de Dirección Postal
Ya hemos terminado con el diseño del contenedor que se utilizará para que el usuario introduzca sus datos personales. Ahora añade un nuevo Contenedor al Navegador del proyecto y selecciónalo para acceder al Editor de Diseño asociado.
Utiliza el Panel Inspector para cambiar los siguientes valores:
- Name: PostalContainer
- Width: 398
- Height: 212
A continuación, haz doble clic sobre el control GroupBox en la Librería para que se añada al nuevo container, y cambia los siguientes valores utilizando el panel inspector asociado:
- Left: 0
- Top: 0
- Width: 398
- Height: 212
- Locking: Cierra los cuatro candados.
- Caption: Postal Address:
Tal y como hicimos en el anterior container, añade en esta ocasión un total de cinco etiquetas y otros tantos campos de texto. El resultado debería ser similar al siguiente:
Alinea todas las etiquetas a la derecha, tal y como hicimos con el anterior Container. Luego, desde arriba hacia abajo, modifica las siguientes propiedades para cada una de ellas:
Label1
- Name: StreetLB
- Text: Street:
Label2
- Name: PostcodeLB
- Text: Postcode:
Label3
- Name: CityLB
- Text: City:
Label4
- Name: ProvinceLB
- Text: Province:
Label5
- Name: CountryLB
- Text: Country or Region:
Y modifica los siguientes valores en el panel inspector para cada uno de los TextField, también desde la parte superior hacia la inferior
TextField1
- Name: StreetTF
- Locking: Bloquea los candados izquierdo, superior y derecho
TextField2
- Name: PostalCodeTF
- Locking: Bloquea los candados izquierdo, superior y derecho
TextField3
- Name: CityTF
- Locking: Bloquea los candados izquierdo, superior y derecho
TextField4
- Name: ProvinceTF
- Locking: Bloquea los candados izquierdo, superior y derecho
TextField5
- Name: CountryTF
- Locking: Bloquea los candados izquierdo, superior y derecho
Una vez finalizado, el diseño para el container PostalContainer tendrá un aspecto similar al siguiente:
Finalizar el diseño de la UI
Con el diseño de nuestros dos container finalizado, es hora de añadirlos a la ventana principal del proyecto (Window1), así como el resto de controles que serán necesarios.
Empieza seleccionando el elemento Window1 en el Navegador para que se muestre en el Editor de Diseño. A continuación, arrastra el container PersonalInfoContainer y suéltalo sobre la parte superior derecha de la ventana en el Editor de diseño. Debería de verse así:
Con el elemento Window1 aun seleccionado en el Navegador es buen momento para cambiar alguna de sus propiedades en el Inspector asociado:
- Width: 600
- Height: 604
- Minimum Width: 600
- Minimum Height: 604
- Maximum Width: 600
- Maximum Height: 604
- Title: QR From vCard – vCard Export
Ahora, selecciona el container PostalContainer y suéltalo justo bajo el container PersonalInfoContainer en el Editor de Diseño correspondiente a Window1. El resultado debería de ser similar al siguiente:
Como puedes ver, el contenedor PostalContainer1 es ligeramente más ancho que el item PersonalInfoContainer1. Selecciona este último en el editor de diseño de Window1 y utiliza el manejador central izquierdo para arrastrarlo hacia la izquierda hasta que aparezca la guía de alineación. Eso significará que ambos contenedores están alineados.
Ahora continuaremos añadiendo los controles necesarios para finalizar la UI:
- Un control ImageWell para mostrar la imagen seleccionada por el usuario para la vCard.
- Un botón que, al pulsarse, permitirá al usuario seleccionar la imagen a usar en la vCard.
- Un control ImageWell que mostrará la vista previa del QR generado a partir de la vCard.
- Un botón que, al pulsarlo, permitirá crear el QR a partir de la vCard así como asignar la imagen resultante en el control de vista previa.
- Un botón que, cuando esté activado, permitirá exportar el QR como archivo de imagen en formato PNG.
- Un botón que, al pulsarlo, permitirá generar la vCard como archivo con el nombre y ubicación seleccionados.
- Un último botón que, al pulsarlo, se encargará de reiniciar la UI a sus valores por omisión.
Seleccionar Imagen de Contacto
La imagen de contacto seleccionada por el usuario se añadirá como parte de la vCard generada como archivo pero no al código QR debido a que éste carece del espacio suficiente como para alojar tal cantidad de información.
Para ello necesitamos añadir a Window1 dos controles: un ImageWell y un botón. Empieza añadiendo un control ImageWell sobre el área superior izquierda de la ventana Window1 en el Editor de diseño:
Y utiliza el panel inspector asociado con dicho control para modificar los siguientes valores:
- Name: PersonPreview
- Left: 20
- Top: 20
- Width: 150
- Height: 150
A continuación suelta un control Button justo bajo PersonPreview, y utiliza el panel inspector asociado para modificar los siguientes valores:
- Name: OpenPictureBT
- Left: 20
- Top: 182
- Width: 150
- Height: 20
- Caption: Open Picture…
El resultado debería tener un aspecto similar al siguiente:
Vista Previa de QR y exportar
Ahora continuaremos con los elementos de UI correspondientes a la vista previa del código QR y los botones para crearlo, exportar el QR o bien exportar la vCard.
Suelta un nuevo control ImageWell desde la librería sobre Window1 en el Editor de Diseño y modifica los siguientes atributos en el panel inspector asociado:
- Name: QRPreview
- Left: 20
- Top: 304
- Width: 150
- Height: 150
Añade un botón justo debajo de QRPreview y utiliza los siguientes valores en el Panel Inspector asociado:
- Name: CreateQRBT
- Left: 20
- Top: 466
- Width: 150
- Height: 20
- Caption: Create QR
Añade un nuevo botón bajo CreateQRBT y modifica los siguientes valores en el panel inspector:
- Name: ExportQRBT
- Left: 20
- Top: 498
- Width: 150
- Height: 20
- Caption: Export QR
- Enabled: Desactivado
Añade un nuevo botón justo bajo ExportQRBT y modifica los siguientes valores en el panel inspector:
- Name: ExportVCardBT
- Left: 20
- Top: 530
- Width: 150
- Height: 20
- Caption: Export vCard
Añade el último de los botones requeridos, justo bajo el contenedor PostalContainer1 y utiliza los siguientes valores en el panel inspector:
- Name: ClearBT
- Left: 500
- Top: 562
- Width: 80
- Height: 20
- Locking: Bloquea sólo los candados inferior y derecho.
- Caption: Clear
¡Hemos terminado con el diseño de la interfaz de usuario! Este es el aspecto que debería de tener:
Añadir funcionalidad al Contenedor PersonalInfoContainer
Es el momento de añadir el código (funcionalidad) a cada uno de los componentes que lo precisen. Empezaremos por PersonalInfoContainer, de modo que tendrás que seleccionarlo en el Navegador. Con PersonalInfoContainer1 seleccionado, elige la opción de menú Insert > Method y utiliza los siguientes valores en el panel inspector asociado:
- Method Name: GetPersonalInformation
- Return Type: String
- Scope: Public
Añadiendo a continuación el siguiente código en el Editor de Código asociado con el método recién añadido:
Var FullName As String = Nametf.Text + " " + SurnameTF.Text Var ReturnedValues() As String If fullname.ReplaceAll(" ", "") <> "" Then ReturnedValues.Add "FN:" + FullName If SurnameTF.Text <> "" Or nametf.Text <> "" Then ReturnedValues.add "N:" + SurnameTF.Text + ";" + NameTF.Text + ";;;" If companytf.Text <> "" Then ReturnedValues.Add "ORG:" + CompanyTF.Text + ";" If TitleTF.Text <> "" Then ReturnedValues.add "TITLE:" + Titletf.Text If phonetf.Text <> "" Then ReturnedValues.add "TEL;Type=HOME:" + PhoneTF.Text If mobiletf.Text <> "" Then ReturnedValues.add "TEL;Type=CELL:" + MobileTF.Text If emailtf.Text <> "" Then ReturnedValues.add "EMAIL;Type=INTERNET;type=WORK;type=pref:" + EmailTF.Text If webtf.Text <> "" Then ReturnedValues.add "URL:" + webtf.Text Return String.FromArray(ReturnedValues, EndOfLine)
Como puedes ver, el código de este método es bastante fácil de seguir. Básicamente sólo se añadirán al Array ReturnedValues los campos de la vCard cuyos TextField contengan valores (es decir, no estén vacíos).
De igual forma, y para mantener el código lo más escueto posible en este tutorial tampoco se realiza ningún tipo de verificación sobre la validez de los datos introducidos.
Añade un nuevo método a PersonalInfoContainer y que será el encargado de limpiar la UI de dicho contendor; utiliza los siguientes valores en el Inspector asociado con el nuevo método:
- Method Name: Clear
- Scope: Public
Y el siguiente código en el Editor de Código asociado para el método Clear:
For Each ctl As DesktopUIControl In self.controls If ctl IsA DesktopTextField Then DesktopTextField(ctl).Text = "" End If Next
Como puedes ver, este código recorre todos los controles del contenedor PersonalInfoContainer y utiliza la palabra clave IsA para comprobar si el control iterado es un DesktopTextField. Si es el caso, entonces hace un cast del control iterado a la clase DesktopTextField para acceder a su propiedad Text y asignarle el valor de cadena vacía (“”).
Añadir funcionalidad al Contenedor PostalContainer
Selecciona ahora el contendor PostalContainer en el Navegador de proyecto. Verás que la funcionalidad será muy similar a la añadida en el anterior.
Crea un nuevo método y utiliza el panel asociado para modificar los siguientes valores:
- Method Name: GetPostalInformation
- Return Type: String
- Scope: Public
Y escribe el siguiente código en el Editor de Código asociado con el método:
Var returnedValue As String Var inputValues() As String inputValues.Add StreetTF.Text inputValues.add CityTF.Text inputValues.add ProvinceTF.Text inputValues.Add PostalCodeTF.Text inputValues.add CountryTF.Text Var address As String = String.FromArray(inputValues, ";") If address.ReplaceAll(";","") <> "" Then returnedValue = "ADR;type=WORK:;;" + address Return returnedValue
Como puedes ver, es muy similar al visto anteriormente. El resultado será el correspondiente al campo “ADR” de una vCard.
Añade un segundo método con los siguientes valores en el panel inspector:
- Method Name: Clear
- Scope: Public
Y escribe el siguiente código en el editor asociado:
For Each ctl As DesktopUIControl In Self.Controls If ctl IsA DesktopTextField Then DesktopTextField(ctl).Text = "" End If Next
En este caso, el código es el mismo que el empleado en el anterior contenedor a la hora de “resetear” su UI a los valores iniciales.
Añadir Funcionalidad General a la Ventana
Selecciona Window1 en el Navegador de proyecto y añade un método utilizando los siguientes valores en el Panel Inspector:
- Method Name: GenerateVCARD
- Parameters: forVCardExport as Boolean = False
- Return Type: String
Y escribe el siguiente código en el Editor de Código asociado:
Var vCard() As String vCard.add "BEGIN:VCARD" vCard.add "VERSION:3.0" vCard.add PersonalInfoContainer1.GetPersonalInformation vCard.add PostalContainer1.GetPostalInformation If PersonPreview.Image <> Nil and forVCardExport Then vCard.add "PHOTO;ENCODING=BASE64;TYPE=JPEG:" + getPersonImage End If vCard.add "REV:" + GetRevisionTime vCard.add "END:VCARD" Return String.FromArray(vCard, EndOfLine)
Añade un segundo método con los siguientes valores:
- Method Name: GetRevisionTime
- Return Type: String
Y escribe las siguientes líneas de código en el editor de código asociado:
Var current As DateTime = DateTime.Now Var currentToUTC As DateTime = New DateTime(current.SecondsFrom1970 - current.Timezone.SecondsFromGMT) return currentToUTC.Year.ToString + currentToUTC.Month.ToString + currentToUTC.Day.ToString + "T" + currentToUTC.Hour.ToString + currentToUTC.Minute.ToString + currentToUTC.Second.ToString+"Z"
Añade el último de los métodos generales y utiliza los siguientes valores en el Inspector:
- Method Name: getPersonImage
- Return Type: String
A continuación, introduce el siguiente código en el editor asociado:
Var returnedValue As String const kWidth as Double = 120 var pHeight as Double If PersonPreview.Image <> Nil Then pHeight = (kWidth * PersonPreview.Image.Height) / PersonPreview.Image.Width Var tempPic As New Picture(kWidth, pHeight) tempPic.Graphics.DrawPicture(PersonPreview.Image, 0, 0, kWidth, pHeight, 0, 0, PersonPreview.Image.Width, PersonPreview.Image.Height) Var mb As MemoryBlock = TempPic.ToData(Picture.Formats.JPEG) returnedValue = EncodeBase64(mb) returnedValue = returnedValue.ReplaceLineEndings("") End If Return returnedValue
Añadir Funcionalidad Específica a los Controles
Para finalizar, sólo nos resta añadir la funcionalidad que se ejecutará al pulsar en los diferentes botones. Comenzaremos seleccionando ClearBT en el Navegador de Proyecto y seleccionando la opción “Add to ‘ClearBT’ > Event Handler…” en el menú contextual. Selecciona el evento Pressed en la ventana resultante y confirma la selección para que dicho evento se añada sobre el control.
Ahora introduce el siguiente código en el editor de código asociado con el evento Pressed del control ClearBT:
PersonPreview.Image = Nil QRPreview.Image = Nil ExportQRBT.Enabled = False PersonalInfoContainer1.clear PostalContainer1.clear
Añade el evento Pressed al control CreateQRBT e introduce el siguiente código en el editor de código asociado:
QRPreview.Image = Nil Var theCard As String = GenerateVCARD Try Var p As Picture = Barcode.Image(theCard, 600, 600) If p <> Nil Then QRPreview.Image = p ExportQRBT.Enabled = True Else ExportQRBT.Enabled = False End If Catch e As UnsupportedOperationException MessageBox("Unable to Create QR" + EndOfLine + EndOfLine + "Probably the provided data exceeds the available room for a QR.") End Try
Añade el evento Pressed sobre el control ExportQRBT e introduce el siguiente código en el editor de código asociado:
If QRPreview.Image <> Nil Then Var f As FolderItem = FolderItem.ShowSaveFileDialog("", "ExportedQR.PNG") If f <> Nil Then QRPreview.Image.Save(f, Picture.Formats.PNG) End If End If
Añade el evento Pressed en el control ExportVCardBT e introduce el siguiente código en el Editor de Código asociado:
Var theCard As String = GenerateVCARD(True) Var f As FolderItem = FolderItem.ShowSaveFileDialog("","Exported.vCard") If f <> Nil Then Var tos As TextOutputStream = TextOutputStream.Create(f) tos.Write(theCard) tos.Flush tos.Close End If
Por último, añade el evento Pressed sobre el control OpenPictureBT y escribe el siguiente código en el Editor de Código asociado:
PersonPreview.Image = Nil Var f As FolderItem = FolderItem.ShowOpenFileDialog( SupportedImageFormats.All ) If f <> Nil Then PersonPreview.Image = Picture.Open(f) End If
Filtrado de imágenes
Como puedes ver, en la segunda línea del anterior código hacemos referencia al objeto SupportedImageFormats.All como parámetro para filtrar el tipo de archivos que puede seleccionar el usuario.
Para ello, añade un nuevo Grupo de Tipos de Archivo desde Insert > File Type Group. Con el nuevo elemento añadido en el Navegador de proyecto seleccionado, haz clic sobre el botón situado más a la izquierda en la barra de herramientas para añadir la entrada “image/jpeg”. Repite la operación para añadir también “image/png”.
Por último, en el panel inspector cambia el nombre del item a SupportedImageFormats. Una vez finalizado, debería de tener el siguiente aspecto:
¡En Marcha!
Todo listo. Hemos completado tanto el diseño como la funcionalidad de nuestra app. Ahora sólo tienes que ejecutarla y realizar algunas pruebas: seleccionando una imagen de contacto (o no), cumplimentando cualquiera de los campos, y generando el QR asociado así como exportarlo… o bien exportar el archivo vCard directamente de modo que lo puedas importar desde cualquier aplicación compatible (por ejemplo, Contactos en macOS).
Por supuesto, puedes ampliar y completar este pequeño ejemplo: desde introducir validaciones para los campos que lo requieran, incrementar la cantidad de campos para que en la vCard también figuren cualesquiera otros de los soportados por el estándar, etc.
Conclusiones
Como has visto, generar tanto la vCard como el QR que contiene dicha información no requiere de una gran cantidad de código, y lo mejor de todo es que con solo un clic del ratón la misma aplicación funcionará tanto en macOS como en Windows y Linux.
¡Feliz programación con Xojo!