terça-feira, setembro 19, 2006

Curso de wxWidgets, post 3: Entendendo o "Hello, world!" do post 2

Agora sim, vamos ver como aquilo tudo funciona! :) Estou supondo que todos já conseguiram compilar o wxWidgets e botar ele pra trabalhar. Quem ainda não conseguiu, deixe comentários no post 2.

Voltando ao "Hello, world!"... Em primeiro lugar, devemos incluir os cabeçalhos do wxWidgets (acho que isso é óbvio):

#include "wx/wx.h"


Essa linha inclui os principais cabeçalhos do wx, mas você pode também inserir apenas os cabeçalhos das classes que deseja usar. Por exemplo, se em seu programa você estiver usando apenas um wxFrame e um wxButton, você poderia fazer assim:

#include "wx/app.h"    // Este é para o wxApp
#include "wx/frame.h" // Este é para o wxFrame
#include "wx/button.h" // Este é para o wxButton


Iniciando o programa

Como todo programador C/C++ sabe, o programa sempre começa na função main(). Com wxWidgets, essa função não será mais utilizada. Na verdade, ela é utilizada internamente pelo wxApp, então, ao invés de usar main(), no wxWidgets usamos wxApp::OnInit().

Primeiro, precisamos criar uma classe que irá representar nosso programa. Essa classe deverá ser derivada de wxApp. Veja o código:

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


Esse trecho de código vai criar a classe MeuPrograma que é derivada de wxApp (para os novatos em orientação a objetos, isso significa que a nossa nova classe vai herdar todos os atributos e métodos de wxApp. É como um wxApp + os métodos e atributos que criarmos nesta classe). O método sobrecarregado MeuPrograma::OnInit() será o main() do nosso programa. É este método que será chamado ao executarmos o aplicativo.

Criação da janela principal

Porém, queremos criar uma janela para o nosso programa. Uma janela em wxWidgets é um wxFrame. Então, para criarmos nossa janela específica, vamos criar uma classe para a janela. Essa classe deve ser derivada de wxFrame, já que queremos usar todo o "comportamento" de um wxFrame, mas com algumas coisas a mais e específicas que iremos implementar:

class MeuFrame: public wxFrame
{
public:
MeuFrame(void);
};


Como na classe MeuPrograma, a classe MeuFrame é uma classe derivada de wxFrame, todos os métodos e atributos dela serão herdadas por nossa classe.

Implementando o programa

Bem, já temos uma classe para nosso aplicativo (MeuPrograma) e uma para nossa janela (MeuFrame). Agora, vamos voltar ao MeuPrograma::OnInit(). Devemos começar a programar aqui:

bool MeuPrograma::OnInit(void)
{
MeuFrame *frame = new MeuFrame();
frame->Show();
SetTopWindow(frame);
return true;
}


Primeiro, declaramos um ponteiro do tipo MeuFrame e criamos uma instância da nossa classe. Na segunda linha, chamamos o método wxFrame::Show() para exibir a janela. Esse método faz com que a janela seja mostrada na tela. Na terceira linha, o método wxApp::SetTopWindow() define a janela instanciada em frame como a janela principal do nosso programa. E por último, return true indica que a inicialização do programa foi feita com sucesso e que ele deve continuar rodando. Se algo acontecesse errado, um return false iria fechar o programa imediatamente.

Bem, isto é o que de fato deve ser feito em wxApp::OnInit(). O resto da implementação deve ficar em outras classes. Mas por enquanto, vamos apenas criar nossa janela. Devemos implementar o construtor dela:

MeuFrame::MeuFrame(void)
:wxFrame(NULL, wxID_ANY, wxT("Meu programa"))
{
}


Nada é feito neste construtor. Na verdade, apenas passamos alguns parâmetros para o construtor do wxFrame. O primeiro parâmetro indica qual janela é pai desta janela. Como esta é a janela principal, ela não tem pai (NULL). O segundo parâmetro diz qual a ID desta janela. Como não fizemos nenhum evento da janela em si, não é preciso especificar uma ID agora (wxID_ANY). O terceiro parâmetro configura o título da janela (wxT("Meu programa")). Verifique a ajuda do construtor do wxFrame para ver os detalhes de todos os parâmetros.

Agora, devemos dizer ao wxWidgets qual é a nossa classe de aplicativo com a macro:

IMPLEMENT_APP(MeuPrograma)


Pronto! Este é o nosso "Hello, world!" explicado. Mas agora, vamos adicionar algumas coisas a ele.

Adicionando objetos

Primeiro, que tal um texto escrito "Hello, world!"? A classe para textos estáticos no wxWidgets é a wxStaticText. Os principais parâmetros do seu construtor (usaremos apenas estes):

wxWindow *parent: a janela pai deste objeto.
wxWindowID id: a ID deste objeto (caso desejamos criar um evento para ele).
wxString &label: o texto que será exibido.

Primeiro, vamos declarar nosso objeto na definição de MeuFrame. Basta adicionar a declaração na definição da classe, vai ficar assim:

class MeuFrame: wxFrame
{
public:
MeuFrame(void);

private:
wxStaticText *text;
};


E em seguida, instanciamos a classe no construtor de MeuFrame, adicionando a seguinte linha:

text = new wxStaticText(this, wxID_ANY, wxT("Hello, world!"));


Vai ficar assim:

MeuFrame::MeuFrame(void)
:wxFrame(NULL, wxID_ANY, wxT("Meu programa"))
{
text = new wxStaticText(this, wxID_ANY, wxT("Hello, world!"));
}


Compile o programa novamente e execute. Você vai ver o texto "Hello, world!". Explicando os parâmetros:

this: indica que a janela MeuFrame é a janela pai do objeto.
wxID_ANY: indica que não estamos associando nenhuma ID específica ao objeto.
wxT("Hello, world!"): o texto que será exibido.

Uma breve explicação sobre a macro wxT()

Vocês devem ter notado que todas as strings estão envoltas na macro wxT(). Bem, antigamente, as strings eram representadas no formato ASCII, cada caractere ocupava um byte na memória. Porém, alguns idiomas contém caracteres especiais, como o japonês, chinês, árabe..., e um byte não era suficiente para representar todos eles, já que com um byte podemos representar apenas 256 valores diferentes. Surgiram então várias codificações de caracteres para representar cada idioma ou região. Então, para padronizar isso, o padrão UNICODE foi criado. Neste padrão, mais de um byte pode ser utilizado.

Mas o wxWidgets pode estar sendo utilizado em um sistema operacional sem suporte a UNICODE, ou até mesmo, o wxWidgets pode ter sido compilado sem suporte a UNICODE, como eu ensinei no post 2. Para não haver problemas com isso e tornar seu código portável, use a macro wxT(). Essa macro não faz nada em compilações sem UNICODE, mas vai converter a string ASCII para UNICODE, caso sua compilação do wxWidgets esteja usando UNICODE.

Faça mais no "Hello, world!"

Para prática, sugiro criar outros objetos na nossa janela. Algumas sugestões: wxButton, wxTextCtrl, wxComboBox, wxCheckBox e wxRadioBox.

No próximo post, vou mostrar como posicionar os objetos na janela (você vai perceber esse problema quando tentar adicionar novos objetos). Em caso de dúvidas, deixem comentários. :)

3 comentários:

Anônimo disse...

beléssaaaaa kapiãooooo
por enquanto, está tudo beleza cara!!
abraço
fillipe(no postt 1 foi eu tbm... )

Anônimo disse...

Excelente curso. Parabéns pela iniciativa

Anônimo disse...

Muito bom o seu blog, espero que vc continue! tá me ajudando e esse post já tem 3 anos. Valew