sexta-feira, 13 de agosto de 2010

Programação de GUIs utilizando GTK - Parte 2

.
Neste post vamos tratar da montagem do ambiente para programação GTK, exemplificando através de uma distribuição Ubuntu, versão 10.04 (GNU/Linux), recém instalada. Os requisitos para acompanhar este e os próximos posts são: conhecimentos (nível intermediário) da linguagem C (incluindo ponteiros), geração de arquivos-fonte e sua compilação pela linha de comando (terminal) utilizando o GCC.

Vamos começar com um programa simples, baseado em GTK+, uma espécie de "Hello World" dos programas em ambiente gráfico: mostra uma janela vazia na tela. O código segue abaixo:

 #include <gtk/gtk.h>
int main (int argc, char *argv[])
{
GtkWidget *window;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Alou, Mundo!!!");
gtk_widget_show (window);
gtk_main ();
return 0;
}

Não se preocupe com os detalhes do programa, veremos isso depois. O objetivo agora é apenas conseguir compilar e executar o dito cujo, pelo terminal. Gere um arquivo-fonte em C com o código acima, digamos, aloumundo.c, e tente compilar:

gcc -o aloumundo aloumundo.c

E receba um monte de mensagens de erro... :-)

 aloumundo.c:2:21: error: gtk/gtk.h: No such file or directory
aloumundo.c: In function ‘main’:
aloumundo.c:6: error: ‘GtkWidget’ undeclared (first use in this function)
aloumundo.c:6: error: (Each undeclared identifier is reported only once
aloumundo.c:6: error: for each function it appears in.)
aloumundo.c:6: error: ‘window’ undeclared (first use in this function)
aloumundo.c:10: error: ‘GTK_WINDOW_TOPLEVEL’ undeclared (first use in this function)

Bom, a coisa começa pelo fato de que o compilador não encontrou a biblioteca gtk (personificada, digamos assim, neste exemplo, pelo arquivo gtk.h). E a partir daí, nada relacionado com gtk foi interpretado.

O que acontece é que, apesar de estarmos usando um ambiente gráfico baseado em GTK (Gnome), ou seja, a biblioteca gtk está garantidamente instalada no sistema, precisamos instalar a biblioteca PARA DESENVOLVIMENTO. Em sistemas baseados no Debian, acho que em 99% dos casos, bibliotecas para desenvolvimento tem seu nome terminado em -dev (em outras distribuições, este tipo de biblioteca tem seu nome terminado em -devel).

Abrimos o gerenciador de pacotes Synaptic, e procuramos por libgtk:



Descobrimos que o nome correto é libgtk2.0-dev. Ao marcarmos para instalação, o Synaptic automaticamente seleciona outros pacotes que também são requeridos. Na verdade, quando falamos em GTK estamos falando em um conjunto de bibliotecas, como por exemplo, GLib (funções utilitárias de propósito geral), GDK (camada entre o sistema gráfico X e GTK), Pango (textos e fontes), ATK (acessibilidade), entre outras.



Agora, com as bibliotecas instaladas, podemos tentar compilar novamente, e.... ué?!?!? Erro de novo?

Isso acontece porque precisamos indicar ao GCC que queremos utilizar uma biblioteca extra, além da biblioteca-padrão, que ele já sabe usar diretamente. Isso significa indicar os seguintes itens:

  • caminho para o diretório onde estão os "includes" da(s) biblioteca(s) que você quer usar. Isso é feito utilizando-se a opção -I (letra "i" maiúscula);
  • caminho para o diretório onde estão as bibliotecas a serem utilizadas. Isso é feito utilizando-se a opção -L (letra "l" maiúscula);
  • finalmente, quais bibliotecas serão utilizadas, com a opção -l (letra "l" minúscula). Nomes de bibliotecas começam pelas letras "lib" (por exemplo, libblabla), e utilizamos com -lblabla (o nome depois do lib).

Já falamos que GTK é composta de várias bibliotecas de suporte. Isso significa dizer que, para compilar usando GTK, teremos que informar ao compilador, usando as opções acima, diretórios e bibliotecas para todas elas. Felizmente, temos um programa que nos auxilia nisso, chamado pkg-config, retornando as informações necessárias, para um pacote/biblioteca específico. Como nos diz o comando man,

