Capítulo 4: Soy un artista... ¡No me coartes!

De doc.ubuntu-es
(Diferencias entre revisiones)
Saltar a: navegación, buscar
(Conclusión)
m (Creación de una wxWindow:)
 
(No se muestran 4 ediciones intermedias realizadas por un usuario)
Línea 26: Línea 26:
 
Ya introducimos esta idea cuando creamos nuestra wxFrame, y ya adelantabamos que cuando nos encontráramos con elementos complicados (una ventana, un dialogo, un canvas, una malla...) debíamos actuar de esta forma.
 
Ya introducimos esta idea cuando creamos nuestra wxFrame, y ya adelantabamos que cuando nos encontráramos con elementos complicados (una ventana, un dialogo, un canvas, una malla...) debíamos actuar de esta forma.
  
Bueno, ya que hemos alineado un poco nuestras ideas, recuperamos nuestro proyecto donde lo dejamos, y creamos dos archivos, llamados "'''mycanvas.cpp'''" y "'''mycanvas.h'''", y como siempre los limpiamos.
+
Bueno, ya que hemos alineado un poco nuestras ideas, recuperamos nuestro proyecto donde lo dejamos, y creamos dos archivos, llamados "'''mycanvas.cpp'''" y "'''mycanvas.h'''".
  
 
Y declaramos nuestra nueva clase, en "<b>mycanvas.h</b>":
 
Y declaramos nuestra nueva clase, en "<b>mycanvas.h</b>":
 +
<pre>
 +
#ifndef _MYCANVAS_H
 +
#define _MYCANVAS_H
  
  class MyCanvas : public wxWindow
+
class MyCanvas : public wxWindow
  {
+
    {
  public:
+
    public:
  MyCanvas(SampleApp * AApp, wxWindow *parent, wxWindowID id, const wxPoint&  
+
        MyCanvas(SampleApp * AApp, wxWindow *parent, wxWindowID id, const wxPoint&  
 
         pos=wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0);
 
         pos=wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0);
 
+
 
  void drawSomething();
+
        void drawSomething();
      wxMemoryDC dc;
+
        wxMemoryDC dc;
      wxGraphicsContext *gc;
+
        wxGraphicsContext *gc;
 
+
 
  protected: // event handlers (NO virtual)
+
protected: // event handlers (NO virtual)
  void OnPaint(wxPaintEvent& event);
+
    void OnPaint(wxPaintEvent& event);
  void OnMaximize(wxSizeEvent& event);
+
    void OnMaximize(wxSizeEvent& event);
  private:
+
    private:
  wxBitmap m_pixels;
+
    wxBitmap m_pixels;
  SampleApp * App;
+
    SampleApp * App;
 
+
 
  // any class wishing to process wxWidgets events must use this macro
+
    // any class wishing to process wxWidgets events must use this macro
  DECLARE_EVENT_TABLE()
+
    DECLARE_EVENT_TABLE()
  };
+
};
 +
 
 +
#endif /* _MYCANVAS_H */
 +
</pre>
  
 
En un acto de previsión, hemos ido añadiendo todo aquello que creemos que vamos a necesitar, tal vez sería buena idea que buscarais en el API todos los elementos que hemos añadido.
 
En un acto de previsión, hemos ido añadiendo todo aquello que creemos que vamos a necesitar, tal vez sería buena idea que buscarais en el API todos los elementos que hemos añadido.
  
 
El siguiente punto es crear nuestra clase, en "<b>mycanvas.cpp</b>":
 
El siguiente punto es crear nuestra clase, en "<b>mycanvas.cpp</b>":
 
+
<pre>
 
   #include <wx/wx.h>
 
   #include <wx/wx.h>
 
   #include <wx/icon.h>
 
   #include <wx/icon.h>
Línea 77: Línea 83:
 
    
 
    
 
   BEGIN_EVENT_TABLE(MyCanvas, wxWindow)
 
   BEGIN_EVENT_TABLE(MyCanvas, wxWindow)
   EVT_PAINT(MyCanvas::OnPaint) //to can paint in window
+
   EVT_PAINT(MyCanvas::OnPaint) // dibujar en la ventana
   EVT_SIZE(MyCanvas::OnMaximize) //answer to size changes (p.ej. maximize events)
+
   EVT_SIZE(MyCanvas::OnMaximize) // responder a los cambios de tamaño (p.ej maximizar)
 
   END_EVENT_TABLE()
 
   END_EVENT_TABLE()
 
    
 
    
Línea 92: Línea 98:
 
   }
 
   }
 
    
 
    
   /***************************************************************/
+
   /* OnMaximize responde a los cambios de tamaño */
  /************** OnMaximize ************************************/
+
  /************** answer to Size changes ************************/
+
  /************** Used to resize all elements ********************/
+
  /***************************************************************/
+
 
   void MyCanvas::OnMaximize(wxSizeEvent& WXUNUSED(event))
 
   void MyCanvas::OnMaximize(wxSizeEvent& WXUNUSED(event))
 
   {
 
   {
 
   }
 
   }
 
    
 
    
   /***************************************************************/
+
   /* OnPaint responde a los eventos de pintar. Prepara la ventana para pintar en ella */
  /************** OnPaint ****************************************/
+
  /************** answer to paint events *************************/
+
  /************** Prepares the window to paint it ****************/
+
  /***************************************************************/
+
 
   void MyCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
 
   void MyCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
 
   {
 
   {
 
   }
 
   }
 
    
 
    
   /***************************************************************/
+
   /* drawSomething pinta */
  /************** drawSomething ********************************/
+
  /************** Paint the canvas ****************************/
+
  /***************************************************************/
+
 
   void MyCanvas::drawSomething()
 
   void MyCanvas::drawSomething()
 
   {
 
   {
 
   }
 
   }
 +
</pre>
  
 
Paremos un segundo a explicar a que viene cada cosa.
 
Paremos un segundo a explicar a que viene cada cosa.
Línea 490: Línea 486:
 
Finalmente nuestros archivos han quedado así:
 
