Introducción

wxWidgets es una librería de clases diseñada para crear aplicaciones con interfaz gráfica (GUI). Al tratarse de una librería de clases, se necesita un lenguaje orientado a objetos para usarla. En nuestro caso, por supuesto, se trata de una librería para programar en C++.
Es una librería multiplataforma, es decir, está disponible para varias plataformas diferentes: Windows, Linux y macOS. Esto significa que el mismo código funcionará en diferentes sistemas operativos, y creará aplicaciones similares y compatibles.
Aunque ses una librería multiplataforma, los ejemplos que se expondrán aquí estarán probados en Windows, usando el IDE Code::Blocks, pero deberían funcionar en cualquier otra plataforma sin modificaciones, o con modificaciones mínimas.
La licencia de la librería wxWindows ha sido aprobada por la Open Source Initiative. Esta licencia tiene por objeto proteger la propia librería, a sus desarrolladores y a sus usuarios. Para más detalles ver Licencia de wxWidgets.
Veremos que usar estas librerías tiene muchas ventajas comparando con usar el API del sistema operativo:
- Al ser multiplataforma no será necesario crear una aplicación diferente para cada sistema operativo, en el caso de que queramos que nuestras aplicaciones puedan usarse en diferentes plataformas.
- La programación orientada a objetos simplifica mucho el diseño de las aplicaciones. Ya en los primeros ejemplos veremos que tenemos que escribir mucho menos código para obtener las mismas aplicaciones que usando directamente el API.
- Disponemos de muchas herramientas que facilitan el diseño de cuadros de diálogo y de validación de datos.
- Podemos usar ficheros de imágenes en muchos formatos diferentes, en lugar de limitarnos, por ejemplo, a los BMP en Windows, o a usar librerías externas si queremos usar otros formatos.
- Y otras ventajas que veremos en el futuro.
Formatos de librerías
Existen varias opciones a la hora de disponer de las librerías para wxWidgets. Podemos dividir estas librerías en varias categorías:
- Producción y depuración. Normalmente dispondremos de dos juegos de librerías de wxWidgets, aunque en ciertos casos es posible que no estén los dos:
- La versión de depuración (debugger) contiene información para la depuración de la propia librería. Raramente vamos a depurar el código de wxWidgets, pero es posible que nos interese disponer de estas versiones. De hecho, las plantillas de Code::Blocks las usan para generar las versiones de depuración de nuestras aplicaciones. Una ventaja de esta versión de las librerías es que lanzarán asserts en determinadas circunstancias, ayudándonos a depurar posibles errores difíciles de detectar en las versiones de producción.
- La versión de producción (release) es más compacta, los ficheros son mucho más pequeños, lo que siempre es preferible para las versiones finales.
- Con o sin soporte UNICODE. Las librerías se pueden compilar con soporte UNICODE o sin él, pero siempre que podamos usaremos las librerías con soporte UNICODE, ya que son más versátiles.
- Librerías monolíticas o separadas. Podemos optar por las versiones monolíticas o las no monolíticas.
- Las versiones monolíticas contienen en una única DLL todo el código necesario para ejecutar aplicaciones basadas en wxWidgets. Se entiende que una DLL para depuración y otra para producción, y que puede tener o no soporte UNICODE. Esto facilita la tarea de generar los ejecutables, ya que solo necesitaremos añadir una librería al enlazador, y también la instalación en otros equipos, de modo que será necesario copiar menos ficheros. Por contra, el tamaño de las DLL es mayor.
- Las no monolíticas dividen el código en varias DLL. Como nuestras aplicaciones probablemente no necesitarán usar todas las características de wxWidgets, nuestros ejecutables no necesitarán tener acceso a todas las DLL. Por ejemplo, si no usamos HTML o XML o RichEdit, no usaremos esas DLL.
- Dinámicas y estáticas. Por último, podemos disponer de librerías de enlace dinámico, DLL, o de enlace estático.
- Las DLL tienen la ventaja de que los ejecutables son más livianos, y las librerías se pueden compartir por varias aplicaciones.
- Las de enlace estático generan ejecutables más pesados, pero no requieren la instalación de librerías externas, y se obtienen aplicaciones "standalone", independientes.
En todos los casos tendremos que disponer de librerías de enlace estáticas para incluir en nuestras aplicaciones. Si usamos las DLL estas librerías de enlace estático son las que permiten acceder las DLL correspondientes y mapear las funciones dentro de ellas. En el caso de las estáticas se incluyen íntegramente en el enlazado del ejecutable final.
Reglas para los identificadores de las librerías
Debido a esta variedad de opciones para las librerías, se han establecido ciertas normas a la hora de nombrarlas.
Para las DLL los nombres se ajustan a esta plantilla:
wxSSSXX[u][d][_TTTT]_[com][YYYY]_[xNN].dll
Donde:
- SSS: plataforma para la que están compiladas, por ejemplo, para Windows es 'MSW'.
- XX: es la versión de wxWidgets (sin puntos). Por ejemplo, '32', para las versiones 3.2.nn.
- u: si aparece es la versión con soporte UNICODE.
- d: si aparece es la versión de depuración.
- TTTT: en versiones no monolíticas, el tipo de de la librería. Por ejemplo 'html' para soporte HTML o 'richedit' para soporte de texto enriquecido.
- com: compilador usado para crear las DLL, por ejemplo 'gcc' para GCC.
- YYYY: versión del compilador, (sin puntos). Por ejemplo, '1220' para la versión 12.20 de GCC.
- xNN: x64 o x32, para las versiones de 64 o 32 bits.
Por ejemplo, "wxmsw32ud_html_gcc1220_x64.dll" es la librería para la versión 3.2 de wxWidgets, con soporte UNICODE, de depuración, para las funciones HTML, compilado con las versión 12.20 de GCC y de 64 bits.
Además encontraremos otras DLL cuyos nombres empiezan con 'wxbase', como wxbase32u_gcc1220_x64.dll.
Para las librerías de enlace estático los nombres se ajustan a esta plantilla:
libwxSSSXX[u][d][_TTTT].a
Con el mismo significado.
Además encontraremos otras librerías con nombres como "libwxbaseXX[u][d][_TTT].a", en las que TTT puede no aparecer, o ser "net" o "xml", así como librerías para usar jpeg, png, zlib, regex, etc.
Eventos y clases
Las aplicaciones que se crean usando wxWidgets, como todas las aplicaciones GUI, se basan en eventos. En este contexto, un evento es cualquier cosa que pase y que pueda afectar al funcionamiento del programa, por ejemplo, un click del ratón, una pulsación de tecla, una señal de un temporizador, una petición desde otro programa, etc. Literalmente, se producen cientos de eventos cada minuto, aunque nuestra aplicación no tiene por qué responder a todos ellos.
Una de las tareas que tenemos que llevar a cabo al escribir un programa es decidir a qué eventos tenemos que responder. Para ello, en general, a cada objeto wxWidgets le corresponderá una tabla de eventos, que definen cuales de ellos procesaremos.
Hay dos formas de que nuestra aplicación responda a los eventos.
Por ejemplo, un programa pude definir una tabla de eventos de esta forma:
BEGIN_EVENT_TABLE(wxEjemploFrame, wxFrame) EVT_CLOSE(wxEjemploFrame::OnClose) END_EVENT_TABLE()
Estas tablas gestionan los eventos estáticamente.
Las tablas de eventos se definen mediante macros, empezando por BEGIN_EVENT_TABLE, que como primer parámetro tiene el identificador del objeto, y como segundo parámetro la clase a la que pertenece. A continuación aparecerá una lista de los eventos a los que queremos responder, y que están definidos en la clase, con un número de parámetros que dependerá del tipo de evento. En nuestro ejemplo, la tabla de eventos está vacía, pero según vayamos avanzando en el curso veremos diferentes tipos de eventos. Finalizaremos la tabla de eventos con la macro END_EVENT_TABLE.
Nuestra clase, en este ejemplo wx001Frame, debe declarar la tabla de eventos mediante la macro DECLARE_EVENT_TABLE().
La otra forma de definir las respuestas a eventos es la dinámica, que usa el método Connect que pertenece a la clase wxEvtHandler, y que veremos con más detalle más adelante.
Connect(idMenuQuit,wxEVT_MENU, (wxObjectEventFunction)&wxEjemploFrame::OnQuit);
Cada clase que encapsule una ventana puede definir su propia colección de eventos, así como sus métodos públicos y sus datos miembro.
Documentación
En este curso, como viene siendo habitual en la página, se incluye una traducción de la documentación oficial, aunque debido a su extensión no estará completa y tampoco actualizada. Debido a que las librerías están en constante actualización, la documentación tampoco será uniforme en cuanto a versiones, cada referencia puede pertenecer a versiones diferentes, y seguramente se produzcan algunas inconsistencias. En caso de duda siempre será una buena opción acudir a la documentación oficial.
Puedes consultar la documentación original en la página documentación wxWidgets. (O a otras versiones, ya que en el momento de escribir esto, la versión 3.3 está bastante adelantada).
Instalación
Para conocer las diferentes opciones a la hora de instalar las librerías wxWidgets consultar los apéndices. La opción recomendada es la del apéndice A.
Cuadro de diálogo de mensaje
Una de las funciones más utilizadas es wxMessageBox, que nos permite mostrar un mensaje en pantalla en un cuadro de diálogo simple. Tendremos que indicar como parámetros el mensaje que queremos mostrar, un texto para el título, y opcionalmente un estilo, que por defecto es wxOK | wxCENTRE, que mostrará un botón de "Aceptar" centrado, un puntero a la ventana padre, y las coordenadas. Usaremos estas cajas de mensaje para indicar al usuario errores, o el resultado de ciertas acciones en los programas de ejemplo.
Contenido del curso de wxWidgets
Empezaremos por hablar de los diferentes tipos de aplicaciones, basadas en marcos o en diálogos. A continuación explicaremos cómo usar los menús y botones.
Después veremos algunos de los diferentes tipos de controles disponibles en wxWidgets.
Muchos de ellos nos serán familiares si somos usuarios de sistemas operativos con interfaces basadas en ventanas, como Windows (que hemos tratado en el curso del API de Windows), pero al tratarse de una librería multiplataforma también incorpora otros controles procedentes de otros entornos, así como controles que son exclusivos de wxWidgets.
Todos los controles están disponibles a través de una clase que los encapsula y que se deriva, directa o indirectamente, de la clase wxControl.
wxWidgets dispone de herramientas muy útiles para el diseño de cuadros de diálogo, que permiten distribuir los controles de forma automática mediante ciertas directrices, denominadas sizers. Además, también dispone de herramientas útiles para la validación de datos. Veremos esos conceptos en el capítulo 4.
Repasaremos el concepto de GDI (Interfaz de Dispositivo Gráfico), que permite el trazado de gráficos en cualquier dispositivo de salida.