Você está na página 1de 45

C++ GUI Programando com Qt4, Segunda Edio

Autores: Jasmin Blanchette e Mark Summerfield


1

Traduo por: Danilo Domingos, Arthur dos Santos Dias


Reviso e edio por: Thiago Rossener Nogueira

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:

Atualizado completamente, com uma novssima cobertura de banco de dados, XML, e


programao Qtopia.

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.

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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

C++ GUI Programando com Qt4, Segunda Edio

Captulo 10: Classes de Visualizao de Itens


Usando Classes de Visualizao de Itens Convenientes
Usando Modelos Predefinidos
Implementando Modelos Customizveis
Implementando Delegates Customizveis
Captulo 11: Classes de Container
Containers Sequenciais
Containers Associativos
Algoritmos Genricos
String, Byte Arrays e Variants
Captulo 12: Input/Output
Lendo e Escrevendo Dados Binrios
Lendo e Escrevendo Texto
Atravessando Diretrios
Incorporando Recursos
Processo Interno de Comunicao
Captulo 13: Bancos de Dados
Conectando e Consultando
Visualizao de Tabelas
Edio de Registros Usando Formulrios
Apresentao de Dados em Formulrios Tabulares
Captulo 14: Multithreading
Criao de Threads
Sincronizao de Threads
Comunicao com a Thread Principal
Usando Classes do Qt em Threads Secundrias
Captulo 15: Rede
Escrevendo Clientes FTP
Escrevendo Clientes HTTP
Gravando Aplicativos Cliente-Servidor TCP
Enviar e Receber Datagramas UDP
Captulo 16: XML
Ler XML com QXmlStreamReader
Ler XML com DOM
Ler XML com SAX
Escrever XML
Captulo 17: Fornecendo Ajuda Online
Tooltips, Status Tips, e Ajuda O que isso?
Usando um Navegador Web para Fornecer Ajuda Online
Usando o QTextBrowser como um Motor de Ajuda Simples
Usando o Qt Assistant para uma Poderosa Ajuda Online
Parte III: Qt Avanado
Captulo 18: Internacionalizao
Trabalhando com Unicode
Fazendo Aplicaes de Traduo Consciente
Troca de Linguagem Dinmica
Traduzindo Aplicaes
Captulo 19: Aparncia e Personalizao
Usando Qt Style Sheets
Herdando de QStyle
Captulo 20: Grficos 3D
Desenhando Usando OpenGL
Combinando OpenGL e QPainter
Fazer Sobreposies Usando Objetos Framebuffer
Captulo 21: Criando Plugins
Estendendo Qt com Plugins
Fazendo Aplicaes com Plugins Concientes
Traduo livre realizada pelos membros do Frum QtBrasil
www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

Escrevendo Aplicaes com Plugins


Captulo 22: Script de Aplicaes
Resumo da Linguagem EMAScript
Estendendo Aplicaes Qt com Script
Implementando Extenses GUI Usando Scripts
Automatizao de Tarefas Usando Scripts
Captulo 23: Recursos Especficos da Plataforma
Interface com APIs Nativas
Usando o ActiveX no Windows
Manipulao de Gerenciamento de Sesso X11
Captulo 24: Programao Incorporada
Introduo ao Qt/ Incorporado ao Linux
Customizando Qt/ Incorporado ao Linux
Integrando Aplicaes Qt com Qtopia
Usando APIs do Qtopia
Parte IV: Apndices
Apndice A: Obteno e Instalao do Qt
Nota sobre Licenciamento
Instalando Qt/Windows
Instalando Qt/Mac
Instalando Qt/X11
Apncide B: Construo de Aplicaes em Qt
Uso do qmake
Usando Ferramentas de Terceiros para Construir
Apndice C: Introduo ao Qt Jambi
Iniciando com o Qt Jambi
Usando o Qt Jambi na IDE Eclipse
Integrando Componentes do C++ com o Qt Jambi
Apndice D: Introduo ao C++ para Programadores Java e C#
Introduo ao C++
Principais Diferenas da Linguagem
Biblioteca Padro do C++
Sobre os Autores
Jasmin Blanchette
Mark Summerfield
Produo
ndice

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

Parte I: O Bsico do Qt
1. Comeando