Finalmente nuestros archivos han quedado así:
  
topframe.h:
+
'''topframe.h:'''
 
+
<pre>
<code>
+
 
class TopFrame : public wxFrame
 
class TopFrame : public wxFrame
 
{
 
{
Línea 512: Línea 507:
 
     DECLARE_EVENT_TABLE()
 
     DECLARE_EVENT_TABLE()
 
};
 
};
</code>
+
</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 "mycanvas.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
 +
wxPanel * ControlPanel = new wxPanel(this, wxID_ANY, wxPoint(0,0), wxSize(256, 32));
 +
wxPanel * ControlPanel2 = new wxPanel(this, wxID_ANY, wxPoint(0,0), wxSize(256, 32));
 +
ProgressBar = new wxGauge(ControlPanel, wxID_ANY, 100, wxPoint(3,3), wxSize(250,32));
 +
MyCanvas * drawPanel = new MyCanvas(App,this, wxID_ANY, wxPoint(0,35), wxSize(640 , 480), wxTAB_TRAVERSAL | wxSUNKEN_BORDER);
 +
    m_drawPanel = drawPanel;
 +
    //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();
 +
wxStaticText * aLabel = new wxStaticText(ControlPanel, wxID_ANY, _T("This is a wxGauge"),
 +
                              wxPoint(250, 60), wxDefaultSize,
 +
                              wxALIGN_CENTRE /*| wxST_NO_AUTORESIZE*/);
 +
    aLabel->SetForegroundColour( *wxBLACK );
 +
wxStaticText * bLabel = new wxStaticText(ControlPanel2, wxID_ANY, _T("This is 2 wxTextCtrl"),
 +
                              wxPoint(250, 60), wxDefaultSize,
 +
                              wxALIGN_CENTRE /*| wxST_NO_AUTORESIZE*/);
 +
    bLabel->SetForegroundColour( *wxBLACK );
 +
// validator that only accept number keys
 +
wxTextValidator OnlyNum = wxTextValidator(wxFILTER_NUMERIC);
 +
    // text box that accepts all
 +
wxTextCtrl * aText = new wxTextCtrl(ControlPanel2, wxID_ANY, _T("Any text"), wxDefaultPosition, wxSize(100, 20), wxTE_RIGHT);
 +
    // text box that only take numbers
 +
wxTextCtrl * bText = new wxTextCtrl(ControlPanel2, wxID_ANY, _T("1"), wxDefaultPosition, wxSize(100, 20), wxTE_RIGHT, OnlyNum);
 +
wxBoxSizer *cpSizer = new wxBoxSizer(wxVERTICAL);
 +
cpSizer->Add(aLabel, wxSizerFlags().Proportion(0).Expand().Border(wxALL,4));
 +
cpSizer->Add(ProgressBar, wxSizerFlags().Proportion(0).Expand().Border(wxALL,4));
 +
ControlPanel->SetSizer/*AndFit*/(cpSizer);
 +
wxBoxSizer *cpSizer2 = new wxBoxSizer(wxVERTICAL);
 +
cpSizer2->Add(bLabel, wxSizerFlags().Proportion(0).Expand().Border(wxALL,4));
 +
cpSizer2->Add(aText, wxSizerFlags().Proportion(0).Expand().Border(wxALL,4));
 +
cpSizer2->Add(bText, wxSizerFlags().Proportion(0).Expand().Border(wxALL,4));
 +
ControlPanel2->SetSizer/*AndFit*/(cpSizer2);
 +
wxBoxSizer *auxSizer = new wxBoxSizer(wxHORIZONTAL);
 +
auxSizer->Add(ControlPanel2, wxSizerFlags().Proportion(0).Expand().Border(wxALL,4));
 +
auxSizer->Add(drawPanel, wxSizerFlags().Proportion(1).Expand().Border(wxALL,4));
 +
wxBoxSizer * topSizer = new wxBoxSizer(wxVERTICAL);
 +
topSizer->Add(ControlPanel, wxSizerFlags().Proportion(0).Expand());
 +
topSizer->Add(auxSizer, wxSizerFlags().Proportion(1).Expand());
 +
SetSizerAndFit(topSizer);
 +
    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();
 +
            }
 +
            m_drawPanel->drawSomething();
 +
        }
 +
        for(i=99;i>=2;i--)
 +
        {
 +
            ProgressBar->SetValue(i);
 +
            while((TopFrame *) App->Pending())
 +
            {
 +
                token_true=(TopFrame *) App->Dispatch();
 +
            }
 +
            m_drawPanel->drawSomething();
 +
        }
 +
    }
 +
}
 +
void TopFrame::OnStop(wxCommandEvent& WXUNUSED(event))
 +
{
 +
    m_running = false;
 +
}
 +
</pre>
 +
 
 +
'''mycanvas.h'''
 +
<pre>
 +
class MyCanvas : public wxWindow
 +
{
 +
public:
 +
MyCanvas(SampleApp * AApp, wxWindow *parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0);
 +
void drawSomething();
 +
    wxMemoryDC dc;
 +
    wxGraphicsContext *gc;
 +
    int countx, county;
 +
protected: // event handlers (NO virtual)
 +
void OnPaint(wxPaintEvent& event);
 +
void OnMaximize(wxSizeEvent& event);
 +
private:
 +
wxBitmap m_pixels;
 +
SampleApp * App;
 +
// any class wishing to process wxWidgets events must use this macro
 +
DECLARE_EVENT_TABLE()
 +
};
 +
</pre>
 +
 
 +
'''mycanvas.cpp'''
 +
<pre>
 +
#include <wx/wx.h>
 +
#include <wx/icon.h>
 +
#include <wx/font.h>
 +
#include <wx/numdlg.h>
 +
#include <wx/string.h>
 +
#include <wx/event.h>
 +
#include <wx/textctrl.h>
 +
#include <wx/wfstream.h>
 +
#include <wx/datstrm.h>
 +
#include <wx/txtstrm.h>
 +
#include <wx/access.h>
 +
#include <wx/window.h>
 +
