Nesse post vou falar um pouco sobre o básico do QT, de forma que depois de ler você já saia programando interfaces relativamente complexas. Por essa razão, esse tutorial não vai explicar muitos detalhes. O QT possui algumas coisas estranhas para quem não está acostumado, simplesmente aceite-as :P. Se você nunca viu QT, este tutorial aqui é um bom começo
Pré-requisitos: saber C e pelo menos o básico de orientação a objetos em C++ (como criar classes, subclasses), saber o que é um makefile
Pós-requisitos: saber criar uma interface em QT e interagir com esta interface
QT é um framework multi-plataforma (entre eles windows e linux) para desenvolvimento de aplicações. Seu sucesso está no desenvolvimento de interfaces gráficas, porém também podemos usá-la para outros fins. O QT já está na versão 4 e tudo o que você precisará saber está nessa página (no caso da versão 4.2):
http://doc.trolltech.com/4.2/index.html
Parte 1: Instalação
No link anterior há instruções de instalação, mas se sua distro também tem apt-get e não quer perder tempo já pode instalar os seguintes pacotes: libqt4-dev, qt4-designer, qt4-dev-tools e qt4-qtconfig.
Parte 2: Overview das Classes
O QT é baseado em classes. A nomenclatura é bem direta: um label (texto na janela) é um objeto da classe QLabel, um botão é um objeto da classe QPushButton. Obviamente, há também classes não relacionadas a interface gráfica, como QString para representar uma string, QImage para representar uma imagem. Os widgets (widget denota qualquer componente de interação com usuário numa interface gráfica) são subclasses de QWidget e portanto herdam alguns métodos de QWidget como setVisible, setSize, etc. A maioria desses widgets possuem como parâmetro do construtor o widget a qual ele está conectado.
Ok Rafael, mas onde o aplicativo começa para que eu possa ir adicionando os widgets? Como interagir com esses widgets? Bem, chegaremos lá.
Parte 3: Rodando um aplicativo em QT
Onde começar a interface gráfica? Obviamente do main
mas para iniciar a interface gráfica é suficiente (mas não necessariamente :)) que você deixe seu main mais ou menos assim:
#include <QApplication>
#include <QtGui>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QPushButton *pb = new QPushButton(”clica em mim”);
pb->show();
return app.exec();
}
Quando executar esse programa, uma janela é aberta com um botão com o texto “clica em mim”. Também nada acontece quando você clica. Mas como compilar esse código?
Parte 3.1: Compilando
Essa é a parte estranha
você poderia pensar que para compilar seria: g++ teste.cpp -lQT… bem, não é assim. É necessário incluir várias opções na compilação e para facilitar eles fornecem uma ferramenta chamada qmake. O qmake vai gerar um makefile automaticamente para você e quando você fizer make, o seu programa é compilado e seu executável terá o mesmo nome do diretório. Um detalhe é que o qmake vai ler todo o diretório atual e subdiretórios, então o ideal é que quando você criar esses testes, coloque-os em uma pasta especial.
Parte 3.2: qmake
Com o intuito de facilitar a explicação, suponha que o diretório atual se chama “teste”. Para gerar o produto final que queremos (o makefile) é necessário 2 etapas:
1) gerar um arquivo de projeto
2) gerar o arquivo makefile
Para gerar o arquivo de projeto, você deve fazer: qmake -project
Isso criará um teste.pro (lembre-se que teste é o nome do diretório). Esse arquivo contém uma lista de arquivos e opções que fazem parte do seu projeto, mas em geral você não precisa alterá-lo.
Para gerar o makefile, você deve fazer: qmake -makefile. Com isso, será gerado um makefile baseado no arquivo teste.pro.
Resumindo para compilar e executar o programa:
qmake -project
qmake -makefile
make
./teste
Parte 4: Elaborando interfaces maiores
Tudo o que fizemos no aplicativo anterior foi criar uma aplicação QApplication, criar um QPushButton, chamar o seu método show para exibi-lo na tela e mandar executar o aplicativo. Obviamente, queremos uma interface gráfica mais complexa. Como dito anteriormente, os widgets em sua maioria possuem como parâmetro do construtor um widget ‘pai’. Então uma janela com dois botões pode ser criado instanciando um objeto da class QWidget e mais dois objeto QPushButton:
QWidget *widget = new QWidget();
QPushButton *b1 = new QPushButton(widget, “clica em mim aqui”);
QPushButton *b1 = new QPushButton(widget, “oba”);
widget->show();
Isso vai resultar na seguinte interface:
Como vocês podem ver, um botão saiu em cima do outro. Bem, ele não tem um gerenciador automático de layouts (e nem faria muito sentido ter). Mas você pode usar classes como QVBoxLayout para isso. Mas não se preocupe! Você não precisa programar a esse ponto, afinal daria muito trabalho. Para poupar trabalho da criação da interface, existe o qt-designer.
Parte 4.1: QT Designer
Você pode iniciar o qt-designer executando designer-qt4. Deve aparecer uma nova janela perguntando qual tipo de formulário você quer. Escolha Widget (como vimos antes, a janela pode ser um widget). Depois é só arrastar os componentes que quiser no widget, alterar suas propriedades, etc (bem, a interface é bem intuitiva!).
Tente criar uma interface parecida com essa:
Salve (digamos com o nome interface.ui). Esse arquivo .ui é um XML que contém a descrição do seu formulário. A questão é: como gerar um código a partir desse XML que crie a mesma interface correspondente? O primeiro passo é fazer qmake -project novamente. Se você abrir o teste.pro verá algo parecido com isso:
FORMS += interface.ui
SOURCES += teste.cpp
O qmake -project reconheceu que tem um arquivo de formulário no diretório e o acrescentou em FORMS. Quando você fizer qmake -makefile, o makefile terá um comando para converter esse .ui em um .h. No caso de interface.ui, após executar make, será criado um arquivo ui_interface.h (dê uma espiada nele :)).
O ui_interface.h contém uma classe Ui_Form (você pode mudar o nome pelo qt-designer, o padrão do nome do form é Form) com tudo necessário para a criação do widget que você mesmo criou no qt-designer. E o que interessa nessa classe? O método setupUi:
void setupUi(QWidget *Form)
Você passa um objeto QWidget a este método e ele trata de adicionar neste widget todos os componentes que você especificou em suas devidas posições, tamanhos, valores, etc.
Vamos agora mudar o nosso teste.cpp
#include <QApplication>
#include <QtGui>
#include “ui_interface.h”
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget *widget = new QWidget();
Ui::Form form;
form.setupUi(widget);
widget->show();
return app.exec();
}
Pronto, make e já pode executar.
Parte 5: Interagindo com os widgets
O programa anterior exibiu os widgets conforme especificamos no qt-designer, mas ainda não é possível interagir com esses widgets. Como fazer? Para essa interface, vamos fazer três coisas:
1) Quando clicar em ‘here we go’, mudar o QLabel para dizer qual o melhor time do mundo.
2) Quando clicar em ‘quit’, sair do programa.
3) Quando mudar o spinbox ou a barra de rolagem mudar o valor do outro, de forma que ambos apresentem a mesma quantidade.
Parte 5.1: como os widgets interagem
Os widgets se interagem através de sinais. Quando o usuário clica na setinha do spinbox, um sinal é emitido e alguma função registrada para atender esse sinal será chamada. Vá na documentação do spinbox e vejá qual o sinal que é emitido quando o usuário clica na setinha:
http://doc.trolltech.com/4.2/qspinbox.html
Achou?
-
void valueChanged ( int i )
-
void valueChanged ( const QString & text )
São dois tipos de sinais e mais 3 herdados de outras classes. Então para interagir com um widget você precisa saber 2 coisas:
1) Onde está o objeto que representa aquele widget
2) Qual o sinal que você quer tratar
Se você olhou o ui_interface.h pôde ver que os objetos estão na classe Ui_Form:
QPushButton *pushButton;
QLabel *label;
QPushButton *pushButton_2;
QSpinBox *spinBox;
QScrollBar *horizontalScrollBar;
Os nomes aqui estão pelo padrão do qt-designer. Mas você pode optar obviamente por nomes mais intuitivos, mudando pela interface do qt-designer
Parte 5.2: conectando os sinais
Para registrar uma função que deva tratar um sinal de um widget, utilize a função connect:
connect(widget,SIGNAL(sinal()),this,SLOT(funcao()));
Mas há uma forma que eu pessoalmente achei mais conveniente de usar: a conexão automática. Funciona assim: você especifica na classe que contém o objeto widget em questão um método chamado: on_<widget>_<sinal>(parametros)
E essa função automaticamente já tratará esse sinal emitido por esse widget. Então por exemplo, queremos tratar o sinal valueChanged do objeto spinBox, criamos a função:
void on_spinBox_valueChanged(int value);
Você pode alterar o ui_interface.h para implementar esses métodos, mas NÃO FAÇA ISSO… obviamente porque se você alterar depois a interface do interface.ui, você vai perder o ui_interface.h antigo. Uma solução é criar uma subclasse de QWidget e colocar o Ui::Form form como atributo desse classe. Depois você pode implementar esses métodos nessa subclasse que o QT cuida de registrar as funções.
Parte 6: implementação final
O interface.h:
#ifndef INTERFACE_H
#define INTERFACE_H
#include “ui_interface.h”
#include <QtGui>
#include <QWidget>
class Interface : public QWidget{
Q_OBJECT
public:
Interface(QWidget *parent = 0) : QWidget(parent) {
form.setupUi(this);
}
private slots:
void on_pushButton_clicked(bool checked) {
form.label->setText(”XV de Piracicaba”);
}
private:
Ui::Form form;
};
#endif
e o teste.cpp:
#include <QApplication>
#include <QtGui>
#include “interface.h”
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Interface inter;
inter.show();
return app.exec();
}
O resto fica como exercício
verificar os sinais do spinBox e do horizontalScrollBar para sincronizá-los.






