quarta-feira, dezembro 27, 2006

Criando uma classe de janela em FLTK2 usando o FLUID

Reblog de um antigo artigo meu sobre programação. Espero que aproveitem.

Criando uma classe de janela em FLTK2 usando o FLUID

Por Fábio Emilio Costa

Simples e multiplataforma, a FLTK (lê-se "fullticks") é uma interface gráfica despretenciosa e que oferece recursos básicos para o seu desenvolvedor. Ela gera programas extremamente enxutos e leves em sua interface gráfica e está disponível em várias das principais plataformas e SOs da atualidade.

Nesse artigo, veremos como desenvolver uma classe de Janela utilizando-se do FLUID, um gerador de interface simplificado que vêm com o FLTK.

Nota: Os exemplos serão apresentados para o Dev-C++ for Windows. Para outros compiladores e ambientes operacionais, leia a documentação do compilador e obtenha maiores informações em http://www.fltk.org e http://www.fltk.net. Apesar disso, os exemplos de programação são todos genéricos, podendo ser usados em qualquer platadforma e compilador.

1-) Obtendo os DevPaks:

O Dev-C++ tem como principais características ser free software (GPL) e ser muito extensível, através dos DevPaks, pacotes especiais instalados no ambiente de desenvolvimento. Se você não tiver o Dev-C++, você poderá o obter em http://www.bloodshed.net/dev.
A primeira coisa é obter o DevPak do FLTK. Ele pode ser obtido em http://www.fltk.net/files/devpak/FLTK2.DevPak. Você também precisará do DevPak de libpthreads, copiado em http://www.fltk.net/files/devpak/libpthread.DevPak. Esses dois pacotes são necessários.

Com o Dev-C++ instalado, basta clicar duas vezes nos arquivos dos DevPak. Instale primeiro o libpthread.DevPak, em seguida o FLTK2.DevPak.

2-) Preparando o Dev-C++:

Você precisará preparar o ambiente, inserindo nele o FLUID. Para isso, clique no menu Ferramentas. Você terá um menu semelhante o abaixo.

No caso, o FLUID já está inserido, mas vejamos como inserí-lo no menu. Escolha a opção "Configurar Ferramentas". Aparecerá uma janela como a abaixo.




Clique em "Adicionar" e você receberá uma nova janela, como a seguinte:

Digite "FLUID" em Título e escolha os caminhos do programa e do diretório de trabalho. Em geral o caminho do programa será C:\Dev-Cpp\bin\fluid.exe, e o diretório de trabalho, C:\Dev-Cpp\bin\. Corrija esses dados conforme sua instalação.

Clique OK. Aparecerá a entrada do FLUID na Janela "Configuração das Ferramentas". Clique OK. O FLUID já deverá estar no menu Ferramentas do Dev-C++.

Agora que o Dev-C++ já está configurado, vamos passar a ver como o FLUID funciona.

3-) Desenhando uma tela no FLUID:

Para começar, chame o FLUID no Menu Ferramentas. Você deverá receber uma janela como a seguinte.

O FLUID exige uma função para poder começar a criar os Widgets (os objetos de Janela). Para colocar uma função no fluid, vá em New | Code | Function/Method.


Você receberá uma janela como a seguinte (você pode ignorar por enquanto as opções e ir direto ao assunto clicando OK):

Com o tempo você poderá ver essas opções. De imediato, ignore-as e vamos para o assunto que é criar a janela: Vá em New | Group | fltk::Window. Isso irá lhe abrir uma janela. Clique duas vezes sobre ela e você irá receber uma janela de configurações do Widget. Sempre que precisar dessa janela para um certo Widget, clique duas vezes sobre ele:



Por enquanto vamos nos ater à aba GUI. Na aba Style você
encontrará configurações relacionadas a cores e fontes do Widget. Na aba
C++, você encontrará configurações expecíficas de C++, como visibilidade do
Widget e por aí afora.



Na aba GUI, para a Window, alteraremos apenas a propriedade Label.
Diferentemente de outras APIs de Interface Gráfica, a FLTK coloca labels em todos
os seus componentes. Na verdade, o componente raiz de todos os demais componentes, fltk::Widget, pode ser usado como um Label caso necessário. No caso,
vamos definir o Label como "Hello World!". As demais propriedades podem ficar como
estão. Clique em OK ou aperte ENTER.



