Anda di halaman 1dari 33

C++ Programando GUI com Qt4, Segunda Edio

Publicado por: Prentice Hall


Data de Publicao: 04/02/2008
Traduzido por:
Arthur Dias
Danilo Domingos


Viso Geral

O nico oficialmente publicado Guia das melhores prticas para programao Qt 4.3

Usando Trolltechs Qt 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 surpeendentes com a mais recente verso do Qt: Qt 4.3.

Carregado com exemplops prticos e realistas e IN-DEPH ADVICE, 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:

Atualizado completamente, com um novssima cobertura de Databases, XML, e
programao Qtopia

Notificaes e 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

Novos captulos a respeito de otimizao look-and-feel e sobre criao de scripts para
aplicaes

Ilustra a arquitetura de visualizao e modelagem do Qt4, suporte a plugins, Manuteno
de Layout, processamento de eventos, classes containers, e muito mais

Apresenta tcnicas avanadas vistas em nenhum outro livro - desde criao de plugins at
interao com APIs nativas

Inclui um novo apndice de Qt Jambi, a nova verso Java do Qt



Tabela de Contedos
Parte 1: Qt Bsico
Captulo 1: Comeando
Ol Qt
Fazendo conexes
Modelando Widgets
Usando Documentao de Referncia
Captulo 2: Criando Dialogs
Subclasse QDialog
Signals e Slots
Design de um Dialog Rpido
Dialogs com mudana no Tamanho
Dialogs Dinmicos
Classes Dialog e Widget construdas
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: Manuteno de Layout
Modelando Widgets em um Form
Layouts Empilhados
Splitters
reas Rolveis
DOCK Janelas e Barras de ferramentas





Parte I: O Bsico do Qt ( Por Danilo Domingos)

1. Comeando
Hello Qt
Fazendo Conexes
Alinhando Widgets
Utilizando a Referncia

Este captulo mostra como combinar C++ bsico com a funcionalidade disponibilizada
por
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 o Apndice D Introduo ao C++.

HELLO QT


Vamos comear com um programa bem simples. Vamos estud-lo linha a linha e depois
ver 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
de Qt existe um arquivo header com o mesmo nome (e distino entre maisculas e
minsculas) que contem a definio da classe.

A linha 5 cria um objeto QApplication para gerenciar os recursos da aplicao no geral. A
construtora de QApplication requer os argumentos argc e argv porque Qt interpreta
alguns argumentos de linha de comando prprios do Qt.

A linha 6 cria um widget QLabel que mostra o texto Hello Qt!. No Qt e na terminologia
Unix, um widget um elemento visual numa interface grfica. O termo vem da
expresso window gadget e equivalente a tanto controle como container na
terminologia do Windows. Botes, menus, barras de rolagem e frames so exemplos de
widgets. Widgets podem conter outros widgets; por exemplo, uma janela , geralmente,
um widget que contem um QMenuBar, algumas QToolBars, uma QStatusBar, e alguns
outros widgets. A maioria das aplicaes usa uma QMainWindow ou um QDialog como
janelas principais da aplicao, mas Qt to flexvel que qualquer widget pode ser uma
janela. Neste exemplo, o widget QLabel a janela da aplicao.

A linha 7 torna a label visvel. Widgets so criados, por padro, como invisveis para que
possamos customiz-los antes de serem exibidos, deste modo evitando flickering.

A linha 8 passa o controle da aplicao para o Qt. Neste ponto, o programa entra no
chamado loop de eventos. Imagine o loop de eventos como um modo de espera onde o
programa espera por aes do usurio como clicks do mouse ou ento pressionamento
de teclas. Aes do usurio geram eventos (tambm chamados de mensagens) para
os
quais o programa responde, geralmente executando uma ou mais funes. Por exemplo,
quando o usurio clica em um widget, os eventos pressionamento do boto do mouse e
liberao do boto do mouse so gerados. Neste ponto, aplicaes grficas diferem
significativamente de programas BAT convencionais, nos quais praticamente s
processam uma entrada, desenvolvem algum procedimento, e terminam sem interao
humana.

