Skip to content

Construcción Automática de ventanas en Pharo Spec2

Gastón Ginestet edited this page Feb 19, 2021 · 13 revisions

Construcción Automática de ventanas en Pharo/Spec2

Facultad de Informática - Universidad Nacional de La Plata

Materia: Orientación a Objetos 2

Profesores: Federico Balaguer , Alejandra Garrido, Alejandro Fernández, Gustavo Rossi.

Alumno: Gastón Ginestet

Resumen

En Pharo existe un framework para construir ventanas que se llama Spec2 (es la evolución de Spec1). Con este framework se están implementando todas las herramientas de programación dentro de Pharo 9 (en desarrollo).

En Spec 2 (como en Spec1) no hay un editor de ventanas sino que se especifican con métodos de clase que construyen la vista. Por lo tanto , realizar una herramienta visual de especificación de ventanas es un trabajo duro y tedioso y sobre todo más sabiendo que existen editores muy buenos como por ejemplo Qt Designer o WxSmith (que es parte de Code::Blocks), también hay otras aplicaciones para dibujar "Wire Frames".

Estas herramientas suelen guardar/exportar las especificaciones como archivos xml o json.

En este proyecto consiste en desarrollar en Pharo Smalltalk una herramienta que lea el diseño de ventanas (XML o JSON) y genere el código necesario para mostrarlo con Spec2.


Tareas realizadas

Para leer el diseño de la ventana exportado por QTDesigner se utiliza XMLParser

XMLDOMParser parseFileNamed: 'C:\...\Ejemplos QT Designer/TreeAndList.ui'.

Entonces el primer objetivo que me propuse fue poder reconocer las clases de los elementos en los que tenía que crearlos en Spec.

image

Ejemplo al visualizar un archivo generado por QTDesigner

Motivación para el primer objetivo:

De alguna forma necesito recorrer todos los nodos y poder crear las clases correspondientes con sus diferentes valores. Entonces con el patrón Visitor de Erich Gamma, Richard Held, Ralph Johnson y John Vlissides creé una jerarquía de clases “Nodo” en mi caso es QWidget ,donde al recorrer cada elemento del xml pueda entender como crear el elemento , y creé una clase visitante que recorre cada elemento denominada QVisitor. Diagrama Visitor Diagrama en Lucidchart

Ejemplo

qv:= QVisitor new.
qv visit: 'C:\...\Ejemplos QT Designer/TreeAndList.ui'.

Al llamar ahora:

qv elements. 

Muestra los elementos creados.

image

Como segundo objetivo y a continuación cuento la motivación, fue que en base a los elementos creados , poder mostrarlos en Spec.

Motivación para el segundo objetivo:

Bien , ahora que tengo los elementos y sus propiedades de alguna forma quiero dibujar o construir de una forma compatible con Spec 2 y visualizarlo en Pharo.

image

Desde QTDesigner a Spec 2 , como tendría que visualizarse

Entonces gracias al patrón Builder, de esa clase QWidget y cada subclase que hereda cada uno tiene su diferente forma de representarse en Spec 2 como si fuera un objeto que hereda de SpPresenter y el objeto que antes actuaba de visitante , ahora dirige la construcción . Concatenando strings logré crear cada uno de los elementos correspondientes.

En este video se muestra el resultado buscado.

Demo

Como se puede apreciar en el video se crea un paquete nuevo en Pharo que se llama QWidget-Build donde contiene la clase SpWidgetTreeAndList (el nombre puede variar según el nombre que tenga la ventana principal , en este caso el nombre de la ventana principal es TreeAndList y se le agrega antes SpWidget . Esta clase hereda de SpPresenter y por cada widget que contenga, crea su respectiva variable de instancia 'treeView listView addButton removeButton ' . Después se crean dos métodos de instancia que necesita Spec 2 para poder dibujar la ventana: InitializePresenters y InitializeWindow:

initializePresenters
	treeView := self newTreeTable.
	listView := self newList.
	addButton := self newButton label: #addButton.
	removeButton := self newButton label: #removeButton.

Este método inicializa todos los widgets correspondientes a como sería en Spec 2.

initializeWindow: aWindowPresenter
	aWindowPresenter
		title: #TreeAndList;
		initialExtent: 465 @ 300.

Este método inicializa la ventana donde en initialExtent: 465 @ 300. equivale a lo que sería el ancho y la altura de la ventana principal

Y un método de clase llamado defaultSpec que es esencial para la creación de la ventana .

defaultSpec
	^ SpBoxLayout newHorizontal
		add: #treeView
			withConstraints: [ :c | 
			c width: 161.
			c height: 281 ];
		add: #listView
			withConstraints: [ :c | 
			c width: 161.
			c height: 281 ];
		add: #addButton
			withConstraints: [ :c | 
			c width: 88.
			c height: 34 ];
		add: #removeButton
			withConstraints: [ :c | 
			c width: 88.
			c height: 34 ];
		yourself.

Se puede observar que el ancho y la altura se pueden replicar pero lo que faltaría para hacer cuando termine de desarrollarse Spec 2 es la posición de cada elemento con X e Y

SpWidgetTreeAndList new openWithSpec.

Motivación para el tercer objetivo:

Después de haber corregido errores y detalles, fui agregando más elementos hasta que se presentó una nueva y última dificultad: ¿Qué pasaría con los elementos que se representan en QTDesigner pero no en Spec 2?

Gracias al patrón NullObject (de Johnson y Wolff) , todos los elementos que están en QTDesigner por ejemplo y no en Spec 2 van a poder visualizarse como NullWidget

Ejemplo:

image

Acá vemos que debajo del RadioButton se encuentra un “ToolButton”

Vemos como queda en Spec 2..

image

En initializePresenters se representa "ToolButton" de esta forma

	toolButton := self newButton
		disable;
		label: #null

Por último se armó un repositorio público en Github y dejé armado un Baseline y un Readme para el que requiera hacer pruebas con opción también de poder descargar ejemplos para analizar.

Para poder descargar alguno de los ejemplos en el Readme , haga click derecho y click en "Guardar enlace como.." , elegís el destino para guardarlo y ya podes utilizarlo cuando instales el proyecto en Pharo.

Elementos soportados de QTDesigner en Spec 2 / Pharo

  • QWidget (es el elemento base que se inizializa en QTDesigner)
  • QCheckBox
  • QLineEdit
  • QListView
  • QPlainTextEdit
  • QPushButton
  • QRadioButton
  • QTreeView
  • NullWidget → destinado para los que no estén soportados en Spec 2

Conclusiones

A pesar del inconveniente de que en Spec 2 todavía sigue en desarrollo y muchas cosas no están terminadas se pudo lograr con los objetivos planteados. Me quedará pendiente continuar con el trabajo y poder ir acomodando los detalles que se plantearon.

Poder trabajar con ventanas y entender como funcionan fue una experiencia muy gratificante ya que pude aprender mucho sobre Pharo en general y poder comprender más acerca de la importancia en haber trabajado con esto.

Lo mismo aplicado para los conceptos aprendidos en esta materia. Poder entender acerca de lo que es un Framework (Spec 2) , poder estudiar y aplicar los patrones y poder refactorizar el código dejándolo un poco más claro y más legible.

No quiero dejar de mencionar lo importante que es trabajar en un proyecto por mi cuenta, estoy agradecido por la oportunidad que me dieron y poder haber desarrollado en algo que me interesa para una materia.