Hello Qt

Fazendo Conexes

Alinhando Widgets

Usando a Documentao de Referncia

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

C++ GUI Programando com Qt4, Segunda Edio

A linha 5 cria um objeto QApplication para gerenciar os recursos da aplicao no geral. O


construtor de QApplication requer os argumentos argc e argv porque o 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 contm um QMenuBar,
algumas QToolBars, uma QStatusBar, e alguns outros widgets. A maioria das aplicaes usa
uma QMainWindow ou um QDialog como janela principal da aplicao, mas o 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 num 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. (Todos
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
Traduo livre realizada pelos membros do Frum QtBrasil
www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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 verso comercial do 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
e compilando o programa no Visual Studio. Se voc estiver usando o Xcode no Mac, voc pode
gerar um projeto Xcode usando o comando
qmake -spec macx-xcode hello.pro

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.

Figura 1.2: Uma label com formatao HTML bsica

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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.

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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.

Figura 1.4 A aplicao da idade

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. O QWidget no tem pais porque est sendo usado como uma janela top-level. Os
construtores de QWidget e de todas as suas subclasses tem QWidget * como parmetro que
especifica quem o pai da widget em questo.
Aqui est o cdigo fonte:
1
2
3
4

#include
#include
#include
#include

<QApplication>
<QHBoxLayout>
<QSlider>
<QSpinBox>

5 int main(int argc, char *argv[])


6 {
7
QApplication app(argc, argv);
8
9

QWidget *window = new QWidget;


window->setWindowTitle("Enter Your Age");

10
11
12
13

QSpinBox *spinBox = new QSpinBox;


QSlider *slider = new QSlider(Qt::Horizontal);
spinBox->setRange(0, 130);
slider->setRange(0, 130);

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

QHBoxLayout *layout = new QHBoxLayout;


layout->addWidget(spinBox);
layout->addWidget(slider);
window->setLayout(layout);

23

window->show();

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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.

Figura 1.5 Mudando o valor de um widget, muda os dois

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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:

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.

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

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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.

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 explcito quando construmos o
widget que ser colocado em um layout.
Figura 1.7 Os widgets e o layout da aplicao da idade

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.

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

13

Usando a Documentao de 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 lista 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 as funes que utilizamos neste captulo.
Figura 1.8 Documentao do Qt no Qt Assistant sob Windows Vista

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.

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Figura 1.9 rvore de herana para as classes de Qt vistas at agora
14

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.

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

15

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

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Figura 2.1. A caixa de dilogo de busca.
16

O cdigo fonte est dividido em dois


Comearemos pelo header (finddialog.h):

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;

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);
A macro Q_OBJECT no comeo da definio da classe necessria 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.
O construtor 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.

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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.

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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

caseCheckBox = new QCheckBox(tr("Match &case"));


backwardCheckBox = new QCheckBox(tr("Search &backward"));

11
12
13

findButton = new QPushButton(tr("&Find"));


findButton->setDefault(true);
findButton->setEnabled(false);

14

closeButton = new QPushButton(tr("Close"));

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

connect(lineEdit, SIGNAL(textChanged(const QString &)),


this, SLOT(enableFindButton(const QString &)));
connect(findButton, SIGNAL(clicked()),
this, SLOT(findClicked()));
connect(closeButton, SIGNAL(clicked()),
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 delet-lo).
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
22

QHBoxLayout *topLeftLayout = new QHBoxLayout;


topLeftLayout->addWidget(label);

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


23

topLeftLayout->addWidget(lineEdit);

24
25
26
27

QVBoxLayout *leftLayout = new QVBoxLayout;


leftLayout->addLayout(topLeftLayout);
leftLayout->addWidget(caseCheckBox);
leftLayout->addWidget(backwardCheckBox);

28
29
30
31

QVBoxLayout *rightLayout = new QVBoxLayout;


rightLayout->addWidget(findButton);
rightLayout->addWidget(closeButton);
rightLayout->addStretch();

32
33
34
35

QHBoxLayout *mainLayout = new QHBoxLayout;


mainLayout->addLayout(leftLayout);
mainLayout->addLayout(rightLayout);
setLayout(mainLayout);

19

Depois disso, ns alinhamos os widgets filhos utilizando gerenciadores de layout. Layouts


podem conter ambos widgets e 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.
Figura 2.2. Os layouts do dialog de busca

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 slidas 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
37
38 }