Por simplicidade, ns no nos preocupamos em chamar o delete para o objeto QLabel
ao
final da funo main(). Este vazamento de memria (memory leak) inofensivo num
programa to pequeno, j que a memria alocada ser desalocada quando o programa
terminar.

J possvel testar o programa na sua mquina. Ele deve se parecer com o mostrado
na
Figura 1.1. Primeiro voc ter que instalar o Qt 4.3.2 (ou uma verso mais recente), este
procedimento explicado no Apndice A. De agora em diante, vamos assumir que voc
tem uma cpia corretamente instalada do Qt e que o diretrio Bin est na sua varivel
PATH de ambiente. (No Windows isso feito automaticamente pelo instalador do Qt)
Voc tambm precisar que o cdigo deste programa esteja num arquivo hello.cpp nun
diretrio chamado hello. Voc mesmo pode escrever o arquivo hello.cpp ou copi-lo dos
exemplos que acompanham este livro, que est disponvel em
examples/chap01/hello/hello.cpp. (Todo os exemplos esto disponveis no site do livro,
http://www.informit.com/title/0132354160.)



Figura 1.1 - Hello no Linux



Do prompt de comando, v at o diretrio hello e digite:

qmake project

Para criar um arquivo projeto que independente da plataforma, e depois digite:

qmake hello.pro

Para criar um arquivo makefile especfico para a plataforma que est usando. (A
ferramenta qmake discutida em mais detalhes no apndice B.) Digite make para
construir o programa. Rode-o digitando hello no Windows, ./hello no Unix, e open
hello.app no Mac. Para terminar o programa, clique no boto fechar na barra de ttulo da
janela.

Se voc estiver usando o Windows e tiver instalado a verso Open Source do Qt e o
compilador MinGW, voc ter um atalho chamado prompt de comando do Qt que tem
todas as variveis de ambiente corretamente ajustadas. Se voc conseguiu visualizar a
janela ento voc pode compilar aplicaes do Qt utilizando qmake e make como
descritos anteriormente. Os executveis so colocados na pasta debug ou release da
aplicao (por exemplo, C:\examples\chap01\hello\release\hello.exe).

Se voc estiver utilizando o Microsoft Visual C++ com uma vero comercial de Qt, voc
utilizar o nmake ao invs de make. Alternativamente, voc pode criar um arquivo
projeto do Visual Studio a partir do arquivo hello.cpp digitando:

qmake -tp vc hello.pro

Antes de irmos para o prximo exemplo vamos nos divertir um pouco: Substitua a linha

QLabel *label = new QLabel("Hello Qt!");

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.

Figura 1.2: Uma label com formatao HTML bsica

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 }



Os widgets de 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
automticamente. No nosso exemplo, nos conectamos o sinal clicked() do boto para o
slot quit() do objeto QApplication. Os macros SIGNAL() e SLOTS() fazem parte da
sintaxe.

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 denovo 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.


A aplicao consiste em trs widgets: um QSpinBox, um QSlider e um QWidget. O
QWidget a janela principal da aplicao. O QSpinBox e o QSlider so apresentados
dentro da QWidget; eles so filhos de QWidget. Alternativamente, podemos dizer que
QWidget pai de QSpinBox e QSlider. QWidget no tem pais porque est sendo usada
como uma janela top-level. As construtoras de QWidget e de todas as suas subclasses
tem QWidget * como parmetro que especifica quem o pai da widget em questo.

Cdigo Fonte:

1 #include <QApplication>
2 #include <QHBoxLayout>
3 #include <QSlider>
4 #include <QSpinBox>