"The pkg-config program is used to retrieve information about installed libraries in the system. It is typically used to compile and link against one or more libraries."

Então vamos experimentar, digite no terminal:

pkg-config --cflags --libs gtk+-2.0

A opção --cflags diz para retornar informações acerca dos includes, e --libs para bibliotecas, tudo isso relativo ao pacote indicado no final da linha, "gtk+-2.0".

Você deve ter obtido a seguinte saída:

-pthread -D_REENTRANT -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/gio-unix-2.0/ -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/directfb -I/usr/include/libpng12 -pthread -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgio-2.0 -lpangoft2-1.0 -lgdk_pixbuf-2.0 -lm -lpangocairo-1.0 -lcairo -lpango-1.0 -lfreetype -lfontconfig -lgobject-2.0 -lgmodule-2.0 -lgthread-2.0 -lrt -lglib-2.0

... ou seja, todos os parâmetros necessários para você compilar um programa que utilize a biblioteca GTK (e suas companheiras).

E como utilizamos isso? Copio essa coisa toda e digito junto com o comando de compilação, gcc?? Não precisa. Podemos simplesmente indicar ao GCC que os parâmetros de compilação vão ser informados pelo pkg-config. Fazemos isso dessa forma:

gcc -o aloumundo aloumundo.c `pkg-config --cflags --libs gtk+-2.0`

A linha acima tem o seguinte efeito: o comando pkg-config é executado, e sua saída é integrada ao resto da linha (compilação com o gcc) como se tivesse sido digitada normalmente. Agora, CUIDADO!! O caracter que envolve o pkg-config é a CRASE (não é a aspa simples, não é o acento agudo!).

Agora, você deve obter uma compilação sem erros, já que todas as bibliotecas estão instaladas no sistema, e você indicou ao compilador como usá-las.

Falta só executar sua obra-prima.... :-)

./aloumundo



Algumas observações finais:

  • se você clicar no 'X' para fechar a janela, ela fecha, mas o programa continua sendo executado (o terminal fica "travado"). Para liberar o terminal, precisamos finalizar o programa na marra, teclando CONTROL-C. Isso acontece porque o 'X' causa apenas a parte gráfica da coisa (a janela some da tela), mas não a finalização do programa. Isso é nossa responsabilidade, e veremos como fazer isso posteriormente.
  • note que você pode mover a janela, minimizar, maximizar, redimensionar.... como isso é possível, se não escrevemos código para isso? Isso é papo pro próximo artigo.

Abraços a todas e a todos!

Carlão

sexta-feira, 30 de julho de 2010

O openSUSE é Software Livre? Acho que não...

Esbarrei outro dia numa notícia sobre o lançamento de uma nova versão (11.3) da distribuição openSUSE. Como gosto muito de experimentar várias distribuições Linux, ainda mais com as facilidades trazidas pela virtualização, baixei a dita cuja pra brincar um pouco.

Criei a máquina virtual, bootei, escolhi linguagem... e cheguei numa página onde eu tinha que aceitar uma licença. Como eu brinco com meus alunos, "aquela página que ninguém lê, vai logo clicando em aceito...". Bom, eu parei pra ler.

Começou promissor... "The openSUSE Project grants to you a license to this collective work pursuant to the GNU General Public License version 2...". Bom, não entendo muito de licenciamento, mas até onde sei, GPL é a licença que garante as liberdades de um software livre. Beleza então, tudo certo!

Até que li mais um pouco... "As required by US law, you represent and warrant that you: (...) c) will not export, re-export, or transfer openSUSE 11.3 to any prohibited destination, entity... d) will not use or transfer openSUSE 11.3 for use in any sensitive nuclear, chemical, or biological weapons or missile technology end-uses... "

Parou, parou, parou.... Se me lembro bem, duas das quatro liberdades do software livre são "a liberdade de executar o programa, para qualquer propósito" e "a liberdade de redistribuir cópias de modo que você possa ajudar ao seu próximo".

Então, voltamos a pergunta do título... o openSUSE é Software Livre?

