Escolar Documentos
Profissional Documentos
Cultura Documentos
qtbrasil.com
Viso Geral
O nico oficialmente publicado guia das melhores prticas para programao Qt 4.3
Usando o Qt da Trolltech possvel criar aplicaes C++ de alta performance que rodem em
mquinas Windows, Linux/Unix, Mac OS X, e demais extenses Linux sem que seja necessrio
fazer alteraes de cdigo. Agora, dois membros da Trolltech lhe oferecem este guia completo
para que voc alcance resultados surpreendentes com a mais recente verso do Qt: Qt 4.3.
Carregado com exemplos prticos, realistas e conselhos profundos, este o livro usado pela
Trolltech para ensinar Qt para seus prprios novos funcionrios. Revisado e expandido
constantemente, este livro nos revela os melhores padres atuais para se trabalhar com Qt
para diversos usos, que vo desde implementao de arquiteturas de modelagem at o uso da
engine grfica do Qt 4.3. Voc encontrar solues para diversas tarefas de desenvolvimento
GUI, assim como tcnicas sofisticadas para sistemas com acesso a banco de dados, integrao
com XML, uso de subclasses, composio, e muito mais. Seja voc um novo usurio de Qt, ou
um usurio antigo que est aprendendo a nova verso, este livro certamente vai lhe ajudar a
tirar vantagem de tudo que o Qt 4.3 capaz de fazer.
Eis algumas novidades que encontraro neste livro:
Cobertura de tudo que mudou do Qt 4.2 para 4.3, incluindo integrao com Windows
Vista, suporte nativo a CSS para estilizao de aplicativos, e gerao de arquivos SVG.
Captulos separados para assuntos relacionados a 2D e 3D, cobertura das novas classes
de visualizao grfica do Qt 4.3, alm de uma cobertura total do QPainters OpenGL.
Apresenta tcnicas avanadas vistas em nenhum outro livro - desde criao de plugins
at interao com APIs nativas.
Tabela de Contedos
Parte 1: Qt Bsico
Captulo 1: Comeando
Hello Qt
Fazendo Conexes
Alinhando Widgets
Usando a Documentao de Referncia
Captulo 2: Criando Dialogs
Herdando de QDialog
Signals e Slots a Fundo
Design Rpido de Dialogs
Modificando a Forma dos Dialogs
Dialogs Dinmicos
Classes Nativas de Widgets e Dialogs
Captulo 3: Criando Janelas Principais
Subclasse QMainWindow
Criando Menus e Barras de Ferramentas
Ajustando a Barra de Status
Desenvolvendo o Menu Arquivo
Usando Dialogs
Armazenando Configuraes
Documentos Mltiplos
Misturar Telas
Captulo 4: Implementao da Funcionalidade da Aplicao
O Widget Central
Subclasse QTableWidget
Carregando e Salvando
Implementao do Menu Editar
Implementando os Outros Menus
Subclasse QTableWidgetItem
Captulo 5: Criando Widgets Customizveis
Customizando Qt Widgets
Subclasse QtWidget
Integrando Widgets Customizveis com Qt Designer
Buffering Duplo
Parte II: Qt Intermedirio
Captulo 6: Gerenciamento de Layout
Modelando Widgets em um Form
Layouts Empilhados
Splitters
reas Rolveis
Janelas Dock e Barras de Ferramentas
Interface de Documento Mltiplo
Captulo 7: Processamento de Eventos
Reimplementando Manipuladores de Eventos
Instalando Filtros de Eventos
Manter Respondendo durante Processamento Intensivo
Captulo 8: Grficos 2D
Pintando com QPainter
Transformaes de Coordenadas de Sistema
Renderizando em Alta-Qualidade com QImage
Renderizando Itens Bsicos com Visualizadores de Grfico
Imprimindo
Captulo 9: Arrastar e Soltar
Habilitando Arrastar e Soltar
Suportando Tipos de Arrastar Personalizados
Manipulao de Clipboard
Traduo livre realizada pelos membros do Frum QtBrasil
www.qtbrasil.com
Parte I: O Bsico do Qt
1. Comeando
Hello Qt
Fazendo Conexes
Alinhando Widgets
Este captulo mostra como combinar C++ bsico com a funcionalidade disponibilizada pelo Qt
para criar algumas aplicaes de interface grfica pequenas. Este captulo tambm introduz
duas idias chave do Qt: signals e slots e layouts. No Captulo 2, iremos mais a fundo, e no
Captulo 3, comearemos a construir aplicaes mais realsticas.
Se voc j conhece Java ou C# mas tem uma experincia limitada com C++, ento
recomendado que voc comece lendo a Introduo ao C++ no Apndice D.
Hello Qt
Vamos comear com um programa bem simples. Vamos estud-lo linha a linha e depois
veremos como compil-lo e rod-lo.
1 #include <QApplication>
2 #include <QLabel>
3 int main(int argc, char *argv[])
4 {
5
QApplication app(argc, argv);
6
QLabel *label = new QLabel("Hello Qt!");
7
label->show();
8
return app.exec();
9 }
As linhas 1 e 2 incluem as definies das classes QApplication e QLabel. Para cada classe do
Qt existe um arquivo header com o mesmo nome (e distino entre maisculas e minsculas)
que contm a definio da classe.
Traduo livre realizada pelos membros do Frum QtBrasil
www.qtbrasil.com
Antes de irmos para o prximo exemplo vamos nos divertir um pouco: Substitua a linha
QLabel *label = new QLabel("Hello Qt!");
por
QLabel *label = new QLabel("<h2><i>Hello</i> "
"<font color=red>Qt!</font></h2>");
E recompile a aplicao. Quando rodar, ela deve parecer com a Figura 1.2. Como este exemplo
ilustra, fcil diferenciar uma aplicao de interface de usurio Qt utilizando apenas uma
formatao HTML.
Fazendo Conexes
O segundo exemplo mostra como responder s aes do usurio. A aplicao consiste em um
boto que o usurio pode clicar para sair. O cdigo muito similar ao exemplo anterior, com
exceo do uso de um QPushButton no lugar de uma QLabel como nosso widget principal, e
ns estamos conectando a ao do usurio (clique) a um bloco de cdigo.
O cdigo desta aplicao est em examples/chap01/quit/quit.cpp; a aplicao em
andamento mostrada na Figura 1.3. Aqui est o contedo do arquivo:
1 #include <QApplication>
2 #include <QPushButton>
3 int main(int argc, char *argv[])
4 {
5
QApplication app(argc, argv);
6
QPushButton *button = new QPushButton("Quit");
7
QObject::connect(button, SIGNAL(clicked()),
8
&app, SLOT(quit()));
9
button->show();
10
return app.exec();
11 }
Figura 1.3 A aplicao que fecha
Os widgets do Qt emitem sinais para indicar que uma ao de usurio ou uma mudana de
estado ocorreu. [*] Por exemplo, QPushButton emite um sinal clicked() quando o usurio
clica no boto. Um sinal pode se conectar com uma funo (chamada de slot nesse contexto)
para que quando o sinal for emitido, o slot seja executado automaticamente. No nosso
exemplo, ns conectamos o sinal clicked() do boto com o slot quit() do objeto
QApplication. As macros SIGNAL() e SLOT() fazem parte da sintaxe.
[*] Sinais do Qt no tem nenhuma relao com sinais do Unix. Neste livro, estamos tratando somente dos sinais do Qt.
Vamos construir a aplicao. Assumimos que voc criou um diretrio chamado quit contendo
o arquivo quit.cpp. Rode o qmake no diretrio quit para gerar o arquivo projeto, e depois
rode-o novamente para gerar o makefile, como segue:
qmake -project
qmake quit.pro
Agora construa a aplicao e rode-a. Se voc clicar em Quit, ou pressionar a barra de espao
(que pressiona o boto), a aplicao terminar.
Alinhando Widgets
Nesta seo, iremos criar um pequeno exemplo que demonstra como usar layouts para
gerenciar a geometria dos widgets em uma janela e como usar sinais e slots para sincronizar
dois widgets. A aplicao (mostrada na Figura 1.4) pergunta pela idade do usurio, a qual o
usurio pode informar manipulando um spin box ou um slider.
#include
#include
#include
#include
<QApplication>
<QHBoxLayout>
<QSlider>
<QSpinBox>
10
11
12
13
14
15
16
17
18
QObject::connect(spinBox, SIGNAL(valueChanged(int)),
slider, SLOT(setValue(int)));
QObject::connect(slider, SIGNAL(valueChanged(int)),
spinBox, SLOT(setValue(int)));
spinBox->setValue(35);
19
20
21
22
23
window->show();
10
24
25 }
return app.exec();
As linhas 8 e 9 preparam a QWidget que servir como a janela principal da aplicao. Podemos
chamar setWindowTitle() para escolher o texto que ser exibido na barra de ttulo da janela.
As linhas 10 e 11 criam um QSpinBox e um QSlider, e as linhas 12 e 13 atribuem seus
intervalos vlidos. Podemos assumir que o usurio tem at 130 anos de idade. Poderamos
passar window para os construtores de QSpinBox e QSlider especificando que estes widgets
devem ter window como pai deles, mas no necessrio porque o sistema de layout ir
configurar isso sozinho e automaticamente atribuir o pai do spin box e do slider, como
veremos a seguir.
As duas chamadas QObject::connect() mostradas nas linhas 14 at 17 asseguram que o spin
box e o slider estejam sincronizados para que eles sempre mostrem o mesmo valor. Sempre
que o valor de um dos widgets mudar, o sinal valueChanged() de um deles ser emitido, e o
slot setValue(int) do outro ser chamado com o novo valor.
A linha 18 predefine o valor do spin box para 35. Quando isso acontece, o QSpinBox emite o
sinal valueChanged(int) com um argumento do tipo int valendo 35. Esse argumento
passado para o slot setValue(int) do QSlider, que ajusta o valor do slider para 35. O slider
ento emite um sinal valueChanged(int) porque o prprio valor mudou, ativando o slot
setValue(int) do spin box. Mas nesse ponto, setValue(int) no emite nenhum sinal, j que
o valor do spin box j 35. Isso evita a recurso infinita. A Figura 1.5 ilustra a situao.
11
Nas linhas 19 at 22, ns alinhamos o spin box e o slider usando um gerenciador de layouts.
Este gerenciador um objeto que define o tamanho e a posio dos widgets que esto sob sua
responsabilidade. O Qt tem trs tipos principais de gerenciadores de layouts:
Estilos de Widgets
Os screenshots que vimos at agora tm sido tirados no Linux, mas aplicaes em Qt
podem parecer nativas de cada plataforma suportada. O Qt consegue fazer isso
emulando o look and feel de cada plataforma, ao invs de conter um kit de widgets de
uma plataforma particular.
Figura 1.6 Estilos pr-definidos
O estilo Plastique o estilo padro para aplicaes Qt/X11 rodando sob o KDE, e o
Cleanlooks o padro sob o GNOME. Estes estilos utilizam gradientes e anti-aliasing
12
para gerar um look and feel moderno. Usurios de aplicaes Qt podem substituir os
estilos padro utilizando o comando style na linha de comando. Por exemplo, para
iniciar a aplicao de idade acima utilizando o estilo Motif sob X11, simplesmente digite o
comando:
./age -style motif
Diferente dos outros estilos, Windows XP, Windows Vista, e Mac apenas so visualizados
nas plataformas nativas, j que dependem de dispositivos de tema de cada plataforma.
Um estilo adicional chamado QtDotNet est disponvel no Qt Solutions. Tambm
possvel criar estilos customizados, como ser explicado no Captulo 19.
13
Note que funes herdadas so documentadas na classe base; por exemplo, QPushbutton no
tem uma funo prpria show(), mas herda uma de QWidget. A Figura 1.9 mostra como as
classes que vemos at agora se relacionam umas com as outras.
A documentao de referncia para a atual verso do Qt e para algumas verses mais recentes
est disponvel online em http://doc.trolltech.com/. Este site tambm tem artigos selecionados
do Qt Quarterly, o newsletter dos programadores Qt enviado para todas as licenas comerciais.
Este captulo introduziu os conceitos chave de conexes signal-slot e layouts. Ele tambm
comeou a revelar a perspectiva total e consistente de orientao a objetos at a construo e
uso de widgets. Se voc procurar pela documentao do Qt, voc encontrar uma
uniformidade de exibio que a torna bem direta no que se diz respeito ao uso de novos
widgets, e voc tambm descobrir que Qt escolheu cuidadosamente os nomes para funes,
parmetros, enums e assim por diante, que fazem com que programar em Qt se torne
incrivelmente agradvel e fcil.
Os captulos seguintes da Parte I se apoiam nos fundamentos aqui abordados, mostrando
como criar uma GUI completa com menus, toolbars, janelas de documentos, status bars, e
dialogs, em conjunto com a funcionalidade bsica de leitura, processamento e escrita de
arquivos.
15
2. Criando Dialogs
Herdando de QDialog
Dialogs Dinmicos
Este captulo vai te ensinar como criar caixas de dilogo utilizando Qt. Caixas de dilogo
apresentam aos usurios opes e escolhas, e permitem que eles ajustem opes dos seus
parmetros preferidos e que faam suas escolhas. Eles so chamados de caixas de dilogo, ou
apenas dialogs, porque eles fornecem os meios pelos quais os usurios conversam com as
aplicaes.
A maioria das aplicaes GUI (graphics user interface, ou interface grfica de usurio)
consiste em uma mainwindow com um menubar e uma toolbar, em conjunto com dezenas de
dialogs que complementam a mainwindow. Tambm possvel criar dialogs que respondam
diretamente s escolhas do usurio aplicando as aes necessrias (por exemplo, uma
calculadora).
Criaremos nosso primeiro dialog puramente por cdigo e mostraremos como funciona. Depois
veremos como criar dialogs pelo Qt Designer, a ferramenta visual de design do Qt. Utilizar o Qt
Designer um jeito muito mais rpido (do que cdigo puro) e faz com que seja fcil testar
designs diferentes e at mesmo modificar designs j existentes no futuro.
Herdando de QDialog
Nosso primeiro exemplo um dialog de busca, escrito totalmente em C++. Ele mostrado na
Figura 2.1. Vamos implementar o dialog como uma classe prpria. Fazendo isso, a tornamos
independente, um componente encapsulado, com signals e slots prprios.
arquivos:
finddialog.h
finddialog.cpp.
1 #ifndef FINDDIALOG_H
2 #define FINDDIALOG_H
3 #include <QDialog>
4
5
6
7
class
class
class
class
QCheckBox;
QLabel;
QLineEdit;
QPushButton;
17
13 signals:
14
void findNext(const QString &str, Qt::CaseSensitivity cs);
15
void findPrevious(const QString &str, Qt::CaseSensitivity cs);
A seo signals declara dois sinais que o dialog emitir quando o usurio clicar no boto
Find. Se a opo Search Backward estiver selecionada, o dialog emite findPrevious()
caso contrrio, emite findNext().
A palavra-chave signals , na verdade, uma macro. O pr-processador C++ o converte para
padres C++ antes que o compilador veja. Qt::CaseSensitivity um enum que pode
assumir os valores Qt::CaseSensitive (um) e Qt::CaseInsensitive (zero).
16 private slots:
17
void findClicked();
18
void enableFindButton(const QString &text);
19 private:
20
QLabel *label;
21
QLineEdit *lineEdit;
22
QCheckBox *caseCheckBox;
23
QCheckBox *backwardCheckBox;
24
QPushButton *findButton;
25
QPushButton *closeButton;
26 };
27 #endif
Na seo privada da classe, declaramos dois slots. Para implementar os slots, precisaremos
acessar a maioria dos widgets filhos do dialog, ento mantemos ponteiros para eles tambm. A
palavra-chave slots , como signals, uma macro que se transforma em uma construo que
C++ pode digerir.
Para as variveis private, usamos foward declarations das respectivas classes. Isso foi
possvel porque so todos ponteiros e no precisamos acess-los no header, ento o
compilador no precisa de todas as definies da classe. Poderamos ter includo os includes
(<QCheckBox>, <QLabel>, etc.), mas utilizando foward declarations quando possvel, isso
torna o tempo de compilao menor.
Vamos para o arquivo da implementao da classe FindDialog, o finddialog.cpp:
1 #include <QtGui>
2 #include "finddialog.h"
Primeiramente inclumos <QtGui>, um arquivo header que contm a definio das classes GUI
do Qt. Qt consiste de vrios mdulos, cada um com sua prpria biblioteca. Os mdulos mais
importantes so QtCore, QtGui, QtNetwork, QtOpenGL, QtScript, QtSql, QtSvg e QtXml. O
header <QtGui> contm a definio de todas as classes que so parte dos mdulos QtCore e
QtGui. Incluir este header nos economiza a incluso individual de cada classe do nosso dialog.
No arquivo finddialog.h, ao invs de incluir <QDialog> e utilizar foward declarations para
QCheckBox, QLabel, QLineEdit e QPushButton, poderamos simplesmente ter includo
<QtGui>. Entretanto no aconselhvel incluir um arquivo header to grande, especialmente
em aplicaes grandes.
18
3 FindDialog::FindDialog(QWidget *parent)
4
: QDialog(parent)
5 {
6
label = new QLabel(tr("Find &what:"));
7
lineEdit = new QLineEdit;
8
label->setBuddy(lineEdit);
9
10
11
12
13
14
Na linha 4, passamos o parmetro parent para o construtor da classe base. Depois criamos os
objetos filhos. A funo tr() marca a string literal para futuras tradues para outras lnguas.
Esta funo declarada em QObject e em todas as classes que contm a macro Q_OBJECT.
um bom hbito cercar strings visveis aos usurios com tr(), mesmo que voc no tenha
planos imediatos para traduzir sua aplicao para outras lnguas. Tradues sero estudadas
no Captulo 18.
Em strings literais, utilizamos o smbolo & para indicar teclas de atalho. Por exemplo, a linha
11 cria o boto Find, o qual o usurio pode ativar utilizando Alt+F nas plataformas que
suportam teclas de atalho. O smbolo & tambm pode ser utilizado para controlar o foco: na
linha 6 criamos uma label com a tecla de atalho (Alt+W), e na linha 8 ns definimos o lineedit
como companheiro (buddy) da label. Um buddy um widget que aceita o foco quando a tecla
de atalho do outro pressionada. Ento quando o usurio pressiona Alt+W (atalho da label), o
foco vai para o lineedit (buddy da label).
Na linha 12, fazemos com que o boto Find seja o padro chamando setDefault(true). O
boto padro o boto que, quando o usurio pressiona Enter, pressionado. Na linha 13,
desabilitamos o boto Find. Quando um widget est desabilitado ele geralmente mostrado
em tons acinzentados e no responder s interaes do usurio.
15
16
17
18
19
20
topLeftLayout->addWidget(lineEdit);
24
25
26
27
28
29
30
31
32
33
34
35
19
setWindowTitle(tr("Find"));
setFixedHeight(sizeHint().height());
20
Finalmente, definimos o ttulo a ser mostrado na barra de ttulo e uma altura fixa para a
janela, j que no existem widgets dentro do dialog que possam ocupar um espao vertical
significativo. A funo QWidget::sizeHint() retorna o tamanho ideal do widget.
Isso completa a reviso do construtor da classe FindDialog. J que criamos os objetos e
layouts atravs de new, razovel pensar que devemos deletar cada widget e layout com um
delete. Mas no necessrio, o Qt automaticamente deleta objetos filhos quando o pai
destrudo, e todos os widgets e layouts do nosso dialog so descendentes do prprio dialog.
Agora, vamos definir os slots do dialog:
39 void FindDialog::findClicked()
40 {
41
QString text = lineEdit->text();
42
Qt::CaseSensitivity cs =
43
caseCheckBox->isChecked() ? Qt::CaseSensitive
44
: Qt::CaseInsensitive;
45
if (backwardCheckBox->isChecked()) {
46
emit findPrevious(text, cs);
47
} else {
48
emit findNext(text, cs);
49
}
50 }
51 void FindDialog::enableFindButton(const QString &text)
52 {
53
findButton->setEnabled(!text.isEmpty());
54 }
O slot findClicked() chamado quando o usurio clica no boto Find. Ele emite o sinal
findPrevious() ou findNext(), dependendo da opo Search Backward. A palavra-chave
emit especfica do Qt; como outras extenses Qt ela convertida em C++ padro pelo prprocessador C++.
O slot enableFindButton() chamado sempre que o usurio muda o texto contido no
lineedit. Isso ativa o boto se houver algum texto no lineedit, e desabilita caso contrrio.
Estes dois slots finalizam o dialog. Podemos, ento, criar um main.cpp para testar nosso
widget FindDialog:
2 #include "finddialog.h"
3 int main(int argc, char *argv[])
4 {
5
QApplication app(argc, argv);
6
FindDialog *dialog = new FindDialog;
7
dialog->show();
8
return app.exec();
9 }
Para compilar o programa, utilize qmake como de usual. Uma vez que a definio da classe
FindDialog contm a macro Q_OBJECT, ento o makefile gerado pelo qmake incluir regras
especiais para executar o moc, o meta-object compiler do Qt. (O sistema meta-object ser
estudado na prxima seo).
Para que o moc funcione corretamente necessrio colocar a definio da classe em um
arquivo header, fora da implementao. O cdigo gerado pelo moc inclui esse arquivo header e
adiciona alguns cdigos padres do C++ por si prprio.
Classes que utilizam a macro Q_OBJECT devem ser executadas pelo moc. Isso no um
problema porque o qmake automaticamente adiciona as regras necessrias para o makefile.
Mas se voc esquecer de gerar seu makefile usando qmake e o moc no tiver rodado, o linker
reclamar dizendo que algumas funes foram declaradas mas no implementadas. As
mensagens podem ser relativamente obscuras. O GCC produz mensagens de erro desse tipo:
finddialog.o: In function `FindDialog::tr(char const*, char const*)':
/usr/lib/qt/src/corelib/global/qglobal.h:1430: undefined reference to
`FindDialog::staticMetaObject'
Se isso acontecer com voc algum dia, execute o qmake de novo para atualizar o arquivo
makefile, e reconstrua a aplicao.
Agora, execute o programa. Se as teclas de atalho so exibidas em sua plataforma, verifique
se as teclas de atalho Alt+W, Alt+C, Alt+B, e Alt+F acionam o comportamento correto.
Pressione a tecla tab para navegar pelos widgets com o teclado. A ordem de tabulao padro,
a ordem na qual os widgets foram criados. Isso pode ser mudado usando
QWidget::setTabOrder().
Fornea uma ordem razovel para a tecla tab e bons atalhos de teclado de forma que usurios
que no querem (ou que no podem) usar um mouse sejam capazes de usar ao mximo a
aplicao. Controle total sobre o teclado tambm apreciado por digitadores rpidos.
No Captulo 3, ns usaremos o dialogo de busca numa aplicao real, e ns conectaremos os
sinais findPrevious() e findNext() a alguns slots.
22
23
disconnect(lcd, SIGNAL(overflow()),
this, SLOT(handleMathError()));
Isso raramente necessrio, porque o Qt automaticamente remove todas as conexes
envolvendo um objeto quando ele deletado.
Para conectar um sinal a um slot com sucesso (ou outro signal), eles precisam ter os mesmos
tipos de parmetros na mesma ordem:
connect(ftp, SIGNAL(rawCommandReply(int, const QString &)),
this, SLOT(processReply(int, const QString &)));
Excepcionalmente, se um sinal tem mais parmetros que o slot ao qual est conectado, os
parmetros adicionais so simplesmente ignorados.
connect(ftp, SIGNAL(rawCommandReply(int, const QString &)),
this, SLOT(checkErrorCode(int)));
24
O Sistema Meta-Object do Qt
Uma das maiores conquistas do Qt foi a extenso do C++ com um mecanismo de criao
de componentes de software independentes que podem ser ligados sem nem saberem
informaes sobre o componente aos quais esto conectados.
O mecanismo chamado sistema meta-object e fornece dois servios chave: signalsslots, e introspeco. A funcionalidade da introspeco necessria para implementar
signals e slots, e permite programadores obterem informaes meta sobre sub-classes
QObject em tempo de execuo, incluindo a lista de sinais e slots suportados pelo objeto
e nome da sua classe. O mecanismo tambm suporta propriedades (amplamente usadas
pelo Qt Designer) e traduo de texto (para internacionalizao), e estabelece as bases
do mdulo QtScript. A partir do Qt 4.2, propriedades podem ser adicionadas
dinamicamente, um recurso que veremos em ao nos Captulos 19 e 22.
O C++ padro no fornece suporte para as meta-informaes dinmicas que o sistema
de meta-objeto de Qt precisa. O Qt resolve isso com uma ferramenta separada, o moc.
Ele analisa as definies de Q_OBJECT e faz com que a informao fique disponvel
atravs de funes C++. J que o moc implementa toda a sua funcionalidade usando
C++ puro, o sistema meta-object funciona com qualquer compilador C++.
O mecanismo funciona da seguinte forma:
Tudo isso feito automaticamente pelo qmake, moc e QObject, ento voc dificilmente
ter que pensar nisso. Mas se estiver curioso voc pode ler a documentao da classe
QMetaObject e os cdigos C++ gerados pelo moc para ver como a implementao
funciona.
25
O primeiro passo criar widgets filhos e coloc-los no formulrio. Criar uma label, um line
editor, um spacer horizontal, e dois botes. Para cada item, arraste o nome ou o cone da
caixa de widgets do Qt Designer e solte-o aproximadamente onde ele deveria estar no
formulrio. O spacer, que invisvel no formulrio final, mostrado no Qt Designer como uma
pequena mola azul.
Agora arraste a borda inferior do formulrio pra encurt-lo. Isso deveria produzir um
formulrio que similar ao da Figura 2.6. No gaste muito tempo posicionando os itens
precisamente no formulrio. Os gerenciadores de layouts vo posicion-los de forma precisa
posteriormente.
Figura 2.6. O formulrio com alguns widgets
27
28
Agora clique em Edit|Edit Tab Order. Um nmero em um retngulo azul aparecer prximo
de cada widget que possa admitir foco, como mostrado na Figura 2.9. Clique em cada widget
para escolher a ordem de cada um, depois clique em Edit|Edit Widgets para deixar o modo
de edio de tabs.
Para visualizar o dialog, clique em Form|Preview. Note a ordem dos tabs que voc predefiniu
pressionando Tab repetidamente. Feche o dialog utilizando o boto fechar na barra de ttulo.
Salve as alteraes como gotocelldialog.ui em um diretrio chamado gotocell, e crie um
arquivo main.cpp no mesmo diretrio utilizando um editor de texto:
#include <QApplication>
#include <QDialog>
#include "ui_gotocelldialog.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Ui::GoToCellDialog ui;
QDialog *dialog = new QDialog;
ui.setupUi(dialog);
dialog->show();
return app.exec();
}
Agora execute o qmake para criar um arquivo .pro e um makefile (qmake project; qmake
gotocell.pro). A ferramenta qmake inteligente o bastante para detectar o arquivo de
interface do usurio gotocelldialog.ui e para gerar as regras apropriadas do makefile para
chamar uic, o compilador de interfaces de usurio do Qt. A ferramenta uic converte o arquivo
gotocelldialog.ui em cdigo C++ e pe o resultado no arquivo ui_gotocelldialog.h.
O arquivo ui_gotocelldialog.h gerado contm as definies para a classe
Ui::GoToCellDialog, que um equivalente C++ do gotocelldialog.ui. A classe declara
variveis membro que armazenam os layouts e widgets filhos do formulrio, e uma funo
setupUi() que inicializa o formulrio. A classe gerada se parece com isso:
29
class Ui::GoToCellDialog
{
public:
QLabel *label;
QLineEdit *lineEdit;
QSpacerItem *spacerItem;
QPushButton *okButton;
QPushButton *cancelButton;
...
void setupUi(QWidget *widget) {
...
}
};
A classe gerada no tem nenhuma classe base. Quando utilizamos essa classe no main.cpp,
ns criamos um QDialog e o passamos para setupUI().
Se voc executar o programa agora, o dilogo vai funcionar, mas ele no funciona exatamente
como queremos:
O line Edit aceita qualquer texto, ao invs de s aceitar posies validas de clula.
Ns podemos fazer com que o dilogo funcione corretamente escrevendo algum cdigo. O jeito
mais organizado de fazer isso criando uma classe que derivada de ambos QDialog e
Ui::GoToCellDialog e que implemente a funcionalidade faltante (deste modo provando a
mxima de que qualquer problema do software pode ser resolvido simplesmente adicionando
outra camada de meios indiretos). A conveno de nomeao dar o mesmo nome da classe
gerada pelo o uic mas sem o prefixo Ui::.
Usando um editor de texto, crie um arquivo chamado gotocelldialog.h que contenha o
seguinte cdigo:
#ifndef GOTOCELLDIALOG_H
#define GOTOCELLDIALOG_H
#include <QDialog>
#include "ui_gotocelldialog.h"
class GoToCellDialog : public QDialog, public Ui::GoToCellDialog
{
Q_OBJECT
public:
GoToCellDialog(QWidget *parent = 0);
private slots:
void on_lineEdit_textChanged();
};
#endif
30
Aqui, utilizamos herana pblica porque queremos acessar todos os widgets do dialog de fora
do dialog. A implementao pertence ao arquivo gotocelldialog.cpp:
#include <QtGui>
#include "gotocelldialog.h"
GoToCellDialog::GoToCellDialog(QWidget *parent)
: QDialog(parent)
{
setupUi(this);
QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");
lineEdit->setValidator(new QRegExpValidator(regExp, this));
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
}
void GoToCellDialog::on_lineEdit_textChanged()
{
okButton->setEnabled(lineEdit->hasAcceptableInput());
}
31
Para widgets, o pai tem um significado adicional: Widgets filhos so mostrados dentro da rea
do pai. Quando deletamos o Widget pai, no somente os filhos so liberados da memria como
tambm desaparecem da tela.
Ao fim do construtor, ns conectamos o boto OK ao slot accept() do QDialog e o boto
Cancel ao slot reject(). Ambos os slots fecham o dialog, mas accept() define o valor de
resultado do dialog para QDialog::Accepted (que 1), e o reject() define o resultado para
QDialog::Rejected (que 0). Quando ns usamos esse dialog, ns podemos usar o resultado
para ver se o usurio clicou OK e atua de acordo.
O slot on_lineEdit_textChanged() ativa ou desativa o boto OK, dependendo se o line edit
contm uma localizao vlida de clula. QLineEdit::hasAcceptableInput() usa o validador
que escolhemos no construtor.
Isso completa o dialog. Podemos agora reescrever o arquivo main.cpp para us-lo:
#include <QApplication>
#include "gotocelldialog.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
GoToCellDialog *dialog = new GoToCellDialog;
dialog->show();
return app.exec();
}
Construa o arquivo gotocell.pro usando qmake project (j que adicionamos arquivos fonte
ao projeto), execute qmake gotocell.pro para atualizar o makefile, depois construa e execute
a aplicao de novo. Digite A12 no editor, e perceba que o boto OK se torna ativo. Tente
digitar alguns textos aleatrios para ver como o validator funciona. Clique Cancel para fechar
o dialog.
O dialog funciona corretamente, mas para usurios do Mac, os botes esto um pouco
diferentes. Escolhemos adicionar cada boto individualmente, para mostrar como era feito,
mas ns deveramos ter usado um QDialogButtonBox, um widget que contm os botes que
especificamos e que os apresenta na forma correta para o sistema de janelas no qual a
aplicao est sendo executada, como mostrado na Figura 2.10.
Para fazer com que o dialog use um QDialogButtonBox, ns devemos modificar ambos o
design e o cdigo. No Qt Designer, existem apenas quatro passos a tomar:
32
33
usurio do dialog salva em um arquivo .ui (um arquivo no formato XML), enquanto que
funcionalidades prprias so implementadas derivando da classe gerada pelo uic.
Este dilogo um dilogo de classificao de uma aplicao de planilhas, onde o usurio pode
selecionar uma ou vrias colunas para que sejam classificadas. A verso simples do dilogo
permite que ele escolha apenas uma chave de classificao, enquanto que a verso estendida
fornece os meios para duas chaves extras. O boto more permite que o usurio alterne entre
as verses.
Criaremos o widget com sua verso expandida no Qt Designer, e esconderemos as chaves
extras em tempo de execuo conforme necessrio. O dilogo parece complicado, mas fcil
faz-lo no Qt Designer. O truque fazer a primeira chave primeiro, depois duplic-la duas
vezes para obter as outras:
34
9* lS542j 8 6[/Bo42j 8 lS545j 8 6[/Bo45j 8 lST0 0 1 56 1 3222j 1 04.72024 36 reW* 0 0 1 56 1 3222j 1 04.72024 36 reET
35
1. Aumente a altura do dilogo para que ele seja capaz de armazenar as outras duas
chaves.
2. Segure o Ctrl (Alt no Mac), clique e arraste o primeiro group box para criar uma cpia
dele (e de seu contedo) sobre o original. Arraste a cpia para baixo do original, ainda
segurando o Ctrl (ou Alt). Repita esse processo para criar um terceiro group box,
arrastando-o para baixo do segundo.
3. Mude as propriedades title deles para &Seconday Key e &Tertiary Key.
4. Crie um spacer vertical e coloque-o entre o primeiro e o segundo group box.
5. Organize os widgets no padro grid mostrado na Figura 2.13(a).
6. Clique no formulrio para limpar possveis selees, clique em Form|Lay Out in a
Grid. Agora arraste o canto inferior direito do formulrio para cima e para esquerda
para deix-lo menor possvel. O formulrio deveria se parecer com a Figura 2.13(b).
7. Ajuste a propriedade sizeHint dos dois spacers verticais para [20,0].
O layout em grid resultante tem duas colunas e quarto linhas, totalizando oito clulas. O
primeiro group box, o spacer vertical da esquerda, o segundo group box, e o terceiro group
box, cada um ocupa uma nica clula. O layout vertical contendo os botes OK, Cancel, e More
ocupa duas clulas.
Isso deixa duas clulas vazias na rea inferior direita do dilogo. Se voc no tem o mesmo
resultado, desfaa o layout, reposicione os widgets, e tente de novo.
Renomeie o formulrio para SortDialog e mude o ttulo da janela para Sort. Defina os
nomes dos widgets filhos para aqueles da Figura 2.14.
Clique em Edit|Edit Tab Order. Clique em cada combo box de cima para baixo, nos botes
OK, Cancel, e More. Clique em Edit|Edit Widgets para deixar o modo de edio de tabs.
Agora que o formulrio foi desenhado, estamos prontos para torn-lo funcional designando
algumas conexes signals-slots. O Qt Designer nos permite que estabeleamos conexes entre
widgets que compartilham do mesmo formulrio. Precisamos estabelecer duas delas.
Clique em Edit|Edit Signals/Slots para entrar no modo de conexes do Qt Designer.
Conexes so representadas por setas azuis entre os widgets do formulrio, como mostrado
na Figura 2.15, e elas tambm so listadas na janela de edio de signals/slots do Qt
Designer. Para estabelecer uma conexo entre dois widgets, clique no widget remetente e
arraste a seta vermelha para o widget destinatrio, e solte o boto do mouse. Isso vai fazer
com que um dilogo seja exibido, permitindo que voc escolha o sinal e o slot que pertencero
a conexo.
Figura 2.15. Conectando os widgets
37
A primeira conexo a ser feita entre o boto okButton e o slot accept() do formulrio.
Arraste a seta vermelha do boto okButton para uma parte vazia do formulrio, solte o boto
para configurar a conexo pelo dilogo de configurao que ser aberto, como mostrado na
Figura 2.16. Escolha clicked() como sinal e accept() como slot, e clique OK.
Figura 2.16. Dilogo de editor de conexes do Qt Designer
Para a segunda conexo, arraste a seta vermelha do boto cancelButton para uma parte
vazia do formulrio, e no dilogo de configurao conecte o sinal clicked() ao slot reject()
do formulrio.
A terceira conexo a ser estabelecida entre o boto moreButton e o group box
secondaryGroupBox. Arraste a seta vermelha entre estes widgets, ento selecione o sinal
toggled(bool) e o slot setVisible(bool). Por padro, o Qt Designer no lista o slot
setVisible(bool) na lista de slots, mas ele aparece se voc habilitar a opo Show all
signals and slots.
A quarta e ltima conexo entre o sinal toggled(bool) do boto moreButton e o slot
setVisible(bool) do terceiro group box. Uma vez que as conexes foram estabelecidas,
clique em Edit|Edit Widgets para deixar o modo de conexes.
Salve o dilogo como sortdialog.ui em um diretrio chamado sort. Para adicionar cdigo ao
formulrio, ns usaremos o mesmo principio de herana mltipla que usamos para o dilogo
Go to Cell na seo anterior.
Primeiro, crie um arquivo sortdialog.h com o seguinte contedo:
#ifndef SORTDIALOG_H
#define SORTDIALOG_H
#include <QDialog>
#include "ui_sortdialog.h"
class SortDialog : public QDialog, public Ui::SortDialog
{
Q_OBJECT
Traduo livre realizada pelos membros do Frum QtBrasil
www.qtbrasil.com
38
public:
SortDialog(QWidget *parent = 0);
void setColumnRange(QChar first, QChar last);
};
#endif
Agora crie o sortdialog.cpp:
1 #include <QtGui>
2 #include "sortdialog.h"
3 SortDialog::SortDialog(QWidget *parent)
4
: QDialog(parent)
5 {
6
setupUi(this);
7
8
9
10
11 }
secondaryGroupBox->hide();
tertiaryGroupBox->hide();
layout()->setSizeConstraint(QLayout::SetFixedSize);
setColumnRange('A', 'Z');
secondaryColumnCombo->addItem(tr("None"));
tertiaryColumnCombo->addItem(tr("None"));
primaryColumnCombo->setMinimumSize(
secondaryColumnCombo->sizeHint());
21
22
23
24
25
26
27
28 }
QChar ch = first;
while (ch <= last) {
primaryColumnCombo->addItem(QString(ch));
secondaryColumnCombo->addItem(QString(ch));
tertiaryColumnCombo->addItem(QString(ch));
ch = ch.unicode() + 1;
}
39
diferentes tipos de widgets, ou widgets similares com contedos diferentes, podem ser
designados com diferentes tamanhos pelo sistema de layout. Para comboboxes, isso significa
que os comboboxes secundrio e tercirio, que contm None, acabam maiores que o
primeiro combobox, que contm
s entradas de letras individuais. Para evitar essa
inconsistncia, ns definimos o tamanho mximo da primeira combobox para o tamanho ideal
do segundo combobox.
Aqui est uma funo teste main() que define o intervalo para incluir as colunas de C a F e
depois mostra o dilogo:
#include <QApplication>
#include "sortdialog.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
SortDialog *dialog = new SortDialog;
dialog->setColumnRange('C', 'F');
dialog->show();
return app.exec();
}
Isso completa o dilogo de extenso. Como o exemplo mostra, este tipo de dilogo no to
mais difcil de desenhar do que o dilogo plano: Tudo que precisamos era um boto de
alternncia, algumas conexes extras, e um layout no redimensionvel. Em aplicaes de
produo, bem comum que o boto de alternncia tenha o texto Advanced >>> quando o
dilog bsico exibido e Advanced <<< quando a extenso mostrada. Isso fcil de
conseguir com Qt chamando setText() no QPushButton sempre que for clicado.
O outro tipo comum de dilogos que mudam as formas, dilogos de mltiplas pginas, so at
mais fceis de criar em Qt, tanto por cdigo ou com o Qt Designer. Tais dilogos podem ser
construdos de diferentes maneiras:
Um QTabWidget pode ser usado. Ele fornece uma tab bar que controla um
QStackedWidget interno.
Dialogs Dinmicos
Dialogs dinmicos so aqueles que so criados em tempo de execuo a partir de arquivos .ui
produzidos no Qt Designer. Ao invs de converter o arquivo .ui para cdigo C++ utilizando
uic, ns podemos carregar o arquivo em tempo de execuo usando a classe QUiLoader:
40
QUiLoader uiLoader;
QFile file("sortdialog.ui");
QWidget *sortDialog = uiLoader.load(&file);
if (sortDialog) {
...
}
Podemos acessar os widgets filhos utilizando QObject::findChild<T>():
QComboBox *primaryColumnCombo =
sortDialog->findChild<QComboBox *>("primaryColumnCombo");
if (primaryColumnCombo) {
...
}
A funo findChild<T>() uma funo membro template que retorna o objeto filho que
corresponde com o nome e tipo de dados. Por causa de uma limitao do compilador, isso no
est disponvel para MSVC 6. Se voc precisa usar o compilador MSVC 6, utilize a funo
global qFindChild<T>(), que funciona essencialmente da mesma forma.
A classe QUiLoader est localizada em uma biblioteca separada. Para usar QUiLoader a partir
de uma aplicao Qt, ns devemos adicionar esta linha ao arquivo .pro da aplicao:
CONFIG += uitools
Dilogos dinmicos tornam possvel mudar o layout de um formulrio sem recompilar a
aplicao. Eles podem tambm ser usados para criar aplicaes thin-client, onde o
executvel meramente tem um formulrio front-end interno e todos os outros formulrios so
criados quando necessrio.
45