A empresa Norueguesa Troll Tech (http://www.troll.no) disponibiliza um chamado conjunto de ferramentas de GUI, chamado Qt . Assim, GUI significa "Graphical User Interface - Interface Gráfico de Utilizador", e assim, as aplicações baseadas na Qt representam-se com botões, janelas etc, permitindo inserção de dados do utilizador visualizando as funções que a aplicação disponibiliza. Este conjunto de ferramentas é necessário para o desenvolvimento de aplicações gráficas que corram no Interface X-Window em Sistemas Unix, porque o X não contém um interface de utilizador pré-definido em si. Apesar de outros conjuntos de ferramentas estarem também disponíveis para criar Interfaces de Utilizador, a Qt oferece algumas vantagens técnicas que tornam o desenho de aplicações muito fácil. Adicionalmente, o conjunto de ferramentas Qt também está disponível para o sistema Microsoft Windows, o que permite aos programadores disponibilizarem as suas aplicações para ambas as plataformas.
A Equipa KDE (http://www.kde.org) juntou-se com o objectivo de tornar a utilização de Sistemas Unix mais amigável, e decidiu utilizar o conjunto de ferramentas Qt para o desenvolvimento de um gestor de janelas no X-Window, mais uma variedade de ferramentas incluídas com os pacotes KDE. O Ambiente de Trabalho K contém assim o gestor de janelas kwm, o gestor de ficheiros kfm e o painel de controlo kpanel como sendo os componentes principais mais uma variedade de utilitários e aplicações de primeira classe. Depois do KDE ter saido, muitos dos programadores voltaram os seus olhos no sentido deste novo ambiente e do que tem para lhes oferecer. As bibliotecas KDE estão a disponibilizar métodos e classes fundamentais que fazem com que todas as aplicações desenhadas com elas tenham um aspecto similar e consistente, e o utilizador tem a grande vantagem de apenas ter de se acostumar com a utilização específica de uma aplicação, não com o manuseamento de diálogos ou botões. Também, os programas KDE integram-se no ambiente de trabalho e são capazes de interagir com o gestor de ficheiros através do arrastar e largar (drag and drop), oferecer gestão de sessões e muito mais, se todas as funcionalidades oferecidas pelas bibliotecas KDE forem utilizadas.
Ambos, o conjunto de ferramentas Qt e as bibliotecas KDE , são implementadas na linguagem de programação C++; assim aplicações que façam uso destas bibliotecas são também maioritariamente escritas em C++. No capítulo seguinte, faremos uma breve viagem através das bibliotecas para ver o que já é disponibilizado e como as aplicações Qt e KDE são criadas em geral.
Como foi dito, a biblioteca Qt é um conjunto de ferramentas que oferece elementos gráficos que são utilizados para criar GUI's de aplicações e são necessárias para programação X-Window. Adicionalmente, este conjunto de ferramentas oferece:
Um conjunto completo de classes e métodos prontos a utilizar para questões de programação não-gráfica,
Uma boa solução no sentido da interacção do utilizador através de métodos virtuais e mecanismos sinal/espaço,
Um conjunto de elementos GUI pré-definidos, chamados "widgets", que podem ser facilmente utilizados para criar elementos visíveis
Diálogos adicionais completamente pré-definidos que são muitas vezes utilizados em aplicaçãis tais como diálogos de progresso e de ficheiros.
Posto isto conhecer as classes Qt é essêncial, mesmo se você apenas deseja programar aplicações KDE. Para ter uma ideia do conceito basico sobre como as aplicações GUI são construidas e compiladas, iremos primeiro observar um programa exemplo apenas Qt ; depois extende-lo-emos para um programa KDE.
Como normalmente, programas em C++ têm de conter a função main(), que é o ponto de partida para a execução da aplicação. Como queremos que seja graficamente visível em janelas e ofereça interacção do utilizador, temos primeiro que saber, como se podem mostrar a si próprias ao utilizador. Por exemplo, iremos observar o primeiro programa de tutor incluido com a Documentação Electrónica de Referência Qt e explicar os passos de execução básicos; também como e porquê as janelas da aplicação aparecem:
#include <qapplication.h> #include <qpushbutton.h> int main( int argc, char **argv ) { QApplication a( argc, argv ); QPushButton hello( "Hello world!" ); hello.resize( 100, 30 ); a.setMainWidget( &hello ); hello.show(); return a.exec(); } |
Esta aplicação meramente pinta uma janela contendo um botão com "Hello world" ("Olá Mundo") como texto. Como todas as aplicações baseadas na Qt , primeiro tem de declarar uma instância da classe QApplication, representada por a.
Depois, o programa cria uma instância da classe QPushButton chamada hello, isto será o botão. O constructor do hello obtém uma string (conjunto de caracteres) como parâmetro, que é o conteudo do widget visível como sendo o texto do botão.
Depois o método resize() é chamado sobre o botão hello. Isto muda o tamanho de defeito que um widget (que é neste caso o QPushButton) tem quando criado para o comprimento de 100 pixels e a altura de 30 pixels. Finalmente, o método setMainWidget() é chamado para a e o método show() para hello. A QApplication é finalmente executada por a.exec(), entra no ciclo de acontecimento principal e aguarda até que tenha de devolver um valor inteiro para a camada do Sistema Operativo assinalando que a aplicação terminou.
Agora, vamos observar rapidamente a documentação de referência da biblioteca Qt . Para fazer isto, inicie o KDevelop e seleccione "biblioteca Qt " a partir do menu "Ajuda" na barra de menu. O navegador de documentação abre e mostra-lhe a página inicial da referência Qt . Isto irá ser o seu primeiro local para obter informação sobre a Qt , suas classes e as funções disponíveis que oferece. Também, o programa acima mostrado é o primeiro que é incluído na secção dos tutores. Para obter as classes que desejamos observar, QApplication e QPushButton, seleccione "Lista Alfabética de Classes" e procure os nomes correspondentes. Siga qualquer uma delas para observar a documentação de classes .
Para a QApplication, verá o construtor e todos os outros métodos que esta classe disponibiliza. Se seguir uma hiper-ligação, irá obter mais informação sobre a utilização e significado dos métodos, o que é muito útil quando você às vezes não consegue detectar a utilização correcta ou deseja ver um exemplo. Isto também vale para a documentação da biblioteca KDE, que utiliza um tipo de documentação similar; assim isto é praticamente tudo o que tem de saber sobre a utilização da referência de classes com o navegador de documentação.
Começando com a QApplication, você irá ver todos os métodos utilizados no nosso primeiro exemplo:
o construtor QApplication(),
o método setMainWidget() e
o método exec().
A interpretação sobre porque utilizamos estes métodos é muito simples:
primeiro criamos uma instância da classe QApplication com o construtor, para que possamos utilizar os elementos GUI disponibilizados pela Qt ,
criamos um widget que será o contentor da janela do nosso programa,
definimos o widget como sendo o widget principal para a,
executamos a instância a da QApplication.
O segundo objecto do nosso programa é o botão, como uma instância da classe QPushButton. Dos dois construtores dados para criar uma instância, nós utilizamos o segundo: este aceita um texto, que é a etiqueta do conteudo do botão; aqui, a etiqueta é o texto "Hello world!". Depois chamamos o método resize() para modificar o tamanho do botão de acordo com o seu conteudo- o botão tem de ser maior para tornar o texto completamente visível.
Mas e então o método show()? Agora, você vê que tal como a maior parte dos outros widgets, QPushButton é baseado numa herança única- aqui, a documentação diz, Herda QButton. Siga a hiper-ligação para a classe QButton. Isto irá mostrar-lhe imensos outros métodos que são herdados pelo QPushButton, que iremos utilizar mais tarde para explicar o mecanismo sinal/espaço. De qualquer modo, o método show() não está listado, pelo que, tem de ser um método que é disponibilizado também por herança. A classe que o QButton herda, é QWidget. Basta seguir de novo a hiper-ligação, e irá ver imensos métodos que a classe QWidget disponibiliza; incluindo o método show(). Agora nós compreendemos o que foi feito no exemplo com o botão:
criar uma instância do QPushButton, utilizar uma segunda construção para definir o texto do botão,
redimensionar o widget para o seu conteudo,
definir o widget como sendo o widget principal da instância a da QApplication,
dizer ao widget para se mostrar no ecrã chamando show(), um método herdado de QWidget.
Após chamar o método exec(), a aplicação é visível para o utilizador, mostrando uma janela com um botão apresentando "Hello world!". Agora, programas GUI comportam-se de um modo ligeiramenta diferente das aplicações processuais. A coisa principal aqui é que a aplicação entra num chamado "ciclo de evento principal". Isto significa que o programa tem de aguardar por acções do utilizador e depois reagir a estas, também que para uma aplicação Qt , o programa tem de estar no ciclo de evento principal para iniciar o manuseamento de eventos. A secção seguinte diz-lhe de forma breve o que isto significa para o utilizador e o que a Qt oferece para processar eventos do utilizador.
(Para utilizadores já avançados: O botão não tem pai declarado no construtor, por isso é por si só um widget de nível superior e corre num ciclo de evento local que não tem de aguardar pelo ciclo de evento principal, veja a documentação de classe QWidget e O Guia de Referência da Biblioteca KDE)
Sumário:
Uma aplicação Qt tem sempre de ter uma instância da classe QApplication. Isto permite que possamos criar janelas que são a representação gráfica de programas para o utilizador final e permitem interacção. O conteudo da janela em si é chamado o "Widget Principal", significando que todos os elementos gráficos são baseados na classe QWidget e podem ser qualquer tipo de widget que sirva as necessidades da aplicação para comunicar com o utilizador. Assim, todos os elementos de utilizador têm de herdar de uma forma ou de outra QWidget para serem visíveis.
Após ler as secções anteriores, você já deverá saber:
o que a biblioteca Qt disponibiliza em termos de aplicações GUI,
como é que um programa que utilize a Qt é criado e
onde e como obter informação sobre classes que deseja utilizar com o navegador de documentação
Agora iremos começar a dar "vida" à aplicação através do processamento de eventos do utilizador. Geralmente, o utilizador tem duas formas de interagir com o programa: o rato e o teclado. Para ambas as formas, um interface gráfico de utilizador (GUI) tem de disponibilizar métodos que detectem acções e métodos que façam alguma coisa como reacção a estas acções.
O sistema de Janelas assim envia todos os eventos de interacção para a respectiva aplicação. A QApplication envia-os então para a janela activa como um QEvent e os prórpios widgets têm de decidir o que fazer com os eventos. Um widget recebe o evento e processa QWidget::event(QEvent*)/, que então decide que evento foi executado e como reagir; event() é assim quem faz o manuseamento principal de eventos. Depois, a função event() passa o evento para os chamados filtros de eventos, que determinam que aconteceu e o que fazer com o evento. Se nenhum filtro encontra um responsável pelo evento, os manuseadores especializados de eventos são chamados. Assim podemos decidir entre:
a) Eventos de Teclado -- teclas TAB e Shift-TAB:
muda o focus de entrada do teclado do widget actual para o widget seguinte na ordem de focus. O focus pode ser atribuido aos widgets chamando setFocusPolicy() e processar os seguintes indicadores de eventos:
virtual void focusInEvent ( QFocusEvent * )
virtual void focusOutEvent ( QFocusEvent * )
b) todos os restantes eventos de teclado:
virtual void keyPressEvent ( QKeyEvent * )
virtual void keyReleaseEvent ( QKeyEvent * )
c) movimentos do rato:
virtual void mouseMoveEvent ( QMouseEvent * )
virtual void enterEvent ( QEvent * )
virtual void leaveEvent ( QEvent * )
d) acções de botões do rato:
virtual void mousePressEvent ( QMouseEvent * )
virtual void mouseReleaseEvent ( QMouseEvent * )
virtual void mouseDoubleClickEvent ( QMouseEvent * )
e) eventos da janela que contém o widget:
virtual void moveEvent ( QMoveEvent * )
virtual void resizeEvent ( QResizeEvent * )
virtual void closeEvent ( QCloseEvent * )
Note que todas as funções de eventos são virtuais e protegidas; assim você pode re-implementar os eventos que necessitar nos seus próprios widgets e especificar como o seu widget tem de reagir. O QWidget também contém alguns outros métodos virtuais que podem ser úteis nos seus programas; de qualquer modo, é suficiente saber sobre o QWidget de uma forma geral.
Agora estamos a chegar às vantagens mais óbvias do conjunto de ferramentas Qt : o mecanismo sinal/espaço. Isto oferece uma solução bastante "à-mão" e útil para interacção de objectos, que é normalmente resolvido através de funções de callback para conjuntos de ferramentas X-Window. Como esta comunicação requer uma programação estrita e às vezes torna a criação de interfaces gráficos muito difícil (como referido pela documentação Qt e explicado em Programação com Qt por K.Dalheimer), a Troll Tech inventou um novo sistema onde objectos podem emitir sinais que podem ser conectados a métodos declarados como espaços. Para a parte C++ do programador, ele apenas tem de saber algumas coisas sobre este mecanismo:
a declaração de classe da classe que utiliza sinais/espaços tem de conter a macro Q_OBJECT no início (sem o ponto e vírgula); e tem de derivar da classe QObject,
um sinal pode ser emitido por uma palavra-chave emit, por ex. emit signal(parâmetros); a partir de qualquer função membra de uma classe que permita sinais/espaços,
todos os sinais utilizados pelas classes que não são herdadas têm de ser adicionados à declaração da classe através de uma secção signals:,
todos os métodos que podem ser conectados com um sinal são declarados em secções com a palavra-chave adicional slot, por ex. public slots: dentro da declaração da classe,
o compilador de meta-objectos moc tem de correr sobre o ficheiro header para expandir as macros e produzir a implementação (que não é necessário saber.). Os ficheiros resultantes do moc são compilados também pelo compilador C++.
Outra forma de utilizar sinais sem derivar de QObject é utilizar a classe QSignal- veja a documentação de referência para mais informação e exemplos de utilização. Nos exemplos seguintes, nós assumimos que você está a derivar da QObject.
Desta forma, a sua classe é capaz de enviar sinais para qualquer lado e de disponibilizar espaços a onde se possam conectar sinais. Utilizando os sinais, você não tem de se preocupar com quem os está a receber- você apenas tem de emitir o sinal e qualquer que seja o espaço que lhe queira conectar poderá reagir à emissão. Também os espaços podem ser utilizados como métodos normais durante a implementação.
Agora, para conectar um sinal a um espaço, tem de utilizar os métodos connect() que são disponibilizados através do QObject ou, onde disponível, métodos especiais que os objectos disponibilizam para definir a conecção para um certo sinal.
Para explicar a forma como definir interacção de objectos, iremos agarrar de novo no nosso primeiro exemplo e extende-lo através de uma conecção simples:
#include <qapplication.h> #include <qpushbutton.h> int main( int argc, char **argv ) { QApplication a( argc, argv ); QPushButton hello( "Hello world!" ); hello.resize( 100, 30 ); a.setMainWidget( &hello ); connect(&hello, SIGNAL( clicked() ), &a, SLOT( quit() ); hello.show(); return a.exec(); } |
Como vê, a única adição para dar ao botão mais interacção é utilizar um método connect(): connect(&hello, SIGNAL( clicked() ), &a, SLOT( quit() ); é tudo o que temos de acrescentar. Qual é o significado agora? A declaração da classe de QObject diz sobre o método connect():
bool connect ( const QObject * sender, const char * signal, const QObject * receiver, const char * member )
Isto significa, você tem de especificar um ponteiro de uma instância de QObject que é o emissor do sinal, significando que pode emitir este sinal como primeiro parâmetro; depois você tem de especificar o sinal a que se deseja conectar. Os dois últimos parâmetros são o objecto receptor que disponibiliza um espaço, seguido pela função membro que é na realidade o espaço que será executado aquando da emissão do sinal.
Utilizando sinais e espaços, os objectos do seu programa podem interagir entre eles facilmente sem dependerem explicitamente do tipo de objecto receptor. Você irá aprender mais sobre a utilização deste mecanismo para utilização produtiva mais tarde neste manual. Mais informação sobre o mecanismo Sinal/Espaço pode ser encontrado no Guia de Referência da Biblioteca KDE e na referência electrónica Qt .