Abortei a instalação, desliguei a máquina virtual, apaguei o arquivo ISO. Fica pruma outra oportunidade...

Abraços a todas e a todos!
Carlão

quinta-feira, 22 de julho de 2010

"Esse pessoal de Piracicaba, não é mole não!!"


Costumo ouvir (e fazer...) muitas críticas à nossa Universidade, em especial por conta da burocracia absurda que assola nosso trabalho docente e de pesquisa, no dia-a-dia.

Mas dessa vez, devemos aplaudir de pé!! O motivo é a nomeação, feita pelo CONSU/UESC, do novo prédio da Pós-Graduação como PAVILHÃO PROF. MAX DE MENEZES.

Não tive, infelizmente, muito contato com o Max no dia a dia. Mas nesse pouco contato já dava pra sentir aquela simpatia infinita, acompanhada daquele sorriso maroto piracicabano... O cara era, simplesmente, muito gente boa!!

Vai ser bom entrar no Pavilhão Prof. Max de Menezes. Vai ser como estar perto do coração dele mais uma vez.

Tchau Max! A gente se esbarra por aí um dia desses!

Abraços!

Carlão

segunda-feira, 7 de junho de 2010

Propaganda azul da morte...

.
Sábado passado, num monitor de propaganda no aeroporto de Congonhas...




Hehehehehehehehehehehehehe... Tenta Linux da próxima vez... :-)

Abraços!
Carlão

quinta-feira, 3 de junho de 2010

Como inserir código-fonte em uma postagem de um blog

.
No post anterior, precisei colocar vários códigos-fonte de exemplos, o que foi uma tarefa árdua. Por algum motivo que os experts em html devem saber (mas eu não...), o Blogger cismava de estragar minha formatação. Identação então, nem pensar... o bicho teimava em colocar tudo alinhado a esquerda! Achei que tinha resolvido isso, usando a dupla <> e < / pre >, e colocando um pontinho na primeira posição, pra ele respeitar meus espaços da identação...

Tava indo tudo muito bem, até que tentei colocar um exemplo de um laço for... rapaiz, nem com reza braba!! O bicho simplesmente sumia com um pedaço do código! Alguma combinação de caracteres no for deve significar alguma coisa doida pra ele...

Enfim, acho que encontrei a solução para o dilema: sites que formatam código fonte, gerando código html prontinho pra você colocar no post. São eles:

Source code formatter
http://codeformatter.blogspot.com/2009/06/about-code-formatter.html

Format my source code
http://formatmysourcecode.blogspot.com

Em ambos, o funcionamento é o mesmo: você digita seu código-fonte numa caixa, aperta um botão, e ele gera o código html que formata seu código. Os sites geram também um preview, pra você conferir o resultado.

A partir daí, é só copiar o código em html gerado, e levar para seu post. No caso do blogger, quando você estiver na tela de digitação do post, clique na aba "editar html", e cole o código gerado na posição correta.

Abraços!

Carlão

segunda-feira, 31 de maio de 2010

Programação de GUIs utilizando GTK - Parte 1

.

Começo a partir de hoje uma série de posts para compartilhar minha experiência no aprendizado da biblioteca GTK, utilizada para desenvolvimento de software com interface gráfica para o usuário (GUI, Graphical User Interface).

Quero ressaltar que não sou um grande conhecedor da biblioteca, pelo contrário, estou ainda em processo de aprendizado. Tenho apenas um software completo desenvolvido com interface em GTK, que provavelmente serve muito mais como exemplo de como NÃO programar do que qualquer outra coisa ... :-) (apesar da ajuda inestimável do amigo Bruno Boaventura!).

O objetivo aqui é apenas compartilhar o conhecimento, mas mais que isso, motivar outras pessoas a ingressarem no mundo GTK, GNOME, e quem sabe um dia nos tornarmos desenvolvedores/colaboradores dessa que é a melhor interface gráfica do mundo!!! :-) (usuários KDE, por favor, levem na brincadeira... :-) )