#include <wx/treectrl.h>
 +
#include <wx/spinctrl.h>
 +
#include <wx/collpane.h>
 +
#include <wx/stdpaths.h>
 +
#include <wx/datetime.h>
 +
#include <wx/graphics.h>
 +
#include "main.h"
 +
#include "mycanvas.h"
 +
BEGIN_EVENT_TABLE(MyCanvas, wxWindow)
 +
EVT_PAINT(MyCanvas::OnPaint) //to can paint in window
 +
EVT_SIZE(MyCanvas::OnMaximize) //answer to size changes (p.ej. maximize events)
 +
END_EVENT_TABLE()
 +
const int BMPW = 3000; //auxvars
 +
const int BMPH = 2000; //auxvars
 +
MyCanvas::MyCanvas(SampleApp * AApp, wxWindow *parent, wxWindowID id, const wxPoint& pos /*= wxDefaultPosition*/, const wxSize& size /*= wxDefaultSize*/, long style /*= 0*/)
 +
:wxWindow(parent,id,pos,size,style),
 +
m_pixels(BMPW,BMPH,-1)
 +
{
 +
    App = AApp;
 +
}
 +
/***************************************************************/
 +
/************** OnMaximize ************************************/
 +
/************** answer to Size changes ************************/
 +
/************** Used to resize all elements ********************/
 +
/***************************************************************/
 +
void MyCanvas::OnMaximize(wxSizeEvent& WXUNUSED(event))
 +
{
 +
}
 +
/***************************************************************/
 +
/************** OnPaint ****************************************/
 +
/************** answer to paint events *************************/
 +
/************** Prepares the window to paint it ****************/
 +
/***************************************************************/
 +
void MyCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
 +
{
 +
  wxPaintDC Pdc(this);
 +
Pdc.DrawBitmap(m_pixels, 0, 0, false);
 +
}
 +
/***************************************************************/
 +
/************** drawSomething ********************************/
 +
/************** Paint the canvas ****************************/
 +
/***************************************************************/
 +
void MyCanvas::drawSomething()
 +
{
 +
    wxMemoryDC dc;
 +
    dc.SelectObject( m_pixels );
 +
    dc.Clear();
 +
    dc.SetPen(wxPen(wxColour(0,0,0)));  //black pen
 +
    dc.DrawLine(countx, county*5, countx, county*5 + 5);
 +
    int sizex,sizey;
 +
    GetSize(&sizex, &sizey); //take sizes to scale some elements
 +
    countx++;
 +
    if(countx>sizex)
 +
    {
 +
        countx = 0;
 +
        county++;
 +
    }
 +
    dc.SelectObject( wxNullBitmap ); //unselect the bitmap
 +
    Refresh(false); //draw everything
 +
    Update();
 +
}
 +
</pre>
  
 
== Primera despedida ==
 
== Primera despedida ==

Última revisión de 13:50 8 jun 2010

Contenido

[editar] Introducción

En este capítulo no vamos a introducir nada nuevo, tan sólo vamos a trabajar con dos elementos un tanto singulares, ambos dedicados a desarrollarnos como artistas, pues el primero son los sizers, que nos ayudarán enormemente a organizar nuestras ventanas, y el segundo es wxWindow, que serán las ventanas donde pintaremos.

Parecerá chocante la forma de moverse de wxWidgets en cuanto a nomenclatura, pues las wxWindow serán para nosotros lo que para el resto de la humanidad son las Canvas, wxFrame, como ya vimos en capítulos anteriores, no serán pantallas (para pintar por ejemplo), sino ventanas de cabecera. El único que mantiene una cierta línea clásica es wxDialog, que aunque no llegaremos a usarlo, os podeis imaginar que su uso será del todo análogo.

Por tanto presentemos el plan de trabajo para este capítulo:

  • Plan de trabajo del capítulo 4:
    • Creación de una wxWindow:
      Crearemos nuestra primera ventana para pintar, dentro del propio TopFrame.
    • Organización de los elementos en la ventana (sizers):
      Usando los sizers colocaremos a nuestro gusto todos los elementos que tenemos.
      • Creación de algunos elementos basura:
        Crearemos unos cuantos cuadros de texto y labels para tener mas objetos que poder colocar.
      • Colocación de los elementos.
    • Pintado de la wxWindow:
      • Pintado directo (wxPaintDC).
      • Pintado sobre un bitmap (wxMemoryDC).
      • Pintado con contexto gráfico. (de momento queda pendiente)

El último punto es realmente interesante, y una de las más modernas implementaciones de estas magníficas librerías. No obstante esta herramienta nos costará algunos disgustos cuando compilemos en Windows, lo primero porque en Windows tienes que añadir estas librerías manualmente, y lo segundo porque sufren de una alta inestabilidad.

Hecha esta breve introducción, procedamos a trabajar un poco...

[editar] Creación de una wxWindow:

Como siempre, con nuestra API bien cerquita, acudimos a ella y buscamos wxWindow, y nos informamos de todas las posibilidades que tiene (que son muchas). Para proceder con una wxWindow, al igual que con una wxFrame, y con un wxDialog, nos crearemos una clase heredada de wxWindow.

Ya introducimos esta idea cuando creamos nuestra wxFrame, y ya adelantabamos que cuando nos encontráramos con elementos complicados (una ventana, un dialogo, un canvas, una malla...) debíamos actuar de esta forma.

Bueno, ya que hemos alineado un poco nuestras ideas, recuperamos nuestro proyecto donde lo dejamos, y creamos dos archivos, llamados "mycanvas.cpp" y "mycanvas.h".

Y declaramos nuestra nueva clase, en "mycanvas.h":

#ifndef _MYCANVAS_H
#define	_MYCANVAS_H

class MyCanvas : public wxWindow
    {
    public:
        MyCanvas(SampleApp * AApp, wxWindow *parent, wxWindowID id, const wxPoint& 
        pos=wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0);

        void drawSomething();
        wxMemoryDC dc;
        wxGraphicsContext *gc;

protected: // event handlers (NO virtual)
    void OnPaint(wxPaintEvent& event);
    void OnMaximize(wxSizeEvent& event);
    private:
    wxBitmap m_pixels;
    SampleApp * App;

    // any class wishing to process wxWidgets events must use this macro
    DECLARE_EVENT_TABLE()
};