5 int main(int argc, char *argv[])
6 {
7 QApplication app(argc, argv);

8 QWidget *window = new QWidget;
9 window->setWindowTitle("Enter Your Age");

10 QSpinBox *spinBox = new QSpinBox;
11 QSlider *slider = new QSlider(Qt::Horizontal);
12 spinBox->setRange(0, 130);
13 slider->setRange(0, 130);

14 QObject::connect(spinBox, SIGNAL(valueChanged(int)),
15 slider, SLOT(setValue(int)));
16 QObject::connect(slider, SIGNAL(valueChanged(int)),
17 spinBox, SLOT(setValue(int)));
18 spinBox->setValue(35);

19 QHBoxLayout *layout = new QHBoxLayout;
20 layout->addWidget(spinBox);
21 layout->addWidget(slider);
22 window->setLayout(layout);

23 window->show();

24 return app.exec();
25 }

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 validos. Podemos assumir que o usurio tem at 130 anos de idade.
Poderamos passar window para as construtoras de QSpinBox e QSlider especificando
que estes widgets tivessem 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.



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. Qt tem trs tipos principais de gerenciadores de layouts:

QHBoxLayout alinha os widgets horizontalmente da esquerda para a direita (da
direita para a esquerda para algumas culturas).

QVBoxLayout alinha os widgets verticalmente de cima para baixo.

QGridLayout alinha os widgets em um grid.

A chamada de QWidget::setLayout() na linha 22 instala o gerenciador na janela. Mas na
verdade, o QSpinBox e o QSlider tm seu pai redefinido para o widget no qual o layout
foi instalado, e por essa razo no temos que especificar um pai explicito quando
costrurmos a widget que ser colocada em um layout.

Apesar de no termos escolhido a posio e o tamanho dos widgets explicitamente, o
QSpinBox e o QSlider so dispostos visualmente de modo agradvel de um lado at o
outro. Isso ocorre porque QHBoxLayout automaticamente designa posies e tamanhos
razoveis para os widgets dos quais responsvel, baseado nas necessidades deles.
Os
gerenciadores de layouts nos privam da ocupao de posicionar, por puro cdigo, os
objetos na tela e garantem que a janela se redimensione suavemente.

O modo apresentado por Qt para construir interfaces de usurio simples de entender e
muito flexvel. O procedimento mais comum que programadores Qt utilizam
instanciar os widgets necessrios e depois definir suas propriedades conforme
necessrio. Programadores adicionam widgets aos layouts, que automaticamente
cuidam
do posicionamento e redimensionamento. O comportamento da interface de usurio
gerenciada conectando widgets uns aos outros usando o mecanismo de sinais e slots.

As screenshots tiradas at agora foram tiradas no Linux, mas aplicaes Qt so
mostradas com a interface nativa de cada plataforma. Qt consegue fazer isso
emulando o look and feel de cada plataforma, ao invs de conter um kit de
widgets de uma plataforma particular.


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 para gerar um look nfeel 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 e dispositivos de tema
de cada plataforma.

Um estilo adicional chamado QtDotNet esta disponvel no Qt Solutions. Tambm
possvel criar estilos customizados, como ser explicado no Captulo 19.

UTILIZANDO A REFERNCIA

A documentao de referncia do Qt uma ferramenta essencial para qualquer
desenvolvedor. Ela cobre todas as classes e funes no Qt. Esse livro faz o uso de
diversas classes e funes do Qt, mas no cobre todas elas e nem fornece todos os
detalhes das que so mencionadas. Para tirar proveito mximo do Qt, voc deve se
familiarizar com a documentao do Qt o mais rpido possvel.

A documentao est disponvel em HTML no diretrio doc/HTML do Qt e pode ser lida
atravs de qualquer browser. Voc tambm pode usar o Qt Assistant, o browser de
ajuda
do Qt, que tem recursos poderosos de busca e indexao que o tornam mais rpido e
fcil comparado com um web browser.