Agora temos uma janela vazia com um título na Janela ("Hello
World!
"). Agora vamos adicionar dois componentes na janela, mais exatamente um
fltk::ReturnButton. Para
isso, clique com o botão direito sobre a Janela. Você irá receber um menu semelhante
àquele aonde você adicionou a função e a Janela. Escolha primeiro text |
fltk::Input. Dimensione-a e posicione-a aonde preferir, como em qualquer
outro ambiente RAD (como o VisualStudio ou o Delphi). Depois de posicioná-lo aonde
desejar, clique duas vezes sobre o Input para chamar a janela de propriedades. O
fltk::Input é como um componente Edit do Delphi ou um
TextBox do VisualStudio. Ele aceita dados e pode alterá-los e tudo o
mais.



Na janela de propriedades do fltk::Input, primeiro
digite em Label "Digite o seu nome:". Depois, vá até Alignment. Perceba que
há quatro setas indicando para as quatro direções básicas (para cima, para baixo, direita
e esquerda). Clique na seta para cima para marcá-la e na seta para a direita para
desmarcá-la. Clique novamente em OK ou pressione Enter. Repare que o label foi parar em
cima do Input e centralizado em relação a ele.



Vamos agora para o fltk::ReturnButton. O fltk::ReturnButton é como um botão normal de outros RAD, mas com uma
diferença fundamental: no Window aonde ele estiver, ele sempre será acionado quando a
tecla Enter for pressionada. Você deve estar pensando agora no botão OK dentro da janela
de propriedades do FLUID: ele é um fltk::ReturnButton. Para
botões normais, a FLTK oferece o componente fltk::Button, sendo
que o fltk::ReturnButton e o fltk::ReturnButton são intercambiáveis.



Clique duas vezes no fltk::ReturnButton. Na janela
de propriedades, vamos mudar apenas o Label para "Hello World!".



Se você seguiu corretamente todos os passos, você deverá ter conseguido um
Form similar a esse:





Se você conseguiu, parabéns! Você criou sua primeira janela no FLUID. Vá em
File | Save e salve a janela criada pelo FLUID.



Nota: Em Windows o FLUID tem um bug no qual não pode
salvar-se nenhuma janela em diretórios que tenham espaço no nome. Tenha sempre isso em
mente ao salvar a janela.





Depois de salvar a janela, vá em File | Write Code. O FLUID irá gerar dois
arquivos com o mesmo nome que você deu para a sua janela, mas com extensões .cxx e .h. Serão esses os arquivos que iremos
usar no projeto. Pode fechar o FLUID após isso.



4-) Criando um Projeto FLTK2:



OK... Agora que fechamos o FLUID, a primeira coisa que precisamos fazer é voltar ao
Dev-C++ e criar um projeto FLTK2 para podermos compilar o código gerado no FLTK.



Voltando ao projeto... Imaginando que tudo tenha sido feito corretamente,
você agora terá dois arquivos, .h.
E agora voltamos ao Dev-C++.



A primeira coisa é ir em Arquivo | Novo | Projeto. Vai
abrir-se uma janela como a abaixo:





Escolha, na guia FLTK2
(Static). Dê um nome qualquer ao projeto nas Opções de Projeto (Por exemplo, Teste). Vai se abrir uma janela normal, solicitando um local para
gravar o arquivo .dev do projeto. Escolha um diretório qualquer
conveniente para salvar este arquivo. Você receberá uma janela como a seguinte:






Perceba que o sistema já lhe gera um main.cpp. Não
iremos o utilizar, mas se quiser compilá-lo para fazer um teste se o FLTK está bem
instalado, pressione F9 ou vá em Executar | Compilar &
Executar. Salve o arquivo se necessário (no diretório escolhido para o projeto!),
e se tudo foi instalado corretamente (e deve ter sido para ter chegado até aqui), você
receberá a seguinte janela:






PS: Os ícones na Barra de Tarefas não são partes da FLTK, e sim de um
Plugin do WinAMP chamado WinAmpBar...



Se estiver tudo OK, voltemos ao projeto. Vamos inserir os dois arquivos gerados pelo
FLUID no projeto. Para isso, copie os arquivos gerados pelo FLUID para o diretório aonde
você salvou o seu projeto. Aproveite e renomeie o arquivo, mudando sua extensão de .cxx para .cpp. Depois, vá até o lado direito,
aonde está o teu projeto e clique com o botão direito. Um menu como o abaixo irá
aparecer. Clique em Adicionar ao Projeto e escolha os arquivos gerados pelo FLUID
(relembrando que o .cxx teve sua extensão alterada para .cpp) .





