terça-feira, 22 de maio de 2012

OpenGL com wxWidgets

Introdução
   Para utilizar opengl com wxWidgets nós dispomos da classe wxGLCanvas. Esta classe possui os métodos SetColor(const wxString& cor) que seta a cor da janela de vizualização usando um nome de cor pré-definido, sendo portanto, uma alternativa para a função OpenGL 'glColor3f', SetCurrent(), que seta o estado representado pelo contexto de renderização OpenGL e SwapBuffers(), que é o método reponsável pela troca dos buffers atual e de fundo e vice-versa, permitindo dessa forma, que os comando OpenGL prévios (de fundo) sejam mostrados na janela de vizualização.

Exemplo
   No nosso exemplo fazer escrever uma aplicação que mostra um cubo em 3 dimensões tendo cada face uma cor. Através do movimento da 'rodinha' do mouse nosso cubo poderá ser girado em torno dos eixos x e z em ambos os sentidos, mostrando suas diferentes faces.



//main.h
#ifndef _glpane
#define _glpane

#include "wx/wx.h"
#include "wx/glcanvas.h"

class PainelGL : public wxGLCanvas
{
    public:
        float rot;
        PainelGL(wxFrame* pai);
        void resized(wxSizeEvent& evt);
        void Desenha(wxPaintEvent& evt);
        void preparaViewport3D(int topleft_x, int topleft_y, int bottomrigth_x, int bottomrigth_y);
        //evento responsável pela rotação
        void mouseWheelMoved(wxMouseEvent& evt);

        DECLARE_EVENT_TABLE()
};

class MinhaApp : public wxApp
{
    virtual bool OnInit();
    wxFrame *janela;
    PainelGL *glPainel;
};
#endif

//main.cpp
#include "wx/sizer.h"
#include "wx/glcanvas.h"
#include "main.h"

#ifdef __WXMAC__
#include "OpenGL/glu.h"
#include "OpenGL/gl.h"
#else
#include <GL/glu.h>
#include <GL/gl.h>
#endif

IMPLEMENT_APP(MinhaApp)

bool MinhaApp::OnInit()
{
    wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
    janela = new wxFrame(NULL, -1, _("OpenGL com wxWidgets"), wxDefaultPosition, wxSize(400,400));
    glPainel = new PainelGL(janela);   
    sizer->Add(glPainel, 1, wxEXPAND);
    janela->SetSizer(sizer);
    janela->SetAutoLayout(true);
    janela->Show();
    return true;
}

BEGIN_EVENT_TABLE(PainelGL, wxGLCanvas)   
    EVT_MOUSEWHEEL(PainelGL::mouseWheelMoved)
    EVT_PAINT(PainelGL::Desenha)
END_EVENT_TABLE()

void PainelGL::mouseWheelMoved(wxMouseEvent& evt)
{
    //o metodo GetWheelRotation nos indica o sentido da rotação da 'rodinha' do mouse, positivo/negativo - pra frente/pra tras
    if(evt.GetWheelRotation() > 0)
        rot += 0.5f;
    else
        rot -= 0.5f;
    //atualizamos o desenho mostrando a rotação
    Refresh();
}

PainelGL::PainelGL(wxFrame *pai) :
    wxGLCanvas(pai, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)
{
    //inicializamos o valor de rotação   
    rot = 0.5f;
    SetBackgroundStyle(wxBG_STYLE_CUSTOM);
}

void PainelGL::resized(wxSizeEvent& evt)
{
    //atualizamos o desenho no caso de redimensionamento da janela
    Refresh();
}