Para iniciar o Qt Assistant, clique em Qt by Trolltech v4.x.x|Assistant no Windows, digite
assistant na linha de comando no Unix, ou d um duplo-clique em Assistant na busca do
Mac. Os links na seo Referncia API na pgina inicial fornecem diferentes modos de
navegar pelas classes de Qt. A pgina Todas as classes list todas as classes na API do
Qt. A pgina Classes principais lista apenas as classes mais utilizadas de Qt. Como um
exerccio, procure as classes e funo que utilizamos neste captulo.


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 de total e consistente de orientao a objetos
at 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 1 se apiam 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 escritura de arquivos.



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

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 mostrar 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.


O cdigo fonte est dividido em dois arquivos: finddialog.h e finddialog.cpp.
Comearemos pelo header (finddialog.h):


1 #ifndef FINDDIALOG_H
2 #define FINDDIALOG_H
3 #include <QDialog>
4 class QCheckBox;
5 class QLabel;
6 class QLineEdit;
7 class QPushButton;

As linhas 1 e 2 (e 27) protegem o header contra mltiplos includes.

A linha 3 inclui a definio de QDialog, a classe base para dialogs em Qt.
QDialog derivado de QWidget.

A linha 4 at 7 apresenta foward declarations das classes de Qt que sero
utilizadas na implementao do dialog (em finddialog.cpp). [*] Uma foward declaration
diz ao compilador C++ que esta classe existe sem dar mais detalhes sobre a definio
da classe (normalmente localizada no header da classe). Voltaremos a falar disso em
breve.
Depois, definimos FindDialog como uma subclasse de QDialog:

8 class FindDialog : public QDialog
9 {
10 Q_OBJECT
11 public:
12 FindDialog(QWidget *parent = 0);

O macro Q_OBJECT no comeo da definio da classe necessrio para todas
as classes que definem seus prprios signals e slots.
[*] Foward declarations s podem ser utilizadas quando as variveis forem
ponteiros. O compilador no precisa, de inicio, de mais informaes sobre a classe. J
que todos os ponteiros tem tamanho fixo: 4 bytes.
A construtora de FindDialog um exemplo tpico de classes Qt. O parmetro
parent especifica o widget pai. O padro para este parmetro um ponteiro nulo,
significando que o widget no tem pai.

13 signals:
14 void findNext(const QString &str, Qt::CaseSensitivity cs);
15 void findPrevious(const QString &str, Qt::CaseSensitivity cs);

A seo signal 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, um macro. O pr-processador C++
converte-o 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 slot , como signals, um 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 torna o tempo de compilao menor.

Vamos para o arquivo da implementao da classe FindDialog, finddialog.cpp:

1 #include <QtGui>
2 #include "finddialog.h"

Primeiramente inclumos <QtGui>, um arquivo header que contm a definio
das classes GUI de Qt. Qt consiste de vrio mdulos, cada um com sua prpria livraria.
O mdulos mais importantes so QtCore, QtGui, QtNetwork, QtOpenGL, QtScript,
QtSql, QtSvg e QtXml. O header <QtGui> contem 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.

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 caseCheckBox = new QCheckBox(tr("Match &case"));
10 backwardCheckBox = new QCheckBox(tr("Search &backward")
);
11 findButton = new QPushButton(tr("&Find"));
12 findButton->setDefault(true);
13 findButton->setEnabled(false);
14 closeButton = new QPushButton(tr("Close"));

Na linha 3, passamos o parmetro parent para a construtora da classe base.
Depois criamos os objetos filhos. A funo tr() marca a string literal para futuras
tradues para outras lnguas. Esta funo declara em QObject e em todas as
classes que contem o macro Q_OBJECT. um bom habito 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 nos 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 connect(lineEdit, SIGNAL(textChanged(const QString &)),
16 this, SLOT(enableFindButton(const QString &)));
17 connect(findButton, SIGNAL(clicked()),
18 this, SLOT(findClicked()));
19 connect(closeButton, SIGNAL(clicked()),
20 this, SLOT(close()));

O slot privado enableFindButton(const QString &) chamado sempre que o
texto do lineedit mudar. O slot privado findClicked() chamado quando o usurio
clicar no boto Find. O dialog se fecha quando o usurio clicar em Close. O slot
close() herdado de QWidget, e o seu comportamento padro esconder o widget de
visualizao (sem deletlo). Estudaremos o cdigo para os slots enableFindButton() e
findClicked() mais adiante.

J que QObject um dos ancestrais do nosso dialog, ento podemos omitir o
prefixo QObject:: das chamadas de connect().

21 QHBoxLayout *topLeftLayout = new QHBoxLayout;
22 topLeftLayout->addWidget(label);
23 topLeftLayout->addWidget(lineEdit);
24 QVBoxLayout *leftLayout = new QVBoxLayout;
25 leftLayout->addLayout(topLeftLayout);
26 leftLayout->addWidget(caseCheckBox);
27 leftLayout->addWidget(backwardCheckBox);
28 QVBoxLayout *rightLayout = new QVBoxLayout;
29 rightLayout->addWidget(findButton);
30 rightLayout->addWidget(closeButton);
31 rightLayout->addStretch();
32 QHBoxLayout *mainLayout = new QHBoxLayout;
33 mainLayout->addLayout(leftLayout);
34 mainLayout->addLayout(rightLayout);
35 setLayout(mainLayout);

Depois disso, ns alinhamos os widgets filhos utilizando gerenciadores
de layout. Layouts podem conter ambos widgets ou outros layouts. Misturando
QHBoxLayouts, QVBoxLayout e QGridLayout, possvel gerar dialogs bem
sofisticados.

Para nosso dialog, usaremos dois QHBoxLayout e dois QVBoxLayout, como
mostrados na Figura 2.2. O layout externo o principal; ele instalado no FindDialog
na linha 35 e responsvel por toda a rea do layout. Os outros trs layouts so
sub-layouts. A pequena mola na parte inferior direita da Figura 2.2. um spacer
(ou stretch). Ele usa o espao vazio abaixo dos botes Find e Close, garantindo que
esses botes ocupem o topo do layout em que esto.

Um aspecto sutil de classes de gerenciamento de layouts que no so
widgets. Ao invs disso, so derivadas de QLayout. Que por sua vez derivado
de QObject. Na figura, widgets so representados por linhas solidas e layouts so
representados por linhas tracejadas para destacar a diferena entre eles. Durante a
execuo do programa, layouts so invisveis.

Quando sub-layouts so adicionados ao layout pai (linhas 23, 33 e 34), os sub-
layouts tm seus pais redefinidos. Da, quando o layout principal instalado no dialog
(linha 35), ele se torna filho do dialog e todos os widgets dentro dos layouts tm seus
pais redefinidos como o dialog. A hierarquia resultante mostrada na Figura 2.3.

36 setWindowTitle(tr("Find"));
37 setFixedHeight(sizeHint().height());
38 }

Finalmente, definimos o titulo 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 da construtora 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, 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 pr-processador 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:

1 #include <QApplication>
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 contem o 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 q utilizam o macro Q_OBJECT devem ser executadas pelo moc. Isso
no um problema porque 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'

A sada do Visual C++ comea assim:

finddialog.obj : error LNK2001: unresolved external symbol
"public:~virtual int __thiscall MyClass::qt_metacall(enum
QMetaObject
::Call,int,void * *)"

Se isso acontecer com voc algum dia, execute o qmake de novo para atualizar
o arquivo makefile, e reconstrua a aplicao.

Fornecer uma ordem razovel para a tecla tab e outros atalhos garante 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.

Signals e Slots a Fundo

O mecanismo de sinais e slots fundamental para programao em Qt. Ele
permite que o programador estabelea um elo entre os objetos sem que os objetos
saibam uns dos outros. Ns j conectamos alguns sinais e slots, declaramos nossos
prprios sinais e slots, implementamos nossos slots e emitimos nossos sinais. Vamos
dar uma olhada no mecanismo mais de perto.