O livro que estou utilizando para esse estudo é o excelente "Foundations of GTK+ Development", de Andrew Krause (Apress). Recomendo fortemente sua aquisição para quem deseja programar com GTK seriamente. O livro é completo e objetivo. Para cada elemento da biblioteca, o autor apresenta um ou mais códigos-fonte de exemplo, mostrando suas características fundamentais. Para aqueles com poucos recursos, a Apress comercializa uma versão PDF (ebook), a um preço um pouco mais acessível do que a versão em papel, principalmente porque não é preciso pagar o frete para o envio da versão em papel, que as vezes custa mais que o próprio livro... Um arquivo com todos os códigos-fonte dos exemplos do livro pode ser baixado gratuitamente no site oficial do livro, neste link.

Conto com a ajuda e a colaboração dos amigos que estiverem lendo isso, caso percebam algum erro no conteúdo apresentado, ou mesmo para proporem alguma adição que explique melhor algum ponto.

Ah, mais uma coisinha: o requisito básico para se acompanhar estes posts (e, de certa forma, pra estudar GTK) é um forte conhecimento da linguagem C básica, incluindo PONTEIROS.


***************

Pra começar: GTK+ é uma biblioteca escrita na linguagem C, sob o paradigma da orientação a objetos.

Ué, (dirá você), mas a linguagem C NÃO é orientada a objetos!! Como pode?

Esse é um erro comum de muita gente boa. Uma coisa é um paradigma de programação, ou seja, uma forma de organizar as idéias para criar um programa de computador. Outra coisa são as características e os recursos de uma linguagem de programação específica. Uma coisa não está completamente amarrada a outra. O que acontece é que existem linguagens de programação MAIS ADEQUADAS para utilização com um certo paradigma. Por exemplo, as linguagens C++ e Java foram criadas com recursos que tornam a programação no paradigma orientado a objetos mais confortável. Mas isso não significa que não se possa programar "orientado a objetos" com a linguagem C. O que vai acontecer é que teremos um "trabalhinho adicional", já que C não vem preparada para orientação a objetos. Por sorte, este trabalhinho já está pronto, na figura da biblioteca GObject, utilizada pela biblioteca GTK.

Vamos neste post, portanto, ver algumas características bem básicas do paradigma de orientação a objetos, fundamentais para que possamos entender como programar utilizando GTK.

Mas atenção! O que vai ser apresentado aqui é um resumo básico, introdutório, e principalmente, incompleto! Portanto, se você é aluno de computação, envolvido com as questões de orientação a objetos, não deixe de ler alguma referência oficial sobre o assunto. E depois volte aqui pra me ajudar a complementar o texto... :-)


DIFERENÇAS FUNDAMENTAIS ENTRE OS PARADIGMAS "PROCEDURAL" E "ORIENTADO A OBJETOS"


No paradigma procedural, temos duas características fundamentais:

  • código e dados bem separados;
  • o código atua sobre os dados;

Por exemplo, um programa que faça o gerencimento de uma conta bancária, no paradigma procedural, poderia ser representado pela seguinte figura:


Para, por exemplo, verificar o saldo da conta de "beltrano", o código (função) "saldo" atua sobre os dados da conta de beltrano:


No paradigma orientado a objetos, código e dados são reunidos em entidades chamadas "objetos". Um objeto possui características (dados, atributos) e também um comportamento (o objeto "faz" alguma coisa, ele responde a solicitações, é o seu código).


Repetindo o exemplo acima, para verificar o saldo da conta de "beltrano", agora nós enviamos uma "mensagem" para o objeto "conta de beltrano", para que esse objeto nos diga qual é o saldo da conta. Ou seja, este objeto tem um dado (o valor do saldo), e um comportamento (o objeto sabe responder quando lhe perguntamos seu saldo). Uma analogia: o objeto "ser humano" tem um dado (seu nome), e um comportamento (sabe responder quando lhe perguntam o nome). Se eu mandar, para um objeto "ser humano" a mensagem "qual é o seu nome?", o objeto ser humano devolve o valor armazenado na variável NOME... :-)


Resumindo: o objeto é responsável, ele mesmo, por verificar (e exibir) o saldo da conta.

CLASSE: MODELO GENÉRICO DE UM OBJETO

