Biblioteca QtHaskell

De Wikihaskell
Saltar a: navegación, buscar
QtHaskell
Interfaces de usuarios con QtHaskell
Lenguaje Haskell
Biblioteca QtHaskell
Autores David Mariscal Martínez
Diego Sánchez Díaz
José Tomás Tocino García

QtHaskell es un conjunto de bindings en Haskell para las bibliotecas Qt de Nokia. Proporciona acceso a un amplio abanico de tecnologías para el desarrollo de aplicaciones multiplataforma, incluyendo un sistema de señales y slots para la especificación de la lógica de las aplicaciones, que ha servido como base para muchos otros sistemas basados en callbacks. Con QtHaskell es posible desarrollar, de forma rápida, sofisticadas y eficientes aplicaciones multiplataforma.

Además, es totalmente compatible con la suite de herramientas de Qt, incluyendo el diseñador de interfaces Qt Designer, el sistema de traducciones Qt Linguist e incluso el motor de Javascript embebido de Qt.

Qt es la base del sistema de escritorio KDE, además de usarse en multitud de software, tanto libre como privativo, como Google Earth, Skype o VLC.

Contenido

Introducción

Dependencias previas

Para trabajar con QtHaskell debemos usar el compilador GHC. Su instalación en sistemas GNU/Linux basados en Debian es bastante sencilla:

   sudo apt-get install ghc6 libghc6-parsec-dev libghc6-network-dev libghc6-http-dev libghc6-opengl-dev
   libghc6-mtl-dev zlib1g-dev libghc6-parallel-dev

Para cualquier duda sobre la instalación y ejecución de este compilador, puede consultar el artículo sobre el mismo en este wiki.

También tendremos que instalar la biblioteca Qt, contenida en los siguientes paquetes:

   sudo apt-get install libqt4-dev qt4-qmake 

Con esto tendremos satisfechas las dependencias, y podremos pasar al siguiente paso.

Construyendo la biblioteca

En este momento podremos descargar qtHaskell desde su página oficial. Lo habitual es descargar el fichero .tar.gz y descomprimirlo de la siguiente manera:

   tar -xzf qtHaskell-1.1.4.1.tar.gz

Esto generará un directorio llamado qthaskell-1.1.4. Entramos en el mismo y ejecutamos el script de instalación

   cd qthaskell-1.1.4
   ./build

La ejecución de este script durará bastante tiempo, ya que recompilará la biblioteca Qt para su uso con Haskell. Habitualmente tardará entre 30 y 50 minutos en compilar, dependiendo de la capacidad del ordenador. En las etapas finales de su ejecución el script necesitará la participación del usuario para poder instalar la biblioteca en carpetas protegidas del sistema. En tales casos simplemente introducimos la contraseña de root y aceptamos.

El script también compilará una serie de ejemplos de prueba que podremos encontrar en la carpeta examples.

Compilando y ejecutando

Para compilar un archivo creado usando la librería QtHashell con extensión ".hs" debemos utilizar el compilador GHC usando la siguiente orden en la terminal:

   ghc --make NombreArchivoFuente.hs -o NombreArchivoEjecutable

Para ejecutar el archivo binario generado se debe ejecutar de la siguiente forma:

   ./NombreArchivoEjecutable

Aplicación básica

En este apartado se irá explicando un pequeño programa con el fin de ir viendo poco a poco las distintas funciones de esta librería y sus usos. Se indicará de que se trata la aplicación, se mostrará su código fuente acompañado con una imagen que muestra su ejecución y finalmente se explicarán sus funciones de forma detallada.

Hola Mundo

Esta aplicación muestra una ventana al usuario que contiene un botón llamado "Hola Mundo".

  1. module Main where
  2.  
  3. import Qt
  4.  
  5. main :: IO Int
  6. main = do
  7.   qApplication ()
  8.   hola <- qPushButton "Hola Mundo"
  9.   resize hola (200::Int, 60::Int)
  10.   qshow hola ()
  11.   qApplicationExec ()
  12.  
QtHaskell-HolaMundo.jpg

