Capítulo 2.- ¡Esta vivo! ¡vivoooooo! ¡JAJAJA!

De doc.ubuntu-es
Saltar a: navegación, buscar

Contenido

Introducción

En este capítulo vamos a aprender a crear una ventana, y con ello empezaremos a trazar un protocolo sobre la creación de diálogos y "canvas", que iremos puliendo en los siguientes capítulos.

Creación de nuestra primera ventana

El primer paso sera recuperar el trabajo donde lo dejamos, esto se puede hacer de dos formas, abriendo code::blocks, el cual nos mostrará los proyectos más recientes, o directamente desde la carpeta /home/user/proyectos_codeblocks/learn_0.01, haciendo dobleclick sobre learn_0.01.cbp.

  • Es una buena política, aunque en nuestro caso innecesaria, pues sólo estamos jugueteando, cada vez que vayamos a cambiar algo, crear una nueva versión, es decir, duplicar la carpeta /home/user/proyectos_codeblocks/learn_0.01 en /home/user/proyectos_codeblocks/learn_0.02.

Realmente, la forma más purista sería crear un nuevo proyecto, copiar todos los fuentes y los headers del antiguo, e importarlos, pero eso sólo cuando vayamos a lanzar una versión de verdad.

Pero sigamos a lo nuestro... Una vez recuperado nuestro trabajo, sin duda ninguna tendremos que trazarnos un plan de trabajo:

  • Plan de trabajo del capítulo 2:
    En este capítulo nos conformaremos con poco, simplemente crearemos una ventana con el título "Welcome to wxWidgets!" (como en los ejemplos de wxWidgets, nada original), la cual tendrá una barra de menús con el menu file/exit. El uso del menu lo dejaremos para un capítulo posterior, que no es bueno forzar...

Asi que al turrón, la ventana que vamos a insertar es un tanto especial, y no es la que usaremos habitualmente, se trata de wxFrame (en el resto de ocasiones usaremos wxDialog, y en su día entenderemos la diferencia, aunque podeís encontrarla en la documentación). Así que lo primerísimo que tenemos que hacer es tener bien presente la información necesaria sobre wxFrame, por lo tanto abrimos nuestro wx.chm (preludio de este capítulo), y en la pestaña índice buscamos wxFrame.

Breves anotaciones sobre la documentacion:

Siempre que busquemos cualquier elemento, nos apareceran en este orden las siguientes cosas:

  • Una breve descripcion del elemento
  • Los includes que son necesarios. Muchas veces, estos includes ya estan llamados por otros, asi que os recomiendo no incluirlos a menos que recibais un error en la compilacion que os diga que no esta declarado.
  • Los macros de los estilos, si los tiene (ya hablaremos de ellos, espero...)
  • Los eventos que maneja (Tambien hablaremos de ellos, seguro)
  • Anotaciones
  • Temas relacionados
  • Funciones miembro, de las cuales la primera, y mas importante, siempre sera el constructor


Bueno, Ahora que ya tenemos localizado el elemento a introducir, aparquemos momentaneamente esa información, ya que antes debemos darle un nombre, ¡"TopFrame" será una buena alternativa!

Asi que por dicho, vamos a crear nuestra clase, para ello vamos a Code::Blocks y creamos dos archivos, "topframe.cpp" y "topframe.h". (Por supuesto, todo lo que se encuentre en un tutorial anterior no se repite)

Como es lógico, empezaremos por la cabecera, asi que abrimos "topframe.h", y borramos la morralla que nos haya creado (dejándolo), y creamos nuestra clase:

class TopFrame : public wxFrame
{
};