Os objetos são criados a partir de um "modelo", que diz como o objeto será (quais são seus atributos, dados, e qual é seu comportamento, código). Por exemplo, podemos definir a classe "ser humano", e a partir desse modelo, criar efetivamente os objetos "Ana", "Bianca", "Claudia", etc...

Eu comparo, mal-e-porcamente, uma classe a uma struct em C. Com a struct, temos dois momentos: o de definição da struct, e o de efetivamente criar uma variável a partir da struct. Assim, por exemplo,

struct AGENDA
{
. char NOME[30];
. char EMAIL[20];
}

... na verdade cria apenas um modelo de como será a struct AGENDA. Mas não há efetivamente nada criado na memória para guardar NOME e/ou EMAIL. Com a seguinte instrução,

struct AGENDA MinhaAgenda;

... aí sim, criamos na memória a variável "MinhaAgenda", e dentro dela temos NOME e EMAIL.

Uma classe é, portanto, uma "struct metida a besta", que além de dados, tem também código. :-)

Vamos ver um exemplo do que poderia ser uma classe "conta bancária", e alguns objetos gerados a partir dela:


Na figura, "instanciar" é simplesmente o processo de gerar um objeto, a partir de uma classe.

Uma classe, portanto, define todas as características comuns a um tipo de objeto.

Outro conceito pertencente ao paradigma de orientação a objetos é o de ENCAPSULAMENTO. Como o nome diz, traz a idéia de "cápsula", ou seja, a idéia de que não podemos ver o que tem dentro da cápsula. Outra analogia (bem simplória), numa cápsula de remédio, não sabemos o que tem dentro da cápsula (as várias substâncias e suas respectivas quantidades). Também não podemos (ou pelo menos, não devemos... :-) ) abrir a cápsula e manipular diretamente algum ingrediente específico.

Da mesma forma, um objeto não pode (ou não deve...) manipular diretamente os dados internos de outro objeto. Assim, no exemplo visto, só quem pode manipular o saldo (dado) que existe no objeto "conta de fulano" é o código que também existe dentro do mesmo objeto... não faria sentido o código que está dentro do objeto "conta de beltrano" manipular a variável SALDO existente dentro do objeto "conta de fulano"!!

ALGUNS TERMOS DA O.O.

Atributos: dados armazenados dentro dos objetos

Métodos: as funções (ou seja, o código) internas aos objetos, que manipulam os atributos

Envio de mensagem: dizemos que um objeto "envia uma mensagem" a outro objeto, para que este último faça alguma coisa. Por exemplo, podemos ter o objeto "caixa eletrônico da rua 5" enviando a mensagem "mostre o saldo" para o objeto "conta de fulano". O objeto "conta de fulano" então realiza esta ação, e devolve o valor para o objeto "caixa eletrônico", que vai mostrar na tela, imprimir, ou o que quer que seja.

Na prática, é uma chamada de função, ou melhor, a execução de um método presente em um objeto.

Em um código-fonte fictício, isso seria:

objeto "caixa eletrônico"
{
. ...
. conta_de_fulano.verificar_saldo();
. ...
}

Ou seja, estamos chamando a função (método) "verificar_saldo()", que existe dentro do objeto "conta_de_fulano".

Interface de um objeto: o conjunto de métodos (e seus parâmetros) que existem em um objeto.


HERANÇA

Essa é uma das características fundamentais da orientação a objetos, cujo conhecimento é muito importante para programação utilizando a biblioteca GTK.

A herança é um mecanismo que permite basear uma nova classe na definição de uma classe previamente existente. Ou seja, não precisamos ficar "reinventando a roda" a todo momento. Pega-se algo que já está pronto, e adicionamos outros recursos. Usando herança, sua nova classe herda todos os atributos e métodos presentes na classe previamente existente.

Como exemplo, vamos pensar em duas classes: "homem" e "mulher". Serão classes diferentes, já que apresentarão diferenças de comportamento entre si (por exemplo, os objetos "homem" terão o método "entender a lei do impedimento"... os objetos "mulher" terão o método "reconhecer a cor fúcsia"... :-) ). Só que, além de diferenças, terão também características em comum, como por exemplo, ambos os objetos terão um "nome" e uma "idade", e ambos os objetos saberão "dizer seu nome" e "dizer sua idade". Desta forma, podemos criar uma classe "ser humano", com essas características básicas, e A PARTIR DELA, as duas classes "homem" e "mulher", com as características específicas de cada uma.