#endif	/* _MYCANVAS_H */

En un acto de previsión, hemos ido añadiendo todo aquello que creemos que vamos a necesitar, tal vez sería buena idea que buscarais en el API todos los elementos que hemos añadido.

El siguiente punto es crear nuestra clase, en "mycanvas.cpp":

  #include <wx/wx.h>
  #include <wx/icon.h>
  #include <wx/font.h>
  #include <wx/numdlg.h>
  #include <wx/string.h>
  #include <wx/event.h>
  #include <wx/textctrl.h>
  #include <wx/wfstream.h>
  #include <wx/datstrm.h>
  #include <wx/txtstrm.h>
  #include <wx/access.h>
  #include <wx/window.h>
  #include <wx/treectrl.h>
  #include <wx/spinctrl.h>
  #include <wx/collpane.h>
  #include <wx/stdpaths.h>
  #include <wx/datetime.h>
  #include <wx/graphics.h>
  #include "main.h"
  #include "mycanvas.h"
  
  BEGIN_EVENT_TABLE(MyCanvas, wxWindow)
  	EVT_PAINT(MyCanvas::OnPaint)			// dibujar en la ventana
  	EVT_SIZE(MyCanvas::OnMaximize)			// responder a los cambios de tamaño (p.ej maximizar)	
  END_EVENT_TABLE()
  
  const int BMPW = 3000;	//auxvars
  const int BMPH = 2000;	//auxvars
  
  MyCanvas::MyCanvas(SampleApp * AApp, wxWindow *parent, wxWindowID id, const wxPoint& 
   pos /*= wxDefaultPosition*/, const wxSize& size /*= wxDefaultSize*/, long style /*= 0*/)
  :wxWindow(parent,id,pos,size,style),
  m_pixels(BMPW,BMPH,-1)
  {
      App = AApp;
  }
  
  /* OnMaximize responde a los cambios de tamaño */
  void MyCanvas::OnMaximize(wxSizeEvent& WXUNUSED(event))
  {
  }
  
  /* OnPaint responde a los eventos de pintar. Prepara la ventana para pintar en ella */
  void MyCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
  {
  }
  
  /* drawSomething pinta */
  void MyCanvas::drawSomething()
  {
  }

Paremos un segundo a explicar a que viene cada cosa.

  1. De repente añado un montón de librerías, que ni siquiera nos son necesarias... Esas librerías son las típicas que casi seguro tarde o temprano terminareis por usar, es por eso que las añado.
  2. ¿Un sizeevent?... Como maximizamos nuestra TopFrame, es previsible que el tamaño de esta ventana cambie junto a el, On Maximize será el encargado de arreglar los posibles desperfectos.
  3. ¿Dos constantes?... Efectivamente, si miramos esas líneas de código:
 (...)
 const int BMPW = 3000;	//auxvars
 const int BMPH = 2000;	//auxvars
 
 MyCanvas::MyCanvas(SampleApp * AApp, wxWindow *parent, wxWindowID id, const wxPoint& 
  pos /*= wxDefaultPosition*/, const wxSize& size /*= wxDefaultSize*/, long style /*= 0*/)
 :wxWindow(parent,id,pos,size,style),
 m_pixels(BMPW,BMPH,-1)
 (...)

Lo que hacemos es crear un ancho y un alto, y montar con ellos nuestro bitmap (m_pixels). Ya veremos su utilidad, de momento nos bastará con saber que estos valores deben ser superiores a la resolución de pantalla, o por lo menos al tamaño de la ventana.

Respecto a las funciones, pues lo mas interesante es que tenemos un drawSomething(), que será al que llamaremos para pintar, y que será el que cree el evento para que OnPaint haga el trabajo. Esto es un primer esbozo, porque pronto veremos como no trabajaremos exactamente así.

Bueno, y ahora solo resta añadirla a topframe, así que empezamos por "topframe.h":

 (...)
 private:
 	SampleApp * App;
 	MyCanvas * m_drawPanel;
     DECLARE_EVENT_TABLE()
 };

Haber incluido esta clase en la cabecera de topframe, nos obliga a que siempre que se incluya "topframe.h", haya que incluir antes "mycnavas.h", y por otro lado, "mycanvas.h" requiere de "main.h" antes de ella. Así, en "main.cpp" debemos añadir lo siguiente:

 (...)
 #include "main.h"
 #include "mycanvas.h"
 #include "topframe.h"
 (...)

Y añadimos y construimos MyCanvas en "topframe.cpp":

 (...)
 #include "main.h"
 #include "mycanvas.h"
 #include "topframe.h"
 #include "header.h"
 (...)
(...)
 	ProgressBar = new wxGauge(ControlPanel, wxID_ANY, 100, wxPoint(3,3), wxSize(250,32));
 	MyCanvas * drawPanel = new MyCanvas(App,this, wxID_ANY, wxPoint(0,35), wxSize(640 , 480), wxTAB_TRAVERSAL | wxSUNKEN_BORDER);
     m_drawPanel = drawPanel;
 
     //toolbar
(...)

Con lo que creamos nuestra ventana en el punto wxPoint(0,35) con un tamaño de wxSize(640 , 480).

Compilamos y ejecutamos... ¡Y allí está! ¡nuestra ventana!

Pero el aspecto no es precisamente el deseado ¿verdad?, para arreglar esto vamos a recurrir a los sizers.

[editar] Organización de los elementos en la ventana (sizers):

Los sizers son una herramienta indispensable en la programación con wxWidgets, y se deben tener siempre presentes a la hora de programar. Nosotros concretamente vamos a usar wxBoxSizer, aunque existen algunas otras variantes que pueden ser muy interesantes. Pero para poder dar un poco más de juego, vamos primero a crear algunos elementos basura.