Efectivamente, declaramos una clase llamada TopFrame, que hereda todas las propiedades de wxFrame. Ahora nos disponemos a crear el constructor, éste constructor debe recibir todos los parametros que pudieran ser necesarios para wxFrame, asi que recuperamos nuestra documentación, y buscamos el constructor de wxFrame (wxFrame::wxFrame). Solo tiene un posible constructor, así que no hay mucho donde elegir (para los que el tema de las clases no les sea familiar, simplemente, que no se estressen, lo irán entendiendo poco a poco), así que analizemos los parametros que debe recibir:

  • wxWindow* parent: Se tratará del elemento que la crea, o que la contiene, en este caso ninguno, pues para algo es nuestra TopFrame (no dependerá ni de nada nji de nadie). Así que este parametro no habrá de recibirlo (en TopFrame, clar esta, y si no lo está, lo va a estar enseguida), pues siempre será NULL.
  • wxWindowID id: De momento no vamos a introducir la utilidad de los id, simplemente decir que cuando no nos interesa tenerlo (como es el caso), ponemos wxID_ANY. Así que este tampoco será un parametro a solicitar.
  • const wxString& title: Será el título de nuestra ventana. A partir de ahora, salvo casos excepcionales, wxString serán nuestras cadenas de texto por defecto (podeís ir buscando un poco de información, pero las vamos a trillar tanto que las conocereis como a vuestras hijas). Aunque en un principio este valor también lo conocemos, lo meteremos como parámetro, por tener alguno...
  • Parámetros con valor por defecto: Los siguientes parámetros, ya tienen un valor por defecto, y por ahora para nosotros, ese valor estará bien (si acaso os sentís con ánimo, jugar un poco a ver si conseguis tocotear)
    • Posición: (en wxWidgets, las posiciones siempre se cuentan desde la esquina superior izquierda, es decir, esta sería la posición de la esquina superior izquierda de la ventana respecto de la esquina superior izquierda de la pantalla). Se podría introducir por ejemplo como wxPoint(15,15), lo que la situaría en el pixel 15,15.
    • Tamaño: Medido en pixeles, se podría meter como wxSize(100,100), lo que haría que la ventana tuviera un tamaño de 100x100 pixels
    • Estilo: Sería activar los macros que te gusten, para mezclar macros se hace con el simbolo "|", por ejemplo: wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxRESIZE_BORDER | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN.
    • Nombre: Se usan para la ayuda, nosotros no llegaremos a usarlo, pero esta bien saberlo.

Así que nada, ya lo tenemos clarísimo, nuestra wxFrame tan sólo solicita de TopFrame el título de la ventana, y como nuestro TopFrame no requiere datos adicionales (de momento), este será el único parámetro que solicitará, así que añadamos nuestro constructor a la clase:


 class TopFrame : public wxFrame
 {
 public:
     TopFrame(wxString Title);
 };


El constructor siempre será una clase pública, pues se tiene que poder acceder a él.

  • Respecto de public:
    • Public: Todo el código puede acceder a él.
    • Protected: Sólo la propia clase, y sus heredadas pueden acceder a él.
    • Private: Sólo la propia clase puede acceder a él.

De momento nuestro TopFrame no tendrá nada más, así que cambiémonos a "topframe.cpp" para implementar el constructor. Evidentemente, lo primero que querremos en "topframe.cpp" serán las cabeceras (las estandar de C, las de wxWidgets, y la cabecera que acabamos de crear), así que nuestras primeras lineas serán:

#include <math.h>
#include <stdio.h>
#include <wx/wx.h>
#include <wx/string.h>
#include "topframe.h"

Fijaos que he añadido la libreria wx/string.h, probar a no añadirla, vereís que pronto os dice que wxString no esta definida.

Y ahora a implementar el constructor, así que nuestras siguientes líneas serán:

TopFrame::TopFrame(wxString Title)
{
    
}

Donde efectivamente creamos el constructor de TopFrame, que debe recibir el parámetro Title, de tipo wxString, pero hace falta implementarle la clase heredada, así que a continuación, o debajo (como hago yo) introducimos la siguiente línea:

 TopFrame::TopFrame(wxString Title)
 : wxFrame(NULL, wxID_ANY, Title)
 {
     
 }

Donde a wxFrame, como parent, le pasamos NULL, como id le pasamos wxID_ANY, y como título le pasamos el título que ha recibido TopFrame, llamado Title. ¿Empezais a verle el truquillo?

Claro, eso requiere que cada vez que haya que llamar a TopFrame (en este caso no hay problema, pues sólo lo haremos una vez) haya que pasarle el título, pero ¿no sería mas lógico que ya tuviera un título preasignado? Pues sí, lo sería, así que volvamos a "topframe.h", y cambiemos ligeramente el constructor:

 class TopFrame : public wxFrame
 {
 public:
     TopFrame(wxString Title = _T("Welcome to wxWidgets") );
 };