void PainelGL::preparaViewport3D(int topleft_x, int topleft_y, int bottomrigth_x, int bottomrigth_y)
{
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //fundo preto
    glClearDepth(1.0f);
    glEnable(GL_DEPTH_TEST); //habilita teste de profundidade   
    //testa se o valor de profundidade é menor ou igual o valor armazenado
      //passando no caso de ser verdadeiro    
    glDepthFunc(GL_LEQUAL);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    glEnable(GL_COLOR_MATERIAL);
    //define dimensões da viewport
    glViewport(topleft_x, topleft_y, bottomrigth_x, bottomrigth_y);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
   
    float ratio = (float) (bottomrigth_x ) / (float) (bottomrigth_y );
    gluPerspective(45 /*angulo de visao*/, ratio, 0.2 /*corte pra perto*/, 200 /*corte pra longe*/);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void PainelGL::Desenha(wxPaintEvent& evt)
{
    if(!IsShown())
        return;

    wxGLCanvas::SetCurrent();
    wxPaintDC(this);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   
    preparaViewport3D(0,0,GetSize().x, GetSize().y);
    glLoadIdentity();

    glColor4f(0,0,1,1);
    glTranslatef(0,0,-5);

    //rotação  nos eixos x e z
    glRotatef(rot,   1.0f, 0.0f, 1.0f);
    glBegin(GL_QUADS); //começamos a desenhar o cubo
        glColor3f(0.0f,1.0f,0.0f); //verde
        glVertex3f(1.0f, 1.0f, -1.0f);
        glVertex3f(-1.0f, 1.0f, -1.0f);
        glVertex3f(-1.0f, 1.0f, 1.0f);
        glVertex3f(1.0f, 1.0f, 1.0f);

        glColor3f(1.0f, 0.5f, 0.0f); //laranja
        glVertex3f(1.0f, -1.0f, 1.0f);
        glVertex3f(-1.0f, -1.0f, 1.0f);
        glVertex3f(-1.0f, -1.0f, -1.0f);
        glVertex3f(1.0f, -1.0f, -1.0f);

        glColor3f(1.0f, 0.0f, 0.0f); //vermelho
        glVertex3f(1.0f, 1.0f, 1.0f);
        glVertex3f(-1.0f, 1.0f, 1.0f);
        glVertex3f(-1.0f, -1.0f, 1.0f);
        glVertex3f(1.0f, -1.0f, 1.0f);

        glColor3f(1.0f, 1.0f, 0.0f); //amarelo
        glVertex3f(1.0f, -1.0f, -1.0f);
         glVertex3f(-1.0f, -1.0f, -1.0f);
        glVertex3f(-1.0f, 1.0f, -1.0f);
        glVertex3f(1.0f, 1.0f, -1.0f);

        glColor3f(0.0f, 0.0f, 1.0f); //azul
        glVertex3f(-1.0f, 1.0f, 1.0f);
        glVertex3f(-1.0f, 1.0f, -1.0f);
        glVertex3f(-1.0f, -1.0f, -1.0f);
        glVertex3f(-1.0f, -1.0f, 1.0f);

        glColor3f(1.0f, 0.0f, 1.0f); //violeta
        glVertex3f(1.0f, 1.0f, -1.0f);
        glVertex3f(1.0f, 1.0f, 1.0f);
        glVertex3f(1.0f, -1.0f, 1.0f);
        glVertex3f(1.0f, -1.0f, -1.0f);
    glEnd();

    glFlush();
    SwapBuffers();   
}

Para compilar:
g++ main.cpp -o exemplo_gl `wx-config --libs --cxxflags --gl-libs` -lGLU

Referências:
http://wiki.wxwidgets.org/WxGLCanvas

http://docs.wxwidgets.org/trunk/classwx_g_l_canvas.html#a9f9ab3909606484e717904064d4e7b4f
http://nehe.gamedev.net/tutorial/3d_shapes/10035/


segunda-feira, 22 de agosto de 2011

Sockets de rede com wxWidgets

Introdução
    Em computação sockets são basicamente o elo de ligação entre duas máquinas na rede. O socket pode ser entendido como sendo IP:Porta (Protocolo TCP) onde os dados são transmitidos entre cliente e servidor como uma cadeia de bytes. Existe também a transmissão em forma de datagramas não confiáveis (Protocolo UDP).
   O endereço IP identifica a máquina à qual eu quero me conectar e a porta o serviço executando nesta máquina. Para que um cliente se conecte à determinada máquina em determinada porta é preciso que um servidor esteja 'escutando' nesta porta.
   Em wxWidgets nós temos algumas classes usadas com o propósito de comunicação em rede através de sockets. A classe wxSocketBase, de onde descendem as demais classes relacionadas com sockets, como wxSocketClient e wxSocketServer. Para mais informações acerca destas classes visite: http://docs.wxwidgets.org/stable/wx_wxsocketbase.html#wxsocketbase.

Exemplo
    Em nosso exemplo vamos escrever uma aplicação que será o cliente e outra que será o servidor. Para que o cliente se conecte é preciso que o servidor esteja em execução, 'escutando' na porta definida. O cliente e o servidor podem ser executados na mesma máquina ou em máquinas separadas, conectadas à mesma rede. No primeiro caso fornecemos para o cliente como nome do host servidor a string 'localhost', no segundo caso fornecemos uma string com o número ip da máquina onde está o aplicativo servidor. A aplicação cliente enviará uma string ao servidor que retornará esta mesma string para o cliente, então, o cliente compara a string recebida de volta pelo servidor com a string enviada. Uma mensagem é mostrada dependendo do resultado da comparação (sucesso ou falha).



Vamos ao exemplo:

//cliente.cpp
#include <wx/wx.h>
#include <wx/socket.h>
#include <wx/wfstream.h>

class MeuFrame : public wxFrame {
    public:
        MeuFrame(const wxString &titulo);
        void Conectar(wxCommandEvent &evt);
        void Enviar(wxCommandEvent &evt);
        void Desconectar(wxCommandEvent &evt);
        void EscreveStatus(wxString status, int onde);
    private:
        wxBoxSizer *box;
        wxButton *btn_conectar;
        wxButton *btn_enviar;
        wxButton *btn_desconectar;
        wxTextCtrl *txt_status;     
        wxSocketClient *m_socket;
};

MeuFrame::MeuFrame(const wxString &titulo):
          wxFrame(NULL, wxID_ANY, titulo, wxDefaultPosition, wxSize(360,200))
{
     wxPanel *painel = new wxPanel(this);
     box = new wxBoxSizer(wxVERTICAL);
     wxBoxSizer *box_texto = new wxBoxSizer(wxVERTICAL);
     wxGridSizer *grid_botoes = new wxGridSizer(1,3,5,5);
     txt_status = new wxTextCtrl(painel, -1, _(""),wxDefaultPosition,wxDefaultSize,wxTE_MULTILINE | wxTE_READONLY); 
     box_texto->Add(txt_status,1,wxEXPAND); 
     btn_conectar = new wxButton(painel,1000,_("Conectar"));
     Connect(1000,wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(MeuFrame::Conectar));
     btn_enviar = new wxButton(painel,1001,_("Enviar"));
     Connect(1001,wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(MeuFrame::Enviar));
     btn_desconectar = new wxButton(painel,1002,_("Desconectar"));
     Connect(1002,wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(MeuFrame::Desconectar));
     grid_botoes->Add(btn_conectar,1,wxALL,5);
     grid_botoes->Add(btn_enviar,1,wxALL,5);
     grid_botoes->Add(btn_desconectar,1,wxALL,5);
     box->Add(box_texto,1,wxEXPAND);
     box->Add(grid_botoes,1,wxEXPAND);
     painel->SetSizer(box);
     //criamos o socket
     m_socket = new wxSocketClient();
     //definimos o manipulador de eventos para o socket
     m_socket->SetEventHandler(*this,1003);
     //
     m_socket->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
     m_socket->Notify(true);
     #if wxUSE_STATUSBAR
        //barra de status da aplicação
        CreateStatusBar(2);
     #endif
     EscreveStatus(_("Desconectado"),1);
   
     Centre();
}

void MeuFrame::Conectar(wxCommandEvent &evt)
{
    wxIPV4address end;
    wxString host = wxGetTextFromUser(_("Digite o endereço do servidor"),
                                      _("Conectar"),
                                      _("localhost")
                                      );
    //atribuimos o nome do host digitado pelo usuario
    //no nosso caso 'localhost' (o host no qual o servidor está executando),
    //mas poderia ser um numero de ip de uma máquina na rede
    end.Hostname(host);
    //o numero da porta do serviço ao qual queremos nos conectar
    //utilizamos um numero alto para evitar conflitos com portas que já são utilizadas por outros serviços
    end.Service(3000);
    //fazemos uma tentativa de conexão
    //quando o segundo parametro é true a aplicação é paralisada
    //enquantro a conexão não se estabelece
    //quando é false a conexão é tentada e retorna-se logo em seguida
    //mesmo sem sucesso
    //em caso de sucesso o método retorna true, caso contrário, retorna false
    m_socket->Connect(end,false);
    //esperamos 10 segundos tentando estabelecer a conexão
    m_socket->WaitOnConnect(10);
    if(m_socket->IsConnected())
    {
        EscreveStatus(_("Conexão realizada com sucesso!"),0);
        EscreveStatus(_("Conectado"),1);       
    }
    else
    {
        EscreveStatus(_("Não foi possível realizar a conexão!"),0);  
        EscreveStatus(_("Desconectado"),1);     
        wxMessageBox(_("Não é possível estabelecer uma conexão com o host especificado!"),_("Alerta"));
    }

}

void MeuFrame::Enviar(wxCommandEvent &evt)
{
    unsigned char tam;
    wxString str_envio;
    wxChar *str_resposta;
    m_socket->SetFlags(wxSOCKET_WAITALL);
    str_envio = wxGetTextFromUser(_("Digite um texto para enviar ao servidor"),
                                  _("Texto"),
                                  _("")
                                 );  
                                
    str_resposta = new wxChar[wxStrlen(str_envio)+1];
    //tamanho da string enviada em bytes
    tam = (unsigned char) ((wxStrlen(str_envio)+1) * sizeof(wxChar));
    txt_status->AppendText(_("\nEnviando um buffer de texto para o servidor..."));
  
    //o primeiro byte é o tamanho da string o restante é a string em si
    m_socket->Write(&tam,1);
    m_socket->Write(str_envio,tam);
    if(m_socket->Error())
    {
        txt_status->AppendText(_("\nFalha!"));
        return;
    }
    else
    {
        txt_status->AppendText(_("\nSucesso!"));
    }
 
    txt_status->AppendText(_("\nRecebendo o texto de volta do servidor..."));
  
    //armazenamos a string de resposta do servidor em str_resposta
    m_socket->Read(str_resposta,tam);
 
    txt_status->AppendText(_("\nComparando as duas strings..."));
  
    //comparamos a string enviada com a string de resposta do servidor
    if(memcmp(str_resposta,str_envio,tam) == 0)
    {
       wxString s;
       s.Printf(_("\nSucesso! String Recebida: %s"), str_resposta);
       txt_status->AppendText(s);
    }
    else
    {
       txt_status->AppendText(_("\nFalha na recepção!"));
    }
    delete[] str_resposta;
}

void MeuFrame::Desconectar(wxCommandEvent &evt)
{
    //desconectamos do servidor
    m_socket->Close();
    EscreveStatus(_(""),0);
    EscreveStatus(_("Desconectado"),1);
}

void MeuFrame::EscreveStatus(wxString status, int onde)
{
    #if wxUSE_STATUSBAR
        SetStatusText(status,onde);
    #endif
}

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

IMPLEMENT_APP(MinhaApp)

bool MinhaApp::OnInit()
{
    MeuFrame *frame = new MeuFrame(_("Sockets com wxWidgets: Cliente"));
    frame->Show(true);
    return true;
}

//servidor.cpp
#include <wx/wx.h>
#include <wx/socket.h>

enum 
{
    ID_SERVER = 1000,
    ID_SOCKET   
};

class MeuFrame : public wxFrame
{
    public:
        MeuFrame(const wxString titulo);
        void OnSocketEvent(wxSocketEvent &evt);
        void OnServerEvent(wxSocketEvent &evt);
        void Recebe(wxSocketBase *socket);
        void EscreveStatus();
    private:
        wxTextCtrl *texto;
        wxSocketServer *m_server;
        int num_clientes;
};

MeuFrame::MeuFrame(const wxString titulo):
          wxFrame(NULL, wxID_ANY, titulo, wxDefaultPosition, wxSize(360,200))
{
  
    texto = new wxTextCtrl(this,-1,_(""), wxDefaultPosition,wxDefaultSize,
                           wxTE_MULTILINE | wxTE_READONLY);
    wxIPV4address end;
    end.Service(3000);

    m_server = new wxSocketServer(end);

    //verificamos se o servidor está 'escutando'
    if(m_server->Ok())
    {
        texto->AppendText(_("Servidor escutando...\n"));
    }
    else
    {
        texto->AppendText(_("Não é possével escutar na porta especificada\n"));
        return;
    }
    
    //conectamos os eventos de socket aos seus respectivos manipuladores
    Connect(ID_SERVER,wxEVT_SOCKET,wxSocketEventHandler(MeuFrame::OnServerEvent));
    Connect(ID_SOCKET,wxEVT_SOCKET,wxSocketEventHandler(MeuFrame::OnSocketEvent));

    //configura manipulador de eventos do servidor
    m_server->SetEventHandler(*this,ID_SERVER);
    //especifica quais eventos de socket serão enviados ao manipulador de eventos
    m_server->SetNotify(wxSOCKET_CONNECTION_FLAG);
    //Notify(true) habilita os eventos de socket especificados
    m_server->Notify(true);
    num_clientes = 0;
    #if wxUSE_STATUSBAR
       //barra de status da aplicação
       CreateStatusBar(1);
    #endif
    EscreveStatus();
}

void MeuFrame::Recebe(wxSocketBase *socket)
{
    unsigned char tam;
    char *str;
    texto->AppendText(_("Recebendo dados...\n"));
    socket->SetFlags(wxSOCKET_WAITALL);
    //lemos o tamanho da string
    socket->Read(&tam,1);  
    str = new char[tam];
    //lemos a string recebida e armazenamos em str
    socket->Read(str,tam);   
    texto->AppendText(_("Enviando a string de volta...\n"));
    //enviamos a string recebida de volta ao cliente
    socket->Write(str,tam);
    delete[] str;
    texto->AppendText(_("String enviada ao cliente...\n"));
}

void MeuFrame::OnServerEvent(wxSocketEvent &evt)
{
    wxSocketBase *sock;
    //aceita uma nova conexão e cria um novo objeto wxSocketBase que representa o lado servidor da conexão
    sock = m_server->Accept(false);
    if(sock)
    {
       texto->AppendText(_("Novo cliente aceito\n"));
    }
    else
    {
       texto->AppendText(_("Não foi possível aceitar uma nova conexão\n"));
       return;
    }

    sock->SetEventHandler(*this, ID_SOCKET);
    sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
    sock->Notify(true);
    num_clientes++; 
    EscreveStatus();  
}

void MeuFrame::OnSocketEvent(wxSocketEvent &evt)
{
    wxSocketBase *sock = evt.GetSocket();

    switch(evt.GetSocketEvent())
    {
        case wxSOCKET_INPUT:
        {
           //desabilitamos novos eventos de entrada temporariamente
           sock->SetNotify(wxSOCKET_LOST_FLAG);
           //recebemos e reenviamos a string para o cliente
           Recebe(sock);
           //habilitamos os eventos de entrada novamente
           sock->SetNotify(wxSOCKET_LOST_FLAG | wxSOCKET_INPUT_FLAG);
           break;
        }
        case wxSOCKET_LOST:
        {
            num_clientes--;
            EscreveStatus();
            texto->AppendText(_("Deletando socket.\n\n"));
            //destruimos o socket
            sock->Destroy();
            break;
        }
        default: ;
    }

}

void MeuFrame::EscreveStatus()
{
     wxString s;
     s.Printf(_("Numero de clientes conectados: %d"), num_clientes);
     #if wxUSE_STATUSBAR
        SetStatusText(s,0);
     #endif
}

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

IMPLEMENT_APP(MinhaApp)

bool MinhaApp::OnInit()
{
    MeuFrame *frame = new MeuFrame(_("Sockets com wxWidgets: Servidor"));
    frame->Show(true);
    return true;
}




domingo, 8 de maio de 2011

GDI (Graphics Device Interface)

Introdução
    O GDI (Graphics Device Interface) - Interface para dispositivos gráficos - abstrai a comunicação entre um programa e os dispositivos gráficos de saída, como monitor e impressora, por exemplo. Devido à esta abstração um programador não precisa conhecer detalhes específicos sobre o hardware para escrever um programa que desenhe primitivas gráficas. Através do GDI podemos trabalhar com gráficos vetoriais 2D, imagens e fontes. Para isso nós precisamos criar um Contexto de Dispositivo (DC - Device Context), em wxWidgets esta classe é a wxDC (que não pode ser usada diretamente). A classe wxDC é uma classe genérica que possui classes derivadas para diferentes tarefas, estas classes são:
  • wxBufferedDC
  • wxBufferedPaintDC
  • wxPostScriptDC
  • wxMemoryDC
  • wxPrinterDC
  • wxScreenDC
  • wxClientDC
  • wxPaintDC
  • wxWindowDC
      A classe wxScreenDC é usada para desenhar em qualquer lugar na tela. A classe wxWindowDC é usada para desenhar em qualquer local da janela (apenas Windows). A classe wxClientDC é usada para desenhar na área cliente da janela, isto é, menos barra de título e bordas. A classe wxPaintDC faz o mesmo que wxClientDC exceto pelo fato de que wxPaintDC só pode ser usada no evento wxPaintEvent e wxClientDC não pode ser usada neste evento. A classe wxMemoryDC é usada para desenhar gráficos em bitmap. A classe wxPostScriptDC é usada para criar arquivos PostScript. A classe wxPrinterDC é usada para acessar a impressora (apenas no Windows).

wxColour
   A classe wxColour representa uma cor RGB (Red, Green, Blue). Seu construtor define a intensidade de cada uma dessas três cores que varia de 0 a 255. Todas as outras cores são variações de intensidade das combinações das cores RGB.

wxPen
    A classe wxPen é utilizada para desenhar linhas e bordas de primitivas, como retângulos, elipses, etc. Em seu construtor podemos definir a cor, largura (default = 1) e o estilo (default = wxSOLID) da linha ou borda.

wxBrush
    A classe wxBrush é utilizada para definir a cor de preenchimento das primitivas gráficas, o brush pode ter uma cor e um estilo (default = wxSOLID).

Exemplo
    Para desenhar um retângulo de cor vermelha com borda branca faríamos da seguinte forma:

    void OnPaint(wxPaintEvent &evt)
    {
         int x = 10, y = 10, largura = 10, altura = 20;
         wxPaintDC dc(this);
         wxBrush brush(wxColour(255,0,0), wxSOLID);
         dc.SetBrush(brush);
         wxPen pen(wxColour(255,255,255);
         dc.SetPen(pen);
         dc.DrawRectangle(x, y, largura, altura);
    }

O jogo da "cobrinha"
    Quem nunca viu o famoso jogo da cobrinha? Se você nunca viu (o que eu duvido), abaixo segue uma imagem do jogo, que eu fiz utilizando wxWidgets (com alguns pequenos "bugs ", mas, bugs à parte, o objetivo foi dar um exemplo prático de utilização da GDI com wxWidgets e outras classes que serão abordadas em posts futuros). O projeto pode ser baixado em: http://www.4shared.com/file/b0KZqryl/JogoCobrinha.html









sexta-feira, 29 de abril de 2011

Sliders

Introdução
    Sliders são controles que nós podemos manipular movendo para frente e para trás (horizontal) ou para cima e para baixo (vertical) alterando seu valor. Em wxWidgets um slider é representado pela classe wxSlider. Podemos obter o valor de um wxSlider através do método GetValue() que nos retorna um número inteiro e definir seu valor através do método SetValue(int valor). No construtor da classe podemos definir seu valor inicial, valor mínimo, valor máximo, tamanho, orientação, etc. Para uma referência completa dos métodos da classe wxSlider visite: http://docs.wxwidgets.org/stable/wx_wxslider.html

Exemplo
    Como exemplo vamos nos basear no post sobre caixas de texto onde fizemos um programa para cálculo do volume do cilindro, mas ao invés de fornecer o raio e a altura através de caixas de texto vamos fornecer estes valores através de sliders (um para o raio e outro para altura). À medida que movemos os sliders os valores de raio e altura são alterados e o volume é calculado sendo mostrado através de um wxStaticText.



Código:

#include <wx/wx.h>

class Slider : public wxFrame
{
    private:
        wxSlider *sliderRaio;
        wxSlider *sliderAltura;
        wxStaticText *txtVolume;
        wxGridSizer *grid;
        double raio, altura, volume;

    public:
        Slider(const wxString &titulo);
        double Volume(double raio, double altura);
        void OnSlide(wxScrollEvent &evt);

};

const int ID_SL_RAIO = 1000;
const int ID_SL_ALTURA = 1001;


#include "slider.h"

Slider::Slider(const wxString &titulo) :
wxFrame(NULL, -1, titulo, wxDefaultPosition, wxSize(240,240))
{
   wxPanel *painel = new wxPanel(this, -1);
   grid = new wxFlexGridSizer(2,3,5,5);
   //criamos um slider com valor inicial = 0, valor minimo = 0, valor maximo = //100, 200 px de tamanho, orientado verticalmente e mostrando o valor //selecionado
   sliderRaio = new wxSlider(painel, ID_SL_RAIO, 0, 0, 100, wxDefaultPosition, wxSize(-1,200), wxSL_VERTICAL | wxSL_LABELS);
   //conectamos o metodo OnSlide ao evento do slider
   //ao movimentar o slide este metodo e chamado
   Connect(ID_SL_RAIO, wxEVT_COMMAND_SLIDER_UPDATED, wxScrollEventHandler(Slider::OnSlide));
   //criamos um slider com valor inicial = 0, valor minimo = 0, valor maximo = //100, 200 px de tamanho, orientado verticalmente e mostrando o valor //selecionado
   sliderAltura = new wxSlider(painel, ID_SL_ALTURA, 0, 0, 100, wxDefaultPosition, wxSize(-1,200), wxSL_VERTICAL | wxSL_LABELS);
   //conectamos o metodo OnSlide ao evento do slider
   //ao movimentar o slide este metodo e chamado
   Connect(ID_SL_ALTURA, wxEVT_COMMAND_SLIDER_UPDATED, wxScrollEventHandler(Slider::OnSlide));
   txtVolume = new wxStaticText(painel, -1, wxT("0"));
   grid->Add(new wxStaticText(painel, -1, wxT("Raio")), 1, wxLEFT, 20);
   grid->Add(new wxStaticText(painel, -1, wxT("Altura")), 1, wxLEFT, 20);
   grid->Add(new wxStaticText(painel, -1, wxT("Volume")), 1, wxLEFT, 38);
   grid->Add(sliderRaio, 1, wxLEFT, 22);
   grid->Add(sliderAltura, 1, wxLEFT, 24);
   grid->Add(txtVolume, 1, wxTOP | wxLEFT, 48);
   painel->SetSizer(grid);
   Centre();
}

double Slider::Volume(double raio, double altura)
{
    this->raio = raio;
    this->altura = altura;
    volume = 3.14 * (this->raio*this->raio) * altura;
    return volume;
}

void Slider::OnSlide(wxScrollEvent &evt)
{
   //o metodo GetValue retorna o valor do slider
   double v = Volume(sliderRaio->GetValue(), sliderAltura->GetValue());
   txtVolume->SetLabel(wxString() << v);
}


#include "slider.h"

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

#include "main.h"

IMPLEMENT_APP(MinhaApp)

bool MinhaApp::OnInit()
{
    Slider *slider = new Slider(wxT("Slider com wxWidgets"));
    slider->Show(true);
    return true;
}

segunda-feira, 25 de abril de 2011

CheckBox com wxWidgets

Introdução
     Um checkbox é um widget que pode ter dois estados: ligado ou desligado (checado ou não). Quanto um checkbox está checado ele apresenta um "tick" na caixa que representa o widget. Esta caixa pode ter um label associado a ela do lado esquerdo ou direito. Um checkbox pode ser usado em diversas situações, como marcar ou desmarcar opções, aceitar ou não termos de uso, mostrar ou esconder outros widgets, entre outras. Em wxWidgets um checkbox é representado pela classe wxCheckBox.

Exemplo
    Em nosso exemplo vamos fazer um programa que mostra ou esconde o título da aplicação dependendo do estado do checkbox. Quanto o checkbox estiver checado o título é mostrado, do contrário o título não aparece.


Código

#include <wx/wx.h>
//checkbox.h

class CheckBox : public wxFrame
{
public:
    CheckBox(const wxString& title);

    void Alternar(wxCommandEvent& event);

    wxCheckBox *m_cb;
};

#include "checkbox.h"
//checkbox.cpp

CheckBox::CheckBox(const wxString& title) : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(270, 150))
{
  wxPanel *panel = new wxPanel(this, wxID_ANY);

  m_cb = new wxCheckBox(panel, 100, wxT("Mostra o título"), wxPoint(20, 20));
  m_cb->SetValue(true);
  Connect(100, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(CheckBox::Alternar));
  Centre();
}

void CheckBox::Alternar(wxCommandEvent& WXUNUSED(event))
{

  if (m_cb->GetValue()) {
      this->SetTitle(wxT("CheckBox com wxWidgets"));
  } else {
      this->SetTitle(wxT(" "));
  }
}

#include <wx/wx.h>
//main.h
class MyApp : public wxApp
{
  public:
    virtual bool OnInit();
};

#include "main.h"
#include "checkbox.h"
//main.cpp

IMPLEMENT_APP(MyApp)

bool MyApp::OnInit()
{

    CheckBox *cb = new CheckBox(wxT("CheckBox com wxWidgets"));
    cb->Show(true);

    return true;
}

terça-feira, 19 de abril de 2011

Menus com wxWidgets

Introdução
    Através dos menus nós podemos agrupar os comandos de nossa aplicação para que possamos executá-los de maneira rápida e intuitiva. Em wxWidgets os menus são compostos basicamente de uma barra de menu (wxMenuBar), os menus propriamente ditos (wxMenu) e os items pertencentes a cada menu (wxMenuItem). Através do método SetMenuBar() nós adicionamos uma barra de menu à aplicação. O método Append() adiciona um menu à barra de menu e um item de menu ao menu.
   No nosso exemplo criaremos uma aplicação com uma barra de menu que tem o menu 'Arquivo' que por sua vez tem os items de menu: 'Novo', 'Abrir', 'Salvar' e 'Sair'. Ao clicarmos no item de menu 'Sair' a aplicação é fechada.


Código:

#include <wx/wx.h>
//menu.h

class Menu : public wxFrame
{
        private:
            wxMenuBar *barramenu;
            wxMenu *arquivo;
            wxMenuItem *novo;
            wxMenuItem *abrir;
            wxMenuItem *salvar;
            wxMenuItem *sair;

        public:
            Menu(const wxString &titulo);
            void Sair(wxCommandEvent &evt);
};

#include "menu.h"
//menu.cpp

Menu::Menu(const wxString &titulo) :
      wxFrame(NULL, -1, titulo, wxDefaultPosition, wxSize(500, 400))
      {
            //criamos a barra de menu
            barramenu = new wxMenuBar;
            //criamos o menu Arquivo
            arquivo = new wxMenu;
            novo = new wxMenuItem(arquivo, 1000, wxT("&Novo"));
            abrir = new wxMenuItem(arquivo, 1001, wxT("A&brir"));
            salvar = new wxMenuItem(arquivo, 1002, wxT("&Salvar"));
            sair = new wxMenuItem(arquivo, 1003, wxT("Sai&r"));
            //conectamos o método Sair() ao item de menu de id = 1003
            Connect(1003, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(Menu::Sair));
            //adicionamos os items de menu ao menu arquivo
            arquivo->Append(novo);
            arquivo->Append(abrir);
            arquivo->Append(salvar);
            arquivo->Append(sair);
            //adicionamos o menu Arquivo à barra de menu
            barramenu->Append(arquivo, wxT("&Arquivo"));
            //adicionamos a barra de menu 'barramenu' à aplicacao
            SetMenuBar(barramenu);
            Centre();
      }

void Menu::Sair(wxCommandEvent &evt)
{
    //fechamos a aplicacao
    Close();
}

#include "menu.h"
//main.h

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

#include "main.h"
//main.cpp

IMPLEMENT_APP(MinhaApp)

bool MinhaApp::OnInit()
{
        Menu *menu = new Menu(wxT("Menus com wxWidgets"));
        menu->Show(true);
        return true;
}

sábado, 16 de abril de 2011

Caixas de Texto

Introdução
      Caixas de texto são utilizadas em sistemas com interface gráfica para capturar entrada de dados do usuário. Através de caixas de texto podemos entrar com nomes de usuário e senhas para validação, gravar informações em um banco de dados e setar variáveis de nossos programas para fazer cálculos, por exemplo. Em wxWidgets a classe que representa uma caixa de texto é a wxTextCtrl.
    Para capturar o valor de um wxTextCtrl utilizamos o método GetValue() que retorna um wxString.     
    Para setar o valor de um wxTextCtrl utilizamos o método SetValue(wxString valor).

Cálculo do volume do cilindro

     Neste post vou mostrar um programa para calcular o volume de um cilindro. O usuário entrará com o raio da base e a altura do cilindro. A fórmula para calculo do volume do cilindro é dada por: A = PI * r^2 * h, onde r é o raio e h é a altura. O programa avisará através de uma caixa de mensagem (wxMessageBox) se o usuário deixar algum campo vazio ou se os valores digitados não forem números.


     


     

Segue abaixo o código da aplicação:

#include <wx/wx.h>
//cilindro.h

class Cilindro : public wxFrame {

    public:

        Cilindro(const wxString &titulo);

        double Volume(double raio, double altura);

        void Calcula(wxCommandEvent &evt);
        void Limpa(wxCommandEvent &evt);

    private:

       double raio, altura, volume;

       wxTextCtrl *txtraio;
       wxTextCtrl *txtaltura;
       wxTextCtrl *txtvolume;
       wxStaticText *stcraio;
       wxStaticText *stcaltura;
       wxStaticText *stcvolume;
       wxButton *calcular;
       wxButton *limpar;

};

#include "cilindro.h"
//cilindro.cpp

Cilindro::Cilindro(const wxString &titulo) : wxFrame(NULL, -1, titulo, wxDefaultPosition, wxSize(290, 180))
{
    wxPanel *painel = new wxPanel(this, -1);
    wxBoxSizer *boxprincipal = new wxBoxSizer(wxVERTICAL);
    wxGridSizer *boxtexto = new wxGridSizer(3, 2, 5, 5);
    wxBoxSizer *boxbotoes = new wxBoxSizer(wxHORIZONTAL);
    txtraio = new wxTextCtrl(painel, -1, wxT(""));
    txtaltura = new wxTextCtrl(painel, -1, wxT(""));
    txtvolume = new wxTextCtrl(painel, -1, wxT(""));
    stcraio = new wxStaticText(painel, -1, wxT("Raio:"));
    stcaltura = new wxStaticText(painel, -1, wxT("Altura:"));
    stcvolume = new wxStaticText(painel, -1, wxT("Volume:"));
    calcular = new wxButton(painel, 1000, wxT("Calcular"));
    Connect(1000, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(Cilindro::Calcula));
    limpar = new wxButton(painel, 1001, wxT("Limpar"));
    Connect(1001, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(Cilindro::Limpa));
    boxtexto->Add(stcraio, 1, wxALL, 10);
    boxtexto->Add(txtraio, 1, wxALL, 5);
    boxtexto->Add(stcaltura, 1, wxALL, 10);
    boxtexto->Add(txtaltura, 1, wxALL, 5);
    boxtexto->Add(stcvolume, 1, wxALL, 10);
    boxtexto->Add(txtvolume, 1, wxALL, 5);
    boxbotoes->Add(calcular, 1, wxALL, 10);
    boxbotoes->Add(limpar, 1, wxALL, 10);
    boxprincipal->Add(boxtexto, 1, wxEXPAND);
    boxprincipal->Add(boxbotoes, 1, wxEXPAND);
    painel->SetSizer(boxprincipal);
    txtraio->SetFocus();
    Centre();
}

double Cilindro::Volume(double raio, double altura)
{
    this->raio = raio;
    this->altura = altura;
    volume = 3.14 * (this->raio*this->raio) * altura;
    return volume;
}

void Cilindro::Calcula(wxCommandEvent &evt)
{
    double r, h, a;
    //verificamos se algum dos campos está vazio
    //se estiver mostramos uma mensagem de alerta
    if((txtraio->IsEmpty()) || (txtaltura->IsEmpty())) {
        wxMessageBox(wxT("Nao podem haver campos vazios!"), wxT("Aviso"));
        return;
    }
    //verificamos se os valores digitados sao numeros
    //se nao forem exibimos uma mensagem de alerta
    if((!txtraio->GetValue().ToDouble(&r)) || (!txtaltura->GetValue().ToDouble(&h))) {
        wxMessageBox(wxT("Os valores dos campos devem ser numericos!"), wxT("Aviso"));
        return;
    }
    //chamamos o metodo Area() para calcular o volume do cilindro
    a = Volume(r, h);
    //setamos o textbox volume com o valor calculado
    txtvolume->SetValue(wxString() << a);
}

void Cilindro::Limpa(wxCommandEvent &evt)
{
    //limpamos os campos com o método Clear()
    txtraio->Clear();
    txtaltura->Clear();
    txtvolume->Clear();
}

#include "cilindro.h"
//main.h


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

#include "main.h"
//main.cpp

IMPLEMENT_APP(MinhaApp)

bool MinhaApp::OnInit()
{
    Cilindro *cilindro = new Cilindro(wxT("Calculo da area do cilindro"));
    cilindro->Show(true);
    return true;
}