Capítulo 3: ¡Qué aburrido! yo quiero interactuar

De doc.ubuntu-es
(Diferencias entre revisiones)
Saltar a: navegación, buscar
m (Evento cerrar del menú)
 
(No se muestran 5 ediciones intermedias realizadas por 2 usuarios)
Línea 42: Línea 42:
 
Lo cierto es que nuestros eventos serán una cosa privada (private:), que sólo la clase en cuestión debe manejar, ya no sólo porque es intuitivamente lo lógico, sino porque nos puede ahorrar algunos problemillas.
 
Lo cierto es que nuestros eventos serán una cosa privada (private:), que sólo la clase en cuestión debe manejar, ya no sólo porque es intuitivamente lo lógico, sino porque nos puede ahorrar algunos problemillas.
  
Bueno, hemos declarado la tabla de eventos, ahora vamos a declarar un método para controlar el evento. Llamémoslo por ejemplo "OnQuit", y lo pondremos como privado, ya que será el que maneje el evento... No obstante, puede ocurrir que más tarde algún elemento pueda tener la necesidad de cerrar el programa, así que la gestión de cierre deberá ser algo publico, así que crearemos otro método llamado "Quit", que será realmente el que nos cierre la aplicación (todo esto tendrá un transfondo mucho más interesante, que entenderemos más adelante). También necesitamos saber que tipo de evento manejaremos, así que en nuestra API (a partir de ahora denominaremos así al wx.chm) buscamos wxMenu, y en el apartado "Event handling", nos da este evento: "wxCommandEvent", que será el que habremos de usar...
+
Bueno, hemos declarado la tabla de eventos, ahora vamos a declarar un método para controlar el evento. Llamémoslo por ejemplo "OnQuit", y lo pondremos como privado, ya que será el que maneje el evento... No obstante, puede ocurrir que más tarde algún elemento pueda tener la necesidad de cerrar el programa, así que la gestión de cierre deberá ser algo publico, así que crearemos otro método llamado "Quit", que será realmente el que nos cierre la aplicación (todo esto tendrá un transfondo mucho más interesante, que entenderemos más adelante). También necesitamos saber que tipo de evento manejaremos, así que en nuestra API (a partir de ahora denominaremos así al wx.chm o a la [http://docs.wxwidgets.org/stable/ página de documentación oficial]) buscamos [http://docs.wxwidgets.org/stable/wx_wxmenu.html#wxmenu wxMenu], y en el apartado "Event handling", nos da este evento: "wxCommandEvent", que será el que habremos de usar...
  
 
Así pues, nuestra cabecera deberá modificarse así:
 
Así pues, nuestra cabecera deberá modificarse así:
Línea 284: Línea 284:
 
     toolBar->SetToolBitmapSize(wxSize(32, 32));//recoratara las imagenes a 32x32
 
     toolBar->SetToolBitmapSize(wxSize(32, 32));//recoratara las imagenes a 32x32
  
Que hace exactamente lo que pone en los comentarios, y por último añadimos nuestros dos elementos:
+
Que hace exactamente lo que pone en los comentarios, y por último añadimos nuestros dos elementos y seteamos la toolBar:
  
 
     toolBar->AddTool(ID_START, wxBITMAP(start), wxNullBitmap, false, wxDefaultCoord, wxDefaultCoord, (wxObject *)NULL, _T("Start"), _T("Run the progress bar"));
 
     toolBar->AddTool(ID_START, wxBITMAP(start), wxNullBitmap, false, wxDefaultCoord, wxDefaultCoord, (wxObject *)NULL, _T("Start"), _T("Run the progress bar"));
 
     toolBar->AddTool(ID_STOP, wxBITMAP(stop), wxNullBitmap, false, wxDefaultCoord, wxDefaultCoord, (wxObject *)NULL, _T("Start"), _T("Run the progress bar"));
 
     toolBar->AddTool(ID_STOP, wxBITMAP(stop), wxNullBitmap, false, wxDefaultCoord, wxDefaultCoord, (wxObject *)NULL, _T("Start"), _T("Run the progress bar"));
 +
 
 +
    toolBar->Realize();
  
 
Como siempre, para saber que es lo que hace cada parámetro, recurrir a la API. Aunque cabe destacar la imagen, que hemos introducido con:
 
Como siempre, para saber que es lo que hace cada parámetro, recurrir a la API. Aunque cabe destacar la imagen, que hemos introducido con:
Línea 391: Línea 393:
  
 
¡Algo va mal! ¡No puedo pararlo! ¡La barra no se actualiza!. Bien, vuelve a code::blocks, y usa el botón rojo con un aspa blanca para detener el código.
 
¡Algo va mal! ¡No puedo pararlo! ¡La barra no se actualiza!. Bien, vuelve a code::blocks, y usa el botón rojo con un aspa blanca para detener el código.
 +
 +
==== Cola de eventos ====
  
 
Bien, el primer problema a corregir es que no podemos parar el código, esto se debe a que, aunque efectivamente al presionar cualquier botón se genera un evento, este evento no se procesa nunca, ya que nuestro código esta enfrascado en un bucle sin fin, así que parece estar claro ¿no?, tenemos que pedirle a nuestro código que procese los evento que se generen dentro del bucle, eso se hace (buscando como siempre en el API) con dos órdenes llamadas Pending() y Dispatch(). Pero claro, ambas órdenes forman parte de wxApp, luego necesitamos que TopFrame conozca SampleApp (que es nuestra wxApp).
 
Bien, el primer problema a corregir es que no podemos parar el código, esto se debe a que, aunque efectivamente al presionar cualquier botón se genera un evento, este evento no se procesa nunca, ya que nuestro código esta enfrascado en un bucle sin fin, así que parece estar claro ¿no?, tenemos que pedirle a nuestro código que procese los evento que se generen dentro del bucle, eso se hace (buscando como siempre en el API) con dos órdenes llamadas Pending() y Dispatch(). Pero claro, ambas órdenes forman parte de wxApp, luego necesitamos que TopFrame conozca SampleApp (que es nuestra wxApp).
Línea 407: Línea 411:
 
   (...)
 
   (...)
  
Y lo implementamos en "<b>topframe.cpp</b>"
+
Y lo implementamos en "<b>topframe.cpp</b>", empezando porque ahora nuestra clase hace uso de SampleApp, luego necesitamos su cabecera, así que añadimos lo siguiente:
  
la barra se mantiene inmutable, como oir llover vamos, esto se debe a que aunque nosotros actualizamos la barra, no actualizamos la ventana (topframe), luego esta no pinta los cambios.  
+
  (...)
 +
  #include "stop.xpm"
 +
  <b>#include "main.h"</b>
 +
  #include "topframe.h"
 +
  #include "header.h"
 +
  (...)
  
   Contruyendo...
+
Es fundamental el orden, ya que cuando incluyas "topframe.h", esta ya debe conocer el contenido de "minimal.h" (es interesante probar a cambiarlo, para ver como nos devulve un error de que SampleApp no esta declarado). Este orden será necesario cambiarlo también en "main.cpp"
 +
 
 +
Y por supuesto tenemos que cambiar el constructor:
 +
 
 +
  TopFrame::TopFrame(<b>SampleApp * AApp</b>, wxString Title)
 +
  : wxFrame(NULL, wxID_ANY, Title)
 +
  {
 +
  <b>App = AApp;</b>
 +
  (...)
 +
 
 +
Donde efectivamente recibimos un SampleApp, e inmediatamente después lo volcamos sobre una variable nuestra.
 +
 
 +
Lo único que resta para poder disfrutar nuestro SampleApp es mandarselo en "<b>main.cpp</b>", así que cambiamos la orden de la siguiente manera:
 +
 
 +
  (...)
 +
    frame = new TopFrame(<b>this,</b> _T("Welcome to wxWidgets!"));
 +
  (...)
 +
 
 +
Y ya está, ya podemos usar a SampleApp en nuestra TopFrame.
 +
 
 +
Bien, las órdenes que queremos usar se utilizan como sigue (en "<b>topframe.cpp</b>"):
 +
 
 +
  void TopFrame::OnStart(wxCommandEvent& WXUNUSED(event))
 +
  {
 +
      int i;
 +
      <b>bool token_true;</b>
 +
 
 +
      m_running = true;
 +
 
 +
      while(m_running)
 +
      {
 +
          for(i=1;i<=100;i++)
 +
          {
 +
              ProgressBar->SetValue(i);
 +
          }
 +
          for(i=99;i>=2;i--)
 +
          {
 +
              ProgressBar->SetValue(i);
 +
          }
 +
          <b>while((TopFrame *) App->Pending())
 +
          {
 +
              token_true=(TopFrame *) App->Dispatch();
 +
          }</b>
 +
      }
 +
  }
 +
 
 +
Efectivamente son unas órdenes un poco extravagantes, pero nuevamente asumimos que se usan así, y no nos preocupamos más. Efectivamente, declaramos un tolken_true, que realmente es una variable basura, para dar coherencia de compilación. Y cada vez que la barra de progreso haga un "release", nos dedicamos a procesar evento mientras sigan existiendo evento pendientes.
 +
 
 +
Compilamos y ejecutamos...
 +
 
 +
¡Algo hace! Pero desde luego, el gra avance es que podemos detener el código.
 +
 
 +
Nuestro siguiente problema es que la barra de progreso se mantiene inmutable (o casi), como oir llover vamos. Esto se debe a que aunque nosotros actualizamos la barra, esta requiere que sus eventos sean procesados, luego la solución es la mar de simple, tan sólo tenemos que poner nuestras órdenes de análisis de eventos en cada iteración:
 +
 
 +
  void TopFrame::OnStart(wxCommandEvent& WXUNUSED(event))
 +
  {
 +
      int i;
 +
      bool token_true;
 +
 
 +
      m_running = true;
 +
 
 +
      while(m_running)
 +
      {
 +
          for(i=1;i<=100;i++)
 +
          {
 +
              ProgressBar->SetValue(i);
 +
              <b>while((TopFrame *) App->Pending())
 +
              {
 +
                  token_true=(TopFrame *) App->Dispatch();
 +
              }</b>
 +
          }
 +
          for(i=99;i>=2;i--)
 +
          {
 +
              ProgressBar->SetValue(i);
 +
              <b>while((TopFrame *) App->Pending())
 +
              {
 +
                  token_true=(TopFrame *) App->Dispatch();
 +
              }</b>
 +
          }
 +
      }
 +
  }
 +
 
 +
Compilamos y ejecutamos... ¡Éxito rotundo! Si, aunque vaya a toda pastilla y no se vea del todo bien.
 +
 
 +
Finalmente nuestros archivos han quedado así:
 +
 
 +
header.h
 +
<pre>
 +
const int ID_START = wxID_HIGHEST+0;
 +
const int ID_STOP = wxID_HIGHEST+1;
 +
</pre>
 +
 
 +
main.h
 +
<pre>
 +
class SampleApp : public wxApp
 +
{
 +
public:
 +
virtual bool OnInit();
 +
};
 +
</pre>
 +
 
 +
main.cpp
 +
<pre>
 +
#include <math.h>
 +
#include <stdio.h>
 +
#include <wx/wx.h>
 +
#include <wx/string.h>
 +
#include "main.h"
 +
#include "topframe.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(this, _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();
 +
}
 +
</pre>
 +
 
 +
topframe.h
 +
<pre>
 +
class TopFrame : public wxFrame
 +
{
 +
public:
 +
    TopFrame(SampleApp * AApp, wxString Title = _T("Welcome to wxWidgets"));
 +
    void Quit();
 +
    wxGauge * ProgressBar;
 +
    bool m_running;
 +
 
 +
protected:
 +
    void OnQuit(wxCommandEvent& event);
 +
    void OnQuitX(wxCloseEvent& event);
 +
    void OnStart(wxCommandEvent& event);
 +
    void OnStop(wxCommandEvent& event);
 +
    // any class wishing to process wxWidgets events must use this macro
 +
private:
 +
SampleApp * App;
 +
    DECLARE_EVENT_TABLE()
 +
};
 +
</pre>
 +
 
 +
topframe.cpp
 +
<pre>
 +
#include <math.h>
 +
#include <stdio.h>
 +
#include <wx/wx.h>
 +
#include <wx/string.h>
 +
#include "start.xpm"
 +
#include "stop.xpm"
 +
#include "main.h"
 +
#include "topframe.h"
 +
#include "header.h"
 +
 
 +
BEGIN_EVENT_TABLE(TopFrame, wxFrame)
 +
    EVT_MENU(wxID_EXIT,  TopFrame::OnQuit)
 +
    EVT_MENU(ID_START,  TopFrame::OnStart)
 +
    EVT_MENU(ID_STOP,  TopFrame::OnStop)
 +
    EVT_CLOSE(TopFrame::OnQuitX)
 +
END_EVENT_TABLE()
 +
 
 +
TopFrame::TopFrame(SampleApp * AApp, wxString Title)
 +
: wxFrame(NULL, wxID_ANY, Title)
 +
{
 +
App = AApp;
 +
 
 +
//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);
 +
 
 +
    // Panel de herramientas (selector de vista)
 +
wxPanel * ControlPanel = new wxPanel(this, wxID_ANY, wxPoint(0,0), wxSize(256, 32));
 +
ProgressBar = new wxGauge(ControlPanel, wxID_ANY, 100, wxPoint(3,3), wxSize(250,32));
 +
 
 +
    //toolbar
 +
    wxToolBar *toolBar = CreateToolBar();//nueva toolbar(constructor)
 +
    toolBar->SetMargins(5, 5);//margenes
 +
    toolBar->SetToolBitmapSize(wxSize(32, 32));//recoratara las imagenes a 32x32
 +
 
 +
    toolBar->AddTool(ID_START, wxBITMAP(start), wxNullBitmap, false, wxDefaultCoord, wxDefaultCoord, (wxObject *)NULL, _T("Start"), _T("Run the progress bar"));
 +
    toolBar->AddTool(ID_STOP, wxBITMAP(stop), wxNullBitmap, false, wxDefaultCoord, wxDefaultCoord, (wxObject *)NULL, _T("Start"), _T("Run the progress bar"));
 +
    
 +
    toolBar->Realize();
 +
 
 +
    m_running = false;
 +
}
 +
 
 +
void TopFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
 +
{
 +
    Quit();
 +
}
 +
 
 +
void TopFrame::Quit()
 +
{
 +
    // true is to force the frame to close
 +
    Close(true);
 +
}
 +
 
 +
void TopFrame::OnQuitX(wxCloseEvent& WXUNUSED(event))
 +
{
 +
    /**************************************/
 +
    /***** | Aqui todas las ordenes | *****/
 +
    /***** |  previas al cerrado    | *****/
 +
    /******V************************V******/
 +
    // Por ejemplo
 +
    // remove( "temporal.tmp" );
 +
    /******A************************A******/
 +
    /***** | Aqui todas las ordenes | *****/
 +
    /***** |  previas al cerrado    | *****/
 +
    /**************************************/
 +
 
 +
 
 +
Destroy();
 +
}
 +
 
 +
void TopFrame::OnStart(wxCommandEvent& WXUNUSED(event))
 +
{
 +
    int i;
 +
    bool token_true;
 +
 
 +
    m_running = true;
 +
 
 +
    while(m_running)
 +
    {
 +
        for(i=1;i<=100;i++)
 +
        {
 +
            ProgressBar->SetValue(i);
 +
            while((TopFrame *) App->Pending())
 +
            {
 +
                token_true=(TopFrame *) App->Dispatch();
 +
            }
 +
        }
 +
        for(i=99;i>=2;i--)
 +
        {
 +
            ProgressBar->SetValue(i);
 +
            while((TopFrame *) App->Pending())
 +
            {
 +
                token_true=(TopFrame *) App->Dispatch();
 +
            }
 +
        }
 +
    }
 +
}
 +
 
 +
void TopFrame::OnStop(wxCommandEvent& WXUNUSED(event))
 +
{
 +
    m_running = false;
 +
}
 +
</pre>
 +
 
 +
Ahora si que se puede decir que no tengo nada más que enseñar, con esto ya se puede uno lanzar al mundo de wxWidgets sin problemas, pero de todas formas seguiremos rizando un poco más el rizo, añadiendo una ventana para pintar, y algún diálogo, que nos sirvan para fijar ideas. Pero eso será en próximos capítulos.
  
 
{| border=1 class="wikitable" align=center
 
{| border=1 class="wikitable" align=center
Línea 419: Línea 689:
 
| style="text-align: center; border: 2px solid #8B673A; background-color: #F0E2C6; -moz-border-radius: 8px; margin: 10 10 10 10; padding: 5px; font-weight: bold;" | [[Capítulo 4: Soy un artista... ¡No me coartes!]]
 
| style="text-align: center; border: 2px solid #8B673A; background-color: #F0E2C6; -moz-border-radius: 8px; margin: 10 10 10 10; padding: 5px; font-weight: bold;" | [[Capítulo 4: Soy un artista... ¡No me coartes!]]
 
|}
 
|}
 +
 +
 +
<!-- Categoría -->
 +
[[Categoría:Programación]]

Última revisión de 16:54 6 jun 2010

Contenido

[editar] Introducción

En este capítulo comenzaremos a preparar la interfaz para que pueda interactuar con el usuario, e introduciremos (ya que son la misma cosa) los eventos. Este será un paso de gigante, ya que nos permitirá introducir un par de órdenes esenciales para todo código que vaya a entrar en bucles largos, para ello nos crearemos una barra de progreso que no hara más que rellenarse y vaciarse, y unos botones de start y stop.

Sería interesante introducir una pantalla para imprimir cosas, pero eso parece ya demasiado para este capítulo.

Así que nuestro plan de trabajo será tal que:

  • Plan de trabajo del capítulo 3:
    • Manejo de eventos (I):
      Crearemos nuestra primera tabla de eventos, y aprenderemos a manejar nuestros primeros eventos
      • Evento cerrar:
        • Evento cerrar del menú:
          Crearemos la respuesta al evento de cerrar a través del menú "file/exit..."
        • Evento cerrar de la barra de título:
          Crearemos la respuesta al evento de cerrar a través de la "X" de la barra de título.
    • Creación de una ProgressBar:
      Crearemos una Barra de progresos, y sus controles.
      • Barra de progreso:
        Haciendo uso de la documentación encontraremos cual es el objeto que buscamos, y lo implementaremos.
      • Controles de la barra:
        Crearemos una pequeña barra de herramientas para controlar a esta barra de progreso.
    • Manejo de eventos (II):
      Crearemos todo lo necesario para manejar la barra de control.
      • Evento de "Start":
        El que nos permitirá poner a funcionar la barra de progreso.
      • Evento de "Stop":
        El que nos permitirá parar la barra.
        • Cola de eventos:
          No impacientarse, veremos que es lo que ocurre...


[editar] Manejo de eventos

En la programación con interfaz gráfica, el manejo de eventos se vuelve la llave que abre todas las puertas, y es que nos permite hacer cosas que en un principio solo se podrían hacer acudiendo a los multiprocesos. La idea básicamente consistirá en lo siguiente, cada uno de los elementos de la interfaz gráfica, cada vez que se actúe sobre él, emitirá un evento, de una clase o de otra dependiendo la acción que se haya llevado (porque evidentemente no deberá comportarse igual cuando cambies su tamaño, que cuando lo cierres). Ese evento lo anclaremos mediante tablas de eventos, a un método (método = función) que ejecutará las acciones pertinentes (las que nosotros deseemos para esa actuación).


[editar] Evento cerrar

Para manejar nuestro primer evento, ya dejamos preparado un menú tal que "file/exit...". Este evento será muy interesante, ya que deberá compartir sus acciones con el evento de cerrar presionando sobre la "X" de la ventana. Eso nos enseñará dos cosas, como manejar eventos que necesiten ID, y como manejar los que no lo necesiten (que no tienen ninguna diferencia, pero que nos enseñará que en algunos casos, los eventos no necesitan ID), y lo que es más importante, nos enseñará a hacer las cosas bien (para no duplicar código).

[editar] Evento cerrar del menú

Bien, así que recuperamos nuestro trabajo donde lo dejamos, y acudimos presto a abrir "topframe.h". Las tablas de eventos hay que predeclararlas, y eso se hace en nuestra cabecera, simplemente añadiendo las siguientes líneas:

 class TopFrame : public wxFrame
 {
 public:
     TopFrame(wxString Title = _T("Welcome to wxWidgets"));
 private:
     // any class wishing to process wxWidgets events must use this macro
     DECLARE_EVENT_TABLE()
 };

Lo cierto es que nuestros eventos serán una cosa privada (private:), que sólo la clase en cuestión debe manejar, ya no sólo porque es intuitivamente lo lógico, sino porque nos puede ahorrar algunos problemillas.

Bueno, hemos declarado la tabla de eventos, ahora vamos a declarar un método para controlar el evento. Llamémoslo por ejemplo "OnQuit", y lo pondremos como privado, ya que será el que maneje el evento... No obstante, puede ocurrir que más tarde algún elemento pueda tener la necesidad de cerrar el programa, así que la gestión de cierre deberá ser algo publico, así que crearemos otro método llamado "Quit", que será realmente el que nos cierre la aplicación (todo esto tendrá un transfondo mucho más interesante, que entenderemos más adelante). También necesitamos saber que tipo de evento manejaremos, así que en nuestra API (a partir de ahora denominaremos así al wx.chm o a la página de documentación oficial) buscamos wxMenu, y en el apartado "Event handling", nos da este evento: "wxCommandEvent", que será el que habremos de usar...

Así pues, nuestra cabecera deberá modificarse así:

 class TopFrame : public wxFrame
 {
 public:
     TopFrame(wxString Title = _T("Welcome to wxWidgets"));    
     void Quit();
 private:
     void OnQuit(wxCommandEvent& event);    
     // any class wishing to process wxWidgets events must use this macro
     DECLARE_EVENT_TABLE()
 };

Donde efectivamente llevamos a cabo todas las operaciones que planteabamos...

El siguiente punto sin duda debería ser implementar todo esto, así que abrimos "topframe.cpp", y lo primero de todo añadimos la tabla de eventos:

 BEGIN_EVENT_TABLE(TopFrame, wxFrame)  
 END_EVENT_TABLE()
 
 TopFrame::TopFrame(wxString Title)
 : wxFrame(NULL, wxID_ANY, Title)
 {
   (...)

Ahora recuperamos nuestra documentación, justo en el lugar donde la dejamos, y nos encontramos que el macro en la tabla de eventos es "EVT_MENU", pero necesitamos saber como funciona, así que lo buscamos, y nos encontramos "wxCommandEvent", lo abrimos, y alli esta: "EVT_MENU(id, func) "

  • id: Ya lo conocemos, le pusimos wxID_EXIT.
  • func: La función a la queremos anclarlo la hemos declarado como OnQuit.

Así que la tabla de eventos quedará de la forma:

 BEGIN_EVENT_TABLE(TopFrame, wxFrame)
     EVT_MENU(wxID_EXIT,  TopFrame::OnQuit)
 END_EVENT_TABLE()

Ahora debemos implementar nuestros dos métodos, empezemos con el que maneja el evento (OnQuit), para ello, al final del archivo añadimos las siguientes líneas:

 void TopFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
 {
 }

Como no queremos sacrale más partido a este evento, pues con saber que se ha emitido la orden de cerrar nos es suficiente, ponemos como entrada "wxCommandEvent& WXUNUSED(event)". No actuaremos así por ejemplo cuando manejemos el ratón, pues necesitaremos información sobre donde estaba, o que botón apretó.

Bueno, este método lo único que hará será llamar a la función que realmente gestiona el cierre:

 void TopFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
 {
     Quit();
 }

Con esta argucia hemos arreglado un problema interesante, pues imaginemos que algún otro objeto, o algún otro método quisieran cerrar la aplicación, de ser el gestor el anterior método, para llamarle sería necesario generar un evento, pues necesitariamos ese parámetro, pero ahora van a poder llamar a Quit(), y listos.

  • Esto se puede hacer de muchas maneras, una sería por ejemplo poner un evento por defecto, tal y como hicimos con el título de TopFrame, no obstante, esta manera me parece más legible y elegante.

Ahora toca, casi a la fuerza, implementar nuestro método "Quit", así que nuevamente al final de archivo añadimos:

 void TopFrame::Quit()
 {
 }

Y este método lo único que habrá de hacer bserá cerrar la aplicación:

 void TopFrame::Quit()
 {
     // true is to force the frame to close
     Close(true);
 }

Esa orden que hemos añadido lo que hace es crear un evento de cerrar, que es un evento que tiene la peculiaridad de tener una función ya asociada que se encarga de cerrarlo por nosotros, pero en breves momentos cambiaremos esa situación a nuestro favor.

Bueno, ya podemos hacer alguna prueba, compilamos, y ejecutamos. Vamos al menú "file", y seleccionamos "Exit Alt-F4". ¡Y se cierra! ¡Lo hemos logrado!

Ya sabemos crear menús, y anclarlos a eventos que apuntaran a los métodos que nos interese, pero vamos a seguir rizando el rizo...

[editar] Evento cerrar de la barra de título

Bueno, hasta el momento nos las hemos apañado para que nuestro "Exit Alt-F4" sea capaz de cerrar la aplicación, y como el botoncito de cerrar de la barra de título ya lo tenía implementado, pues efectivamente, en primera instancia habríamos terminado. Pero supongamos que nuestro programa puede estar manejando algun archivo, o requiere, al cerrar, borrar una serie de archivos temporales (algo muy típico por otra parte), o que por ejemplo queramos que el programa pregunte si queremos guardar anters de salir (más típico todavia). En la concepción actual, podríamos meterlo en la función Quit(), pero entonces al darle a cerrar en la barra de título no funcionaría, necesitamos un nuevo evento, y un método asociado a él.

Así que lo primero es encontrar información de lo que buscamos, para ello vamos a nuestra API, y buscamos "close event", e inmediatamente nos aparece "wxCloseEvent", así que lo ojeamos, y nos da la solución: "EVT_CLOSE(func)".

Pues bien, ya tenemos lo que necesitamos para empezar, y por tanto abrimos "topframe.h" para añadir el siguiente método:

 class TopFrame : public wxFrame
 {
 public:
     TopFrame(wxString Title = _T("Welcome to wxWidgets"));
 
     void Quit();
 private:
     void OnQuit(wxCommandEvent& event);
     void OnQuitX(wxCloseEvent& event);
     // any class wishing to process wxWidgets events must use this macro
     DECLARE_EVENT_TABLE()
 };

Y ahora añadimos a la tabla de eventos en "topfrmae.cpp":

 BEGIN_EVENT_TABLE(TopFrame, wxFrame)
     EVT_MENU(wxID_EXIT,  TopFrame::OnQuit)
     EVT_CLOSE(TopFrame::OnQuitX)
 END_EVENT_TABLE()

Y al final del archivo el método:

 void TopFrame::OnQuitX(wxCloseEvent& WXUNUSED(event))
 {
 }

La orden que permitirá el "escape" de la aplicación será la destrucción de TpoFrame. A los locos de C++, en wxWidgets las cosas no se destruyen con delete, sino que implementan una función llamada Destroy() que hace todas las operaciones necesarias, y termina por llamar a delete. Con esta premisa ya podemos completar nuestro método de la forma:

 void TopFrame::OnQuitX(wxCloseEvent& WXUNUSED(event))
 {
     /**************************************/
     /***** | Aqui todas las ordenes | *****/
     /***** |  previas al cerrado    | *****/
     /******V************************V******/
     // Por ejemplo
     // remove( "temporal.tmp" );
     /******A************************A******/
     /***** | Aqui todas las ordenes | *****/
     /***** |  previas al cerrado    | *****/
     /**************************************/  
 
     Destroy();
 }

Compilar, y vereis como el programa se comporta exactamente igual.

  • Resumiendo... ¿Qué esta ocurriendo realmente? Pues lo que esta ocurriendo es lo siguiente:
    • Cuando se presiona el botón de cerrar de la barra de título:
      1.- Se crea un wxCloseEvent
      2.- Se acude a la tabla de eventos a este punto: EVT_CLOSE(TopFrame::OnQuitX)
      3.- Le redirecciona a la función: TopFrame::OnQuitX
      4.- Este método llama a: Destroy(); Que destruye "TopFrame"
      5.- Con TopFrame destruido el programa queda fuera de flujo, y por tanto se termina.
    • Cuando se usa la barra de menús:
      1.- Se crea un wxCommandEvent
      2.- Se acude a la tabla de eventos a este punto: EVT_MENU(wxID_EXIT, TopFrame::OnQuit)
      3.- Le redirecciona a la función:TopFrame::OnQuit
      4.- Esta llama a:Close(true);
      5.- Se genera un wxCloseEvent
      6.- Se repite todo el punto anterior.

¿A que ahora si veís claro por qué reservamos una función especial para gestionar el cierre, y cómo funciona todo el sistema de eventos?

¡Ya esta! ¿Qué más puedo necesitar saber? Pues aún hay algo que te puedo enseñar (realmente el único conocimiento nuevo de verdad que me queda por dar, ya que los próximos capítulos afianzarán ideas, y mostrarán algunos elementos, pero no introducirán nada nuevo).

Y para ver este nuevo conocimiento necesitamos algunas cosas, como pueda ser una progress bar, y unos controles...

[editar] Creación de una ProgressBar:

Ahora vamos plantearnos crear los lementos de la barra de progreso, y de la barra de heramientas, y luego nos ocuparemos de manejarlos.

[editar] Barra de progreso:

Bueno, lo primero que necesitaremos sin duda será una ProgressBar, que seguro que wxWidgets ya sabe hacer, asi que vayamos a nuestra querida API, y busquemos progress bar. Aparecerán ante nuestros ojos dos títulos interesantes, uno será wxProgressDialog, que pudiera ser interesante (existen un montón de dialogos prefabricados que siempre son una buena opción a tener en cuenta para ahorrar trabajo), pero en nuestra concepción inicial no queríamos que estuviera en un diálogo a parte, así que el título que de verdad nos va a interesar es wxGauge, así que lo seleccionamos y lo ojeamos.

Parece que no hay nada especial en cuanto a librerías a añadir, ni en cuanto a eventos se refiere (parece un elemento de lo más simple, y eso es bueno). Los estilos, pues principalmente el horizontal y el vertical, porque existe otro, pero no nos lo recomienda, por no ser compatible con la mayoría de plataformas, y como nosotros queremos que sea multiplataforma, no lo usaremos...

Así que este es un buen momento para recuperar nuestro trabajo donde lo dejamos, y comenzaremos con la declaración de la ProgessBar en topframe.h, así que lo abrimos, y la declaramos:

 (...)
 public:
     TopFrame(wxString Title = _T("Welcome to wxWidgets"));
     void Quit();
     wxGauge * ProgressBar;
 private:
 (...)

Muy bien, ahora vamos a incluirla en nuestra TopFrame, para ello vamos a topframe.cpp, y añadimos un panel...

  • Para añadir elementos en los diálogos, se añaden sobre paneles, que luego iremos colocando con los sizers, ya lo veremos, por ahora nuestra ventana será de lo más feucho posible...

Para ello, al final del constructor hacemos lo siguiente:

 (...)
 // Panel de herramientas (selector de vista)
 wxPanel * ControlPanel = new wxPanel(this, wxID_ANY, wxPoint(0,0), wxSize(256, 32));
 (...)

Donde estamos creando un panel, cuyo parente es this (TopFrame), sin ningún ID, en el punto (0,0) (esquina superior izquierda), y que mide 256x32 pixels.

En realidad no os estresseis demasiado con los tamaños, pues en cuanto aprendamos a manejar los sizers, los tamaños casi siempre se autoajustarán.

Bueno, ya tenemos un panel sobre el que añadir la ProgressBar, así que construyámosla (justo después):

 (...)
 // Panel de herramientas (selector de vista)
 wxPanel * ControlPanel = new wxPanel(this, wxID_ANY, wxPoint(0,0), wxSize(256, 32));	
 ProgressBar = new wxGauge(ControlPanel, wxID_ANY, 100, wxPoint(3,3), wxSize(250,32));
 (...)

Donde hemos construido una barra de progreso cuyo parent es el panel que acababamos de crear, sin nigún ID, con un rango de 100 (100%, aunque esto no será habitual, lo normal es que el rango sea el valor máximo que esparas alcanzar), a 3x3 pixeles de la esquina superiopr izquierda, y con un tamaño tal que deja 3x3 pixeles hasta la esquina inferior derecha.

Compilamos y ejecutamos para ver que tal aspecto tiene... Bueno, pues ahi tenemos nuestra pequeña ProgressBar...

[editar] Controles de la barra:

Bueno, ahora vamos a crear una barra de herramientas para controlar nuestra barra de progreso, para ello usaremos las dos imagenes adjuntas: Imagen de start Imagen de stop

Colócalas en el mismo lugar donde tenmos los cpp y los h (en la carpeta learn0.X)

Abrelas con el gimp, y guárdarlas en dos formatos diferentes, según estas instrucciones:

 wxstart.jpg -> start.bmp
 wxstart.jpg -> start.xpm
 wxstop.jpg -> stop.bmp
 wxstop.jpg -> stop.xpm

Las .bmp las usaremos en windows en su día, y están bien como están, pero las xpm, que son las que vamos a usar en linux, no están bien, y hay que hacer un par de operaciones previas...

Abriéndolas nuevamente con el gimp (las xpm), vamos a introducirlas transparecia, para ello:

  1. Vamos a "capa/transparencia/añadir canal alfa".
  2. Seleccionamos la herramienta varita mágica, y con ella seleccionamos todo el gris de la imagen, y le damos a "Supr". Las reguardamos con el mismo nombre, y salimos de gimp.

Ocurre que el formato xpm no le hace mucha gracia a c++, y si intentamos usarlas tal y como están, nos dará un montón de errores (advertencias) por conversión obsoleta, así que las abrimos con gedit, o con cualquier editor de texto (lo que pasa que gedit nos va a permitir hacerlo como las balas), y hacemos lo siguiente:

  1. Nos aseguramos que la segunda línea es como sigue para cada uno de nuestros archivos:
    start.xpm -> static char * start_xpm[] = {
    stop.xpm -> static char * stop_xpm[] = {
  2. Escribimos al comienzo de la tercera línea lo siguiente:
    (char *)
  3. Vamos a "editar/reemplazar", y escribimos lo siguiente (comillas incluidas):
    buscar: ",\n"
    Reemplazar con: ",\n(char *) "
    Y damos a Reemplazar todo.
  4. Reguardamos y salimos.

Bien, ya tenemos listas las imágenes, así que ya podemos empezar a crear nuestra barra de herramientas...

Lo primero de todo es indicarle a nuestro programa que queremos que tenga esas imágenes, para ello recurrimos a este par de órdenes al comienzo de "topframe.cpp":

 #include "start.xpm"
 #include "stop.xpm"

En priomera instancia, cuando se manejan imágenes, se puede actuar de dos formas, una es teniendo las imágenes, en cualquier formato, en un lugar conocido, y abriéndolas cada vez que las necesitemos, y la otra es, incluyéndola en Linux, debiendo tener formato xpm, o en Windows poniéndola en las resources, debiendo tener formato bmp.

La primera forma tiene la ventaja de que el código medirá menos, y compilará más rápido, la segunda tiene la ventaja de que las imágenes forman parte del código, y así el programa no requiere que las imágenes estén a parte, teniendo siempre que transportar ambas cosas.

El como se manejan las imágenes de ésta innovadora segunda forma, lo vamos a ver en breve.

Crear una barra de herramientas es muy parecido a crear el menú (que por cierto, se puede tratar de ampliar después con estos dos nuevos elementos), simplemente necesitaremos un par de ID para poder manejar nuestros eventos, así que nos vamos a crear un nuevo archivo llamado "header.h", y dentro escribiremos esto:

 const int ID_START = wxID_HIGHEST+0;
 const int ID_STOP = wxID_HIGHEST+1;

Efectivamente, los ID no son más que enteros que declaramos como constantes para poder tenerlos como constantes globales. Y para no interferir con ningún ID de wxWidgets, usamos este ID que ya han preparado ellos, llamado wxID_HIGHEST, que se corresponde con el ID más alto sin usar (por eso +0, y no +1).

Bueno, ahora regresamos a nuestro TopFrame, "topframe.cpp", y añadimos nuestra cabecera:

 #include "header.h"

Bueno, esto marcha, conocidos nuestros ID, ya podemos crear nuestra barra, para ello comenzamos creando, al final de "topframe.cpp", una barra de herramientas con las siguientes órdenes (que como siempre podeis en contrar en el API):

   //toolbar
   wxToolBar *toolBar = CreateToolBar();//nueva toolbar(constructor)
   toolBar->SetMargins(5, 5);//margenes
   toolBar->SetToolBitmapSize(wxSize(32, 32));//recoratara las imagenes a 32x32

Que hace exactamente lo que pone en los comentarios, y por último añadimos nuestros dos elementos y seteamos la toolBar:

   toolBar->AddTool(ID_START, wxBITMAP(start), wxNullBitmap, false, wxDefaultCoord, wxDefaultCoord, (wxObject *)NULL, _T("Start"), _T("Run the progress bar"));
   toolBar->AddTool(ID_STOP, wxBITMAP(stop), wxNullBitmap, false, wxDefaultCoord, wxDefaultCoord, (wxObject *)NULL, _T("Start"), _T("Run the progress bar"));
 
   toolBar->Realize();

Como siempre, para saber que es lo que hace cada parámetro, recurrir a la API. Aunque cabe destacar la imagen, que hemos introducido con:

 wxBITMAP(start)

Cuando escribimos wxBITMAP(), el ya entiende que tratamos de recurrir a un recurso incrustado en el código, a diferencia de wxBitmap(), que es el constructor de la clase con el mismno nombre de wxWidgets. Por otro lado, ponemos start, porque si recordais, cuando editamos nuestro archivo start.xpm, yo insistí en que os ceriorárais de que la segunda línea era tal y como sigue:

static char * start_xpm[] = {

Bien, compilamos y ejecutamos... ¡Y allí esta, nuestra barra de herramientas con nuestros dos botones!

[editar] Manejo de eventos (II):

Con nuestra barra creada, por supuesto nuestro siguiente objetivo es usar nuestros dos elementos. Ya veremos que el evento de start nos vendrá rodado, pero el evento de stop nos dará una pequeña sorpresita.

[editar] Evento de "Start":

Bueno, para nuestro evento de "start", lo único que necesitamos es una función que lo maneje, así que en el protegido de "topframe.h", añadimos una nueva función tal que:

 private:
   void OnQuit(wxCommandEvent& event);
   void OnQuitX(wxCloseEvent& event);
   void OnStart(wxCommandEvent& event);
   void OnStop(wxCommandEvent& event);
   // any class wishing to process wxWidgets events must use this macro
   DECLARE_EVENT_TABLE()

Y una variable que controle cuando estamos corriendo, que la declararemos en el público como:

 public:
   TopFrame(wxString Title = _T("Welcome to wxWidgets"));
   void Quit();
   wxGauge * ProgressBar;
   bool m_running;


Vamos declarando ya también la de "stop". Los eventos de la barra de herramientas son exactamente iguales que los de la barra de menús que ya hemos utilizado, es por eso que aparece "wxCommandEvent& event".

Bien, acudamos a la tabla de eventos de nuestro "topframe.cpp", y añadamos un nuevo evento:

 BEGIN_EVENT_TABLE(TopFrame, wxFrame)
   EVT_MENU(wxID_EXIT,  TopFrame::OnQuit)
   EVT_MENU(ID_START,  TopFrame::OnStart)
   EVT_CLOSE(TopFrame::OnQuitX)
 END_EVENT_TABLE()

Y al final del constructor, demos la señal de que está parado:

 (...)
   toolBar->AddTool(ID_STOP, wxBITMAP(stop), wxNullBitmap, false, wxDefaultCoord, wxDefaultCoord, (wxObject *)NULL, _T("Start"), _T("Run the progress bar"));
   m_running = false;

}


Y al final del todo añadamos la siguiente rutina:

 void TopFrame::OnStart(wxCommandEvent& WXUNUSED(event))
 {
     int i;
     m_running = true;
     while(m_running)
     {
         for(i=1;i<=100;i++)
         {
             ProgressBar->SetValue(i);
         }
         for(i=99;i>=2;i--)
         {
             ProgressBar->SetValue(i);
         }
     }
 }


Si recordáis como trabajamos con OnQuit(), lo mas puritano hubiera sido crear otro método llamado start(), y OnStart() tan sólo debería activar m_running, y llamar a start(), pero como siempre, las normas están para saltárselas, y por ahorrar un poco de tiempo, pues actuamos así, sin que sirva de precedente.

Respecto a la función, pues sólo es un bucle que va desde 1 hasta 100 y vuelve, dando valores a nuestra progresbar, repitiéndose hasta que m_running valga "false".

Bien, con esto ya tenemos nuestro "start", pero antes de nada, pongamos nuestro "stop".

[editar] Evento de "Stop":

Pues actuamos de forma absolutamente análoga, esto es, añadimos lo siguiente en la tabla de eventos (recordando que ya habíamos aprovechado para declarar nuestra función, luego huelga repetir ese paso):

 BEGIN_EVENT_TABLE(TopFrame, wxFrame)
   EVT_MENU(wxID_EXIT,  TopFrame::OnQuit)
   EVT_MENU(ID_START,  TopFrame::OnStart)
   EVT_MENU(ID_STOP,  TopFrame::OnStop)
   EVT_CLOSE(TopFrame::OnQuitX)
 END_EVENT_TABLE()

Y añadimos al final nuestro método:

 void TopFrame::OnStop(wxCommandEvent& WXUNUSED(event))
 {
     m_running = false;
 }

Absolutamente simplón, que lo único que hace es establecer una señal de parado, para que OnStart termine su bucle.

Bien, comnpilamos y ejecutamos... (Y seguimos leyendo, que te adelanto que van a existir problemas)

¡Algo va mal! ¡No puedo pararlo! ¡La barra no se actualiza!. Bien, vuelve a code::blocks, y usa el botón rojo con un aspa blanca para detener el código.

[editar] Cola de eventos

Bien, el primer problema a corregir es que no podemos parar el código, esto se debe a que, aunque efectivamente al presionar cualquier botón se genera un evento, este evento no se procesa nunca, ya que nuestro código esta enfrascado en un bucle sin fin, así que parece estar claro ¿no?, tenemos que pedirle a nuestro código que procese los evento que se generen dentro del bucle, eso se hace (buscando como siempre en el API) con dos órdenes llamadas Pending() y Dispatch(). Pero claro, ambas órdenes forman parte de wxApp, luego necesitamos que TopFrame conozca SampleApp (que es nuestra wxApp).

Esto se puede hacer de otra forma, mucho más limpia, y bastante más elegante, pero que no obstante, no nos da tanta potencia, y por ello, ni tan siquiera la introduzco.

Bien, el primer paso es cambiar nuestro "topframe.h", añadiendo a la entrada de datos del Constructor lo siguiente:

   TopFrame(SampleApp * AApp, wxString Title = _T("Welcome to wxWidgets"));

Y añadiendo una nueva variable privada (reitero, que no os estresse demasiado lo de publico, protegido, o privado, tan solo es una cuestión de limpieza, pero realmente es un poco indiferente):

 (...)
 private:

SampleApp * App;

 (...)

Y lo implementamos en "topframe.cpp", empezando porque ahora nuestra clase hace uso de SampleApp, luego necesitamos su cabecera, así que añadimos lo siguiente:

 (...)
 #include "stop.xpm"
 #include "main.h"
 #include "topframe.h"
 #include "header.h"
 (...)

Es fundamental el orden, ya que cuando incluyas "topframe.h", esta ya debe conocer el contenido de "minimal.h" (es interesante probar a cambiarlo, para ver como nos devulve un error de que SampleApp no esta declarado). Este orden será necesario cambiarlo también en "main.cpp"

Y por supuesto tenemos que cambiar el constructor:

 TopFrame::TopFrame(SampleApp * AApp, wxString Title)
 : wxFrame(NULL, wxID_ANY, Title)
 {
 	App = AApp;
 (...)

Donde efectivamente recibimos un SampleApp, e inmediatamente después lo volcamos sobre una variable nuestra.

Lo único que resta para poder disfrutar nuestro SampleApp es mandarselo en "main.cpp", así que cambiamos la orden de la siguiente manera:

 (...)
   frame = new TopFrame(this, _T("Welcome to wxWidgets!"));
 (...)

Y ya está, ya podemos usar a SampleApp en nuestra TopFrame.

Bien, las órdenes que queremos usar se utilizan como sigue (en "topframe.cpp"):

 void TopFrame::OnStart(wxCommandEvent& WXUNUSED(event))
 {
     int i;
     bool token_true;
     m_running = true;
     while(m_running)
     {
         for(i=1;i<=100;i++)
         {
             ProgressBar->SetValue(i);
         }
         for(i=99;i>=2;i--)
         {
             ProgressBar->SetValue(i);
         }
         while((TopFrame *) App->Pending())
         {
             token_true=(TopFrame *) App->Dispatch();
         }
     }
 }

Efectivamente son unas órdenes un poco extravagantes, pero nuevamente asumimos que se usan así, y no nos preocupamos más. Efectivamente, declaramos un tolken_true, que realmente es una variable basura, para dar coherencia de compilación. Y cada vez que la barra de progreso haga un "release", nos dedicamos a procesar evento mientras sigan existiendo evento pendientes.

Compilamos y ejecutamos...

¡Algo hace! Pero desde luego, el gra avance es que podemos detener el código.

Nuestro siguiente problema es que la barra de progreso se mantiene inmutable (o casi), como oir llover vamos. Esto se debe a que aunque nosotros actualizamos la barra, esta requiere que sus eventos sean procesados, luego la solución es la mar de simple, tan sólo tenemos que poner nuestras órdenes de análisis de eventos en cada iteración:

 void TopFrame::OnStart(wxCommandEvent& WXUNUSED(event))
 {
     int i;
     bool token_true;
 
     m_running = true;
 
     while(m_running)
     {
         for(i=1;i<=100;i++)
         {
             ProgressBar->SetValue(i);
             while((TopFrame *) App->Pending())
             {
                 token_true=(TopFrame *) App->Dispatch();
             }
         }
         for(i=99;i>=2;i--)
         {
             ProgressBar->SetValue(i);
             while((TopFrame *) App->Pending())
             {
                 token_true=(TopFrame *) App->Dispatch();
             }
         }
     }
 } 

Compilamos y ejecutamos... ¡Éxito rotundo! Si, aunque vaya a toda pastilla y no se vea del todo bien.

Finalmente nuestros archivos han quedado así:

header.h

const int ID_START = wxID_HIGHEST+0;
const int ID_STOP = wxID_HIGHEST+1;

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 "main.h"
#include "topframe.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(this, _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(SampleApp * AApp, wxString Title = _T("Welcome to wxWidgets"));
    void Quit();
    wxGauge * ProgressBar;
    bool m_running;

protected:
    void OnQuit(wxCommandEvent& event);
    void OnQuitX(wxCloseEvent& event);
    void OnStart(wxCommandEvent& event);
    void OnStop(wxCommandEvent& event);
    // any class wishing to process wxWidgets events must use this macro
private:
	SampleApp * App;
    DECLARE_EVENT_TABLE()
};

topframe.cpp

#include <math.h>
#include <stdio.h>
#include <wx/wx.h>
#include <wx/string.h>
#include "start.xpm"
#include "stop.xpm"
#include "main.h"
#include "topframe.h"
#include "header.h"

BEGIN_EVENT_TABLE(TopFrame, wxFrame)
    EVT_MENU(wxID_EXIT,  TopFrame::OnQuit)
    EVT_MENU(ID_START,  TopFrame::OnStart)
    EVT_MENU(ID_STOP,  TopFrame::OnStop)
    EVT_CLOSE(TopFrame::OnQuitX)
END_EVENT_TABLE()

TopFrame::TopFrame(SampleApp * AApp, wxString Title)
: wxFrame(NULL, wxID_ANY, Title)
{
	App = AApp;

	//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);

    // Panel de herramientas (selector de vista)
	wxPanel * ControlPanel = new wxPanel(this, wxID_ANY, wxPoint(0,0), wxSize(256, 32));
	ProgressBar = new wxGauge(ControlPanel, wxID_ANY, 100, wxPoint(3,3), wxSize(250,32));

    //toolbar
    wxToolBar *toolBar = CreateToolBar();//nueva toolbar(constructor)
    toolBar->SetMargins(5, 5);//margenes
    toolBar->SetToolBitmapSize(wxSize(32, 32));//recoratara las imagenes a 32x32

    toolBar->AddTool(ID_START, wxBITMAP(start), wxNullBitmap, false, wxDefaultCoord, wxDefaultCoord, (wxObject *)NULL, _T("Start"), _T("Run the progress bar"));
    toolBar->AddTool(ID_STOP, wxBITMAP(stop), wxNullBitmap, false, wxDefaultCoord, wxDefaultCoord, (wxObject *)NULL, _T("Start"), _T("Run the progress bar"));
  
    toolBar->Realize();

    m_running = false;
}

void TopFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    Quit();
}

void TopFrame::Quit()
{
    // true is to force the frame to close
    Close(true);
}

void TopFrame::OnQuitX(wxCloseEvent& WXUNUSED(event))
{
    /**************************************/
    /***** | Aqui todas las ordenes | *****/
    /***** |  previas al cerrado    | *****/
    /******V************************V******/
    // Por ejemplo
    // remove( "temporal.tmp" );
    /******A************************A******/
    /***** | Aqui todas las ordenes | *****/
    /***** |  previas al cerrado    | *****/
    /**************************************/


	Destroy();
}

void TopFrame::OnStart(wxCommandEvent& WXUNUSED(event))
{
    int i;
    bool token_true;

    m_running = true;

    while(m_running)
    {
        for(i=1;i<=100;i++)
        {
            ProgressBar->SetValue(i);
            while((TopFrame *) App->Pending())
            {
                token_true=(TopFrame *) App->Dispatch();
            }
        }
        for(i=99;i>=2;i--)
        {
            ProgressBar->SetValue(i);
            while((TopFrame *) App->Pending())
            {
                token_true=(TopFrame *) App->Dispatch();
            }
        }
    }
}

void TopFrame::OnStop(wxCommandEvent& WXUNUSED(event))
{
    m_running = false;
}

Ahora si que se puede decir que no tengo nada más que enseñar, con esto ya se puede uno lanzar al mundo de wxWidgets sin problemas, pero de todas formas seguiremos rizando un poco más el rizo, añadiendo una ventana para pintar, y algún diálogo, que nos sirvan para fijar ideas. Pero eso será en próximos capítulos.

Capítulo 2.- ¡Esta vivo! ¡vivoooooo! ¡JAJAJA! Nuestra primera interfaz gráfica con CodeBlocks y wxWidgets Capítulo 4: Soy un artista... ¡No me coartes!
Herramientas personales