setWindowTitle(tr("Find"));
setFixedHeight(sizeHint().height());

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

20

Figura 2.3. As relaes de parentesco do dialog

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:

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


1 #include <QApplication>
21

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'

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

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

22

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 publics, 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 estrutura 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. As 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 a serem levadas em considerao.

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

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

Conexes podem ser removidas:

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)));

Se os tipos de parmetros so incompatveis, ou se o sinal ou slot no existirem, o Qt ir


informar atravs de um warning em tempo de execuo (se a aplicao foi construda no modo
debug). Similarmente, o Qt ir lanar um warning se os nomes dos parmetros estiverem
inseridos nas assinaturas do sinal ou do slot.
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;
};

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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:

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

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

25

Design Rpido de Dialogs


O Qt foi planejado para ser agradvel e intuitivo para o desenvolvimento de cdigo a mo, e
no difcil encontrar programadores que desenvolvem suas aplicaes inteiras puramente
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 apenas 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.
Figura 2.4. O dialog de Ir para clula.

Para iniciar o Qt Designer, clique em Qt by Trolltech v4.x.y|Designer no menu Iniciar


no Windows, digite designer na linha de comando do Unix, ou d um duplo-clique em
Designer no Mac OS X 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 mostraremos 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.

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Figura 2.5. Qt Designer em modo Docked Window no Windows Vista
26

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

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.
Traduo livre realizada pelos membros do Frum QtBrasil
www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

27

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


propriedade text para Cancel.
5. Clique no fundo do formulrio para selecion-lo. Ajuste a propriedade objectName para
GoToCellDialog e a propriedade windowTitle 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 como seu buddy. Para deixar o modo de edio
de buddies clique em Edit|Edit Widgets.

Figura 2.7 Formulrio com as propriedades ajustadas

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.
Figura 2.8. Formulrio com Layouts.

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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.

Figura 2.9. Definindo a ordem do tab.

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:

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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 boto OK est sempre desabilitado.

O boto Cancel no faz nada.

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

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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());
}

No construtor, chamamos setupUi() para inicializar o formulrio. Graas herana mltipla,


podemos acessar os membros de Ui::GoToCellDialog diretamente. Depois de criar a
interface de usurio, setupUi() ir automaticamente conectar qualquer slot que siga a
conveno de nome on_objectName_signalName() para o sinal de objectName
correspondente. No nosso exemplo, isso significa que setupUi() ir estabelecer a seguinte
conexo signal-slot:
connect(lineEdit, SIGNAL(textChanged(const QString &)),
this, SLOT(on_lineEdit_textChanged()));

Tambm no construtor, ns criamos um validador (validator) para restringir o intervalo da


entrada. O Qt fornece trs classes internas do tipo validator: QIntValidator,
QDoublrValidator, e QRegExpValidator. Aqui podemos usar um QRegExpValidator com a
expresso regular [A-Za-z][1-9][0-9]{0,2}, que significa: Permita uma letra maiscula ou
minscula, seguida de um digito entre 1 e 9, seguido de zero, 1, ou dois dgitos entre 0 e 9.
(Para uma introduo expresses regulares, veja a documentao da classe QRegExp.)
Passando this para o construtor do QRegExpValidator, fazemos com que ele seja filho do
objeto GoToCellDialog. Fazendo isso, no precisamos nos preocupar em deletar o
QRegExpValidator posteriormente; ele ser deletado automaticamente quando o pai dele for
deletado.
O mecanismo pai-filho implementado em QObject. Quando ns criamos um objeto (um
widget, um validator, ou qualquer outro) com um pai, o pai adiciona o objeto lista dos seus
filhos. Quando o pai deletado, ele percorre a sua lista de filhos e deleta cada um. Os filhos,
por sua vez, deletam todos os seus filhos, e assim por diante recursivamente at que nenhum
sobre. Este mecanismo simplifica muito o gerenciamento de memrias, reduzindo o risco de
vazamento de memria (memory leak). Os nicos objetos que devemos chamar delete so
objetos que criamos com new sem ter pai. E se deletarmos um objeto filho antes do pai, o Qt
ir remover aquele objeto da lista de filhos do pai automaticamente.

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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.