[editar] Creación de algunos elementos basura:

Propongamos poner, en la parte superior la scrollbar con un título (una etiqueta), y debajo, en la izquierda una columna de dos cuadros de texto, precedidos de una label, y en la derecha nuestro recien creado Canvas...

Asi que nos faltan dos etiquetas, y dos cuadros de texto, que por supuesto, para encontrar información sobre ellos, recurrimos a nuestra resabiada API, en la que si buscamos label, podemos encontrar, entre otras cosas, la clase wxStaticText, que es exactamente lo que buscabamos.

Así que vayamos a topframe.cpp, y creemos nuestras dos nuevas etiquetas al final del constructor:

(...)
   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"));
	wxStaticText * aLabel = new wxStaticText(<<DatePanel>>, wxID_ANY, _T("This is a wxGauge"),
                              wxPoint(250, 60), wxDefaultSize,
                              wxALIGN_CENTRE /*| wxST_NO_AUTORESIZE*/);
   aLabel->SetForegroundColour( *wxBLACK );
   
	wxStaticText * bLabel = new wxStaticText(<<DatePanel>>, wxID_ANY, _T("This is 2 wxTextCtrl"),
                              wxPoint(250, 60), wxDefaultSize,
                              wxALIGN_CENTRE /*| wxST_NO_AUTORESIZE*/);
   bLabel->SetForegroundColour( *wxBLACK );
   m_running = false;
(...)

Conviene destacar que les he dado un punto de creación a ambas (250, 60), pero ya vereis como eso no importa... Y es importante reseñar que en el window parent, pongo <<DatePanel>>, esto es porque como aun no hemos creado paneles para introducir estos elementos, para que si se nos olvida, nos devuelva un error.

Ahora volvemos a nuestro API, y buscamos text, encontrando la clase wxTextCtrl, si nos fijamos en su constructor, aparece algo muy interesante, el validador wxValidator (pinchamos sobre el link para conseguir información), que nos va a permitir restringir nuestro segundo cuadro de texto a solo números...

Asi que añadimos sendos cuadros de texto a nuestra interfaz, nuevamente al final de topframe.cpp:

(...)
   bLabel->SetForegroundColour( *wxBLACK );    
	// validator that only accept number keys
	wxTextValidator OnlyNum = wxTextValidator(wxFILTER_NUMERIC);
   // text box that accepts all
	wxTextCtrl * aText = new wxTextCtrl(<<DatePanel>>, wxID_ANY, _T("Any text"), wxDefaultPosition, wxSize(100, 20), wxTE_RIGHT);
   // text box that only take numbers
	wxTextCtrl * bText = new wxTextCtrl(<<DatePanel>>, wxID_ANY, _T("1"), wxDefaultPosition, wxSize(100, 20), wxTE_RIGHT, OnlyNum);
   m_running = false;
(...)

Y ya tenemos nuestros elementos, solo debemos colocarlos...

[editar] Colocación de los elementos.

Como ya hemos dicho, nuestros cuadros de texto irán en una columna diferente de nuestra barra de progreso, luego necesitan un panel distinto, así que creemos un panel para ellos:

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

Y ahora ya si, ¡comenzemos con los wxSizers!, como siempre, lo primero la documentación, en la que buscamos sizer, y que rapidamente nos muestra, entre otras cosas, wxBoxSizer. Bien, si leeemos atentamente la documentación, veremos que estos sizers nos permiten colocar los elementos como si fueran cajas Cuyo alto y ancho debe coincidir entre ellas (con sus proporciones), y que nos permite apilarlas horizontal o verticalmente.

Bien, empezemos con nuestro panel para la scrollbar, en el que recordemos, primero va aLabel, y debajo ProgressBar, así que editamos aLabel para que este en el mismo panel que ProgressBar:

(...)
	wxStaticText * aLabel = new wxStaticText(ControlPanel, wxID_ANY, _T("This is a wxGauge"),
                              wxPoint(250, 60), wxDefaultSize,
                              wxALIGN_CENTRE /*| wxST_NO_AUTORESIZE*/);
   aLabel->SetForegroundColour( *wxBLACK );
(...)

Y al final del constructor de topframe creamos un sizer para ellos:

(...)
	wxBoxSizer *cpSizer = new wxBoxSizer(wxVERTICAL);
	cpSizer->Add(aLabel, wxSizerFlags().Proportion(1).Expand().Border(wxALL,4));
	cpSizer->Add(ProgressBar, wxSizerFlags().Proportion(1).Expand().Border(wxALL,4));
	ControlPanel->SetSizer/*AndFit*/(cpSizer);
(...)

Y repetimos para nuestra columna de cuadros de texto, los cuales editamos para que se incluyan en el ControlPanel2:

(...)
	wxStaticText * bLabel = new wxStaticText(ControlPanel2, wxID_ANY, _T("This is 2 wxTextCtrl"),
                              wxPoint(250, 60), wxDefaultSize,
                              wxALIGN_CENTRE /*| wxST_NO_AUTORESIZE*/);
    bLabel->SetForegroundColour( *wxBLACK );    
	// validator that only accept number keys
	wxTextValidator OnlyNum = wxTextValidator(wxFILTER_NUMERIC); 
    // text box that accepts all
	wxTextCtrl * aText = new wxTextCtrl(ControlPanel2, wxID_ANY, _T("Any text"), wxDefaultPosition, wxSize(100, 20), wxTE_RIGHT);
    // text box that only take numbers
	wxTextCtrl * bText = new wxTextCtrl(ControlPanel2, wxID_ANY, _T("1"), wxDefaultPosition, wxSize(100, 20), wxTE_RIGHT, OnlyNum);
(...)

Y creamos el sizer para este panel:

(...)
	wxBoxSizer *cpSizer2 = new wxBoxSizer(wxVERTICAL);
	cpSizer2->Add(bLabel, wxSizerFlags().Proportion(0).Expand().Border(wxALL,4));
	cpSizer2->Add(aText, wxSizerFlags().Proportion(0).Expand().Border(wxALL,4));
	cpSizer2->Add(bText, wxSizerFlags().Proportion(0).Expand().Border(wxALL,4));
	ControlPanel2->SetSizer/*AndFit*/(cpSizer2);