En el ejemplo anterior se utiliza una sola declaración de importación, import Qt, que importa todos los componentes de la biblioteca. Esto puede servir como método de importación genérico, pero a menudo es más conveniente indicar explícitamente qué partes de qtHaskell queremos importar, ya que al incluir la biblioteca al completo, la compilación puede hacerse lenta y generar ejecutables de un tamaño desproporcionado. En el ejemplo anterior, al reemplazar la importación general por los componentes explícitos, nos quedaría:

  1. module Main where
  2.  
  3. import Qtc.Classes.Qccs
  4. import Qtc.Classes.Gui
  5. import Qtc.Gui.Base
  6. import Qtc.Gui.QApplication
  7. import Qtc.Gui.QPushButton
  8.  
  9. main :: IO Int
  10. main = do
  11.   qApplication ()
  12.   hola <- qPushButton "Hola Mundo"
  13.   resize hola (200::Int, 60::Int)
  14.   qshow hola ()
  15.   qApplicationExec ()
  16.  

Las declaraciones de tipo en QtHaskell tienen la forma qSomeQtClassName, seguidas de una tupla de parámetros. En este ejemplo hay dos: QApplication () y QPushButton "Hola ..." . Hay que tener en cuenta que los casos en los que el constructor no tiene parámetros, es necesario escribir un par de paréntesis vacíos para terminar la instrucción. Esto no es una opción y el programa no se compilará si se omiten. En los constructores que sólo tienen un parámetro se pueden omitir los paréntesis, como en la sintaxis estándar de Haskell.

Aunque los programas QtHaskell generalmente comienzan con una llamada qApplication (), el nombre del programa y otros parámetros del programa se pasan automáticamente a la aplicación Qt.

Las llamadas a las funciones estáticas toman la forma qSomeQtClassNameSomeStaticFunction seguida de una tupla de parámetros. En el ejemplo podemos ver una: qApplicationExec (). Al igual que con los constructores, los paréntesis son obligatorios para las funciones sin parámetros.

Las funciones no estáticas adoptan la forma (q)someNonStaticFunction seguido del nombre del objeto cuya función se está llamando y una tupla de parámetros. Hay dos llamadas de ese tipo en el ejemplo: resize hola (200::Int, 60::Int) y qshow hola (). Hay que tener en cuenta que los valores numéricos literales deben ser explícitamente tipificados en la mayoría de las llamadas en QtHaskell y que los paréntesis son obligatorios una vez más. Además algunas llamadas a los métodos no estáticos requieren que se empiecen con el carácter "q".

Por tanto, podemos formular una regla general para la sintáxis de funciones en QtHaskell:

  • qSomeQtClass () | p1 | (p1) | (p1, p2 ...) construye un objeto de la clase QSomeQtClass.
  • qSomeQtClassSomeStaticMethod () | p1 | (p1) | (p1, p2 ...) llama a la función estática del tipo SomeStaticMethod QSomeQtClass.
  • (q)someNonStaticMethod SomeQtClassObject () | p1 | (p1) | (p1, p2 ...) llama a las funciones no estáticas (q)someNonStaticMethod del objeto QSomeQtClassObject.

Hay algunas excepciones a las reglas anteriores. Las funciones en QtHaskell que conectan señales o ranuras, los controladores de sistema, o los destructores explícitos son ligeramente diferentes. Los constructores de las clases de datos de QtHaskell pueden tener un prefijo "_nf" si no tienen un recogedor de basura automático. De hecho, tanto los constructores como las funciones estáticas pueden empezar por el carácter "q" en algunos casos. Este tipo de diferencias se explicarán más adelante.

Tras comentar cómo se efectúan las llamadas a las funciones y métodos en QtHaskell procedemos a explicar el funcionamiento del código anterior:

  • qApplication () -> Creamos una nueva aplicación.
  • hola <- qPushButton "Hola Mundo" -> se crea en hola un botón con el nombre de Hola mundo.
  • resize hola (200::Int, 60::Int) -> El botón cambia su tamaño a 200 píxeles de ancho y 60 píxeles de alto.
  • qshow hola () -> Se muestra el botón en la aplicación creada.
  • qApplicationExec () -> Se muestra la aplicación en pantalla.

Callbacks

En QtHaskell (y en cualquier otro framework) se denomina callback al mecanismo que nos permite guardar una referencia a una función, método o cualquier otro procedimiento de forma que pueda ser llamado posteriormente. En las bibliotecas de programación de interfaces de usuario, como en este caso Qt, los callbacks se utilizan constantemente para asociar respuestas (en forma de funciones o métodos) a acciones del usuario, por ejemplo asociando el click de un botón a la llamada a una función que muestra un mensaje. En QtHaskell, la gestión la lleva a cabo un bucle de manejo de eventos que se inicia con la ejecución inicial del programa (es decir, al llamar a qApplicationExec ()).