Como os objetos "filhos" herdam todas as características do objeto "pai", independentemente do tipo de objeto (ser humano, homem, mulher), a todos eles poderemos mandar a mensagem "dizer nome", e todos responderão corretamente.

Isso nos leva a outra característica bastante interessante da orientação a objetos:


POLIMORFISMO

Significa "muitas formas" (dããã...). Permite que um único nome de classe ou nome de método represente um código diferente, selecionado por um mecanismo automático. Trocando em miúdos: podemos ter códigos diferentes (que fazem coisas diferentes), mas com o mesmo nome de método, em objetos (classes) diferentes. Na hora da execução, o código correto é selecionado pra execução, a partir do tipo do objeto para o qual se está enviando a mensagem.

Vamos tentar um exemplo "prático" pra deixar isso mais claro.

Imagine o seguinte "código-fonte", fictício, numa linguagem "parecida" com C. Neste código, vamos "definir" a classe "Pessoa", e classes filhas dela, "Pessimista", "Otimista", "Timido" e "Extrovertido". Em todas as classes, vamos definir o mesmo método, "fale()", só que com código diferente em cada uma delas.

classe Pessoa
{
. void fale()
. {
. printf("Eu sou uma pessoa comum\n");
. }
}

classe Pessimista, filha de Pessoa
{
. void fale()
. {
. printf("O copo está meio vazio...\n");
. }
}

classe Otimista, filha de Pessoa
{
. void fale()
. {
. printf("O copo está meio cheio!\n");
. }
}

classe Timido, filha de Pessoa
{
. void fale()
. {
. printf("oi...\n");
. }
}

classe Extrovertido, filha de Pessoa
{
. void fale()
. {
. printf("Olá! blabla..! voce sabia que ... bla bla!\n");
. }
}


Como dissemos anteriormente, uma classe é apenas um modelo. Vamos agora criar objetos, a partir das classes definidas acima (obs: qualquer semelhança com a forma de criar variáveis em C, "tipo nome_variável;" não terá sido mera coincidência... :-) )

Pessimista   Paulo;    /* Paulo é um objeto do tipo "Pessimista" */
Otimista Otavio;
Timido Tiago;
Extrovertido Eduardo;

Vamos agora criar um vetor, para armazenar objetos do tipo "Pessoa":
Pessoa Galera[4];

... ou seja ...

Galera[0] vai armazenar um objeto do tipo Pessoa;
Galera[1] vai armazenar um objeto do tipo Pessoa;
Galera[2] idem...
Galera[3] idem...

E para fechar o exemplo, vamos fazer:

Galera[0] = Paulo;
Galera[1] = Otavio;
Galera[2] = Tiago;
Galera[3] = Eduardo;

Oras... dirá você... mas se você criou um vetor para armazenar "Pessoas", como pode armazenar outra coisa que não "Pessoas" ? Por exemplo, Galera[0] foi criado para armazenar um objeto do tipo "Pessoa", mas estamos armazenando um objeto do tipo "Pessimista" (Paulo)!!

Isto é possível porque a classe "Pessimista" é derivada da classe "Pessoa", ou seja, de certa forma, um "Pessimista" É uma "Pessoa"! O mesmo acontece com as variáveis armazenadas nos outros elementos do vetor.

GTK faz uso extensivo deste recurso, por exemplo, sejam duas classes:

  • GtkWidget: objeto gráfico básico, genérico;
  • GtkWindow: uma janela (com título, botões de max, min, fechar...)
A "widget hierarchy" de GtkWindow é a seguinte:


Independente das "classes intermediárias", podemos dizer que um GtkWindow É um GtkWidget.

Completando o exemplo... como fazemos para enviar a mensagem "fale()" para cada objeto, já que são objetos diferentes, e cada um deveria falar uma coisa diferente?

Bem, sem o recurso da herança, teriamos que ter um monte de IF's aninhados, testando o tipo de cada objeto, e aí chamando a função correta: "se for pessimista, fala isso... senão, se for otimista, fala aquilo... senão... ".