De esta forma, en caso de omisión de este parámetro, asumirá que queríamos pasarle _T("Welcome to wxWidgets").

  • Respecto de _T("Welcome to wxWidgets")...
    • _() Es un wxString que establece que el texto incluido dentro se lee como tal, es decir, no interpreta los \n, ni los \t, ni los %d, ni nada por el estilo.
    • _T() Es un wxString que establece que el texto incluido dentro se lee como tal, pero interpreta los \n, y los \t, aunque no los %d, ni nada por el estilo.
    • wxT() Es un wxString que realiza interpretaciones, como por ejemplo de los \n, de los \t, de los %d etc...

Esta última línea puede no ser correcta, os recomiendo buscar en la documentación

Bueno, ya tenemos la clase completa, vamos a llamarala desde nuestro main, así que abrimos "main.cpp", y una vez allí lo primero que necesitaremos serán las nuevas cabeceras (la de wxString y la de Topframe), así que los includes ahora quedarán así:

#include <math.h>
#include <stdio.h>
#include <wx/wx.h>
#include <wx/string.h>
#include "topframe.h"
#include "main.h"
  • ¡CUIDADO!: Parece una chorrada, pero el orden es importante, si hubiéramos incluido antes "main.h", no podriamos declarar dentro de "main.h" nada referente a TopFrame. En este caso no será importante, pero más tarde si lo será.

En fin, continuemos... El siguiente paso lógico es declarar una TopFrame para nuestro programa, así que añadimos la siguiente línea al código:

 IMPLEMENT_APP(SampleApp)
 bool SampleApp::OnInit()
 {
     TopFrame *frame;
     return true; //true == run the app
     //no delete!!! it's implement in destroy();
 }

Vereís que jugamos muchas veces con la declaración de los tipos: TopFrame *frame; TopFrame frame;

La más interesante es la primera, pero requiere más operaciones, así que cuando podamos optaremos por la segunda.

El siguiente paso es llamar al constructor:

 IMPLEMENT_APP(SampleApp)
 
 bool SampleApp::OnInit()
 {
     TopFrame *frame;
     //frame = new TopFrame();
     frame = new TopFrame(_T("Welcome to wxWidgets!"));
     return true; //true == run the app
     //no delete!!! it's implement in destroy();
 }

Como puedes ver pongo dos constructores diferentes, uno de ellos comentado, si descomentas el primero, y comentas el segundo (cuando hayamos acabado) verás que el título de la ventana pasa de ser "Welcome to wxWidgets!" a ser "Welcome to wxWidgets", que era el que pusimos por defecto.

Bueno, si probaras a compilar ahora, y a ejecutar, el código haría lo mismo que antes, solo que encima ahora nunca se cerraría, y habría que cerrarlo o por Code::Blocks, o por el administrador de procesos. Así que falta una orden para que nos muestre la ventana, como ya hemos dicho, wxFrame es una clase un poquito especial, así que quedaos con que la siguiente orden funciona, aunque no la veais en su documentación, porque la tiene heredada.

 IMPLEMENT_APP(SampleApp)
 
 bool SampleApp::OnInit()
 {
     TopFrame *frame;
     //frame = new TopFrame();
     frame = new TopFrame(_T("Welcome to wxWidgets!"));
     frame->Show(true);	//show the frame of application
     return true; //true == run the app
     //no delete!!! it's implement in destroy();
 }

Y por último, por juguetear un poco, vamos a maximizar:

 IMPLEMENT_APP(SampleApp)
 bool SampleApp::OnInit()
 {
     TopFrame *frame;
     //frame = new TopFrame();
     frame = new TopFrame(_T("Welcome to wxWidgets!"));
     frame->Show(true);	//show the frame of application
     frame->Maximize();	//maximize the frame of application
     return true; //true == run the app
     //no delete!!! it's implement in destroy();
 }

Prueba a compilar y a ejecutar, y a ver que ocurre... ¡¡¡Éxito!!! Aquí tenemos nuestra ventana maximizada dándonos la bienvenida.

Introducción de una barra de menús

Para poner la guinda al pastel, vamos a añadir la barra de menús, que nos servirá en el próximo capítulo...