Figura 2.10. O dialog Ir para clula no Windows Vista e no Mac.

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:

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


1. Clique no formulrio (no em nenhum dos widgets ou layouts) e depois clique em
Form|Break Layout.

32

2. Selecione e delete os botes OK e Cancel, o spacer horizontal e o layout horizontal.


3. Arraste um Button Box para o formulrio, abaixo da label de localizao e do line Edit.
4. Clique no formulrio e depois Form|Lay Out Vertically.
Se ns estivssemos fazendo apenas mudanas no design, como mudar o layout do dialog ou
propriedades de widgets, ns estaramos aptos a simplesmente reconstruir a aplicao. Mas
nesse caso removemos alguns widgets e adicionamos novos widgets, e nestes casos devemos
normalmente modificar o cdigo tambm.
As mudanas necessrias devem ser feitas no arquivo gotocelldialog.cpp. Aqui est a nova
verso do construtor:
GoToCellDialog::GoToCellDialog(QWidget *parent)
: QDialog(parent)
{
setupUi(this);
buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");
lineEdit->setValidator(new QRegExpValidator(regExp, this));
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
}
Na verso anterior ns inicialmente desabilitamos o boto OK no Qt Designer. Ns no
podemos fazer isso com um QDialogButtonBox, ento ns fazemos isso no cdigo,
imediatamente depois da chamada setupUi(). A classe QDialogButtonBox tem um enum de
botes padro, e podemos usar isso para acessar botes particulares, neste caso o boto OK.
Convenientemente, o nome padro para um QDialogButtonBox do Qt Designer buttonBox.
Ambas as conexes so feitas a partir do Button Box ao invs de cada boto propriamente
dito. O sinal accepted() emitido quando o boto com a propriedade AcceptRole clicado, e
similarmente o sinal rejected() emitido por um boto com a propriedade RejectRole. Por
padro, o boto QDialogButtonBox::Ok carrega a propriedade AcceptRole, e o boto
QDialogButtonBox::Cancel carrega a propriedade RejectRole.
Apenas mais uma mudana necessria, no slot on_lineEdit_textChanged():
void GoToCellDialog::on_lineEdit_textChanged()
{
buttonBox->button(QDialogButtonBox::Ok)->setEnabled(
lineEdit->hasAcceptableInput());
}
A nica coisa diferente de antes que ao invs de se referir a um boto particular armazenado
como varivel membro, ns acessamos o boto OK do Button Box.
Uma das facilidades do Qt Designer que ele permite que programadores tenham grande
liberdade para modificar seus prprios formulrios sem serem forados a mudar seus cdigos.
Quando voc desenvolve um formulrio puramente por C++, mudanas no design podem levar
um tempo considervel. Com o Qt Designer, nenhum tempo perdido j que o uic
simplesmente refaz o cdigo fonte de qualquer formulrio que tenha mudado. A interface de

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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.

Modificando a Forma dos Dialogs


Ns vimos como criar caixas de dilogo que sempre mostram os mesmos widgets sempre que
so usados. Em alguns casos, necessrio que caixas de dilogo mudem suas formas. Os
tipos mais comuns de caixas de dilogo que mudam suas formas so dilogos que se
expandem e dilogos de mltiplas pginas. Ambos os tipos podem ser implementados no Qt,
tanto por cdigo como pelo Qt Designer.
Dilogos que se expandem geralmente apresentam uma aparncia simples mas tm um boto
ativvel que permite que o usurio alterne entre o dilogo simples e o dilogo expandido.
Estes dilogos so comumente usados por aplicaes que atingem tanto usurios casuais
quanto avanados, escondendo as opes avanadas a menos que o usurio pea
explicitamente para v-las. Nesta seo, usaremos o Qt Designer para criar o dilogo de
expanso mostrado na Figura 2.11.

Figura 2.11. Caixa de dilogo de classificao nos modos simples e expandido.

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:

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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

Figura 2.13. Alinhando os widgets do formulrio em grid.

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.

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Figura 2.14. Nomeando os widgets
36

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

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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

C++ GUI Programando com Qt4, Segunda Edio

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');