Tipos de funciones Callbacks

En QtHaskell podemos encontrarnos 3 categorías diferentes de este tipo de funciones:

  • Slots: Son activadas por señales en el sistema Qt MetaObject.
  • Manejadores (Handlers): Corresponden a funciones virtuales en la definición C++ de las clases de Qt.
  • Funciones definidas por el usuario: Similares a los manejadores exceptuando que permiten al usuario crear una función virtual para la clase en vez de sustituir una ya existente.

Además, todas las funciones virtuales pueden ser anuladas por especificación de una función de manejo (handler) en QtHaskell aunque el método no corresponda a un evento del sistema.

Señales y slots

Para mostrar este tipo de funciones se modificará el programa de "Hola Mundo" para que, al hacer click en el botón, aparezca un mensaje indicando que se ha presionado. El código de este programa es el siguiente:

  1. module Main where
  2.  
  3. import Qtc.Classes.Qccs
  4. import Qtc.Classes.Gui
  5. import Qtc.ClassTypes.Gui
  6. import Qtc.Core.Base
  7. import Qtc.Gui.Base
  8. import Qtc.Gui.QApplication
  9. import Qtc.Gui.QWidget
  10. import Qtc.Gui.QPushButton
  11. import Qtc.Gui.QAbstractButton
  12. import Qtc.Gui.QMessageBox
  13.  
  14. type MyQPushButton = QPushButtonSc (CMyQPushButton)
  15. data CMyQPushButton = CMyQPushButton
  16.  
  17. myQPushButton :: String -> IO (MyQPushButton)
  18. myQPushButton b = qSubClass $ qPushButton b
  19.  
  20. main :: IO Int
  21. main = do
  22.   qApplication ()
  23.   hola <- myQPushButton "Hola Mundo"
  24.   resize hola (200::Int, 60::Int)
  25.   mb <- qMessageBox hola
  26.   connectSlot hola "clicked()" hola "click()" $ on_hola_clicked mb
  27.   qshow hola ()
  28.   qApplicationExec ()
  29.  
  30. on_hola_clicked :: QMessageBox () -> MyQPushButton -> IO()
  31. on_hola_clicked mb this
  32.   = do
  33.   tt <- text this ()
  34.   setText mb $ "Has hecho click en: " ++ tt
  35.   qshow mb ()
QtHaskell-HolaMundo.jpg


Holamundo Slots.jpg


Los slots están conectados a las señales mediante la instrucción connectSlot. Esta instrucción tiene el siguiente formato:

connectSlot signal_object "signal_signature" slot_object "slot_signature" slot_function

En nuestro ejemplo podemos encontrarla en la línea 26 del código:

   connectSlot hola "clicked()" hola "click()" $ on_hola_clicked mb 

Tanto signal_object como slot_object deben ser declarados como objetos de Qt.

Las cadenas signal_signature y slot_signature indican el nombre y el tipo de parámetros de la señal y el slotsque van a ser conectados. El tipo de parámetro deben de ser el mismo para ambas cadenas.

La función slot_function es una llamada parcial de una función Haskell con el siguiente tipo:

   global_Haskell_parameters -> slot_object_type -> slot_parameters

En el ejemplo se ve que On_hola_Clicked toma 2 argumentos y en la llamada sólo se le ha pasado el primero.

Ambas señales o slots pueden ser construidos a partir de constructores de señales y slots de sus clases Qt, o bien, por constructores de señales y slots personalizados, en este caso no hay que declararlos antes de su uso en una instrucción connectSlot. Si el slot pertenece a un slot de una clase Qt, no es necesario el slot_function, pero elconnectSlot debe terminar con 2 paréntesis vacíos quedando de la siguiente manera:

   connectSlot signal_object "signal_signature" slot_object "slot_signature" ()

También es posible conectar unas señales con otras señales usando la instrucción connectSignal que tiene el siguiente formato:

   connectSignal first_signal_object "first_signal_signature" second_signal_object "second_signal_signature"

Tanto en la conexión de slots como de señales las cadenas empleadas en estas instrucciones siguen el mismo esquema que las macros SIGNAL y SLOT de los programas Qt en C++.