Slots so quase idnticos a funes membro ordinrias do C++. Elas podem
ser virtuais, podem ser sobrecarregadas, podem ser publicas, protecteds ou privates,
podem ser diretamente chamadas como qualquer outra funo membro do C++, e os
seus parmetros podem ser de qualquer tipo. A diferena que um slot tambm pode
ser conectado a um sinal, que no caso ser chamado toda vez que o sinal for emitido.

A declarao da funo connect() se d da seguinte forma:

connect(sender, SIGNAL(signal), receiver, SLOT(slot));

Onde sender e receiver so ponteiros para QObjects e signal e slot so
assinaturas de funes sem nomes de parmetros. Os macros SIGNAL() e SLOT()
essencialmente convertem seus argumentos para uma string.

Nos exemplos que vimos at agora, ns sempre conectamos sinais diferentes
com slots diferentes. Existem outras possibilidades:

Um sinal pode ser conectado a vrios slots:

connect(slider, SIGNAL(valueChanged(int)),
spinBox, SLOT(setValue(int)));
connect(slider, SIGNAL(valueChanged(int)),
this, SLOT(updateStatusBarIndicator(int)));

Quando o sinal emitido, os slots so chamados um a um, numa ordem no
especificada.

Vrios sinais podem ser conectados ao mesmo slot:

connect(lcd, SIGNAL(overflow()),
this, SLOT(handleMathError()));
connect(calculator, SIGNAL(divisionByZero()),
this, SLOT(handleMathError()));

Quando qualquer dos sinais for emitido, o slot chamado.

Um sinal pode ser conectado a outro sinal:

connect(lineEdit, SIGNAL(textChanged(const QString &)),
this, SIGNAL(updateRecord(const QString &)));

Quando o primeiro sinal emitido, o Segundo sinal tambm emitido. Alm
disso, conexes signal-signal so indistinguveis de conexes signal-slot.

Conexes podem ser removidas:

disconnect(lcd, SIGNAL(overflow()),
this, SLOT(handleMathError()));

Isso raramente necessrio, porque 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 signal 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)));

Se os tipos de parmetros so incompatveis, ou se o sinal ou slot no existir,
Qt ira informar atravs de um warning em tempo de execuo (se a aplicao for
construda no modo debug). Similarmente, Qt ir lanar um warning se os nomes dos
parmetros estiverem inseridos nas assinaturas dos signals ou slots.

At agora, apenas utilizamos sinais e slots com widgets. Mas o mecanismo
implementado para QObject e no limitado a programao GUI. O mecanismo pode
ser usado por qualquer subclasse de QObject:

class Employee : public QObject
{
Q_OBJECT
public:
Employee() { mySalary = 0; }
int salary() const { return mySalary; }
public slots:
void setSalary(int newSalary);
signals:
void salaryChanged(int newSalary);
private:
int mySalary;
};

O Sistema Meta-Object de 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:
signals e slots, 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 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. 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++ ento o sistema meta-objeto funciona com qualquer
compilador C++.

O mecanismo funciona da seguinte forma:

O macro Q_OBJECT declara algumas funes de introspeco que devem ser
implementadas em cada subclasse de QObject: metaObject(), tr(), qt_metacall(), entre
outras.
A ferramenta moc gera implementaes para as funes declaradas por
Q_OBJECT e para todos os signals.

As funes membro de QObject (como connect() e disconnect() ) usam as
funes de introspeco para fazer seus trabalhos

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.

void Employee::setSalary(int newSalary)
{
if (newSalary != mySalary) {
mySalary = newSalary;
emit salaryChanged(mySalary);
}
}

Perceba como o slot setSalary() implementado. Ns emitimos o sinal
salaryChanged() apenas se newSalary != mySalary. Isso garante que as conexes
cclicas no levem a loops infinitos.

Design Rpido de Dialogs

Qt foi planejado para ser agradvel e intuitivo para desenvolver cdigo, e no
difcil encontrar programadores que desenvolvem suas aplicaes inteiras escrevendo
cdigo C++. Porm, muitos programadores preferem utilizar uma aproximao visual
para desenvolver formulrios. Porque eles acham que este mtodo mais natural e
rpido do que puro cdigo, e eles querem estar aptos a testar e mudar designs com
mais rapidez e facilidade do que quando desenvolvidos com cdigos puros.