12 void SortDialog::setColumnRange(QChar first, QChar last)


13 {
14
primaryColumnCombo->clear();
15
secondaryColumnCombo->clear();
16
tertiaryColumnCombo->clear();
17
18
19
20

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;
}

O construtor esconde as partes secundrias e tercirias do dilogo. Ele tambm define a


propriedade sizeContraint do layout do formulrio para QLayout::SetFixedSize, fazendo
com que o dilogo se torne no redimensionvel pelo usurio. O layout, ento, assume a
responsabilidade de redimensionar e dimensiona o dilogo automaticamente quando widgets
so mostrados ou escondidos, garantindo que o dilogo ser sempre mostrado no melhor
tamanho.
O slot setColumnRange() inicializa o contedo dos combo boxes baseado nas colunas
selecionadas da planilha. Inserimos um item chamado None para as chaves (opcionais)
secundria e terciria.
As linhas 19 e 20 apresentam uma linguagem sutil de layout. A funo QWidget::sizeHint()
retorna o tamanho ideal do widget, que o sistema de layout tenta seguir. Isso explica porque
Traduo livre realizada pelos membros do Frum QtBrasil
www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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.

Um QListWidget e um QStackWidget podem ser usados em conjunto, com o item atual


do QListWidget determinando qual pgina o QStackedWidget mostra, conectando o
sinal QListWidget::currentRowChanged() ao slot
QStackWidget::setCurrentIndex().

Um QTreeWidget pode ser usado com um QStackedWidget num modo similar ao


QListWidget.

Ns falaremos mais da classe QStackedWidget no Captulo 6.

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:

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

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.

Classes Nativas de Widgets e Dialogs


O Qt fornece um conjunto completo de widgets nativos e dilogos comuns que atendem a
maioria das situaes. Nesta seo, apresentamos as imagens de quase todos eles. Alguns
widgets especializados so adiados: Cobrimos widgets de mainwindows, como QMenuBar,
QToolBar e QStatusBar no Captulo 3, e ns cobrimos widgets relacionados ao layout, como
QSplitter e QScrollArea no Captulo 6. A maioria dos widgets nativos e dilogos so usados
nos exemplos apresentados neste livro. Nas imagens mostradas nas Figuras 2.17 at 2.26,
todos os widgets so mostrados usando o estilo Plastique.

Figura 2.17. Botes do Qt

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Figura 2.18. Containers de pgina nica do Qt
41

Figura 2.19. Containers de mltiplas pginas do Qt

Figura 2.20. Item views do Qt

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Figura 2.21. Widgets de exibio do Qt
42

Figura 2.22. Widgets de entrada do Qt

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Figura 2.23. Dilogos de feedback do Qt
43

Figura 2.24. Dilogos de fonte e cor do Qt

Figura 2.25. Dilogos de impresso e arquivo do Qt

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Figura 2.26. Dilogo Qwizard do Qt
44

O Qt oferece quatro tipos de "botes": QPushButton, QToolButton, QCheckBox e