Si los slots o señales personalizados son usados por alguna clase esta debe ser una subclase. Para ello, se trata de un proceso de 2 fases:

  1. Crear un tipo basado en una clase de Qt que sea una subclase de esta.
  2. Crear un constructor que utiliza qSubClass para llamar al constructor de la clase base.

En el ejemplo se puede ver una subclase de la clase Qt QPushButton para crear un slot personalizado Click().

Esto último tiene la siguiente forma general:

   type MySubClassType = QBaseClassTypeSc (CMySubClassType) 
data CMySubClassType = CMySubClassType

mySubClassType :: p1Type -> p2Type ... -> IO (MySubClassType)
mySubClassType p1 p2 ... = qSubClass $ qBaseClasstype p1 p2 ...

En el ejemplo:

   type MyQPushButton = QPushButtonSc (CMyQPushButton)
data CMyQPushButton = CMyQPushButton

myQPushButton :: String -> IO (MyQPushButton)
myQPushButton b = qSubClass $ qPushButton b

Si un constructor de una señal se conecta a un slot personalizado en un objeto diferente, el objeto de la señal no tiene que ser una subclase. Esto es muy útil en los menú y barras de menú donde se tienen muchos objetos del tipo QAction que pueden conectar sus constructores de la señal Activa() a los slots personalizados del objeto de la aplicación principal, sin tener que usar una subclase.

Manejadores

Un ejemplo simple usando manejadores es el siguiente, que muestra una pantalla cuando se presiona la letra 'A' del teclado:

  1. module Main where
  2.  
  3. import Qtc.Classes.Qccs
  4. import Qtc.Classes.Qccs_h
  5. import Qtc.Classes.Gui
  6. import Qtc.ClassTypes.Gui
  7. import Qtc.Gui.Base
  8. import Qtc.Enums.Base
  9. import Qtc.Enums.Classes.Core
  10. import Qtc.Enums.Core.Qt
  11. import Qtc.Gui.QApplication
  12. import Qtc.Gui.QMessageBox
  13. import Qtc.Gui.QLabel
  14. import Qtc.Gui.QLabel_h
  15. import Qtc.Gui.QKeyEvent
  16.  
  17. main :: IO Int
  18. main = do
  19.   qApplication ()
  20.   tl <- qLabel "presiona la tecla 'A'"
  21.   setAlignment tl (fAlignCenter::Alignment)
  22.   resize tl (200::Int, 60::Int)
  23.   mb <- qMessageBox tl
  24.   setHandler tl "keyPressEvent(QKeyEvent*)" $ tlkp mb
  25.   qshow tl ()
  26.   qApplicationExec ()
  27.  
  28. tlkp :: QMessageBox () -> QLabel () -> QKeyEvent () -> IO()
  29. tlkp mb this ke
  30.   = do
  31.     k <- key ke ()
  32.     if (k == qEnum_toInt eKey_A)
  33.      then
  34.       do
  35.       setText mb $ "¡Has presionado la tecla 'A'!"
  36.       qshow mb ()
  37.      else
  38.       return ()
  39.     keyPressEvent_h this ke

La función setHandler tiene la siguiente signatura:

   setHandler handler_object “handler_signature” handler_function

El handler_object debe ser previamente declarado como objeto de Qt. La cadena "handler_signatura" describe el nombre y los parámetros de tipo controlador que se desea ajustar. La handler_function es una aplicación parcial de una función haskell de tipo:

   Global_Haskell_parameters -> handler_object_type -> handler_parameters

Hay que tener en cuenta que la función del manejador del ejemplo anterior termina con la llamada a la función keyPressEvent_h this ke. Ésta es una llamada a la función de la clase base del manejador que se requiere a menudo en la gestión de eventos, para “transmitir” los eventos a niveles más bajos donde procesarlos de forma normal. Este servicio está disponible para todas las funciones manejadoras en QtHaskell. El nombre de la función a llamar es el mismo que en la handler_string seguido de _h. Los parámetros requeridos son handler_object seguido de handler_parameters.

No hay necesidad de una subclase de objetos con el fin de establecer un controlador en él. Las subclases sólo se requieren para los objetos que tienen señales personalizadas o slots.

Ejemplo contador