O Qt Designer expande as opes disponveis aos programadores fornecendo
uma capacidade visual de design. Qt Designer pode ser usado para desenvolver
todos ou apenas alguns dos formulrios da aplicao. Formulrios que so criados
utilizando o Qt Designer so convertidos em cdigo C++, ento o Qt Designer pode ser
usado com uma variedade de ferramentas convencionais e no impe especificaes
especiais ao compilador.

Nessa seo, usaremos o Qt Designer para criar o dilogo Ir para a clula
mostrado na Figura 2.4. Criar o dialog no Qt Designer ou por cdigo sempre envolve
alguns passos fundamentais:

1. Criar e inicializar widgets filhos.
2. Coloc-los em um layout.
3. Atribuir a ordem dos tabs.
4. Estabelecer conexes signal/slots.
5. Implementar os prprios slots do dialog.



Para iniciar o Qt Designer, clique em Qt by Trolltech v4.x.y|Designer no
menu Iniciar, digite designer na linha decomando do Unix, ou d um duplo-clique
em Designer no MAC finder. Quando o Qt Designer iniciar, ele ir mostrar uma
lista de templates. Clique no template Widget e depois clique em Create. (O
template Dialog with Buttons
Bottom pode parecer tentador, mas para esse exemplo ns criaremos os
botes OK e Cancel manualmente e mostrar como feito.) Voc deve, agora, ter
uma janela chamada Untitled.

Por padro, a interface de usurio do Qt consiste em vrias janelas top-level.
Se voc preferir uma interface MDI (multiple document interface) com uma janela top-
window e vrias subjanelas, como mostrado na Figura 2.5, clique em Edit|Preferences
e ajuste o modo de interface do usurio para Docked Window.





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.



Utilizando o editor de propriedades do Qt Designer ajuste as propriedades de
cada widget:

1. Clique na label TextLabel. Certifique-se de que a propriedade objectName
dela seja label e mude a propriedade text para &Cell Location:.

2. Clique no line editor. Certifique-se de que a propriedade objectName
seja lineEdit.

3. Clique no primeiro boto. Defina a propriedade objectName como okButton,
a propriedade enabled para false, a propriedade text para OK, e a propriedade
default para true.

4. Clique no segundo boto. Defina a propriedade objectName
para cancelButton e a propriedade texto para Cancel.

5. Clique no fundo do formulrio para selecion-lo. Ajuste a propriedade
objectName para GoToCellDialog e a propriedade windoTitle para Go to Cell.

Todos os widgets parecem bem, exceto pela label que mostra &Cell Location.
Escolha Edit|Edit Buddies para entrar em um modo especial de edio que te permite
escolher os Buddies. Depois, clique na tabela, mantenha o boto apertado e arraste
a seta vermelha para o line Edit, e depois libere o boto. A label deveria exibir, agora,
o texto Cell Location, como mostrado na Figura 2.7 e tem o line Edit com seu buddy.
Para deixar o modo de edio de buddies clique em Edit|Edit Widgets.



O prximo passo alinhar os widgets no formulrio:

1. Clique na label Cell Location , pressione a tecla Shift e clique no line Edit
para selecionar os dois widgets. Clique em Form|Lay Out Horizontally.

2. Clique no spacer, segure o Shift e clique em ambos os botes. Clique em
Form|Lay Out Horizontally

3. Clique no fundo do formulrio para remover a seleo anterior de qualquer
widget, depois clique em Form|Lay Out Vertically.

4. Clique em Form|Adjust Size para redimensionar o formulrio para o seu
tamanho preferencial.

As linhas vermelhas mostradas no formulrio mostram os layouts que foram
criados, como mostrado na Figura 2.8. Eles no so visveis quando o formulrio
executado.




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.

Anda mungkin juga menyukai