(...)

Bien, habíamos propuesto que esta columna de cuadros de texto estuvíera emparejada a nuestro canvas, de tal foma que creamos un sizer horizontal (justo a continuación):

(...)
	wxBoxSizer *auxSizer = new wxBoxSizer(wxHORIZONTAL);
	auxSizer->Add(ControlPanel2, wxSizerFlags().Proportion(0).Expand().Border(wxALL,4));
	auxSizer->Add(drawPanel, wxSizerFlags().Proportion(1).Expand().Border(wxALL,4));
(...)

Y por último, esta pareja debe situarse debajo de la progress bar, de tal forma que creamos ya nuestro sizer definitivo, con el que setearemos ya nuestra ventana:

(...)
	wxBoxSizer * topSizer = new wxBoxSizer(wxVERTICAL);
	topSizer->Add(ControlPanel, wxSizerFlags().Proportion(0).Expand());
	topSizer->Add(auxSizer, wxSizerFlags().Proportion(1).Expand());
	SetSizerAndFit(topSizer);
(...)

Es muy importante el tema de las proporciones... Cuando se pone proporción 0, se ajusta al tamaño del elemento, haciéndose tan pequeño como pueda, pero cuando se pone proporción 1, el elemento es el que se ajusta, haciéndose tan grande como pueda, así, si atendemos a nuestros sizers, yo le he puesto proporción 1 al canvas, primero en el modo horizontal en auxSizer, y luego en el modo vertical en topSizer.

Compilar y ejecutar para ver el aspecto... ¡Exito rotundo!

[editar] Pintado de la wxWindow:

Bueno, pues colocados todos los elementos, ya sólo nos queda pintar en nuestra wxWindow. pongamos que pintamos una linea vertical cada vez que se actualiza (en el bucle de la progress bar por ejemplo)...

[editar] Pintado directo (wxPaintDC).

Por supuesto, nada más ver el título, hay que tener ya nuestra documentación en las narices con wxPaintDC abierto. Si investigamos un poco, veremos que hay una gran variedad de formas de pintar en el canvas, pero que destacan dos:

  • wxPaintDC
    Es la forma nativa, y tarde o temprano hay que usarla, ya que es la que nos pinta realmente sobre la pantalla. No obstante es la forma más primitiva de hacerlo, y tiene el problema de que se ve como va evolucionando el pintado, de tal forma que si el pintado requiere un alto número de operaciones, se verá como se va realizando, con un molesto parpadeo (efecto flicker).
  • wxMemoryDC
    Precisamente para evitar este problema, se usa esta clase, que basicamente nos permitirá ir pintando sobre un mapa de bits, y luego pintar este mapa todo de golpe sobre el canvas usando el wxPaintDC.

Así que efectivamente, la clase que nos ocupa unicamente se encargará de pintar el bitmap, así pues, en el metodo OnPaint de mycanvas.cpp añadimos:

(...)
void MyCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
{
   	wxPaintDC Pdc(this);
	Pdc.DrawBitmap(m_pixels, 0, 0, false);
}
(...)

Que efecitamente, cada vez que llamemos a Update() o a Refresh() (o a ambas si queremos forzar el pintado inmediato), se entrará en este método en el que Pdc pintará el bitmap m_pixels.

[editar] Pintado sobre un bitmap (wxMemoryDC).

Este va a ser el que realmente tenga interés, ya que realmente será el que haga todo el trabajo... En este caso acudiremos al método drawSomething(). Pero antes necesitamos dos variables contadoras que nos permitan colocar nuestros palitos horizontal y verticalmente, así que en mycanvas.h añadimos dos contadores:

(...)
public:
	MyCanvas(SampleApp * AApp, wxWindow *parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long  style = 0);
	void drawSomething();
    wxMemoryDC dc;
    wxGraphicsContext *gc;
    int countx, county;
(...)

Y en el constructor de mycanvas, en mycanvas.cpp, iniciamos los contadores:

MyCanvas::MyCanvas(SampleApp * AApp, wxWindow *parent, wxWindowID id, const wxPoint& pos /*= wxDefaultPosition*/, const wxSize& size /*= wxDefaultSize*/, long style /*= 0*/)
:wxWindow(parent,id,pos,size,style),
m_pixels(BMPW,BMPH,-1)
{
    App = AApp;
    countx = 0;
    county = 0;
}

Y ya podemos pasar a pintar, para ello, en este mismo archivo, en el método drawSomething, creamos nuestro pintor:

(...)
void MyCanvas::drawSomething()
{
    wxMemoryDC dc;        
}
(...)

Y como tenemos la documentación, sabemos que lo primero que debemos hacer es seleccionar el bitmap y limpiarlo (el fondo por defecto es blanco, pero se puede cambiar):

(...)
void MyCanvas::drawSomething()
{
    wxMemoryDC dc;        
    dc.SelectObject( m_pixels );
    dc.Clear();
}
(...)

Bien, y ahora pintamos un palote de 5 unidades de alto. Este palote se deberá situar en x=countx, y en y=county*5, luego veremos como nos movemos con countx y county para que hagan los "retornos de carro" al llegar al final de la ventana.

(...)
void MyCanvas::drawSomething()
{
    wxMemoryDC dc;        
    dc.SelectObject( m_pixels );
    dc.Clear();
    dc.SetPen(wxPen(wxColour(0,0,0)));  //black pen
    dc.DrawLine(countx, county*5, countx, county*5 + 5);
}
(...)

Ahora gestionemos countx y county. Countx debe incementarse una unidad cada vez que se llame a drawSomething, y si en algun momento se supera el borde de la wxWindow, deberá volver a ser cero, incrementándose en una unidad county:

(...)
void MyCanvas::drawSomething()
{
    wxMemoryDC dc;        
    dc.SelectObject( m_pixels );
    dc.Clear();
    dc.SetPen(wxPen(wxColour(0,0,0)));  //black pen
    dc.DrawLine(countx, county*5, countx, county*5 + 5);
    int sizex,sizey;
    GetSize(&sizex, &sizey);	//take sizes to scale some elements
    countx++;
    if(countx>sizex)
    {
        countx = 0;
        county++;
    }
}
(...)

Y por último debemos pedirle a nuestro drawSomething que solicite el pintado:

(...)
void MyCanvas::drawSomething()
{
    wxMemoryDC dc;        
    dc.SelectObject( m_pixels );
    dc.Clear();
    dc.SetPen(wxPen(wxColour(0,0,0)));  //black pen
    dc.DrawLine(countx, county*5, countx, county*5 + 5);
    int sizex,sizey;
    GetSize(&sizex, &sizey);	//take sizes to scale some elements
    countx++;
    if(countx>sizex)
    {
        countx = 0;
        county++;
    }
    dc.SelectObject( wxNullBitmap );					//unselect the bitmap
    Refresh(false);							//draw everything
    Update();								//force to paint
}
(...)

Y ya está, ahora sólo hay que pedirle al programa que use este método, y para ello vamos a topframe.cpp, y editamos:

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();
            }
            m_drawPanel->drawSomething();
        }
        for(i=99;i>=2;i--)
        {
            ProgressBar->SetValue(i);
            while((TopFrame *) App->Pending())
            {
                token_true=(TopFrame *) App->Dispatch();
            }
            m_drawPanel->drawSomething();
        }
    }
}

Compilamos, ejecutamos y damos a start. ¡Esto ya si que empieza a ser un programa!

[editar] Pintado con contexto gráfico.

Aún queda un punto importante a la hora de pintar, y es el pintado con contexto grafico. No obstante, esta tecnica es algho mas complicada y larga de explicar, así que sólo haré (al menos de momento) unas breves reseñas.

El pintado con contexto gráfico basicamente lo que permite es hacer uso de funciones de Cairo en Gnome, o de GDI+ en windows, etc... Estas funciones son lo que se denominan arte 2D, y consisten basicamente en uso de texturas, canales alfa (transparencias), y otro tipo de efecto 2D.

El contexto gráfico no esta completamente desarrollado en wxWidgets, pero ya es perfectamente usable.

Basicamente el modo de uso es cuanto menos poco ordinario, ya que consiste en anclarlo a nuestro DC (wxPaintDC o wxMemoryDC), de tal forma que este "hereda" el contexto gráfico.

Uno de los grandes problemas de dicho contexto gráfico es que requiere de algunas librerias un tanto especiales, y hablo de Windows, que puedes tener o no, luego hay que lo grarselas, y compilar wxWidgets cambiando algunos headers para que haga uso de ellas.

[editar] Conclusión

En este capítulo por fin nos hemos logrado un programa decente, y hemos visto dos puntos fundamentales, los 'sizers', y el 'pintado de ventanas'.

Cierto es que hemos dejado de lado el pintado con contexto gráfico, pero le hemos hecho una pequeña introducción que tal vez algún día se complemente con un capítulo dedicado a él.

Con la conclusión de este capítulo ya si que no queda ningún secreto relevante acerca de lo que es la programación con wxWidgets. Dando un breve repaso, las cosas que nos quedan por aprender son:

  • Compilado en Windows
  • Hacer un makefile en Linux (un primer instalador)
  • Hacer un paquete Debian (el instalador que, como usuarios de Ubuntu, más nos interesa)

Este listado no pretende ser intensivo, pero si extensivo, es decir, estos son los puntos que seas como sea hay que controlar, pero no descarto hacer más capítulos con otros puntos.

Aún así, en el proximo capítulo volveremos a sentir este contexto gráfico, pues el primer paso será lograrnos un compilador y las librerías para Windows, y tendremos muy en cuenta este contexto gráfico a la hora de compilar las wxWidgets.

Pero todo eso será en el próximo capítulo, en el que efectivamente aprenderemos todo lo necesario para hacer un compilado en Windows, por ejemplo, haciendo uso de VirtualBox.