En este caso presentamos un ejemplo algo más avanzado del uso de callbacks. Se trata de un contador de pulsaciones de teclas que hace uso del módulo IntMap de Haskell.

  1. module Main where
  2.  
  3. import Qtc.Classes.Qccs
  4. import Qtc.Classes.Qccs_h
  5. import Qtc.Classes.Gui
  6. import Qtc.ClassTypes.Gui
  7. import Qtc.Gui.Base
  8. import Qtc.Enums.Base
  9. import Qtc.Enums.Classes.Core
  10. import Qtc.Enums.Core.Qt
  11. import Qtc.Gui.QApplication
  12. import Qtc.Gui.QMessageBox
  13. import Qtc.Gui.QLabel
  14. import Qtc.Gui.QLabel_h
  15. import Qtc.Gui.QKeyEvent
  16. import Data.IORef
  17. import Data.IntMap
  18.  
  19. type CountMap = IntMap (IORef Int)
  20.  
  21. crearCM :: IO CountMap
  22. crearCM  = do
  23.   listaCeldas <- mapM (\x -> do
  24.     nr <- newIORef 0
  25.     return (x, nr)
  26.    ) [(qEnum_toInt eKey_A)..(qEnum_toInt eKey_Z)]
  27.   return $ fromList listaCeldas
  28.  
  29. main :: IO Int
  30. main = do
  31.   qApplication ()
  32.   tl <- qLabel "Pulsa una tecla de la 'A' a la 'Z'"
  33.   setAlignment tl (fAlignCenter::Alignment)
  34.   resize tl (200::Int, 60::Int)
  35.   mb <- qMessageBox tl
  36.   cm <- crearCM
  37.   setHandler tl "keyPressEvent(QKeyEvent*)" $ tlkp cm mb
  38.   qshow tl ()
  39.   qApplicationExec ()
  40.  
  41. tlkp :: CountMap -> QMessageBox () -> QLabel () -> QKeyEvent () -> IO ()
  42. tlkp cm mb this ke
  43.   = do
  44.     k <- key ke ()
  45.     if (member k cm)
  46.      then
  47.       do
  48.       cck <- readIORef $ cm ! k
  49.       let cp1 = cck + 1
  50.       t <- text ke ()
  51.       setText mb $ "Has pulsado la tecla '" ++ t ++ "' " ++ (tpf cp1) ++ "!"
  52.       modifyIORef (cm ! k) (\_ -> cp1)
  53.       qshow mb ()
  54.      else
  55.       return ()
  56.     keyPressEvent_h this ke
  57.   where
  58.     tpf c
  59.      | c == 1 = "una vez"
  60.      | c == 2 = "dos veces"
  61.      | c > 2 = (show c) ++ " veces"
  62.  

Módulos, funciones y tipos

Tras haber visto algunos programas básicos en QtHaskell, ahora se pasará a ver los módulos, funciones y tipos en esta librería.

Módulos

Por "módulos" nos referimos a módulos Haskell o unidades de un programa. La biblioteca QtHaskell está dividida en módulos, es decir, bloques de código que proveen funcionalidades independientes que se incluyen o importan al inicio de los programas según nuestras necesidades (Base, Gui, Network...). Los denominaremos "módulos Qt".

Los módulos que componen la librería de QtHaskell se pueden dividir en dos categorías principales:

  • Módulos Genéricos. Nos referimos al conjunto o a partes de la biblioteca de QtHaskell, pero no a clases Qt individuales. Para los diferentes tipos de módulos genéricos, por lo general (aunque no necesariamente) existe una correspondencia de cada uno de éste con un módulo Qt.
  • Clases de módulos específicos. Éstos contienen las definiciones de los constructores, métodos, etc para una clase específica.

A continuación se explicarán en profundidad cada una de estas categorías.

Módulos Genéricos

En el espacio de nombres Qtc podemos encontrar los siguientes tipos de módulos genéricos:

  • Módulos en el espacio de nombre Qtc.Classes. Estos módulos contienen definiciones de clases de Haskell para las funciones no estáticas de diferentes clases Qt, que comparten el mismo nombre de método. Hay un Qtc.Classes.QtModule por cada módulo Qt. Se se usan las clases Qt de un módulo Qt determinado, por ejemplo, Core, Gui, Network, etc, posiblemente será necesario importar el Qtc.Classes.QtModule del módulo Qt correspondiente. También existe el módulo Qtc.Classes.Qccs que incluye clases con nombres de métodos cómunes a más de un módulo Qt.