QRadioButton, eles so mostrados na Figura 2.17. QPushButton e QToolButton so mais
comumente usados para iniciar uma ao quando clicados, mas eles tambm podem se
comportar como botes de alternncia (clique para afundar, clique para restaurar). QCheckBox
pode ser usado para independentes opes on/off, enquanto QRadioButtons normalmente so
mutuamente exclusivos.
Widgets containers do Qt so widgets que contm outros widgets. Eles so mostrados na
Figura 2.18 e Figura 2.19. QFrame tambm pode ser usado para simplesmente desenhar linhas
e serve como a classe base para muitas outras classes widget, incluindo QToolBox e QLabel.
QTabWidget e QToolBox so widgets multi-pgina. Cada pgina um widget filho, e as pginas
so numeradas a partir de 0. Para QTabWidgets, tanto a forma como a posio das guias
podem ser definidos.
Os item views, mostrados na Figura 2.20, so otimizados para lidar com grandes quantidades
de dados e muitas vezes usam barras de rolagem. O mecanismo de rolagem implementado
em QAbstractScrollArea, uma classe base para item views e outros tipos de widgets com
elementos de rolagem.
A biblioteca do Qt inclui um mecanismo Rich Text que pode ser usado para exibir e editar texto
formatado. O motor suporta especificaes de fonte, alinhamento de texto, listas, tabelas,
imagens e hiperlinks. Documentos Rich Text podem ser criados pr-gramaticalmente elemento
por elemento ou fornecidos como texto em formato HTML. As tags HTML precisas e
propriedades
CSS
que
o
motor
suporta
so
documentadas
em
http://doc.trolltech.com/4.3/richtext-html-subset.html.
O Qt oferece alguns widgets que so utilizados exclusivamente para exibio de informaes,
eles so mostrados na Figura 2.21. QLabel o mais importante deles, e ela pode ser usada
para mostrar textos simples, HTML e imagens.
A QTextBrowser uma subclasse de QTextEdit de apenas leitura que pode exibir texto
formatado. Essa classe usada em detrimento de QLabel para grandes documentos de texto
formatados, porque ao contrrio de QLabel, ela fornece automaticamente as barras de
rolagem quando necessrio, e tambm fornece amplo suporte para teclado e mouse. O Qt
Assistant 4.3 usa QTextBrowser para apresentar a documentao para o usurio.
O Qt fornece diversos widgets para entrada de dados, como mostrado na Figura 2.22.
QLineEdit pode restringir a sua entrada usando uma mscara de entrada, um validador, ou
Traduo livre realizada pelos membros do Frum QtBrasil
www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

45

ambos. QTextEdit uma subclasse QAbstractScrollArea capaz de editar grandes


quantidades de texto. A QTextEdit pode ser definida para editar texto simples ou Rich Text.
Em ltimo caso, capaz de exibir todos os elementos Rich Text que o motor do Qt suporta.
Ambos QLineEdit e QTextEdit so totalmente integrados com a rea de transferncia.
O Qt fornece uma caixa de mensagem verstil e um dilogo de erro que lembra quais
mensagens mostrou, estes so mostrados na Figura 2.23. O progresso das operaes
demoradas pode ser indicado atravs da QProgressDialog ou usando a QProgressBar
mostrado na Figura 2.21. QInputDialog muito conveniente quando uma nica linha de texto
ou um nmero nico exigido do usurio.
O Qt fornece o conjunto padro de dilogos comuns que tornam mais fcil pedir ao usurio
para selecionar uma cor, fonte, ou arquivo, ou para imprimir um documento. Estes so
mostrados na Figura 2.24 e Figura 2.25.
No Windows e no Mac OS X, o Qt usa os dilogos nativos, em vez de seus prprios dilogos
comuns quando possvel. As cores tambm podem ser escolhidas atravs de um dos widgets
de seleo de cores do Qt Solutions, e fontes podem ser escolhidas usando QFontComboBox.
Finalmente, QWizard fornece uma estrutura para a criao de wizards (tambm chamados de
assistentes no Mac OS X). Wizards so teis para tarefas complexas ou pouco freqentes que
os usurios podem ter dificuldade em aprender. Um exemplo de um assistente mostrado na
Figura 2.26.
Muitas funcionalidades prontas para uso so fornecidas pelos widgets e dilogos comuns. Mais
necessidades especiais podem ser satisfeitas definindo propriedades do widget, ou conectando
sinais aos slots e implementando comportamento personalizado nos slots.
Se nenhum dos elementos comuns ou dilogos fornecidos com o Qt adequado, um pode
estar disponvel a partir do Qt Solutions, ou de verses comerciais ou no comerciais de
terceiros. O Qt Solutions oferece um conjunto de widgets adicionais, incluindo selecionadores
de cores diferentes, um controle de boto giratrio, menus de pizza, e um navegador de
propriedade, bem como uma caixa de dilogo de cpia.
Em algumas situaes, pode ser desejvel para criar um widget personalizado a partir do zero.
O Qt torna isso direto, e widgets personalizados podem acessar todas as mesmas
funcionalidades de desenho de plataformas que os widgets nativos do Qt. Widgets
personalizados podem ainda ser integrados com o Qt Designer, para que possam ser utilizados
da mesma forma como os widgets nativos de Qt. O Captulo 5 explica como criar widgets
personalizados.

Traduo livre realizada pelos membros do Frum QtBrasil


www.qtbrasil.com