Para ello vamos hasta el constructor de TopFrame en "topframe.cpp", y añadimos las siguientes órdenes...**Recordar, toda esta informacion la teneis en la documentación**

  1. Creamos un elemento menú:
     TopFrame::TopFrame(wxString Title)
     : wxFrame(NULL, wxID_ANY, Title)
     {
     	//creamos un menu muy simple
     	wxMenu *fileMenu = new wxMenu;
     }
  1. Le añadimos el comando "Exit Alt+F4"
     TopFrame::TopFrame(wxString Title)
     : wxFrame(NULL, wxID_ANY, Title)
     {
     	//creamos un menu muy simple
     	wxMenu *fileMenu = new wxMenu;
     	fileMenu->Append(wxID_EXIT, _T("&Exit\tAlt-F4"), _T("Termina el programa"));
     }

wxID_EXIT es un ID que ya conoce wxWidgets, normalmente tendremos que crear nosotros nuestros ID, que lo haremos en el siguiente capítulo...

  1. Declaramos y creamos la menubar
     TopFrame::TopFrame(wxString Title)
     : wxFrame(NULL, wxID_ANY, Title)
     {
     	//creamos un menu muy simple
     	wxMenu *fileMenu = new wxMenu;
     	fileMenu->Append(wxID_EXIT, _T("&Exit\tAlt-F4"), _T("Termina el programa"));
     	wxMenuBar *menuBar = new wxMenuBar();
     }

Esta es otra forma muy típica de actuár, realizar la declaración y la construcción en la misma línea.

  1. Añadimos el elemento menu, y le seteamos a Topframe la menubar
     TopFrame::TopFrame(wxString Title)
     : wxFrame(NULL, wxID_ANY, Title)
     {
     	//creamos un menu muy simple
     	wxMenu *fileMenu = new wxMenu;
     	fileMenu->Append(wxID_EXIT, _T("&Exit\tAlt-F4"), _T("Termina el programa"));
     	wxMenuBar *menuBar = new wxMenuBar();
     	menuBar->Append(fileMenu, _T("&File"));
     	SetMenuBar(menuBar);
     }

Finalmente nuestros archivos quedan de la forma:

main.h:

class SampleApp : public wxApp
{
public:
	virtual bool OnInit();
};

main.cpp:

#include <math.h>
#include <stdio.h>
#include <wx/wx.h>
#include <wx/string.h>
#include "topframe.h"
#include "main.h"

/**********************************************************************/
/************** This function run the application         *************/
/************** can force some parameters too (p.ej size) *************/
/**********************************************************************/

IMPLEMENT_APP(SampleApp)

bool SampleApp::OnInit()
{
    TopFrame *frame;
    //frame = new TopFrame();
    frame = new TopFrame(_T("Welcome to wxWidgets!"));
    frame->Show(true);	//show the frame of application
    frame->Maximize();	//maximize the frame of application
    return true; //true == run the app
    //no delete!!! it's implement in destroy();
}

topframe.h:

class TopFrame : public wxFrame
{
public:
    TopFrame(wxString Title = _T("Welcome to wxWidgets"));
};

topframe.cpp:

#include <math.h>
#include <stdio.h>
#include <wx/wx.h>
#include <wx/string.h>
#include "topframe.h"

TopFrame::TopFrame(wxString Title)
: wxFrame(NULL, wxID_ANY, Title)
{
	//creamos un menu muy simple
	wxMenu *fileMenu = new wxMenu;
	fileMenu->Append(wxID_EXIT, _T("&Exit\tAlt-F4"), _T("Termina el programa"));
	wxMenuBar *menuBar = new wxMenuBar();
	menuBar->Append(fileMenu, _T("&File"));
	SetMenuBar(menuBar);
}

Compila y ejecuta... Verás que ha aparecido el menú, pero que no hace nada, así que... ¿Qué toca hacer ahora? Efectivamente, ¡empezar a manejarlo! Pero eso será en el siguiente capítulo...


Capítulo 1.- ¡Mama! ¡Mama! mira lo que hago... Nuestra primera interfaz gráfica con CodeBlocks y wxWidgets Capítulo 3: ¡Qué aburrido! yo quiero interactuar
Herramientas personales