Ejemplos: Qtc.Classes.Core, Qtc.Classes.Gui, Qtc.Classes.Qccs.
Por cada módulo de los antes mencionados hay uno equivalente llamado Qtc.Classes.SomeModule_h. Los módulos con el sufijo "_h" contienen definiciones de clases para los ajustes de las funciones de manejadores y para las llamadas de funciones con sufijo "_h" basadas en métodos de clases que no son de una determinada clase Qt. El módulo Qcss_h se debe importar si los manejadores se deben establecer en cualquier clase desde SetHandler y funciones que usan el mismo nombre ara todos los módulos Qt.
Ejemplos: Qtc.Classes.Core_h, Qtc.Classes.Gui_h, Qtc.Classes.Qccs_h.
  • Módulos en el espacio de nombre Qtc.ClassTypes. Estos módulos contienen definiciones de todos los tipos de Haskell que corresponden a los classTypes Qt de un módulo Qt. Deben ser incluidos cuando se refiere a los tipos de Haskell explícitamente en función de las signaturas, o cuando son una subclase para crear espacios personalizados.
Ejemplos: Qtc.ClassTypes.Core, Qtc.ClassTypes.Gui, Qtc.ClassTypes.OpenGl.
  • Módulos llamados Qtc.SomeQtModuleName.Base. Estos módulos contienen algunas de las funciones de uso común, la mayoría de las cuales corresponden a los métodos de una clase del módulo Qt SomeQtModuleName
Ejemplos: Qtc.Core.Base, Qtc.Gui.Base.
  • El módulo Qtc.Enums.Classes.Core contiene las definiciones de clases de los valores de tipo enumerado que tienen nombres comunes a más de un tipo enumerado. Puesto que no hay muchos de estos en Qt ellos están contenidos en este módulo independientemente del módulo Qt al que pertenezcan.
  • El módulo Qtc.Enums.Base contiene funciones Haskell para la conversión de los tipos enumerados.

Clases de módulos específicos

En el espacio de nombres Qtc podemos encontrar los siguientes tipos de módulos específicos:

  • Módulos llamados Qtc.SomeQtModule.SomeQtClass. Estos son los módulos que definen las funciones Haskell para los constructores Qt, los métodos estáticos y destructores de la clase respectiva. Para las clases que tienen funciones virtuales también hay un módulo correspondiente Qtc.SomeQtModule.SomeQtClass_h que contienen las instancias que configuran los manejadores y las funciones con el sufijo "_h" de la clase base para la clase.
Ejemplos: Qtc.Core.QFile, Qtc.Gui.QWidget.
  • Módulos llamados Qtc.Enums.SomeQtModule.SomeQtClass. Estos contienen las definiciones de tipo enumerado, si las hay, para la clase Qt correspondiente.
Ejemplos: Qtc.Enums.Core.QlineF, Qtc.Enums.Gui.QMessageBox.
  • El módulo Qtc.Enums.Core.Qt que contiene las definiciones de los tipos enumerados para el espacio de nombres Qt de C++.

Espacio de nombres Qth

El espacio de nombres Qth tiene una estructura análoga a la del espacio de nombre Qtc con un directorio Classtypes y uno por módulo de clase para cada clase en un directorio Core. Muchas veces es necesario utilizar una importación de Qth.Core solo utilizando las clases Qth, ya que rara vez se utilizan de forma aislada.

Funciones

Vamos a ver algunos puntos importantes de las funciones de qhaskell.

"q"

Las funciones de QtHaskell que corresponden a miembros no estáticos de una clase Qt no están prefijadas con el nombre de esta clase. Esto significa que algunas de ellas (ej: show, read) son las mismas que las funciones del prelude de Haskell. Para evitar la necesidad de siempre cualificar entre una función de qtHaskell o una función del prelude, la función qtHaskell es prefijada con "q".

Las funciones qtHaskell que correspondan a cualquier constructor Qt o métodos que toman como parámetros de tipo: QRect, Qline, QPoint, QSize son implementadas tomando los parámetros correspondientes al tipo del nombre de la clase Qt, ej: Rect, Line, Point, Size. Una función que toma parámetros del tipo original se conserva y se prefija con "q". Un constructor ó métodoi estático en este caso tendrá una variante de la forma qqSomeConstructorOrStaticMethod. Los métodos no estáticos que toman parámetros de este tipo y cuyos nombres corresponden a funciones del prelude de Haskell tambien tomarán el prefijo de doble q "qq".

"_nf"