Finalmente nuestros archivos han quedado así:

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;
	MyCanvas * m_drawPanel;
    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 "mycanvas.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
	wxPanel * ControlPanel = new wxPanel(this, wxID_ANY, wxPoint(0,0), wxSize(256, 32));
	wxPanel * ControlPanel2 = new wxPanel(this, wxID_ANY, wxPoint(0,0), wxSize(256, 32));
	ProgressBar = new wxGauge(ControlPanel, wxID_ANY, 100, wxPoint(3,3), wxSize(250,32));
	MyCanvas * drawPanel = new MyCanvas(App,this, wxID_ANY, wxPoint(0,35), wxSize(640 , 480), wxTAB_TRAVERSAL | wxSUNKEN_BORDER);
    m_drawPanel = drawPanel;
    //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();
	wxStaticText * aLabel = new wxStaticText(ControlPanel, wxID_ANY, _T("This is a wxGauge"),
                               wxPoint(250, 60), wxDefaultSize,
                               wxALIGN_CENTRE /*| wxST_NO_AUTORESIZE*/);
    aLabel->SetForegroundColour( *wxBLACK );
	wxStaticText * bLabel = new wxStaticText(ControlPanel2, wxID_ANY, _T("This is 2 wxTextCtrl"),
                               wxPoint(250, 60), wxDefaultSize,
                               wxALIGN_CENTRE /*| wxST_NO_AUTORESIZE*/);
    bLabel->SetForegroundColour( *wxBLACK );
	// validator that only accept number keys
	wxTextValidator OnlyNum = wxTextValidator(wxFILTER_NUMERIC);
    // text box that accepts all
	wxTextCtrl * aText = new wxTextCtrl(ControlPanel2, wxID_ANY, _T("Any text"), wxDefaultPosition, wxSize(100, 20), wxTE_RIGHT);
    // text box that only take numbers
	wxTextCtrl * bText = new wxTextCtrl(ControlPanel2, wxID_ANY, _T("1"), wxDefaultPosition, wxSize(100, 20), wxTE_RIGHT, OnlyNum);
	wxBoxSizer *cpSizer = new wxBoxSizer(wxVERTICAL);
	cpSizer->Add(aLabel, wxSizerFlags().Proportion(0).Expand().Border(wxALL,4));
	cpSizer->Add(ProgressBar, wxSizerFlags().Proportion(0).Expand().Border(wxALL,4));
	ControlPanel->SetSizer/*AndFit*/(cpSizer);
	wxBoxSizer *cpSizer2 = new wxBoxSizer(wxVERTICAL);
	cpSizer2->Add(bLabel, wxSizerFlags().Proportion(0).Expand().Border(wxALL,4));
	cpSizer2->Add(aText, wxSizerFlags().Proportion(0).Expand().Border(wxALL,4));
	cpSizer2->Add(bText, wxSizerFlags().Proportion(0).Expand().Border(wxALL,4));
	ControlPanel2->SetSizer/*AndFit*/(cpSizer2);
	wxBoxSizer *auxSizer = new wxBoxSizer(wxHORIZONTAL);
	auxSizer->Add(ControlPanel2, wxSizerFlags().Proportion(0).Expand().Border(wxALL,4));
	auxSizer->Add(drawPanel, wxSizerFlags().Proportion(1).Expand().Border(wxALL,4));
	wxBoxSizer * topSizer = new wxBoxSizer(wxVERTICAL);
	topSizer->Add(ControlPanel, wxSizerFlags().Proportion(0).Expand());
	topSizer->Add(auxSizer, wxSizerFlags().Proportion(1).Expand());
	SetSizerAndFit(topSizer);
    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();
            }
            m_drawPanel->drawSomething();
        }
        for(i=99;i>=2;i--)
        {
            ProgressBar->SetValue(i);
            while((TopFrame *) App->Pending())
            {
                token_true=(TopFrame *) App->Dispatch();
            }
            m_drawPanel->drawSomething();
        }
    }
}
void TopFrame::OnStop(wxCommandEvent& WXUNUSED(event))
{
    m_running = false;
}

mycanvas.h

class MyCanvas : public wxWindow
{
public:
	MyCanvas(SampleApp * AApp, wxWindow *parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0);
	void drawSomething();
    wxMemoryDC dc;
    wxGraphicsContext *gc;
    int countx, county;
protected: // event handlers (NO virtual)
	void OnPaint(wxPaintEvent& event);
	void OnMaximize(wxSizeEvent& event);
private:
	wxBitmap m_pixels;
	SampleApp * App;
	// any class wishing to process wxWidgets events must use this macro
	DECLARE_EVENT_TABLE()
};

mycanvas.cpp

#include <wx/wx.h>
#include <wx/icon.h>
#include <wx/font.h>
#include <wx/numdlg.h>
#include <wx/string.h>
#include <wx/event.h>
#include <wx/textctrl.h>
#include <wx/wfstream.h>
#include <wx/datstrm.h>
#include <wx/txtstrm.h>
#include <wx/access.h>
#include <wx/window.h>
#include <wx/treectrl.h>
#include <wx/spinctrl.h>
#include <wx/collpane.h>
#include <wx/stdpaths.h>
#include <wx/datetime.h>
#include <wx/graphics.h>
#include "main.h"
#include "mycanvas.h"
BEGIN_EVENT_TABLE(MyCanvas, wxWindow)
	EVT_PAINT(MyCanvas::OnPaint)			//to can paint in window
	EVT_SIZE(MyCanvas::OnMaximize)			//answer to size changes (p.ej. maximize events)
END_EVENT_TABLE()
const int BMPW = 3000;	//auxvars
const int BMPH = 2000;	//auxvars
MyCanvas::MyCanvas(SampleApp * AApp, wxWindow *parent, wxWindowID id, const wxPoint& pos /*= wxDefaultPosition*/, const wxSize& size /*= wxDefaultSize*/, long style /*= 0*/)
:wxWindow(parent,id,pos,size,style),
m_pixels(BMPW,BMPH,-1)
{
    App = AApp;
}
/***************************************************************/
/**************	OnMaximize	************************************/
/************** answer to Size changes	************************/
/************** Used to resize all elements	********************/
/***************************************************************/
void MyCanvas::OnMaximize(wxSizeEvent& WXUNUSED(event))
{
}
/***************************************************************/
/**************	OnPaint	****************************************/
/************** answer to paint events *************************/
/************** Prepares the window to paint it ****************/
/***************************************************************/
void MyCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
{
   	wxPaintDC Pdc(this);
	Pdc.DrawBitmap(m_pixels, 0, 0, false);
}
/***************************************************************/
/**************	drawSomething	********************************/
/************** Paint the canvas	****************************/
/***************************************************************/
void MyCanvas::drawSomething()
{
    wxMemoryDC dc;
    dc.SelectObject( m_pixels );
    dc.Clear();
    dc.SetPen(wxPen(wxColour(0,0,0)));  //black pen
    dc.DrawLine(countx, county*5, countx, county*5 + 5);
    int sizex,sizey;
    GetSize(&sizex, &sizey);	//take sizes to scale some elements
    countx++;
    if(countx>sizex)
    {
        countx = 0;
        county++;
    }
    dc.SelectObject( wxNullBitmap );						//unselect the bitmap
    Refresh(false);											//draw everything
    Update();
}

[editar] Primera despedida

Quiero hacer una primera despedida, ya que si no pretendes que tus codigos sirvan en Windows, y tus aplicaciones no las consideras tan importantes como para construir instaladores, este tutorial se termina aquí para ti...

Espero que hayas disfrutado aprendiendo esta bella, y en el mundo hispano, desconocida herramienta.

Los agradecimientos los dejaré para un capítulo a parte.

Capítulo 3: ¡Qué aburrido! yo quiero interactuar Nuestra primera interfaz gráfica con CodeBlocks y wxWidgets Capítulo 5: El lado oscuro (compilando para Windows)
Herramientas personales