Após adicionar os arquivos, você terá três arquivos no seu projeto: main.cpp e os arquivos .cpp e .h gerados pelo FLUID. Vejamos o .h (no caso,
teste.h):



// generated by Fast Light User Interface Designer (fluid)
version 2.0002 #ifndef teste_h #define teste_h #include <fltk/Window.h> #include
<fltk/Input.h> #include <fltk/ReturnButton.h> extern "C" { fltk::Window*
make_window(); } #endif



Na verdade, não vamos aproveitar muito desse código. Vejamos agora o .cpp (no caso, teste.cpp):



// generated by Fast Light User Interface Designer (fluid)
version 2.0002 #include "teste.h" fltk::Window* make_window() {
fltk::Window* w; {fltk::Window* o = new fltk::Window(267, 99, "Hello
World!"); w = o;
o->begin(); {fltk::Input* o = new fltk::Input(30, 25,
205, 25, "Digite seu nome:");
o->align(fltk::ALIGN_TOP); }
{fltk::ReturnButton* o = new fltk::ReturnButton(70, 60,
130, 25, "Hello World!"); o->shortcut(0xff0d);
} o->end();
} return w; }



Agora podemos dizer qual será a idéia: perceba que o FLUID gerou os objetos
que fltk::Input, e fltk::ReturnButton usando comandos new, pois
eles são objetos declarados nos headers (cabeçalhos) <fltk/Window.h>, <fltk/Input.h> e
<fltk/ReturnButton.h>, que são importados no
header teste.h. No caso, a idéia será
declarar em teste.h uma classe herdando de
fltk::Window, e dentreo criar um fltk::Input*, e fltk::ReturnButton*, dessa forma usando os comandos já gerados
pelo FLUID para gerar os objetos durante à construção de nossa classe herdada. Na
destruição da mesma, deveremos também lembrar de destruir os objetos fltk::Input*, e fltk::ReturnButton*, devolvendo a memória usada por
ele.



Vamos começar:



5-) Modificando o .h:



Primeiro de tudo, vamos alterar o header teste.h. Para
isso, vamos retirar a linha:



extern "C" { fltk::Window* make_window(); }



E colocar o seguinte código para definirmos a classe:



using namespace fltk; class wHelloWorld:public Window {
private: Input *txtHelloWorld;
ReturnButton *btnHelloWorld; public:
wHelloWorld();
~wHelloWorld(); };



Se você conhece bem C++, deve ter notado que originalmente declaramos que o
header usa o namespace fltk.
Quando falavamos lá em cima em fltk::ReturnButton, queríamos
dizer um objeto ReturnButton no namespace fltk. Com o uso do comando using namespace
fltk, evitamos a necessidade de indicar o namespace toda vez.
Caso você acredite que você possa ter conflito de nomes usando esse método, utilize a
declaração explícita com o fltk::.



Logo em seguida declaramos a classe wHelloWorld,
que herda todos os métodos públicos de fltk::Window. Perceba que
aqui poderíamos fazer sobrecarga dos vários métodos que a FLTK oferece para sua classe
fltk::Window. No caso, porém, não iremos fazer isso. Continuemos,
então.



Em seguida, declaramo dois ponteiros para objetos FLTK como privativos:
ReturnButton
*btnHelloWorld. Esses ponteiros indicarão os objetos que iremos manipular.



Logo abaixo, declaramos o construtor e o destrutor da classe wHelloWorld. Será neles que iremos manipular os objetos, criando-os
antes do uso pelo software e os destruindo quando a janela for destruída.



Se você compilar o programa, você receberá o mesmo "Hello World" visto
anteriormente, já que não implementamos a classe wHelloWorld.
Então vamos fazer isso.



6-) Implementando a classe wHelloWorld:



Agora vamos passar para a implementação da classe wHelloWorld. Antes, porém, vejamos o código gerado pelo FLUID para a
janela em teste.cpp:



// generated by Fast Light User Interface Designer (fluid)
version 2.0002 #include "teste.h" fltk::Window* make_window() {
fltk::Window* w; {fltk::Window* o = new fltk::Window(267, 99, "Hello
World!"); w = o; o->begin();
{fltk::Input* o = new fltk::Input(30, 25, 205, 25, "Digite
seu nome:"); o->align(fltk::ALIGN_TOP);
} {fltk::ReturnButton* o = new
fltk::ReturnButton(70, 60, 130, 25, "Hello World!");
o->shortcut(0xff0d); } o->end();
} return w; }



Perceba que ele começa com uma função chamada make_window(), que retorna um ponteiro para uma fltk::Window. Vamos tirar isso e colocar o nosso construtor:



wHelloWorld::wHelloWorld()
:Window(267,
99, "Hello World!") { Window* w;



Perceba que aproveitamos a declaração da Janela gerada pelo FLUID, e
aproveitamos o ponteiro fltk::Window* w declarado, pois
precisaremos de um fltk::Window* dentro do construtor, e o fltk::Window* w declarado presta-se bem para isso.



Agora, vamos substituir as seguintes linhas:



{fltk::Window* o = new fltk::Window(267, 99, "Hello World!");
w = o; o->begin();



Pelo seguinte código:



w=this; w->begin(); Utilizamos aqui o ponteiro
this para auto-referenciar nosso objeto wHelloWorld específico. Em seguida, chamamos o método (ou
função-membro, se você preferir) begin() de w, lembrando que w foi
inicializado como this, ou seja, como o próprio
objeto sendo criado. Esse método begin() é herdado
por fltk::Window de fltk::Group e indica aonde o FLTK deverá começar a contar os
objetos seguintes como parte da Window. Podemos
dizer, utilizando o jargão do VB.Net, que a classe Window
é um componente coleção (ou um objeto container,
no jargão do Delphi), ou seja, pode "armazenar" dentro dele outros objetos. Tudo que
acontece com ele, acontece aos demais objetos: se ele é desativado, todos os demais
objetos o são. Se ele é destruído, todos os demais o são também (em teoria, mas não custa
nada dar uma reforçada).



Agora vamos inicializar o ponteiro para nossa caixa de texto (ou Input), substituindo o seguinte código:



{fltk::Input* o = new fltk::Input(30, 25, 205, 25, "Digite
seu nome:"); o->align(fltk::ALIGN_TOP); }



por:



txtHelloWorld = new Input(30, 25, 205, 25, "Digite seu
nome:"); txtHelloWorld->align(ALIGN_TOP);



Perceba que a sintaxe de quase todos os objetos FLTK é a mesma



<obj>(<x>,<y>,<l>,<h>,<caption>)



Aonde <obj> é o nome da classe, <x> e <y> indicam a posição aonde o
objeto será inserido dentro do conteiner (no caso, wHelloWorld) em pixels, <l> e <h> indicam respectivamente a
largura e a altura do objeto (também em pixels), e <caption> guarda um texto a ser exibido próximo (ou dentro) do
objeto. No caso, o nosso txtHelloWorld é um Input (equivalente ao TextBox do VB.Net e ao TEdit do Delphi), será
construído a 30 pixels do canto direito e a 25 pixels do topo do conteiner
dele (no caso, wHelloWorld), terá 205 pixels de largura, 25
pixels de altura e exibirá próximo a ele o texto "Digite seu
nome:
".



Você deve estar se perguntando "como o FLTK sabe aonde posicionar o
texto dos objetos?
". Todos os objetos da FLTK possuem um método align() que retorna/define o alinhamento do objeto FLTK específico. Seu
default varia de objeto para objeto, mas em geral para os objetos container
(como Group) fica no topo,
centralizado (ou de outra forma no padrão do gerenciador de janelas), em objetos de
edição (como Output ou RadioButton) à esquerda, centralizado na altura e nos demais casos
(como Label), dentro do
Widget. No caso, utilizamos o comando



txtHelloWorld->align(ALIGN_TOP);



para indicarmos que queremos alinhar o texto do nosso txtHelloWorld acima do mesmo,
centralizado em relação ao Widget.



Nota: para pessoas que vêem do background do Delphi e do VB,
deve ser difícil imaginar o texto como sendo o label do widget. Em ambos os
casos, normalmente o texto equivale ao que vai dentro do widget. Na
verdade, existe uma diferença aqui entre label e valor. O texto
(label) é o texto que indica para o usuário o widget. Já o que o VB e o
Delphi entendem como texto é chamado na FLTK de valor (método value()). Veremos mais sobre isso quando estivermos desenvolvendo o
código que interagem com a janela.



Falta pouco para convertermos a nossa janela do FLUID em classe. Mude o
seguinte código:



{fltk::ReturnButton* o = new fltk::ReturnButton(70, 60, 130,
25, "Hello World!"); o->shortcut(0xff0d); }



Para:



btnHelloWorld = new ReturnButton(70, 60, 130, 25, "Hello
World!");



Perceba que não estaremos aproveitando o código:



o->shortcut(0xff0d); }



Isso porque, como o botão escolhido já é um ReturnButton, ou seja, um Botão acionado quando a tecla Return é pressionada, não há necessidade de definir-se um atalho de
teclado para ele, que é a função do método shortcut().



Agora vamos terminar tudo, substituindo esse código:



o->end(); } return w;



Por este:



w->end();



Perceba que não aproveitamos o return, pois quando
utilizamos construtores é esperado que o mesmo receba o objeto construído ao término de
sua construção.



Com isso terminamos o construtor. O destrutor é ainda mais simples:



wHelloWorld::~wHelloWorld() { delete txtHelloWorld; delete
btnHelloWorld; }



Ou seja, apenas destrói os objetos criados pela nossa classe wHelloWorld.



No fim das contas, esse é o código que deveremos ter ao fim de tudo:



// generated by Fast Light User Interface
Designer (fluid) version 2.0002 #include "teste.h" wHelloWorld::wHelloWorld()
:Window(267, 99,
"Hello World!") { Window* w; w=this;
w->begin(); txtHelloWorld = new Input(30, 25, 205, 25, "Digite seu
nome:"); txtHelloWorld->align(ALIGN_TOP); btnHelloWorld = new ReturnButton(70, 60, 130, 25, "Hello
World!"); w->end(); }



wHelloWorld::~wHelloWorld() { delete
txtHelloWorld; delete btnHelloWorld; }



Mas se você compilar e rodar o programa ainda estaremos recebendo o bendito
HelloWorld! Como fazer para receber a nossa janela? Veremos isso agora:



7-) Chamando a Janela desenhada:



Voltemos agora para o nosso main.cpp. Se você
estiver usando o DevPak correto no Dev-C++, você deverá ter o seguinte main.cpp:



// This is just small FLTK2 application // Now you can
imediately compile&run it in Dev-C++ // Enjoy FLTK2 - Dejan Lekic, dejan@fltk.net,
http://dejan.lekic.org #include <fltk/Window.h> #include <fltk/Widget.h>
#include <fltk/run.h>



using namespace fltk; int main(int argc, char **argv) {
Window *window = new Window(300, 180); window->begin();
Widget *box = new Widget(20, 40, 260, 100, "Hello, World!");
box->box(UP_BOX); box->labelfont(HELVETICA_BOLD_ITALIC);
box->labelsize(36); box->labeltype(SHADOW_LABEL);
window->end(); window->show(argc, argv); return run();
}



Perceba que ele já tem uma janela dentro dele. Vamos modificar o
código para que ele receba nossa Janela e a abra.



Primeiro de tudo, remova todo o código de dentro da função main. Mantenha a definição da função e os parâmetros, e mantenha também
o return run(). Você provavelmente terá algo como:



// This is just small FLTK2 application // Now you can
imediately compile&run it in Dev-C++ // Enjoy FLTK2 - Dejan Lekic, dejan@fltk.net,
http://dejan.lekic.org



#include <fltk/Window.h> #include <fltk/Widget.h>
#include <fltk/run.h> using namespace fltk;



int main(int argc, char **argv) { return run();
}



OK... Agora vamos eliminar todos os #includes desnecessários:
apague as seguintes linhas:



#include <fltk/Window.h> #include
<fltk/Widget.h>



E as substitua por:



#include "teste.h"



Com isso você estará indicando ao sistema que você tem um header
teste.h, que você precisará usar. Lembre-se que é em teste.h que é aonde está a definição da nossa classe wHelloWorld.



Perceba que não removemos o header<fltk/run.h>, pois precisaremos da função run() definida nele, que retorna um int com um
código de erro caso tenha havido uma falha de execução, ou 0 se o programa executou
normalmente.



Agora falta muito, muito pouco. Dentro da função main , escreva este código antes de return
run():



wHelloWorld *frmHelloWorld=new wHelloWorld();
frmHelloWorld->show();



O que fazemos aqui é:





  1. Criar um objeto wHelloWorld chamado frmHelloWorld;





  2. Chamar o método show() do objeto frmHelloWorld, que ele herdou da classe fltk::Window;





Se tudo estiver OK, você tem o seguinte código:



// This is just small FLTK2 application // Now you can
imediately compile&run it in Dev-C++ // Enjoy FLTK2 - Dejan Lekic, dejan@fltk.net,
http://dejan.lekic.org



#include "teste.h" #include <fltk/run.h>



using namespace fltk;



int main(int argc, char **argv) {
wHelloWorld *frmHelloWorld=new wHelloWorld(); frmHelloWorld->show();
return run(); } Se estiver, rode e compile o programa, você deverá
ter uma janela como a seguinte:





8-) Implementando funcionalidades na
Janela:



Agora, porém, tente clicar no Botão "Hello World!" ou pressionar
Return dentro da caixa de texto. Você perceberá que nada acontece! Isso se deve pelo fato
de que não avisamos para o FLTK o que ele deve fazer quando o ReturnButton for clicado. No FLTK, isso é feito através de
callbacks.



Para aqueles que vêm do panorama VB.Net, podemos comparar toscamente o
callback como uma espécie de delegate ao contrário. No delegate, é o
objeto que avisa ao sistema que que algo aconteceu com ele, e é o sistema quem deve ter
uma função para tratar o evento delegado (daí o nome delegate). No
callback, é o sistema quem fornece ao objeto uma função que ele deverá chamar
quando algo acontecer com ele (o que que dizer, mal e mal, callback em
inglês).



Em FLTK, exige-se que o callback tenha a seguinte estrutura:



void <nome_func>(Widget*, void*);



Onde <nome_func> é uma função que recebe dois
parâmetros: um ponteiro para o Widget que disparou o evento (normalmente
não-usado) e um ponteiro void (em geral, é por onde vem a janela aonde está o
Widget).



Além disso, o FLTK, quando usado em classe, exige que os callbacks
não sejam funções membros não-static. Nesse caso restam três opções:





  1. usar funções membro static;





  2. deixar os Widget públicos ou;





  3. usar funções friend;





No caso, adotaremos a terceira opção: até agora não consegui utilizar a
primeira no Dev-C++ (por algum motivo de configuração, creio eu) e a segunda não é das
melhores opções.



Para quem não sabe o que são funções friend, elas são funções
não-membro (ou seja, não fazem parte do objeto) que podem acessar os dados
privativos e protegidos (private e protected). Embora elas violem os
conceitos de OOP, o uso de friend permite alguns recursos interessantes, como no
nosso caso.



Comecemos modificando o teste.h. Nas declarações de #include, adicione as seguintes linhas:



#include <fltk/ask.h> #include <iostream>



Precisaremos da função fltk::message() (declarada
no header <fltk/ask.h>) e do objeto std::string, que
pertence ao namespace std (e que está incluído no header <iostream>).



Para nos facilitar a vida com o string, logo abaixo de:



using namespace fltk;



Inclua essa linha:



using namespace std;



Descendo na definição da classe, na parte public, inclua essa
linha:



friend void HelloClick(Widget* w, void* v);



Perceba que essa função HelloClick possui
exatamente o tipo de parâmetros exigidos por padrão de um callback, como vimos
anteriormente.



Aqui acabamos com a questão da definição de classe. Voltemos para o código.
No construtor da classe wHelloWorld, logo abaixo a criação do
objeto btnHelloWorld, acrescente essa linha:



btnHelloWorld->callback(HelloClick,w);



Nesse caso, utilizamos o método callback do objeto
btnHelloWorld para definir o callback do mesmo. No caso, esse método possui o
seguinte protótipo, definido em <fltk/Widget.h>:



void callback(Callback* c, void* p);



No caso, definimos como Callback* (um ponteiro de
função interno do objeto) nossa função HelloClick (ela é passada como um ponteiro
para a função) e passamos como void* o nosso ponteiro w (lembre-se que w é um ponteiro para o objeto
criado). É importante notar que o ReturnButton herda o método
callback da classe-mãe geral fltk::Widget. Como ela é a classe-mãe de todas as demais, isso quer
dizer que todos os objetos FLTK, sem exceção, possuem métodos callback e, portanto, podem receber funções de callback conforme
a necessidade.



OK. Agora, vá até o fim do código fonte e insira o seguinte código:



void HelloClick(Widget* w, void* v) {
wHelloWorld *to=((wHelloWorld*)v);
string strHelloWorld("Olá,");
strHelloWorld+=to->txtHelloWorld->value();
strHelloWorld+="! Sou um programa em FLTK!";
message(strHelloWorld.c_str());
}



Vamos explicar agora o que isso faz:



Perceba que essa função void HelloClick(Widget* w, void*
v) é declarada de forma semelhante à nossa friend definida na classe. Na
prática, essa é a nossa friend! Ela é ligada pela assinatura da
função (ou seja, ela é uma função void, chamada HelloClick, que recebe um Widget* (um ponteiro
para um Widget)e um void* v (um ponteiro "vazio" - um
ponteiro para alguma coisa qualquer).



A primeira coisa que precisamos fazer é transformar o ponteiro void* v recebido em um ponteiro para a nossa janela.

"Mas ele já não é?", você deve se perguntar.



Sim... e não.



Esse ponteiro aponta para o endereço aonde nossa janela foi alocada,
mas ele não sabe que no caso temos um objeto da classe wHelloWorld. Por isso, precisamos trasformar o nosso void* v em um wHelloWorld* (ou seja, um
ponteiro para um objeto wHelloWorld). Para isso, utilizamos um
cast, como o mostrado na linha abaixo:



wHelloWorld *to=((wHelloWorld*)v);



Perceba a declaração do cast: ele associa ao ponteiro wHelloWorld *to o valor de v, mas alertando
para o sistema que v deve ser entendido como um ponteiro para um
objeto wHelloWorld (wHelloWorld*). Perceba que essa indicação fica em parênteses,
como no caso (wHelloWorld*).



As três próximas linhas criam um objeto std::string
e colocam nele informações:



string strHelloWorld("Olá,");
strHelloWorld+=to->txtHelloWorld->value(); strHelloWorld+="! Sou um programa em
FLTK!";



Perceba que não precisamos usar std::, pois já
declaramos o uso do namespace std no teste.h na linha using namespace std. O objeto
strHelloWorld é inicializado com o texto "Olá,
", e ao pouco vai recebendo outros textos que vão sendo contatenados ao fim do
texto. Na segunda linha está o interessante:



strHelloWorld+=to->txtHelloWorld->value();



Utilizando o método value() do nosso objeto txtHelloWorld, ele pega o texto digitado na caixa de texto no momento
em que o callback for acionado e o concatena ao objeto strHelloWorld criado. Em seguida ele adiciona o fim da saudação.



Depois utilizamos a função não-membro do FLTK message() (ou, no caso de não declarar-se o uso de namespace,
fltk::message()) para exibir o texto em uma caixa de informações
(mais ou menos como uma versão rudimentar do MsgBox() do VB.Net
ou do MessageDlg do Delphi):



message(strHelloWorld.c_str());



Essa função, como dissemos anteriormente, é declarado em <fltk/ask.h>. Ele pode receber dois tipos de parâmetros: um char* que será exibido, ou um texto formatado como na função printf() do C, com os devidos dados a serem exibidos. No caso,
precisamos oferecer uma saída do nosso objeto string strHelloWorld como um char* (ponteiro de
caracteres, o tipo de string do C). Para isso, usamos o método c_str() do objeto strHelloWorld.



Agora, compile e rode o programa. Se tudo deu certo, quando você digitar um texto na
caixa de texto, como:






E pressionar a tecla Return ou clicar no botão
?Hello World!?, você irá receber uma mensagem como a seguinte:






Bem, isso conclui nosso rápido interlúdio na FLTK. Para maiores
informações, a API da FLTK2 é divulgada em http://www.fltk.net. Nesse mesmo site podem ser
obtidos cópias para consulta offline da documentação FLTK (embora levemente
desatualizadas, são muito úteis). Outro site importante também é http://www.fltk.org. Nele você poderá encontrar
informações adicionais sobre a FLTK.



Sobre o Autor:



Fábio Emilio Costa é tecnólogo em Desenvolvimento de Software pelas
Faculdades ASMEC, em Ouro Fino/MG. Pode ser encontrado em fabiocosta0305@yahoo.com.br. Desenvolve a
dois anos em C++ e a um ano e meio em FLTK2 e SQLite, além de desenvolver em PHP e Ruby.



powered by performancing firefox

Digg! | links to this post

|

Links to this post:

Criar um link

<< Home