QtHaskell utiliza la recolección de basura nativa de Haskell para eliminar los objetos que corresponden a las clases de datos de Qt automáticamente. Los objetos de algunos de estos tipos de clase como Qimage, QPixmap y QBitmap no se copian internamente por Qt cuando se pasan como parámetros. Estos significa que por lo general, no se pueden eliminar cuando se salga del ámbito de una función Haskell.

Hay dos opciones disponibles para los programadores de haskell en el caso anterior (o en cualquier caso donde un objeto no se va a borrar automáticamente). Pueden almacenar una referencia a los datos del objeto en un tipo IORef del entorno Haskell, o si eso no es conveniente, se puede construir el objeto con un el sufijo "_nf".

Todos los constructores de objetos de QtHaskell tienn una forma "_nf" equivalente, la cual (como sugiere el prefijo), no devuelve una función de finalización para el puntero foráneo. En este caso, sin embargo, el objeto debe ser eliminado explícitamente con una llamada a la función qSomeQtClass_delete apropiada.

Hay también algunas funciones como qPixmapFromImagen y scale, que devuelven nuevas instancias de tipos de datos de Qt aunque no son constructores. Esas funciones tambien tiene forma con prefijo "_nf".

Destructores

Los destructores en QtHaskell tiene la forma qSomeQtClassName_delete y están disponibles para todas los tipos de datos de Qt. Como se discutió en la sección anterior, sólo deben ser usados con los tipos de datos de Qt si el objeto es creado con el sujifo "_nf".

Los destructores de la forma qSomeQtClassName_deleteLater están disponibles para todos los tipos de clases basados en QtObject. Estos destructores son usualmente requeridos para tales tipos de clases.

Tipos Enumerados

Las funciones QtHaskell para los valores de los tipos enumerados y sus correspondientes valores de tipo bandera tiene la forma eSomeEnumeratedTypeValue y fSomeFlagsTypeValue respectivamente. No hay diferencia entre el valor número actual asociado con las funciones "e" y "f" del mismo nombre, pero cada una puede solo ser usada con los parámetros de el tipo respectivo, y sólo las prefijadas con "f" pueden ser combinadas con el operador "+".

Las funciones de tipos enumerados y de bandera no están prefijadas con su correspondiente nombre de tipo, por tanto, la las mismas funciones pueden existir para más de un tipo. En ese caso cualquier uso de la función en cuestión debe ser explicitamente de tipo cualificado cuando se pasan como un patrametro en cualquier método de la función que tiene múltiples parámetros instanciados. Por ejemplo:

 setAlignment tl (fAlignCenter::Alignment)

Tipos

Los tipos en QtHaskell que se corresponden con una clase Qt QSomeQtClass tienen el formato QSomeQtClass a. Se implementan como sombras de tipos, por lo que si un parámetro en una función de qtHaskell tiene el tipo QSomeQtClass a, entonces cualquier objeto puede pasarse como parámetro si su tipo qtHaskell corresponde al tipo Qt QSomeQtClass o cualquier subclase del mismo. Si los tipos de subclase no se utilizan en los parámetros de una función de qtHaskell, se usará entonces el tipo QSomeQtclass ().

Tipos de tipos

Todos los tipos de qtHaskell cuya clase base es QObject también tienen un tipo QSomeQtClassc. Este tipo solo debe utilizarse cuando derivamos de un tipo qtHaskell para añadirle señales o slots adicionales personalizados, por ejemplo:

   type MyQDialog = QWidgetSc (CMyQDialog)

Los tipos enumerados de Qt tienen el formato de C++: QSomeQtClass::SomeQtEnumeratedOrFlagsType. El tipo correspondiente qtHaskell suele ser simplemente SomeQtEnumeratedOrFlagsType. En el caso en que el nombre del tipo enumerado sea compartido por más de una clase, el nombre del tipo qtHaskell pasa a ser SomeQtClassSomeQtEnumeratedOrFlagsType, por ejemplo:

   mb <- qMessageBox (eNoIcon::Icon, "", "", fNoButton::QMessageBoxStandardButtons, dialog)

qCast

Los objetos de QtHaskell pueden convertirse de un tipo a otro sin restricción alguna. Para algunas clases de QtHaskell, hay una función correspondiente qCast_SomeQtClass. Esto convierte un objeto al tipo SomeQtClass manteniendo el valor del puntero interno del valor de retorno. De cualquier modo, esta función debe utilizarse con cautela.

Referencias



Herramientas personales