Com o recurso da herança, e do polimorfismo, essa tarefa fica MUITO mais fácil:

 for ( CONT=0 ; CONT<4 ; CONT++ )
{
Galera[CONT].fale();
}

Passo-a-passo:

  • inicializa CONT com 0;
  • CONT é menor que 4? SIM! entra no laço.
  • chama o método "fale()" na variável Galera[0]
  • agora é que está o "pulo do gato": Galera[0] é do tipo Pessoa, mas nela está armazenado um objeto do tipo "Pessimista", logo, AUTOMATICAMENTE, vai ser chamado o método "fale()" da classe Pessimista, e não o da classe Pessoa!!!
  • fim do laço: CONT fica igual a 1, ainda menor que 4, entra no laço novamente
  • chama o método "fale()" na variável Galera[1]
  • o objeto armazenado em Galera[1] é "Otavio", do tipo "Otimista", então automaticamente vai ser chamada a função "fale()" da classe "Otimista"
  • fim do laço: CONT fica igual a 2, entra no laço novamente
  • e por aí vai...

Assim, a saída que teremos, será:

O copo está meio vazio
O copo está meio cheio
oi...
Olá !! bla bla bla !! ...


Mais um exemplinho... seja uma função qualquer, que receba como PARÂMETRO um objeto do tipo "Pessoa", e retorne um inteiro com a idade dessa pessoa. A função seria escrita assim (na nossa "pseudo" linguagem C... ):

 int Diz_Idade ( Pessoa FulanoDeTal );
{
...
...
}

A seguinte chamada dessa função é válida:

...
Diz_Idade( Paulo );
...

Deixando claro: a função espera receber um parâmetro do tipo "Pessoa". Estamos passando o objeto "Paulo", que é do tipo "Pessimista". Nenhum problema aí, já que "Pessimista" É uma "Pessoa" (pela definição de herança!). As chamadas abaixo também são válidas:

Diz_Idade( Otavio );
Diz_Idade( Tiago );
Diz_Idade( Eduardo );


Pra fechar esse post-monstro, um exemplinho com GTK, pra ir tomando o gosto...
MAS ATENÇÃO!! O exemplo está INCOMPLETO e SIMPLIFICADO!!

1:  int main( ... )
2: {
3: GtkWidget *window;
4:
5: ...
6:
7: window = gtk_window_new ( ... );
8:
9: gtk_window_set_title ( window, "Hello World!!" );
10:
11: ...
12: }


Vamos ver passo a passo?

linha 3: estamos criando uma variável de nome "window", que é do tipo "ponteiro" para o tipo de dados GtkWidget (como já vimos, o tipo de dado básico de todos os objetos em GTK);

linha 7: utilizamos a função "gtk_window_new" que cria toda a definição necessária para uma janela gráfica na memória do computador. Esta função retorna o endereço inicial desta definição (analogia: comando malloc, cria uma área na memória, e devolve o endereço inicial da área). Armazenamos este endereço na variável "window".

linha 9: utilizamos a função "gtk_window_set_title" para definir o texto que será exibido como título da janela. Passamos como parâmetros, obviamente, a variável que tem o endereço da janela cujo título queremos definir (neste exemplo, variável "window"), e o texto que queremos como título (a string "Hello World!").

Aqui podemos ver a herança em ação: a função gtk_window_set_title espera receber de parâmetro um objeto do tipo GtkWindow. Mas, o que passamos foi a variável "window", que é um GtkWidget. Ora, como já vimos no exemplo anterior, e também na hierarquia da classe GtkWindow, uma GtkWindow É um GtkWidget. Logo podemos passar a variável "window" para esta função sem problemas.

Repetindo: este exemplo está SIMPLIFICADO e INCOMPLETO. Foi só pra ilustrar o que vimos até aqui.

Chega por hoje!

Abraços a todas e a todos!

Carlão

sexta-feira, 21 de maio de 2010

(mais) Uma conversa entre Steve Jobs e Bill Gates...

.
Tá rolando essas figuras pela net. Não resisti... :-)