SlideShare une entreprise Scribd logo
1  sur  45
Télécharger pour lire hors ligne
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
1
Autores: Jasmin Blanchette e Mark Summerfield
Tradução por: Danilo Domingos, Arthur dos Santos Dias
Revisão e edição por: Thiago Rossener Nogueira
Visão Geral
O único oficialmente publicado guia das melhores práticas para programação Qt 4.3
Usando o Qt da Trolltech é possível criar aplicações C++ de alta performance que rodem em
máquinas Windows, Linux/Unix, Mac OS X, e demais extensões Linux sem que seja necessário
fazer alterações de código. Agora, dois membros da Trolltech lhe oferecem este guia completo
para que você alcance resultados surpreendentes com a mais recente versão do Qt: Qt 4.3.
Carregado com exemplos práticos, realistas e conselhos profundos, este é o livro usado pela
Trolltech para ensinar Qt para seus próprios novos funcionários. Revisado e expandido
constantemente, este livro nos revela os melhores padrões atuais para se trabalhar com Qt
para diversos usos, que vão desde implementação de arquiteturas de modelagem até o uso da
engine gráfica do Qt 4.3. Você encontrará soluções para diversas tarefas de desenvolvimento
GUI, assim como técnicas sofisticadas para sistemas com acesso a banco de dados, integração
com XML, uso de subclasses, composição, e muito mais. Seja você um novo usuário de Qt, ou
um usuário antigo que está aprendendo a nova versão, este livro certamente vai lhe ajudar a
tirar vantagem de tudo que o Qt 4.3 é capaz de fazer.
Eis algumas novidades que encontrarão neste livro:
 Atualizado completamente, com uma novíssima cobertura de banco de dados, XML, e
programação Qtopia.
 Cobertura de tudo que mudou do Qt 4.2 para 4.3, incluindo integração com Windows
Vista, suporte nativo a CSS para estilização de aplicativos, e geração de arquivos SVG.
 Capítulos separados para assuntos relacionados a 2D e 3D, cobertura das novas classes
de visualização gráfica do Qt 4.3, além de uma cobertura total do QPainter‟s OpenGL.
 Novos capítulos a respeito de otimização look-and-feel e sobre criação de scripts para
aplicações.
 Ilustra a arquitetura de visualização e modelagem do Qt4, suporte a plugins,
manutenção de layout, processamento de eventos, classes containers, e muito mais.
 Apresenta técnicas avançadas vistas em nenhum outro livro - desde criação de plugins
até interação com APIs nativas.
 Inclui um novo apêndice de Qt Jambi, a nova versão Java do Qt.
qtbrasil.com
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
2
Tabela de Conteúdos
Parte 1: Qt Básico
Capítulo 1: Começando
Hello Qt
Fazendo Conexões
Alinhando Widgets
Usando a Documentação de Referência
Capítulo 2: Criando Dialogs
Herdando de QDialog
Signals e Slots a Fundo
Design Rápido de Dialogs
Modificando a Forma dos Dialogs
Dialogs Dinâmicos
Classes Nativas de Widgets e Dialogs
Capítulo 3: Criando Janelas Principais
Subclasse QMainWindow
Criando Menus e Barras de Ferramentas
Ajustando a Barra de Status
Desenvolvendo o Menu Arquivo
Usando Dialogs
Armazenando Configurações
Documentos Múltiplos
Misturar Telas
Capítulo 4: Implementação da Funcionalidade da Aplicação
O Widget Central
Subclasse QTableWidget
Carregando e Salvando
Implementação do Menu Editar
Implementando os Outros Menus
Subclasse QTableWidgetItem
Capítulo 5: Criando Widgets Customizáveis
Customizando Qt Widgets
Subclasse QtWidget
Integrando Widgets Customizáveis com Qt Designer
Buffering Duplo
Parte II: Qt Intermediário
Capítulo 6: Gerenciamento de Layout
Modelando Widgets em um Form
Layouts Empilhados
Splitters
Áreas Roláveis
Janelas Dock e Barras de Ferramentas
Interface de Documento Múltiplo
Capítulo 7: Processamento de Eventos
Reimplementando Manipuladores de Eventos
Instalando Filtros de Eventos
Manter Respondendo durante Processamento Intensivo
Capítulo 8: Gráficos 2D
Pintando com QPainter
Transformações de Coordenadas de Sistema
Renderizando em Alta-Qualidade com QImage
Renderizando Itens Básicos com Visualizadores de Gráfico
Imprimindo
Capítulo 9: Arrastar e Soltar
Habilitando Arrastar e Soltar
Suportando Tipos de Arrastar Personalizados
Manipulação de Clipboard
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
3
Capítulo 10: Classes de Visualização de Itens
Usando Classes de Visualização de Itens Convenientes
Usando Modelos Predefinidos
Implementando Modelos Customizáveis
Implementando Delegates Customizáveis
Capítulo 11: Classes de Container
Containers Sequenciais
Containers Associativos
Algoritmos Genéricos
String, Byte Arrays e Variants
Capítulo 12: Input/Output
Lendo e Escrevendo Dados Binários
Lendo e Escrevendo Texto
Atravessando Diretórios
Incorporando Recursos
Processo Interno de Comunicação
Capítulo 13: Bancos de Dados
Conectando e Consultando
Visualização de Tabelas
Edição de Registros Usando Formulários
Apresentação de Dados em Formulários Tabulares
Capítulo 14: Multithreading
Criação de Threads
Sincronização de Threads
Comunicação com a Thread Principal
Usando Classes do Qt em Threads Secundárias
Capítulo 15: Rede
Escrevendo Clientes FTP
Escrevendo Clientes HTTP
Gravando Aplicativos Cliente-Servidor TCP
Enviar e Receber Datagramas UDP
Capítulo 16: XML
Ler XML com QXmlStreamReader
Ler XML com DOM
Ler XML com SAX
Escrever XML
Capítulo 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 Avançado
Capítulo 18: Internacionalização
Trabalhando com Unicode
Fazendo Aplicações de Tradução Consciente
Troca de Linguagem Dinâmica
Traduzindo Aplicações
Capítulo 19: Aparência e Personalização
Usando Qt Style Sheets
Herdando de QStyle
Capítulo 20: Gráficos 3D
Desenhando Usando OpenGL
Combinando OpenGL e QPainter
Fazer Sobreposições Usando Objetos Framebuffer
Capítulo 21: Criando Plugins
Estendendo Qt com Plugins
Fazendo Aplicações com Plugins Concientes
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
4
Escrevendo Aplicações com Plugins
Capítulo 22: Script de Aplicações
Resumo da Linguagem EMAScript
Estendendo Aplicações Qt com Script
Implementando Extensões GUI Usando Scripts
Automatização de Tarefas Usando Scripts
Capítulo 23: Recursos Específicos da Plataforma
Interface com APIs Nativas
Usando o ActiveX no Windows
Manipulação de Gerenciamento de Sessão X11
Capítulo 24: Programação Incorporada
Introdução ao Qt/ Incorporado ao Linux
Customizando Qt/ Incorporado ao Linux
Integrando Aplicações Qt com Qtopia
Usando APIs do Qtopia
Parte IV: Apêndices
Apêndice A: Obtenção e Instalação do Qt
Nota sobre Licenciamento
Instalando Qt/Windows
Instalando Qt/Mac
Instalando Qt/X11
Apêncide B: Construção de Aplicações em Qt
Uso do qmake
Usando Ferramentas de Terceiros para Construir
Apêndice C: Introdução ao Qt Jambi
Iniciando com o Qt Jambi
Usando o Qt Jambi na IDE Eclipse
Integrando Componentes do C++ com o Qt Jambi
Apêndice D: Introdução ao C++ para Programadores Java e C#
Introdução ao C++
Principais Diferenças da Linguagem
Biblioteca Padrão do C++
Sobre os Autores
Jasmin Blanchette
Mark Summerfield
Produção
Índice
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
5 Parte I: O Básico do Qt
1. Começando
 Hello Qt
 Fazendo Conexões
 Alinhando Widgets
 Usando a Documentação de Referência
Este capítulo mostra como combinar C++ básico com a funcionalidade disponibilizada pelo Qt
para criar algumas aplicações de interface gráfica pequenas. Este capítulo também introduz
duas idéias chave do Qt: “signals e slots” e layouts. No Capítulo 2, iremos mais a fundo, e no
Capítulo 3, começaremos a construir aplicações mais realísticas.
Se você já conhece Java ou C# mas tem uma experiência limitada com C++, então é
recomendado que você comece lendo a “Introdução ao C++” no Apêndice D.
Hello Qt
Vamos começar 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 definições das classes QApplication e QLabel. Para cada classe do
Qt existe um arquivo header com o mesmo nome (e distinção entre maiúsculas e minúsculas)
que contém a definição da classe.
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
6
A linha 5 cria um objeto QApplication para gerenciar os recursos da aplicação no geral. O
construtor de QApplication requer os argumentos argc e argv porque o Qt interpreta alguns
argumentos de linha de comando próprios 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 gráfica. O termo vem da expressão “window
gadget” e é equivalente a tanto “controle” como “container” na terminologia do Windows.
Botões, menus, barras de rolagem e frames são exemplos de widgets. Widgets podem conter
outros widgets; por exemplo, uma janela é, geralmente, um widget que contém um QMenuBar,
algumas QToolBars, uma QStatusBar, e alguns outros widgets. A maioria das aplicações usa
uma QMainWindow ou um QDialog como janela principal da aplicação, mas o Qt é tão flexível
que qualquer widget pode ser uma janela. Neste exemplo, o widget QLabel é a janela da
aplicação.
A linha 7 torna a label visível. Widgets são criados, por padrão, como invisíveis para que
possamos customizá-los antes de serem exibidos, deste modo evitando “flickering”.
A linha 8 passa o controle da aplicação 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 ações do usuário como clicks do mouse ou então pressionamento de teclas. Ações
do usuário geram eventos (também chamados de “mensagens”) para os quais o programa
responde, geralmente executando uma ou mais funções. Por exemplo, quando o usuário clica
em um widget, os eventos “pressionamento do botão do mouse” e “liberação do botão do
mouse” são gerados. Neste ponto, aplicações gráficas diferem significativamente de programas
BAT convencionais, nos quais praticamente só processam uma entrada, desenvolvem algum
procedimento, e terminam sem interação humana.
Por simplicidade, nós não nos preocupamos em chamar o delete para o objeto QLabel ao final
da função main(). Este vazamento de memória (“memory leak”) é inofensivo num programa
tão pequeno, já que a memória alocada será desalocada quando o programa terminar.
Já é possível testar o programa na sua máquina. Ele deve se parecer com o mostrado na
Figura 1.1. Primeiro você terá que instalar o Qt 4.3.2 (ou uma versão mais recente), este
procedimento é explicado no Apêndice A. De agora em diante, vamos assumir que você tem
uma cópia corretamente instalada do Qt e que o diretório bin está na sua variável PATH de
ambiente. (No Windows isso é feito automaticamente pelo instalador do Qt) Você também
precisará que o código deste programa esteja num arquivo hello.cpp num diretório chamado
hello. Você mesmo pode escrever o arquivo hello.cpp ou copiá-lo dos exemplos que
acompanham este livro, que está disponível em examples/chap01/hello/hello.cpp. (Todos
os exemplos estão disponíveis no site do livro, http://www.informit.com/title/0132354160.)
Figura 1.1 - Hello no Linux
Do prompt de comando, vá até o diretório hello, e digite
qmake –project
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
7
para criar um arquivo projeto que é independente da plataforma, e depois digite
qmake hello.pro
para criar um arquivo “makefile” específico para a plataforma que está usando. (A ferramenta
qmake é discutida em mais detalhes no Apêndice 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 botão fechar na barra de título da janela.
Se você estiver usando o Windows e tiver instalado a versão Open Source do Qt e o
compilador MinGW, você terá um atalho chamado “prompt de comando do Qt” que tem todas
as variáveis de ambiente corretamente ajustadas. Se você conseguiu visualizar a janela então
você pode compilar aplicações do Qt utilizando qmake e make como descritos anteriormente. Os
executáveis são colocados na pasta “debug” ou “release” da aplicação (por exemplo,
C:exampleschap01helloreleasehello.exe).
Se você estiver utilizando o Microsoft Visual C++ com uma versão comercial do Qt, você
utilizará o nmake ao invés 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 próximo 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 aplicação. Quando rodar, ela deve parecer com a Figura 1.2. Como este exemplo
ilustra, é fácil diferenciar uma aplicação de interface de usuário Qt utilizando apenas uma
formatação HTML.
Figura 1.2: Uma label com formatação HTML básica
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
8
Fazendo Conexões
O segundo exemplo mostra como responder às ações do usuário. A aplicação consiste em um
botão que o usuário pode clicar para sair. O código é muito similar ao exemplo anterior, com
exceção do uso de um QPushButton no lugar de uma QLabel como nosso widget principal, e
nós estamos conectando a ação do usuário (clique) a um bloco de código.
O código desta aplicação está em examples/chap01/quit/quit.cpp; a aplicação em
andamento é mostrada na Figura 1.3. Aqui está o conteúdo 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 aplicação que fecha
Os widgets do Qt emitem sinais para indicar que uma ação de usuário ou uma mudança de
estado ocorreu. [*] Por exemplo, QPushButton emite um sinal clicked() quando o usuário
clica no botão. Um sinal pode se conectar com uma função (chamada de slot nesse contexto)
para que quando o sinal for emitido, o slot seja executado automaticamente. No nosso
exemplo, nós conectamos o sinal clicked() do botão com o slot quit() do objeto
QApplication. As macros SIGNAL() e SLOT() fazem parte da sintaxe.
[*] Sinais do Qt não tem nenhuma relação com sinais do Unix. Neste livro, estamos tratando somente dos sinais do Qt.
Vamos construir a aplicação. Assumimos que você criou um diretório chamado quit contendo
o arquivo quit.cpp. Rode o qmake no diretório 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 aplicação e rode-a. Se você clicar em Quit, ou pressionar a barra de espaço
(que pressiona o botão), a aplicação terminará.
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
9
Alinhando Widgets
Nesta seção, 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 aplicação (mostrada na Figura 1.4) pergunta pela idade do usuário, a qual o
usuário pode informar manipulando um spin box ou um slider.
Figura 1.4 – A aplicação da idade
A aplicação consiste em três widgets: um QSpinBox, um QSlider e um QWidget. O QWidget é
a janela principal da aplicação. O QSpinBox e o QSlider são apresentados dentro da QWidget;
eles são filhos de QWidget. Alternativamente, podemos dizer que QWidget é pai de QSpinBox e
QSlider. O QWidget não tem pais porque está sendo usado como uma janela top-level. Os
construtores de QWidget e de todas as suas subclasses tem QWidget * como parâmetro que
especifica quem é o pai da widget em questão.
Aqui está o código 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();
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
10 24 return app.exec();
25 }
As linhas 8 e 9 preparam a QWidget que servirá como a janela principal da aplicação. Podemos
chamar setWindowTitle() para escolher o texto que será exibido na barra de título da janela.
As linhas 10 e 11 criam um QSpinBox e um QSlider, e as linhas 12 e 13 atribuem seus
intervalos válidos. Podemos assumir que o usuário tem até 130 anos de idade. Poderíamos
passar window para os construtores de QSpinBox e QSlider especificando que estes widgets
devem ter window como pai deles, mas não é necessário 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
então emite um sinal valueChanged(int) porque o próprio valor mudou, ativando o slot
setValue(int) do spin box. Mas nesse ponto, setValue(int) não emite nenhum sinal, já que
o valor do spin box já é 35. Isso evita a recursão infinita. A Figura 1.5 ilustra a situação.
Figura 1.5 – Mudando o valor de um widget, muda os dois
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
11
Nas linhas 19 até 22, nós alinhamos o spin box e o slider usando um gerenciador de layouts.
Este gerenciador é um objeto que define o tamanho e a posição dos widgets que estão sob sua
responsabilidade. O Qt tem três 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 têm sido tirados no Linux, mas aplicações em Qt
podem parecer nativas de cada plataforma suportada. O Qt consegue fazer isso
emulando o “look and feel” de cada plataforma, ao invés de conter um kit de widgets de
uma plataforma particular.
Figura 1.6 – Estilos pré-definidos
O estilo Plastique é o estilo padrão para aplicações Qt/X11 rodando sob o KDE, e o
Cleanlooks é o padrão sob o GNOME. Estes estilos utilizam gradientes e “anti-aliasing”
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
12
 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 têm seu pai redefinido para o widget no qual o layout foi
instalado, e por essa razão não temos que especificar um pai explícito quando construímos o
widget que será colocado em um layout.
Figura 1.7 – Os widgets e o layout da aplicação da idade
Apesar de não termos escolhido a posição e o tamanho dos widgets explicitamente, o
QSpinBox e o QSlider são dispostos visualmente de modo agradável de um lado até o outro.
Isso ocorre porque QHBoxLayout automaticamente designa posições e tamanhos razoáveis
para os widgets dos quais é responsável, baseado nas necessidades deles. Os gerenciadores
de layouts nos privam da ocupação de posicionar, por puro código, os objetos na tela e
garantem que a janela se redimensione suavemente.
O modo apresentado por Qt para construir interfaces de usuário é simples de entender e é
muito flexível. O procedimento mais comum que programadores Qt utilizam é instanciar os
widgets necessários e depois definir suas propriedades conforme necessário. Programadores
adicionam widgets aos layouts, que automaticamente cuidam do posicionamento e
redimensionamento. O comportamento da interface de usuário é gerenciada conectando
widgets uns aos outros usando o mecanismo de sinais e slots.
para gerar um “look and feel” moderno. Usuários de aplicações Qt podem substituir os
estilos padrão utilizando o comando –style na linha de comando. Por exemplo, para
iniciar a aplicação 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 são visualizados
nas plataformas nativas, já que dependem de dispositivos de tema de cada plataforma.
Um estilo adicional chamado QtDotNet está disponível no Qt Solutions. Também é
possível criar estilos customizados, como será explicado no Capítulo 19.
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
13
Usando a Documentação de Referência
A documentação de referência do Qt é uma ferramenta essencial para qualquer desenvolvedor.
Ela cobre todas as classes e funções no Qt. Esse livro faz o uso de diversas classes e funções
do Qt, mas não cobre todas elas e nem fornece todos os detalhes das que são mencionadas.
Para tirar proveito máximo do Qt, você deve se familiarizar com a documentação do Qt o mais
rápido possível.
A documentação está disponível em HTML no diretório doc/html do Qt e pode ser lida através
de qualquer browser. Você também pode usar o Qt Assistant, o browser de ajuda do Qt, que
tem recursos poderosos de busca e indexação que o tornam mais rápido e fácil 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 seção “Referência API” na página inicial fornecem diferentes modos de
navegar pelas classes de Qt. A página “Todas as classes” lista todas as classes na API do Qt. A
página “Classes Principais” lista apenas as classes mais utilizadas de Qt. Como um exercício,
procure as classes e as funções que utilizamos neste capítulo.
Figura 1.8 – Documentação do Qt no Qt Assistant sob Windows Vista
Note que funções herdadas são documentadas na classe base; por exemplo, QPushbutton não
tem uma função própria show(), mas herda uma de QWidget. A Figura 1.9 mostra como as
classes que vemos até agora se relacionam umas com as outras.
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
14
Figura 1.9 – Árvore de herança para as classes de Qt vistas até agora
A documentação de referência para a atual versão do Qt e para algumas versões mais recentes
está disponível online em http://doc.trolltech.com/. Este site também tem artigos selecionados
do Qt Quarterly, o newsletter dos programadores Qt enviado para todas as licenças comerciais.
Este capítulo introduziu os conceitos chave de conexões signal-slot e layouts. Ele também
começou a revelar a perspectiva total e consistente de orientação a objetos até a construção e
uso de widgets. Se você procurar pela documentação do Qt, você encontrará uma
uniformidade de exibição que a torna bem direta no que se diz respeito ao uso de novos
widgets, e você também descobrirá que Qt escolheu cuidadosamente os nomes para funções,
parâmetros, enums e assim por diante, que fazem com que programar em Qt se torne
incrivelmente agradável e fácil.
Os capítulos 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 básica de leitura, processamento e escrita de
arquivos.
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
15 2. Criando Dialogs
 Herdando de QDialog
 Signals e Slots a Fundo
 Design Rápido de Dialogs
 Modificando a Forma dos Dialogs
 Dialogs Dinâmicos
 Classes Nativas de Widgets e Dialogs
Este capítulo vai te ensinar como criar caixas de diálogo utilizando Qt. Caixas de diálogo
apresentam aos usuários opções e escolhas, e permitem que eles ajustem opções dos seus
parâmetros preferidos e que façam suas escolhas. Eles são chamados de caixas de diálogo, ou
apenas “dialogs”, porque eles fornecem os meios pelos quais os usuários “conversam” com as
aplicações.
A maioria das aplicações GUI (“graphics user interface”, ou interface gráfica de usuário)
consiste em uma mainwindow com um menubar e uma toolbar, em conjunto com dezenas de
dialogs que complementam a mainwindow. Também é possível criar dialogs que respondam
diretamente às escolhas do usuário aplicando as ações necessárias (por exemplo, uma
calculadora).
Criaremos nosso primeiro dialog puramente por código 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 rápido (do que código puro) e faz com que seja fácil 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 própria. Fazendo isso, a tornamos
independente, um componente encapsulado, com signals e slots próprios.
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
16
Figura 2.1. A caixa de diálogo de busca.
O código fonte está dividido em dois arquivos: finddialog.h e finddialog.cpp.
Começaremos 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 múltiplos includes.
A linha 3 inclui a definição 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 serão utilizadas na
implementação do dialog (em finddialog.cpp). [*] Uma “foward declaration” diz ao compilador
C++ que esta classe existe sem dar mais detalhes sobre a definição 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 começo da definição da classe é necessária para todas as classes que
definem seus próprios signals e slots.
[*] Foward declarations só podem ser utilizadas quando as variáveis forem ponteiros. O
compilador não precisa, de inicio, de mais informações sobre a classe. Já que todos os
ponteiros tem tamanho fixo: 4 bytes.
O construtor de FindDialog é um exemplo típico de classes Qt. O parâmetro parent especifica
o widget pai. O padrão para este parâmetro é um ponteiro nulo, significando que o widget não
tem pai.
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
17 13 signals:
14 void findNext(const QString &str, Qt::CaseSensitivity cs);
15 void findPrevious(const QString &str, Qt::CaseSensitivity cs);
A seção signals declara dois sinais que o dialog emitirá quando o usuário clicar no botão
“Find”. Se a opção “Search Backward” estiver selecionada, o dialog emite findPrevious()
caso contrário, emite findNext().
A palavra-chave signals é, na verdade, uma macro. O pré-processador C++ o converte para
padrões 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 seção privada da classe, declaramos dois slots. Para implementar os slots, precisaremos
acessar a maioria dos widgets filhos do dialog, então mantemos ponteiros para eles também. A
palavra-chave slots é, como signals, uma macro que se transforma em uma construção que
C++ pode digerir.
Para as variáveis private, usamos “foward declarations” das respectivas classes. Isso foi
possível porque são todos ponteiros e não precisamos acessá-los no header, então o
compilador não precisa de todas as definições da classe. Poderíamos ter incluído os includes
(<QCheckBox>, <QLabel>, etc.), mas utilizando “foward declarations” quando possível, isso
torna o tempo de compilação menor.
Vamos para o arquivo da implementação da classe FindDialog, o finddialog.cpp:
1 #include <QtGui>
2 #include "finddialog.h"
Primeiramente incluímos <QtGui>, um arquivo header que contém a definição das classes GUI
do Qt. Qt consiste de vários módulos, cada um com sua própria biblioteca. Os módulos mais
importantes são QtCore, QtGui, QtNetwork, QtOpenGL, QtScript, QtSql, QtSvg e QtXml. O
header <QtGui> contém a definição de todas as classes que são parte dos módulos QtCore e
QtGui. Incluir este header nos economiza a inclusão individual de cada classe do nosso dialog.
No arquivo finddialog.h, ao invés de incluir <QDialog> e utilizar “foward declarations” para
QCheckBox, QLabel, QLineEdit e QPushButton, poderíamos simplesmente ter incluído
<QtGui>. Entretanto não é aconselhável incluir um arquivo header tão grande, especialmente
em aplicações grandes.
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
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 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 4, passamos o parâmetro parent para o construtor da classe base. Depois criamos os
objetos filhos. A função tr() marca a string literal para futuras traduções para outras línguas.
Esta função é declarada em QObject e em todas as classes que contém a macro Q_OBJECT. É
um bom hábito cercar strings visíveis aos usuários com tr(), mesmo que você não tenha
planos imediatos para traduzir sua aplicação para outras línguas. Traduções serão estudadas
no Capítulo 18.
Em strings literais, utilizamos o símbolo „&‟ para indicar teclas de atalho. Por exemplo, a linha
11 cria o botão Find, o qual o usuário pode ativar utilizando Alt+F nas plataformas que
suportam teclas de atalho. O símbolo „&‟ também pode ser utilizado para controlar o foco: na
linha 6 criamos uma label com a tecla de atalho (Alt+W), e na linha 8 nós definimos o lineedit
como „companheiro‟ (buddy) da label. Um buddy é um widget que aceita o foco quando a tecla
de atalho do outro é pressionada. Então quando o usuário pressiona Alt+W (atalho da label), o
foco vai para o lineedit (buddy da label).
Na linha 12, fazemos com que o botão Find seja o padrão chamando setDefault(true). O
botão padrão é o botão que, quando o usuário pressiona Enter, é pressionado. Na linha 13,
desabilitamos o botão Find. Quando um widget está desabilitado ele geralmente é mostrado
em tons acinzentados e não responderá às interações do usuário.
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 usuário clicar no botão
Find. O dialog se fecha quando o usuário clicar em Close. O slot close() é herdado de
QWidget, e o seu comportamento padrão é esconder o widget de visualização (sem deletá-lo).
Estudaremos o código para os slots enableFindButton() e findClicked() mais adiante.
Já que QObject é um dos ancestrais do nosso dialog, então podemos omitir o prefixo
„QObject::‟ das chamadas de connect().
21 QHBoxLayout *topLeftLayout = new QHBoxLayout;
22 topLeftLayout->addWidget(label);
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
19
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, nós alinhamos os widgets filhos utilizando gerenciadores de layout. Layouts
podem conter ambos widgets e outros layouts. Misturando QHBoxLayouts, QVBoxLayout e
QGridLayout, é possível 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 é responsável
por toda a área do layout. Os outros três layouts são sub-layouts. A pequena „mola‟ na parte
inferior direita da Figura 2.2. é um spacer (ou “stretch”). Ele usa o espaço vazio abaixo dos
botões Find e Close, garantindo que esses botões ocupem o topo do layout em que estão.
Figura 2.2. Os layouts do dialog de busca
Um aspecto sutil de classes de gerenciamento de layouts é que não são widgets. Ao invés
disso, são derivadas de QLayout. Que por sua vez é derivado de QObject. Na figura, widgets
são representados por linhas sólidas e layouts são representados por linhas tracejadas para
destacar a diferença entre eles. Durante a execução do programa, layouts são invisíveis.
Quando sub-layouts são adicionados ao layout pai (linhas 23, 33 e 34), os sub-layouts têm
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 têm seus pais redefinidos como o
dialog. A hierarquia resultante é mostrada na Figura 2.3.
36 setWindowTitle(tr("Find"));
37 setFixedHeight(sizeHint().height());
38 }
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
20 Figura 2.3. As relações de parentesco do dialog
Finalmente, definimos o título a ser mostrado na barra de título e uma altura fixa para a
janela, já que não existem widgets dentro do dialog que possam ocupar um espaço vertical
significativo. A função QWidget::sizeHint() retorna o tamanho ideal do widget.
Isso completa a revisão do construtor da classe FindDialog. Já que criamos os objetos e
layouts através de „new‟, é razoável pensar que devemos deletar cada widget e layout com um
„delete‟. Mas não é necessário, o Qt automaticamente deleta objetos filhos quando o pai é
destruído, e todos os widgets e layouts do nosso dialog são descendentes do próprio 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 usuário clica no botão Find. Ele emite o sinal
findPrevious() ou findNext(), dependendo da opção „Search Backward‟. A palavra-chave
„emit‟ é específica do Qt; como outras extensões Qt ela é convertida em C++ padrão pelo pré-
processador C++.
O slot enableFindButton() é chamado sempre que o usuário muda o texto contido no
lineedit. Isso ativa o botão se houver algum texto no lineedit, e desabilita caso contrário.
Estes dois slots finalizam o dialog. Podemos, então, criar um main.cpp para testar nosso
widget FindDialog:
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
21
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 definição da classe
FindDialog contém a macro Q_OBJECT, então 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 próxima seção).
Para que o „moc‟ funcione corretamente é necessário colocar a definição da classe em um
arquivo header, fora da implementação. O código gerado pelo moc inclui esse arquivo header e
adiciona alguns códigos padrões do C++ por si próprio.
Classes que utilizam a macro Q_OBJECT devem ser executadas pelo „moc‟. Isso não é um
problema porque o qmake automaticamente adiciona as regras necessárias para o „makefile‟.
Mas se você esquecer de gerar seu „makefile‟ usando qmake e o moc não tiver rodado, o linker
reclamará dizendo que algumas funções foram declaradas mas não 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 saída do Visual C++ começa 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 aplicação.
Agora, execute o programa. Se as teclas de atalho são 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 tabulação padrão,
é a ordem na qual os widgets foram criados. Isso pode ser mudado usando
QWidget::setTabOrder().
Forneça uma ordem razoável para a tecla tab e bons atalhos de teclado de forma que usuários
que não querem (ou que não podem) usar um mouse sejam capazes de usar ao máximo a
aplicação. Controle total sobre o teclado também é apreciado por digitadores rápidos.
No Capítulo 3, nós usaremos o dialogo de busca numa aplicação real, e nós conectaremos os
sinais findPrevious() e findNext() a alguns slots.
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
22
Signals e Slots a Fundo
O mecanismo de sinais e slots é fundamental para programação em Qt. Ele permite que o
programador estabeleça um elo entre os objetos sem que os objetos saibam uns dos outros.
Nós já conectamos alguns sinais e slots, declaramos nossos próprios sinais e slots,
implementamos nossos slots e emitimos nossos sinais. Vamos dar uma olhada no mecanismo
mais de perto.
Slots são quase idênticos a funções membro ordinárias do C++. Elas podem ser virtuais,
podem ser sobrecarregadas, podem ser publics, protecteds ou privates, podem ser
diretamente chamadas como qualquer outra função membro do C++, e os seus parâmetros
podem ser de qualquer tipo. A diferença é que um slot também pode ser conectado a um sinal,
que no caso será chamado toda vez que o sinal for emitido.
A estrutura da função connect() se dá da seguinte forma:
connect(sender, SIGNAL(signal), receiver, SLOT(slot));
Onde „sender‟ e „receiver‟ são ponteiros para QObjects e „signal‟ e „slot‟ são assinaturas de
funções sem nomes de parâmetros. As macros SIGNAL() e SLOT() essencialmente convertem
seus argumentos para uma string.
Nos exemplos que vimos até agora, nós sempre conectamos sinais diferentes com slots
diferentes. Existem outras possibilidades a serem levadas em consideração.
 Um sinal pode ser conectado a vários 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 são chamados um a um, numa ordem não especificada.
 Vários 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 também é emitido. Além disso, conexões
signal-signal são indistinguíveis de conexões signal-slot.
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
23
 Conexões podem ser removidas:
disconnect(lcd, SIGNAL(overflow()),
this, SLOT(handleMathError()));
Isso é raramente necessário, porque o Qt automaticamente remove todas as conexões
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 parâmetros na mesma ordem:
connect(ftp, SIGNAL(rawCommandReply(int, const QString &)),
this, SLOT(processReply(int, const QString &)));
Excepcionalmente, se um sinal tem mais parâmetros que o slot ao qual está conectado, os
parâmetros adicionais são simplesmente ignorados.
connect(ftp, SIGNAL(rawCommandReply(int, const QString &)),
this, SLOT(checkErrorCode(int)));
Se os tipos de parâmetros são incompatíveis, ou se o sinal ou slot não existirem, o Qt irá
informar através de um warning em tempo de execução (se a aplicação foi construída no modo
debug). Similarmente, o Qt irá lançar um warning se os nomes dos parâmetros 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 não é limitado a programação 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;
};
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
24
void Employee::setSalary(int newSalary)
{
if (newSalary != mySalary) {
mySalary = newSalary;
emit salaryChanged(mySalary);
}
}
Perceba como o slot setSalary() é implementado. Nós emitimos o sinal salaryChanged()
apenas se newSalary != mySalary. Isso garante que as conexões cíclicas não levem a loops
infinitos.
O Sistema Meta-Object do Qt
Uma das maiores conquistas do Qt foi a extensão do C++ com um mecanismo de criação
de componentes de software independentes que podem ser ligados sem nem saberem
informações sobre o componente aos quais estão conectados.
O mecanismo é chamado sistema meta-object e fornece dois serviços chave: signals-
slots, e introspecção. A funcionalidade da introspecção é necessária para implementar
signals e slots, e permite programadores obterem “informações meta” sobre sub-classes
QObject em tempo de execução, incluindo a lista de sinais e slots suportados pelo objeto
e nome da sua classe. O mecanismo também suporta propriedades (amplamente usadas
pelo Qt Designer) e tradução de texto (para internacionalização), e estabelece as bases
do módulo QtScript. A partir do Qt 4.2, propriedades podem ser adicionadas
dinamicamente, um recurso que veremos em ação nos Capítulos 19 e 22.
O C++ padrão não fornece suporte para as meta-informações dinâmicas que o sistema
de meta-objeto de Qt precisa. O Qt resolve isso com uma ferramenta separada, o moc.
Ele analisa as definições de Q_OBJECT e faz com que a informação fique disponível
através de funções 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 funções de introspecção que devem ser
implementadas em cada subclasse de QObject: metaObject(), tr(),
qt_metacall(), entre outras.
 A ferramenta moc gera implementações para as funções declaradas por Q_OBJECT
e para todos os signals.
 As funções membro de QObject (como connect() e disconnect() ) usam as
funções de introspecção para fazer seus trabalhos.
Tudo isso é feito automaticamente pelo qmake, moc e QObject, então você dificilmente
terá que pensar nisso. Mas se estiver curioso você pode ler a documentação da classe
QMetaObject e os códigos C++ gerados pelo moc para ver como a implementação
funciona.
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
25
Design Rápido de Dialogs
O Qt foi planejado para ser agradável e intuitivo para o desenvolvimento de código a mão, e
não é difícil encontrar programadores que desenvolvem suas aplicações inteiras puramente
escrevendo código C++. Porém, muitos programadores preferem utilizar uma aproximação
visual para desenvolver formulários, porque eles acham que este método é mais natural e
rápido do que apenas código, e eles querem estar aptos a testar e mudar designs com mais
rapidez e facilidade do que quando desenvolvidos com códigos puros.
O Qt Designer expande as opções disponíveis aos programadores fornecendo uma capacidade
visual de design. Qt Designer pode ser usado para desenvolver todos ou apenas alguns dos
formulários da aplicação. Formulários que são criados utilizando o Qt Designer são convertidos
em código C++, então o Qt Designer pode ser usado com uma variedade de ferramentas
convencionais e não impõe especificações especiais ao compilador.
Nessa seção, usaremos o Qt Designer para criar o diálogo “Ir para a célula” mostrado na
Figura 2.4. Criar o dialog no Qt Designer ou por código 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 conexões signal/slots.
5. Implementar os próprios slots do dialog.
Figura 2.4. O dialog de “Ir para célula”.
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 nós criaremos os botões „OK‟ e
„Cancel‟ manualmente e mostraremos como é feito.) Você deve, agora, ter uma janela
chamada „Untitled‟.
Por padrão, a interface de usuário do Qt consiste em várias janelas „top-level‟. Se você preferir
uma interface MDI (multiple document interface) com uma janela „top-window‟ e várias
subjanelas, como mostrado na Figura 2.5, clique em Edit|Preferences e ajuste o modo de
interface do usuário para „Docked Window‟.
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
26
Figura 2.5. Qt Designer em modo „Docked Window‟ no Windows Vista
O primeiro passo é criar widgets filhos e colocá-los no formulário. Criar uma label, um line
editor, um spacer horizontal, e dois botões. 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
formulário. O spacer, que é invisível no formulário final, é mostrado no Qt Designer como uma
pequena mola azul.
Agora arraste a borda inferior do formulário pra encurtá-lo. Isso deveria produzir um
formulário que é similar ao da Figura 2.6. Não gaste muito tempo posicionando os itens
precisamente no formulário. Os gerenciadores de layouts vão posicioná-los de forma precisa
posteriormente.
Figura 2.6. O formulário 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 botão. Defina a propriedade objectName como “okButton”, a
propriedade enabled para “false”, a propriedade text para “OK”, e a propriedade
default para “true”.
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
27
4. Clique no segundo botão. Defina a propriedade objectName para “cancelButton” e a
propriedade text para “Cancel”.
5. Clique no fundo do formulário 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 edição que te permite escolher os
Buddies. Depois, clique na tabela, mantenha o botão apertado e arraste a seta vermelha para
o line Edit, e depois libere o botão. 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 edição
de buddies clique em Edit|Edit Widgets.
Figura 2.7 Formulário com as propriedades ajustadas
O próximo passo é alinhar os widgets no formulário:
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 botões. Clique em Form|Lay
Out Horizontally.
3. Clique no fundo do formulário para remover a seleção anterior de qualquer widget,
depois clique em Form|Lay Out Vertically.
4. Clique em Form|Adjust Size para redimensionar o formulário para o seu tamanho
preferencial.
As linhas vermelhas mostradas no formulário mostram os layouts que foram criados, como é
mostrado na Figura 2.8. Eles não são visíveis quando o formulário é executado.
Figura 2.8. Formulário com Layouts.
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
28
Agora clique em Edit|Edit Tab Order. Um número em um retângulo azul aparecerá próximo
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 edição 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 botão fechar na barra de título.
Salve as alterações como gotocelldialog.ui em um diretório chamado gotocell, e crie um
arquivo main.cpp no mesmo diretório 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 usuário gotocelldialog.ui e para gerar as regras apropriadas do makefile para
chamar uic, o compilador de interfaces de usuário do Qt. A ferramenta uic converte o arquivo
gotocelldialog.ui em código C++ e põe o resultado no arquivo ui_gotocelldialog.h.
O arquivo ui_gotocelldialog.h gerado contém as definições para a classe
Ui::GoToCellDialog, que é um equivalente C++ do gotocelldialog.ui. A classe declara
variáveis membro que armazenam os layouts e widgets filhos do formulário, e uma função
setupUi() que inicializa o formulário. A classe gerada se parece com isso:
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
29
class Ui::GoToCellDialog
{
public:
QLabel *label;
QLineEdit *lineEdit;
QSpacerItem *spacerItem;
QPushButton *okButton;
QPushButton *cancelButton;
...
void setupUi(QWidget *widget) {
...
}
};
A classe gerada não tem nenhuma classe base. Quando utilizamos essa classe no main.cpp,
nós criamos um QDialog e o passamos para setupUI().
Se você executar o programa agora, o diálogo vai funcionar, mas ele não funciona exatamente
como queremos:
 O botão OK está sempre desabilitado.
 O botão Cancel não faz nada.
 O line Edit aceita qualquer texto, ao invés de só aceitar posições validas de célula.
Nós podemos fazer com que o diálogo funcione corretamente escrevendo algum código. 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
máxima de que qualquer problema do software pode ser resolvido simplesmente adicionando
outra camada de meios indiretos). A convenção de nomeação é 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 código:
#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
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
30
Aqui, utilizamos herança pública porque queremos acessar todos os widgets do dialog de fora
do dialog. A implementação 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 formulário. Graças à herança múltipla,
podemos acessar os membros de Ui::GoToCellDialog diretamente. Depois de criar a
interface de usuário, setupUi() irá automaticamente conectar qualquer slot que siga a
convenção de nome on_objectName_signalName() para o sinal de objectName
correspondente. No nosso exemplo, isso significa que setupUi() irá estabelecer a seguinte
conexão signal-slot:
connect(lineEdit, SIGNAL(textChanged(const QString &)),
this, SLOT(on_lineEdit_textChanged()));
Também no construtor, nós criamos um validador (validator) para restringir o intervalo da
entrada. O Qt fornece três classes internas do tipo validator: QIntValidator,
QDoublrValidator, e QRegExpValidator. Aqui podemos usar um QRegExpValidator com a
expressão regular “[A-Za-z][1-9][0-9]{0,2}”, que significa: Permita uma letra maiúscula ou
minúscula, seguida de um digito entre 1 e 9, seguido de zero, 1, ou dois dígitos entre 0 e 9.
(Para uma introdução à expressões regulares, veja a documentação da classe QRegExp.)
Passando this para o construtor do QRegExpValidator, fazemos com que ele seja filho do
objeto GoToCellDialog. Fazendo isso, não 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 nós 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 memórias, reduzindo o risco de
vazamento de memória (memory leak). Os únicos objetos que devemos chamar delete são
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.
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
31
Para widgets, o pai tem um significado adicional: Widgets filhos são mostrados dentro da área
do pai. Quando deletamos o Widget pai, não somente os filhos são liberados da memória como
também desaparecem da tela.
Ao fim do construtor, nós conectamos o botão OK ao slot accept() do QDialog e o botão
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 nós usamos esse dialog, nós podemos usar o resultado
para ver se o usuário clicou OK e atua de acordo.
O slot on_lineEdit_textChanged() ativa ou desativa o botão OK, dependendo se o line edit
contém uma localização válida de célula. 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 aplicação de novo. Digite “A12” no editor, e perceba que o botão OK se torna ativo. Tente
digitar alguns textos aleatórios para ver como o validator funciona. Clique Cancel para fechar
o dialog.
O dialog funciona corretamente, mas para usuários do Mac, os botões estão um pouco
diferentes. Escolhemos adicionar cada botão individualmente, para mostrar como era feito,
mas nós deveríamos ter usado um QDialogButtonBox, um widget que contém os botões que
especificamos e que os apresenta na forma correta para o sistema de janelas no qual a
aplicação está sendo executada, como mostrado na Figura 2.10.
Figura 2.10. O dialog „Ir para célula‟ no Windows Vista e no Mac.
Para fazer com que o dialog use um QDialogButtonBox, nós devemos modificar ambos o
design e o código. No Qt Designer, existem apenas quatro passos a tomar:
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
32
1. Clique no formulário (não em nenhum dos widgets ou layouts) e depois clique em
Form|Break Layout.
2. Selecione e delete os botões OK e Cancel, o spacer horizontal e o layout horizontal.
3. Arraste um “Button Box” para o formulário, abaixo da label de localização e do line Edit.
4. Clique no formulário e depois Form|Lay Out Vertically.
Se nós estivéssemos fazendo apenas mudanças no design, como mudar o layout do dialog ou
propriedades de widgets, nós estaríamos aptos a simplesmente reconstruir a aplicação. Mas
nesse caso removemos alguns widgets e adicionamos novos widgets, e nestes casos devemos
normalmente modificar o código também.
As mudanças necessárias devem ser feitas no arquivo gotocelldialog.cpp. Aqui está a nova
versão 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 versão anterior nós inicialmente desabilitamos o botão OK no Qt Designer. Nós não
podemos fazer isso com um QDialogButtonBox, então nós fazemos isso no código,
imediatamente depois da chamada setupUi(). A classe QDialogButtonBox tem um enum de
botões padrão, e podemos usar isso para acessar botões particulares, neste caso o botão OK.
Convenientemente, o nome padrão para um QDialogButtonBox do Qt Designer é buttonBox.
Ambas as conexões são feitas a partir do Button Box ao invés de cada botão propriamente
dito. O sinal accepted() é emitido quando o botão com a propriedade AcceptRole é clicado, e
similarmente o sinal rejected() é emitido por um botão com a propriedade RejectRole. Por
padrão, o botão QDialogButtonBox::Ok carrega a propriedade AcceptRole, e o botão
QDialogButtonBox::Cancel carrega a propriedade RejectRole.
Apenas mais uma mudança é necessária, 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 invés de se referir a um botão particular armazenado
como variável membro, nós acessamos o botão OK do Button Box.
Uma das facilidades do Qt Designer é que ele permite que programadores tenham grande
liberdade para modificar seus próprios formulários sem serem forçados a mudar seus códigos.
Quando você desenvolve um formulário puramente por C++, mudanças no design podem levar
um tempo considerável. Com o Qt Designer, nenhum tempo é perdido já que o uic
simplesmente refaz o código fonte de qualquer formulário que tenha mudado. A interface de
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
33
usuário do dialog é salva em um arquivo .ui (um arquivo no formato XML), enquanto que
funcionalidades próprias são implementadas derivando da classe gerada pelo uic.
Modificando a Forma dos Dialogs
Nós vimos como criar caixas de diálogo que sempre mostram os mesmos widgets sempre que
são usados. Em alguns casos, é necessário que caixas de diálogo mudem suas formas. Os
tipos mais comuns de caixas de diálogo que mudam suas formas são diálogos que se
expandem e diálogos de múltiplas páginas. Ambos os tipos podem ser implementados no Qt,
tanto por código como pelo Qt Designer.
Diálogos que se expandem geralmente apresentam uma aparência simples mas têm um botão
„ativável‟ que permite que o usuário alterne entre o diálogo simples e o diálogo expandido.
Estes diálogos são comumente usados por aplicações que atingem tanto usuários casuais
quanto avançados, escondendo as opções avançadas a menos que o usuário peça
explicitamente para vê-las. Nesta seção, usaremos o Qt Designer para criar o diálogo de
expansão mostrado na Figura 2.11.
Figura 2.11. Caixa de diálogo de classificação nos modos simples e expandido.
Este diálogo é um diálogo de classificação de uma aplicação de planilhas, onde o usuário pode
selecionar uma ou várias colunas para que sejam classificadas. A versão simples do diálogo
permite que ele escolha apenas uma chave de classificação, enquanto que a versão estendida
fornece os meios para duas chaves extras. O botão „more‟ permite que o usuário alterne entre
as versões.
Criaremos o widget com sua versão expandida no Qt Designer, e esconderemos as chaves
extras em tempo de execução conforme necessário. O diálogo parece complicado, mas é fácil
fazê-lo no Qt Designer. O truque é fazer a primeira chave primeiro, depois duplicá-la duas
vezes para obter as outras:
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
34
1. Clique em File|New Form e escolha o modelo “Dialog com botões”.
2. Crie um botão OK e arraste para o canto superior direito do formulário. Mude a sua
propriedade do objectName para “okButton” e defina sua propriedade default para
“true”.
3. Crie um botão Cancel, e arraste-o para baixo do botão OK. Mude sua propriedade
objectName para “cancelButton”.
4. Crie um spacer vertical e arraste-o para baixo do botão Cancel, depois crie um botão
More, e arraste-o para baixo do spacer vertical. Mude sua propriedade objectName para
“moreButton”, defina sua propriedade text para “&More”, e sua propriedade checkable
para “true”.
5. Clique no botão OK, segure o Shift e clique no botão Cancel, no spacer vertical, no
botão More e depois clique em Form|Lay Out Vertically.
6. Crie um group box, duas labels, duas comboboxes, e um spacer horizontal e coloque-os
em qualquer lugar do formulário.
7. Arraste o canto inferior direito para aumentá-lo. Insira os outros widgets no groupbox e
posicione-os aproximadamente como é mostrado na Figura 2.12 (a).
8. Arraste a borda direita do segundo combo box para fazê-lo, aproximadamente, duas
vezes maior que o primeiro combobox.
9. Defina a propriedade title do group box para “&Primary Key”, a propriedade text da
primeira label para “Column:”, e a propriedade text da segunda label para “Order:”.
10. Clique com o botão direito na primeira combobox e escolha Edit Items a partir do
menu para editar os itens da combo box. Crie um item com o texto “None”.
11. Clique com o botão direito na segunda combo box e escolha Edit Items. Crie um item
“Ascending” e outro “Descending”.
12. Clique na group box, Form|Lay Out in a Grid. Clique novamente no group box e
depois Form|Adjust Size. Isso vai gerar o layout mostrado na Figura 2.12(b).
Figura 2.12. Alinhando os widgets filhos em grid.
Se um layout não ficar do jeitinho que você queria ou se você cometer um erro, você pode
sempre clicar em Edit|Undo ou Form|Break Layout, depois reposicionar os widgets e tentar
de novo.
Vamos agora adicionar as chaves extras:
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
35
1. Aumente a altura do diálogo 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 cópia
dele (e de seu conteúdo) sobre o original. Arraste a cópia 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 padrão grid mostrado na Figura 2.13(a).
6. Clique no formulário para limpar possíveis seleções, clique em Form|Lay Out in a
Grid. Agora arraste o canto inferior direito do formulário para cima e para esquerda
para deixá-lo menor possível. O formulário 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 formulário em grid.
O layout em grid resultante tem duas colunas e quarto linhas, totalizando oito células. O
primeiro group box, o spacer vertical da esquerda, o segundo group box, e o terceiro group
box, cada um ocupa uma única célula. O layout vertical contendo os botões OK, Cancel, e More
ocupa duas células.
Isso deixa duas células vazias na área inferior direita do diálogo. Se você não tem o mesmo
resultado, desfaça o layout, reposicione os widgets, e tente de novo.
Renomeie o formulário para “SortDialog” e mude o título da janela para “Sort”. Defina os
nomes dos widgets filhos para aqueles da Figura 2.14.
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
36
Figura 2.14. Nomeando os widgets
Clique em Edit|Edit Tab Order. Clique em cada combo box de cima para baixo, nos botões
OK, Cancel, e More. Clique em Edit|Edit Widgets para deixar o modo de edição de tabs.
Agora que o formulário foi desenhado, estamos prontos para torná-lo funcional designando
algumas conexões signals-slots. O Qt Designer nos permite que estabeleçamos conexões entre
widgets que compartilham do mesmo formulário. Precisamos estabelecer duas delas.
Clique em Edit|Edit Signals/Slots para entrar no modo de conexões do Qt Designer.
Conexões são representadas por setas azuis entre os widgets do formulário, como é mostrado
na Figura 2.15, e elas também são listadas na janela de edição de signals/slots do Qt
Designer. Para estabelecer uma conexão entre dois widgets, clique no widget remetente e
arraste a seta vermelha para o widget destinatário, e solte o botão do mouse. Isso vai fazer
com que um diálogo seja exibido, permitindo que você escolha o sinal e o slot que pertencerão
a conexão.
Figura 2.15. Conectando os widgets
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
37
A primeira conexão a ser feita é entre o botão okButton e o slot accept() do formulário.
Arraste a seta vermelha do botão okButton para uma parte vazia do formulário, solte o botão
para configurar a conexão pelo diálogo de configuração que será aberto, como mostrado na
Figura 2.16. Escolha clicked() como sinal e accept() como slot, e clique OK.
Figura 2.16. Diálogo de editor de conexões do Qt Designer
Para a segunda conexão, arraste a seta vermelha do botão cancelButton para uma parte
vazia do formulário, e no diálogo de configuração conecte o sinal clicked() ao slot reject()
do formulário.
A terceira conexão a ser estabelecida é entre o botão moreButton e o group box
secondaryGroupBox. Arraste a seta vermelha entre estes widgets, então selecione o sinal
toggled(bool) e o slot setVisible(bool). Por padrão, o Qt Designer não lista o slot
setVisible(bool) na lista de slots, mas ele aparece se você habilitar a opção “Show all
signals and slots”.
A quarta e última conexão é entre o sinal toggled(bool) do botão moreButton e o slot
setVisible(bool) do terceiro group box. Uma vez que as conexões foram estabelecidas,
clique em Edit|Edit Widgets para deixar o modo de conexões.
Salve o diálogo como sortdialog.ui em um diretório chamado sort. Para adicionar código ao
formulário, nós usaremos o mesmo principio de herança múltipla que usamos para o diálogo
“Go to Cell” na seção anterior.
Primeiro, crie um arquivo sortdialog.h com o seguinte conteúdo:
#ifndef SORTDIALOG_H
#define SORTDIALOG_H
#include <QDialog>
#include "ui_sortdialog.h"
class SortDialog : public QDialog, public Ui::SortDialog
{
Q_OBJECT
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
38 public:
SortDialog(QWidget *parent = 0);
void setColumnRange(QChar first, QChar last);
};
#endif
Agora crie o sortdialog.cpp:
1 #include <QtGui>
2 #include "sortdialog.h"
3 SortDialog::SortDialog(QWidget *parent)
4 : QDialog(parent)
5 {
6 setupUi(this);
7 secondaryGroupBox->hide();
8 tertiaryGroupBox->hide();
9 layout()->setSizeConstraint(QLayout::SetFixedSize);
10 setColumnRange('A', 'Z');
11 }
12 void SortDialog::setColumnRange(QChar first, QChar last)
13 {
14 primaryColumnCombo->clear();
15 secondaryColumnCombo->clear();
16 tertiaryColumnCombo->clear();
17 secondaryColumnCombo->addItem(tr("None"));
18 tertiaryColumnCombo->addItem(tr("None"));
19 primaryColumnCombo->setMinimumSize(
20 secondaryColumnCombo->sizeHint());
21 QChar ch = first;
22 while (ch <= last) {
23 primaryColumnCombo->addItem(QString(ch));
24 secondaryColumnCombo->addItem(QString(ch));
25 tertiaryColumnCombo->addItem(QString(ch));
26 ch = ch.unicode() + 1;
27 }
28 }
O construtor esconde as partes secundárias e terciárias do diálogo. Ele também define a
propriedade sizeContraint do layout do formulário para QLayout::SetFixedSize, fazendo
com que o diálogo se torne não redimensionável pelo usuário. O layout, então, assume a
responsabilidade de redimensionar e dimensiona o diálogo automaticamente quando widgets
são mostrados ou escondidos, garantindo que o diálogo será sempre mostrado no melhor
tamanho.
O slot setColumnRange() inicializa o conteúdo dos combo boxes baseado nas colunas
selecionadas da planilha. Inserimos um item chamado “None” para as chaves (opcionais)
secundária e terciária.
As linhas 19 e 20 apresentam uma linguagem sutil de layout. A função QWidget::sizeHint()
retorna o „tamanho ideal‟ do widget, que o sistema de layout tenta seguir. Isso explica porque
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
39
diferentes tipos de widgets, ou widgets similares com conteúdos diferentes, podem ser
designados com diferentes tamanhos pelo sistema de layout. Para comboboxes, isso significa
que os comboboxes secundário e terciário, que contém “None”, acabam maiores que o
primeiro combobox, que contém só entradas de letras individuais. Para evitar essa
inconsistência, nós definimos o tamanho máximo da primeira combobox para o tamanho ideal
do segundo combobox.
Aqui está uma função teste main() que define o intervalo para incluir as colunas de „C‟ a „F‟ e
depois mostra o diálogo:
#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 diálogo de extensão. Como o exemplo mostra, este tipo de diálogo não é tão
mais difícil de desenhar do que o diálogo plano: Tudo que precisamos era um botão de
alternância, algumas conexões extras, e um layout não redimensionável. Em aplicações de
produção, é bem comum que o botão de alternância tenha o texto “Advanced >>>” quando o
diálog básico é exibido e “Advanced <<<” quando a extensão é mostrada. Isso é fácil de
conseguir com Qt chamando setText() no QPushButton sempre que for clicado.
O outro tipo comum de diálogos que mudam as formas, diálogos de múltiplas páginas, são até
mais fáceis de criar em Qt, tanto por código ou com o Qt Designer. Tais diálogos podem ser
construídos 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 página 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.
Nós falaremos mais da classe QStackedWidget no Capítulo 6.
Dialogs Dinâmicos
Dialogs dinâmicos são aqueles que são criados em tempo de execução a partir de arquivos .ui
produzidos no Qt Designer. Ao invés de converter o arquivo .ui para código C++ utilizando
uic, nós podemos carregar o arquivo em tempo de execução usando a classe QUiLoader:
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
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 função findChild<T>() é uma função membro template que retorna o objeto filho que
corresponde com o nome e tipo de dados. Por causa de uma limitação do compilador, isso não
está disponível para MSVC 6. Se você precisa usar o compilador MSVC 6, utilize a função
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 aplicação Qt, nós devemos adicionar esta linha ao arquivo .pro da aplicação:
CONFIG += uitools
Diálogos dinâmicos tornam possível mudar o layout de um formulário sem recompilar a
aplicação. Eles podem também ser usados para criar aplicações “thin-client”, onde o
executável meramente tem um formulário front-end interno e todos os outros formulários são
criados quando necessário.
Classes Nativas de Widgets e Dialogs
O Qt fornece um conjunto completo de widgets nativos e diálogos comuns que atendem a
maioria das situações. Nesta seção, apresentamos as imagens de quase todos eles. Alguns
widgets especializados são adiados: Cobrimos widgets de mainwindows, como QMenuBar,
QToolBar e QStatusBar no Capítulo 3, e nós cobrimos widgets relacionados ao layout, como
QSplitter e QScrollArea no Capítulo 6. A maioria dos widgets nativos e diálogos são usados
nos exemplos apresentados neste livro. Nas imagens mostradas nas Figuras 2.17 até 2.26,
todos os widgets são mostrados usando o estilo Plastique.
Figura 2.17. Botões do Qt
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
41
Figura 2.18. Containers de página única do Qt
Figura 2.19. Containers de múltiplas páginas do Qt
Figura 2.20. Item views do Qt
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
42
Figura 2.21. Widgets de exibição do Qt
Figura 2.22. Widgets de entrada do Qt
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
43
Figura 2.23. Diálogos de feedback do Qt
Figura 2.24. Diálogos de fonte e cor do Qt
Figura 2.25. Diálogos de impressão e arquivo do Qt
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
44
Figura 2.26. Diálogo Qwizard do Qt
O Qt oferece quatro tipos de "botões": QPushButton, QToolButton, QCheckBox e
QRadioButton, eles são mostrados na Figura 2.17. QPushButton e QToolButton são mais
comumente usados para iniciar uma ação quando clicados, mas eles também podem se
comportar como botões de alternância (clique para afundar, clique para restaurar). QCheckBox
pode ser usado para independentes opções on/off, enquanto QRadioButtons normalmente são
mutuamente exclusivos.
Widgets containers do Qt são widgets que contêm outros widgets. Eles são mostrados na
Figura 2.18 e Figura 2.19. QFrame também 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 são widgets multi-página. Cada página é um widget filho, e as páginas
são numeradas a partir de 0. Para QTabWidgets, tanto a forma como a posição das guias
podem ser definidos.
Os item views, mostrados na Figura 2.20, são 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 especificações 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 são documentadas em
http://doc.trolltech.com/4.3/richtext-html-subset.html.
O Qt oferece alguns widgets que são utilizados exclusivamente para exibição de informações,
eles são 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 contrário de QLabel, ela fornece automaticamente as barras de
rolagem quando necessário, e também fornece amplo suporte para teclado e mouse. O Qt
Assistant 4.3 usa QTextBrowser para apresentar a documentação para o usuário.
O Qt fornece diversos widgets para entrada de dados, como mostrado na Figura 2.22.
QLineEdit pode restringir a sua entrada usando uma máscara de entrada, um validador, ou
C++ GUI Programando com Qt4, Segunda Edição
Tradução livre realizada pelos membros do Fórum QtBrasil
www.qtbrasil.com
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 são totalmente integrados com a área de transferência.
O Qt fornece uma caixa de mensagem versátil e um diálogo de erro que lembra quais
mensagens mostrou, estes são mostrados na Figura 2.23. O progresso das operações
demoradas pode ser indicado através da QProgressDialog ou usando a QProgressBar
mostrado na Figura 2.21. QInputDialog é muito conveniente quando uma única linha de texto
ou um número único é exigido do usuário.
O Qt fornece o conjunto padrão de diálogos comuns que tornam mais fácil pedir ao usuário
para selecionar uma cor, fonte, ou arquivo, ou para imprimir um documento. Estes são
mostrados na Figura 2.24 e Figura 2.25.
No Windows e no Mac OS X, o Qt usa os diálogos nativos, em vez de seus próprios diálogos
comuns quando possível. As cores também podem ser escolhidas através de um dos widgets
de seleção de cores do Qt Solutions, e fontes podem ser escolhidas usando QFontComboBox.
Finalmente, QWizard fornece uma estrutura para a criação de wizards (também chamados de
assistentes no Mac OS X). Wizards são úteis para tarefas complexas ou pouco freqüentes que
os usuários podem ter dificuldade em aprender. Um exemplo de um assistente é mostrado na
Figura 2.26.
Muitas funcionalidades prontas para uso são fornecidas pelos widgets e diálogos 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 diálogos fornecidos com o Qt é adequado, um pode
estar disponível a partir do Qt Solutions, ou de versões comerciais ou não comerciais de
terceiros. O Qt Solutions oferece um conjunto de widgets adicionais, incluindo selecionadores
de cores diferentes, um controle de botão giratório, menus de pizza, e um navegador de
propriedade, bem como uma caixa de diálogo de cópia.
Em algumas situações, pode ser desejável 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 Capítulo 5 explica como criar widgets
personalizados.

Contenu connexe

Tendances

Usando Git na Unity - Gaming For All 2021
Usando Git na Unity - Gaming For All 2021Usando Git na Unity - Gaming For All 2021
Usando Git na Unity - Gaming For All 2021Erik Cruz
 
Minicurso wxWidgets
Minicurso wxWidgetsMinicurso wxWidgets
Minicurso wxWidgetsRenzo Petri
 
Apresentação wxWidgets
Apresentação wxWidgetsApresentação wxWidgets
Apresentação wxWidgetsRenzo Petri
 
CURSO DELPHI FUND. CLIENT SERVER (DIURNO)
CURSO DELPHI FUND. CLIENT SERVER (DIURNO) CURSO DELPHI FUND. CLIENT SERVER (DIURNO)
CURSO DELPHI FUND. CLIENT SERVER (DIURNO) Grupo Treinar
 
Data Binding Para Vinculo de Dados na UI Android
Data Binding Para Vinculo de Dados na UI AndroidData Binding Para Vinculo de Dados na UI Android
Data Binding Para Vinculo de Dados na UI AndroidVinícius Thiengo
 
Leitor de Códigos no Android com Barcode Scanner API - ZXing
Leitor de Códigos no Android com Barcode Scanner API - ZXingLeitor de Códigos no Android com Barcode Scanner API - ZXing
Leitor de Códigos no Android com Barcode Scanner API - ZXingVinícius Thiengo
 
Introdução ao Github actions - TDC Connections
Introdução ao Github actions - TDC ConnectionsIntrodução ao Github actions - TDC Connections
Introdução ao Github actions - TDC ConnectionsGuillaume Falourd
 
Introdução a Arquitetura Android
Introdução a Arquitetura AndroidIntrodução a Arquitetura Android
Introdução a Arquitetura AndroidMaycon Viana Bordin
 

Tendances (10)

Usando Git na Unity - Gaming For All 2021
Usando Git na Unity - Gaming For All 2021Usando Git na Unity - Gaming For All 2021
Usando Git na Unity - Gaming For All 2021
 
Minicurso wxWidgets
Minicurso wxWidgetsMinicurso wxWidgets
Minicurso wxWidgets
 
Apresentação wxWidgets
Apresentação wxWidgetsApresentação wxWidgets
Apresentação wxWidgets
 
CURSO DELPHI FUND. CLIENT SERVER (DIURNO)
CURSO DELPHI FUND. CLIENT SERVER (DIURNO) CURSO DELPHI FUND. CLIENT SERVER (DIURNO)
CURSO DELPHI FUND. CLIENT SERVER (DIURNO)
 
GIT Básico
GIT BásicoGIT Básico
GIT Básico
 
Data Binding Para Vinculo de Dados na UI Android
Data Binding Para Vinculo de Dados na UI AndroidData Binding Para Vinculo de Dados na UI Android
Data Binding Para Vinculo de Dados na UI Android
 
Leitor de Códigos no Android com Barcode Scanner API - ZXing
Leitor de Códigos no Android com Barcode Scanner API - ZXingLeitor de Códigos no Android com Barcode Scanner API - ZXing
Leitor de Códigos no Android com Barcode Scanner API - ZXing
 
Introdução ao Github actions - TDC Connections
Introdução ao Github actions - TDC ConnectionsIntrodução ao Github actions - TDC Connections
Introdução ao Github actions - TDC Connections
 
Introdução a Arquitetura Android
Introdução a Arquitetura AndroidIntrodução a Arquitetura Android
Introdução a Arquitetura Android
 
Android juliana-mono
Android juliana-monoAndroid juliana-mono
Android juliana-mono
 

Similaire à c-gui-programming-with-qt-4-2ndedition -Cap1e2

Drupal Camp CI&T - Kubernetes and Google Container Engine
Drupal Camp CI&T - Kubernetes and Google Container EngineDrupal Camp CI&T - Kubernetes and Google Container Engine
Drupal Camp CI&T - Kubernetes and Google Container EngineFrancis Fernandes da Luz
 
ASP.NET 5 - Novidades do Desenvolvimento Web em .NET
ASP.NET 5 - Novidades do Desenvolvimento Web em .NETASP.NET 5 - Novidades do Desenvolvimento Web em .NET
ASP.NET 5 - Novidades do Desenvolvimento Web em .NETRenato Groff
 
Qt tchelinux-2010
Qt tchelinux-2010Qt tchelinux-2010
Qt tchelinux-2010Wagner Reck
 
Ferramentas de Planejamento e Acompanhamento
Ferramentas de Planejamento e AcompanhamentoFerramentas de Planejamento e Acompanhamento
Ferramentas de Planejamento e AcompanhamentoRodrigo Azevedo
 
Desenvolvimento orientado a objetos com C++ e QT4 - Henrique Marks
Desenvolvimento orientado a objetos com C++ e QT4 - Henrique MarksDesenvolvimento orientado a objetos com C++ e QT4 - Henrique Marks
Desenvolvimento orientado a objetos com C++ e QT4 - Henrique MarksTchelinux
 
Webinar: Qt: um toolkit, um código-fonte, múltiplas plataformas
Webinar: Qt: um toolkit, um código-fonte, múltiplas plataformasWebinar: Qt: um toolkit, um código-fonte, múltiplas plataformas
Webinar: Qt: um toolkit, um código-fonte, múltiplas plataformasEmbarcados
 
DevOps + Kubernetes: orquestração e deployment automatizado de containers - O...
DevOps + Kubernetes: orquestração e deployment automatizado de containers - O...DevOps + Kubernetes: orquestração e deployment automatizado de containers - O...
DevOps + Kubernetes: orquestração e deployment automatizado de containers - O...Renato Groff
 
Apresentação Docker
Apresentação DockerApresentação Docker
Apresentação DockerAndré Justi
 
Docker de ponta a ponta: do Desenvolvimento à Nuvem - Azure Talks - Agosto-2018
Docker de ponta a ponta: do Desenvolvimento à Nuvem - Azure Talks - Agosto-2018Docker de ponta a ponta: do Desenvolvimento à Nuvem - Azure Talks - Agosto-2018
Docker de ponta a ponta: do Desenvolvimento à Nuvem - Azure Talks - Agosto-2018Renato Groff
 
Docker para Desenvolvedores .NET - .NET SP - Novembro-2018
Docker para Desenvolvedores .NET - .NET SP - Novembro-2018Docker para Desenvolvedores .NET - .NET SP - Novembro-2018
Docker para Desenvolvedores .NET - .NET SP - Novembro-2018Renato Groff
 
Docker de ponta a ponta - do Desenvolvimento à Nuvem - .NET SP - Outubro-2018
Docker de ponta a ponta - do Desenvolvimento à Nuvem - .NET SP - Outubro-2018Docker de ponta a ponta - do Desenvolvimento à Nuvem - .NET SP - Outubro-2018
Docker de ponta a ponta - do Desenvolvimento à Nuvem - .NET SP - Outubro-2018Renato Groff
 
ASP.NET 5 - Novidades do Desenvolvimento Web em .NET (Agosto/2015)
ASP.NET 5 - Novidades do Desenvolvimento Web em .NET (Agosto/2015)ASP.NET 5 - Novidades do Desenvolvimento Web em .NET (Agosto/2015)
ASP.NET 5 - Novidades do Desenvolvimento Web em .NET (Agosto/2015)Renato Groff
 
Entendendo Frameworks web com Python
Entendendo Frameworks web com PythonEntendendo Frameworks web com Python
Entendendo Frameworks web com PythonLuiz Aldabalde
 
Entendendo Framework Web com Python
Entendendo Framework Web com PythonEntendendo Framework Web com Python
Entendendo Framework Web com PythonPythOnRio
 
Docker de ponta a ponta: do Desenvolvimento à Nuvem - UNICID - Novembro-2019
Docker de ponta a ponta: do Desenvolvimento à Nuvem - UNICID - Novembro-2019Docker de ponta a ponta: do Desenvolvimento à Nuvem - UNICID - Novembro-2019
Docker de ponta a ponta: do Desenvolvimento à Nuvem - UNICID - Novembro-2019Renato Groff
 
Desenvolvendo Aplicações Android com Qt
Desenvolvendo Aplicações Android com QtDesenvolvendo Aplicações Android com Qt
Desenvolvendo Aplicações Android com QtSandro Andrade
 
Dev401 novos recursos do microsoft visual basic 2010
Dev401 novos recursos do microsoft visual basic 2010Dev401 novos recursos do microsoft visual basic 2010
Dev401 novos recursos do microsoft visual basic 2010Alexandre Tarifa
 
Desenvolvimento de Aplicações com Visual Studio
Desenvolvimento de Aplicações com Visual StudioDesenvolvimento de Aplicações com Visual Studio
Desenvolvimento de Aplicações com Visual StudioGeovani Ferreira Gonçalves
 
Cloud Solutions com Microsoft Azure - Azure Talks - Novembro-2019
Cloud Solutions com Microsoft Azure - Azure Talks - Novembro-2019Cloud Solutions com Microsoft Azure - Azure Talks - Novembro-2019
Cloud Solutions com Microsoft Azure - Azure Talks - Novembro-2019Renato Groff
 

Similaire à c-gui-programming-with-qt-4-2ndedition -Cap1e2 (20)

Drupal Camp CI&T - Kubernetes and Google Container Engine
Drupal Camp CI&T - Kubernetes and Google Container EngineDrupal Camp CI&T - Kubernetes and Google Container Engine
Drupal Camp CI&T - Kubernetes and Google Container Engine
 
ASP.NET 5 - Novidades do Desenvolvimento Web em .NET
ASP.NET 5 - Novidades do Desenvolvimento Web em .NETASP.NET 5 - Novidades do Desenvolvimento Web em .NET
ASP.NET 5 - Novidades do Desenvolvimento Web em .NET
 
Qt tchelinux-2010
Qt tchelinux-2010Qt tchelinux-2010
Qt tchelinux-2010
 
Introdução ao Qt
Introdução ao QtIntrodução ao Qt
Introdução ao Qt
 
Ferramentas de Planejamento e Acompanhamento
Ferramentas de Planejamento e AcompanhamentoFerramentas de Planejamento e Acompanhamento
Ferramentas de Planejamento e Acompanhamento
 
Desenvolvimento orientado a objetos com C++ e QT4 - Henrique Marks
Desenvolvimento orientado a objetos com C++ e QT4 - Henrique MarksDesenvolvimento orientado a objetos com C++ e QT4 - Henrique Marks
Desenvolvimento orientado a objetos com C++ e QT4 - Henrique Marks
 
Webinar: Qt: um toolkit, um código-fonte, múltiplas plataformas
Webinar: Qt: um toolkit, um código-fonte, múltiplas plataformasWebinar: Qt: um toolkit, um código-fonte, múltiplas plataformas
Webinar: Qt: um toolkit, um código-fonte, múltiplas plataformas
 
DevOps + Kubernetes: orquestração e deployment automatizado de containers - O...
DevOps + Kubernetes: orquestração e deployment automatizado de containers - O...DevOps + Kubernetes: orquestração e deployment automatizado de containers - O...
DevOps + Kubernetes: orquestração e deployment automatizado de containers - O...
 
Apresentação Docker
Apresentação DockerApresentação Docker
Apresentação Docker
 
Docker de ponta a ponta: do Desenvolvimento à Nuvem - Azure Talks - Agosto-2018
Docker de ponta a ponta: do Desenvolvimento à Nuvem - Azure Talks - Agosto-2018Docker de ponta a ponta: do Desenvolvimento à Nuvem - Azure Talks - Agosto-2018
Docker de ponta a ponta: do Desenvolvimento à Nuvem - Azure Talks - Agosto-2018
 
Docker para Desenvolvedores .NET - .NET SP - Novembro-2018
Docker para Desenvolvedores .NET - .NET SP - Novembro-2018Docker para Desenvolvedores .NET - .NET SP - Novembro-2018
Docker para Desenvolvedores .NET - .NET SP - Novembro-2018
 
Docker de ponta a ponta - do Desenvolvimento à Nuvem - .NET SP - Outubro-2018
Docker de ponta a ponta - do Desenvolvimento à Nuvem - .NET SP - Outubro-2018Docker de ponta a ponta - do Desenvolvimento à Nuvem - .NET SP - Outubro-2018
Docker de ponta a ponta - do Desenvolvimento à Nuvem - .NET SP - Outubro-2018
 
ASP.NET 5 - Novidades do Desenvolvimento Web em .NET (Agosto/2015)
ASP.NET 5 - Novidades do Desenvolvimento Web em .NET (Agosto/2015)ASP.NET 5 - Novidades do Desenvolvimento Web em .NET (Agosto/2015)
ASP.NET 5 - Novidades do Desenvolvimento Web em .NET (Agosto/2015)
 
Entendendo Frameworks web com Python
Entendendo Frameworks web com PythonEntendendo Frameworks web com Python
Entendendo Frameworks web com Python
 
Entendendo Framework Web com Python
Entendendo Framework Web com PythonEntendendo Framework Web com Python
Entendendo Framework Web com Python
 
Docker de ponta a ponta: do Desenvolvimento à Nuvem - UNICID - Novembro-2019
Docker de ponta a ponta: do Desenvolvimento à Nuvem - UNICID - Novembro-2019Docker de ponta a ponta: do Desenvolvimento à Nuvem - UNICID - Novembro-2019
Docker de ponta a ponta: do Desenvolvimento à Nuvem - UNICID - Novembro-2019
 
Desenvolvendo Aplicações Android com Qt
Desenvolvendo Aplicações Android com QtDesenvolvendo Aplicações Android com Qt
Desenvolvendo Aplicações Android com Qt
 
Dev401 novos recursos do microsoft visual basic 2010
Dev401 novos recursos do microsoft visual basic 2010Dev401 novos recursos do microsoft visual basic 2010
Dev401 novos recursos do microsoft visual basic 2010
 
Desenvolvimento de Aplicações com Visual Studio
Desenvolvimento de Aplicações com Visual StudioDesenvolvimento de Aplicações com Visual Studio
Desenvolvimento de Aplicações com Visual Studio
 
Cloud Solutions com Microsoft Azure - Azure Talks - Novembro-2019
Cloud Solutions com Microsoft Azure - Azure Talks - Novembro-2019Cloud Solutions com Microsoft Azure - Azure Talks - Novembro-2019
Cloud Solutions com Microsoft Azure - Azure Talks - Novembro-2019
 

Plus de Cedemir Pereira (9)

cdr-intro.pdf
cdr-intro.pdfcdr-intro.pdf
cdr-intro.pdf
 
Livro Cidades Inteligentes(2)-31-66.pdf
Livro Cidades Inteligentes(2)-31-66.pdfLivro Cidades Inteligentes(2)-31-66.pdf
Livro Cidades Inteligentes(2)-31-66.pdf
 
slidesWtisc(1).pptx
slidesWtisc(1).pptxslidesWtisc(1).pptx
slidesWtisc(1).pptx
 
Cap11
Cap11Cap11
Cap11
 
Cap9
Cap9Cap9
Cap9
 
Cap7
Cap7Cap7
Cap7
 
Cap6
Cap6Cap6
Cap6
 
Cap4
Cap4Cap4
Cap4
 
Cap12
Cap12Cap12
Cap12
 

Dernier

Apresente de forma sucinta as atividades realizadas ao longo do semestre, con...
Apresente de forma sucinta as atividades realizadas ao longo do semestre, con...Apresente de forma sucinta as atividades realizadas ao longo do semestre, con...
Apresente de forma sucinta as atividades realizadas ao longo do semestre, con...Colaborar Educacional
 
A CONCEPÇÃO FILO/SOCIOLÓGICA DE KARL MARX
A CONCEPÇÃO FILO/SOCIOLÓGICA DE KARL MARXA CONCEPÇÃO FILO/SOCIOLÓGICA DE KARL MARX
A CONCEPÇÃO FILO/SOCIOLÓGICA DE KARL MARXHisrelBlog
 
Trabalho DAC História 25 de Abril de 1974
Trabalho DAC História 25 de Abril de 1974Trabalho DAC História 25 de Abril de 1974
Trabalho DAC História 25 de Abril de 1974AnaRitaFreitas7
 
Poder do convencimento,........... .
Poder do convencimento,...........         .Poder do convencimento,...........         .
Poder do convencimento,........... .WAGNERJESUSDACUNHA
 
Slides Lição 1, CPAD, O Início da Caminhada, 2Tr24, Pr Henrique.pptx
Slides Lição 1, CPAD, O Início da Caminhada, 2Tr24, Pr Henrique.pptxSlides Lição 1, CPAD, O Início da Caminhada, 2Tr24, Pr Henrique.pptx
Slides Lição 1, CPAD, O Início da Caminhada, 2Tr24, Pr Henrique.pptxLuizHenriquedeAlmeid6
 
FORMAÇÃO POVO BRASILEIRO atividade de história
FORMAÇÃO POVO BRASILEIRO atividade de históriaFORMAÇÃO POVO BRASILEIRO atividade de história
FORMAÇÃO POVO BRASILEIRO atividade de históriaBenigno Andrade Vieira
 
AS REBELIÕES NA AMERICA IBERICA (Prof. Francisco Leite)
AS REBELIÕES NA AMERICA IBERICA (Prof. Francisco Leite)AS REBELIÕES NA AMERICA IBERICA (Prof. Francisco Leite)
AS REBELIÕES NA AMERICA IBERICA (Prof. Francisco Leite)profesfrancleite
 
autismo conhecer.pptx, Conhecer para entender
autismo conhecer.pptx, Conhecer para entenderautismo conhecer.pptx, Conhecer para entender
autismo conhecer.pptx, Conhecer para entenderLucliaResende1
 
PROJETO DE EXTENSÃO - SEGURANÇA, INOVAÇÃO E SUSTENTABILIDADE PARA O BEM COMUM...
PROJETO DE EXTENSÃO - SEGURANÇA, INOVAÇÃO E SUSTENTABILIDADE PARA O BEM COMUM...PROJETO DE EXTENSÃO - SEGURANÇA, INOVAÇÃO E SUSTENTABILIDADE PARA O BEM COMUM...
PROJETO DE EXTENSÃO - SEGURANÇA, INOVAÇÃO E SUSTENTABILIDADE PARA O BEM COMUM...Colaborar Educacional
 
Poema sobre o mosquito Aedes aegipyti -
Poema sobre o mosquito Aedes aegipyti  -Poema sobre o mosquito Aedes aegipyti  -
Poema sobre o mosquito Aedes aegipyti -Mary Alvarenga
 
Depende De Nós! José Ernesto Ferraresso.ppsx
Depende De Nós! José Ernesto Ferraresso.ppsxDepende De Nós! José Ernesto Ferraresso.ppsx
Depende De Nós! José Ernesto Ferraresso.ppsxLuzia Gabriele
 
SEMIOSES DO OLHAR - SLIDE PARA ESTUDO 123
SEMIOSES DO OLHAR - SLIDE PARA ESTUDO 123SEMIOSES DO OLHAR - SLIDE PARA ESTUDO 123
SEMIOSES DO OLHAR - SLIDE PARA ESTUDO 123JaineCarolaineLima
 
Treinamento de Avaliação de Desempenho HBB
Treinamento de Avaliação de Desempenho HBBTreinamento de Avaliação de Desempenho HBB
Treinamento de Avaliação de Desempenho HBBDiegoFelicioTexeira
 
Apresentação sobrea dengue educação.pptx
Apresentação sobrea dengue educação.pptxApresentação sobrea dengue educação.pptx
Apresentação sobrea dengue educação.pptxtaloAugusto8
 
ARTE BARROCA E ROCOCO BRASILEIRO-min.pdf
ARTE BARROCA E ROCOCO BRASILEIRO-min.pdfARTE BARROCA E ROCOCO BRASILEIRO-min.pdf
ARTE BARROCA E ROCOCO BRASILEIRO-min.pdfItaloAtsoc
 
Ressonancia_magnetica_basica_slide_da_net.pptx
Ressonancia_magnetica_basica_slide_da_net.pptxRessonancia_magnetica_basica_slide_da_net.pptx
Ressonancia_magnetica_basica_slide_da_net.pptxPatriciaFarias81
 
Aula 6 - O Imperialismo e seu discurso civilizatório.pptx
Aula 6 - O Imperialismo e seu discurso civilizatório.pptxAula 6 - O Imperialismo e seu discurso civilizatório.pptx
Aula 6 - O Imperialismo e seu discurso civilizatório.pptxMarceloDosSantosSoar3
 
Cruzadinha da dengue - Mosquito Aedes aegypti
Cruzadinha da dengue - Mosquito Aedes aegyptiCruzadinha da dengue - Mosquito Aedes aegypti
Cruzadinha da dengue - Mosquito Aedes aegyptiMary Alvarenga
 
Como fazer um Feedback Eficaz - Comitê de Gestores
Como fazer um Feedback Eficaz - Comitê de GestoresComo fazer um Feedback Eficaz - Comitê de Gestores
Como fazer um Feedback Eficaz - Comitê de GestoresEu Prefiro o Paraíso.
 

Dernier (20)

Apresente de forma sucinta as atividades realizadas ao longo do semestre, con...
Apresente de forma sucinta as atividades realizadas ao longo do semestre, con...Apresente de forma sucinta as atividades realizadas ao longo do semestre, con...
Apresente de forma sucinta as atividades realizadas ao longo do semestre, con...
 
A CONCEPÇÃO FILO/SOCIOLÓGICA DE KARL MARX
A CONCEPÇÃO FILO/SOCIOLÓGICA DE KARL MARXA CONCEPÇÃO FILO/SOCIOLÓGICA DE KARL MARX
A CONCEPÇÃO FILO/SOCIOLÓGICA DE KARL MARX
 
Trabalho DAC História 25 de Abril de 1974
Trabalho DAC História 25 de Abril de 1974Trabalho DAC História 25 de Abril de 1974
Trabalho DAC História 25 de Abril de 1974
 
Poder do convencimento,........... .
Poder do convencimento,...........         .Poder do convencimento,...........         .
Poder do convencimento,........... .
 
Slides Lição 1, CPAD, O Início da Caminhada, 2Tr24, Pr Henrique.pptx
Slides Lição 1, CPAD, O Início da Caminhada, 2Tr24, Pr Henrique.pptxSlides Lição 1, CPAD, O Início da Caminhada, 2Tr24, Pr Henrique.pptx
Slides Lição 1, CPAD, O Início da Caminhada, 2Tr24, Pr Henrique.pptx
 
FORMAÇÃO POVO BRASILEIRO atividade de história
FORMAÇÃO POVO BRASILEIRO atividade de históriaFORMAÇÃO POVO BRASILEIRO atividade de história
FORMAÇÃO POVO BRASILEIRO atividade de história
 
AS REBELIÕES NA AMERICA IBERICA (Prof. Francisco Leite)
AS REBELIÕES NA AMERICA IBERICA (Prof. Francisco Leite)AS REBELIÕES NA AMERICA IBERICA (Prof. Francisco Leite)
AS REBELIÕES NA AMERICA IBERICA (Prof. Francisco Leite)
 
autismo conhecer.pptx, Conhecer para entender
autismo conhecer.pptx, Conhecer para entenderautismo conhecer.pptx, Conhecer para entender
autismo conhecer.pptx, Conhecer para entender
 
PROJETO DE EXTENSÃO - SEGURANÇA, INOVAÇÃO E SUSTENTABILIDADE PARA O BEM COMUM...
PROJETO DE EXTENSÃO - SEGURANÇA, INOVAÇÃO E SUSTENTABILIDADE PARA O BEM COMUM...PROJETO DE EXTENSÃO - SEGURANÇA, INOVAÇÃO E SUSTENTABILIDADE PARA O BEM COMUM...
PROJETO DE EXTENSÃO - SEGURANÇA, INOVAÇÃO E SUSTENTABILIDADE PARA O BEM COMUM...
 
Abordagens 4 (Problematização) e 5 (Síntese pessoal) do texto de Severino (20...
Abordagens 4 (Problematização) e 5 (Síntese pessoal) do texto de Severino (20...Abordagens 4 (Problematização) e 5 (Síntese pessoal) do texto de Severino (20...
Abordagens 4 (Problematização) e 5 (Síntese pessoal) do texto de Severino (20...
 
Poema sobre o mosquito Aedes aegipyti -
Poema sobre o mosquito Aedes aegipyti  -Poema sobre o mosquito Aedes aegipyti  -
Poema sobre o mosquito Aedes aegipyti -
 
Depende De Nós! José Ernesto Ferraresso.ppsx
Depende De Nós! José Ernesto Ferraresso.ppsxDepende De Nós! José Ernesto Ferraresso.ppsx
Depende De Nós! José Ernesto Ferraresso.ppsx
 
SEMIOSES DO OLHAR - SLIDE PARA ESTUDO 123
SEMIOSES DO OLHAR - SLIDE PARA ESTUDO 123SEMIOSES DO OLHAR - SLIDE PARA ESTUDO 123
SEMIOSES DO OLHAR - SLIDE PARA ESTUDO 123
 
Treinamento de Avaliação de Desempenho HBB
Treinamento de Avaliação de Desempenho HBBTreinamento de Avaliação de Desempenho HBB
Treinamento de Avaliação de Desempenho HBB
 
Apresentação sobrea dengue educação.pptx
Apresentação sobrea dengue educação.pptxApresentação sobrea dengue educação.pptx
Apresentação sobrea dengue educação.pptx
 
ARTE BARROCA E ROCOCO BRASILEIRO-min.pdf
ARTE BARROCA E ROCOCO BRASILEIRO-min.pdfARTE BARROCA E ROCOCO BRASILEIRO-min.pdf
ARTE BARROCA E ROCOCO BRASILEIRO-min.pdf
 
Ressonancia_magnetica_basica_slide_da_net.pptx
Ressonancia_magnetica_basica_slide_da_net.pptxRessonancia_magnetica_basica_slide_da_net.pptx
Ressonancia_magnetica_basica_slide_da_net.pptx
 
Aula 6 - O Imperialismo e seu discurso civilizatório.pptx
Aula 6 - O Imperialismo e seu discurso civilizatório.pptxAula 6 - O Imperialismo e seu discurso civilizatório.pptx
Aula 6 - O Imperialismo e seu discurso civilizatório.pptx
 
Cruzadinha da dengue - Mosquito Aedes aegypti
Cruzadinha da dengue - Mosquito Aedes aegyptiCruzadinha da dengue - Mosquito Aedes aegypti
Cruzadinha da dengue - Mosquito Aedes aegypti
 
Como fazer um Feedback Eficaz - Comitê de Gestores
Como fazer um Feedback Eficaz - Comitê de GestoresComo fazer um Feedback Eficaz - Comitê de Gestores
Como fazer um Feedback Eficaz - Comitê de Gestores
 

c-gui-programming-with-qt-4-2ndedition -Cap1e2

  • 1. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 1 Autores: Jasmin Blanchette e Mark Summerfield Tradução por: Danilo Domingos, Arthur dos Santos Dias Revisão e edição por: Thiago Rossener Nogueira Visão Geral O único oficialmente publicado guia das melhores práticas para programação Qt 4.3 Usando o Qt da Trolltech é possível criar aplicações C++ de alta performance que rodem em máquinas Windows, Linux/Unix, Mac OS X, e demais extensões Linux sem que seja necessário fazer alterações de código. Agora, dois membros da Trolltech lhe oferecem este guia completo para que você alcance resultados surpreendentes com a mais recente versão do Qt: Qt 4.3. Carregado com exemplos práticos, realistas e conselhos profundos, este é o livro usado pela Trolltech para ensinar Qt para seus próprios novos funcionários. Revisado e expandido constantemente, este livro nos revela os melhores padrões atuais para se trabalhar com Qt para diversos usos, que vão desde implementação de arquiteturas de modelagem até o uso da engine gráfica do Qt 4.3. Você encontrará soluções para diversas tarefas de desenvolvimento GUI, assim como técnicas sofisticadas para sistemas com acesso a banco de dados, integração com XML, uso de subclasses, composição, e muito mais. Seja você um novo usuário de Qt, ou um usuário antigo que está aprendendo a nova versão, este livro certamente vai lhe ajudar a tirar vantagem de tudo que o Qt 4.3 é capaz de fazer. Eis algumas novidades que encontrarão neste livro:  Atualizado completamente, com uma novíssima cobertura de banco de dados, XML, e programação Qtopia.  Cobertura de tudo que mudou do Qt 4.2 para 4.3, incluindo integração com Windows Vista, suporte nativo a CSS para estilização de aplicativos, e geração de arquivos SVG.  Capítulos separados para assuntos relacionados a 2D e 3D, cobertura das novas classes de visualização gráfica do Qt 4.3, além de uma cobertura total do QPainter‟s OpenGL.  Novos capítulos a respeito de otimização look-and-feel e sobre criação de scripts para aplicações.  Ilustra a arquitetura de visualização e modelagem do Qt4, suporte a plugins, manutenção de layout, processamento de eventos, classes containers, e muito mais.  Apresenta técnicas avançadas vistas em nenhum outro livro - desde criação de plugins até interação com APIs nativas.  Inclui um novo apêndice de Qt Jambi, a nova versão Java do Qt. qtbrasil.com
  • 2. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 2 Tabela de Conteúdos Parte 1: Qt Básico Capítulo 1: Começando Hello Qt Fazendo Conexões Alinhando Widgets Usando a Documentação de Referência Capítulo 2: Criando Dialogs Herdando de QDialog Signals e Slots a Fundo Design Rápido de Dialogs Modificando a Forma dos Dialogs Dialogs Dinâmicos Classes Nativas de Widgets e Dialogs Capítulo 3: Criando Janelas Principais Subclasse QMainWindow Criando Menus e Barras de Ferramentas Ajustando a Barra de Status Desenvolvendo o Menu Arquivo Usando Dialogs Armazenando Configurações Documentos Múltiplos Misturar Telas Capítulo 4: Implementação da Funcionalidade da Aplicação O Widget Central Subclasse QTableWidget Carregando e Salvando Implementação do Menu Editar Implementando os Outros Menus Subclasse QTableWidgetItem Capítulo 5: Criando Widgets Customizáveis Customizando Qt Widgets Subclasse QtWidget Integrando Widgets Customizáveis com Qt Designer Buffering Duplo Parte II: Qt Intermediário Capítulo 6: Gerenciamento de Layout Modelando Widgets em um Form Layouts Empilhados Splitters Áreas Roláveis Janelas Dock e Barras de Ferramentas Interface de Documento Múltiplo Capítulo 7: Processamento de Eventos Reimplementando Manipuladores de Eventos Instalando Filtros de Eventos Manter Respondendo durante Processamento Intensivo Capítulo 8: Gráficos 2D Pintando com QPainter Transformações de Coordenadas de Sistema Renderizando em Alta-Qualidade com QImage Renderizando Itens Básicos com Visualizadores de Gráfico Imprimindo Capítulo 9: Arrastar e Soltar Habilitando Arrastar e Soltar Suportando Tipos de Arrastar Personalizados Manipulação de Clipboard
  • 3. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 3 Capítulo 10: Classes de Visualização de Itens Usando Classes de Visualização de Itens Convenientes Usando Modelos Predefinidos Implementando Modelos Customizáveis Implementando Delegates Customizáveis Capítulo 11: Classes de Container Containers Sequenciais Containers Associativos Algoritmos Genéricos String, Byte Arrays e Variants Capítulo 12: Input/Output Lendo e Escrevendo Dados Binários Lendo e Escrevendo Texto Atravessando Diretórios Incorporando Recursos Processo Interno de Comunicação Capítulo 13: Bancos de Dados Conectando e Consultando Visualização de Tabelas Edição de Registros Usando Formulários Apresentação de Dados em Formulários Tabulares Capítulo 14: Multithreading Criação de Threads Sincronização de Threads Comunicação com a Thread Principal Usando Classes do Qt em Threads Secundárias Capítulo 15: Rede Escrevendo Clientes FTP Escrevendo Clientes HTTP Gravando Aplicativos Cliente-Servidor TCP Enviar e Receber Datagramas UDP Capítulo 16: XML Ler XML com QXmlStreamReader Ler XML com DOM Ler XML com SAX Escrever XML Capítulo 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 Avançado Capítulo 18: Internacionalização Trabalhando com Unicode Fazendo Aplicações de Tradução Consciente Troca de Linguagem Dinâmica Traduzindo Aplicações Capítulo 19: Aparência e Personalização Usando Qt Style Sheets Herdando de QStyle Capítulo 20: Gráficos 3D Desenhando Usando OpenGL Combinando OpenGL e QPainter Fazer Sobreposições Usando Objetos Framebuffer Capítulo 21: Criando Plugins Estendendo Qt com Plugins Fazendo Aplicações com Plugins Concientes
  • 4. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 4 Escrevendo Aplicações com Plugins Capítulo 22: Script de Aplicações Resumo da Linguagem EMAScript Estendendo Aplicações Qt com Script Implementando Extensões GUI Usando Scripts Automatização de Tarefas Usando Scripts Capítulo 23: Recursos Específicos da Plataforma Interface com APIs Nativas Usando o ActiveX no Windows Manipulação de Gerenciamento de Sessão X11 Capítulo 24: Programação Incorporada Introdução ao Qt/ Incorporado ao Linux Customizando Qt/ Incorporado ao Linux Integrando Aplicações Qt com Qtopia Usando APIs do Qtopia Parte IV: Apêndices Apêndice A: Obtenção e Instalação do Qt Nota sobre Licenciamento Instalando Qt/Windows Instalando Qt/Mac Instalando Qt/X11 Apêncide B: Construção de Aplicações em Qt Uso do qmake Usando Ferramentas de Terceiros para Construir Apêndice C: Introdução ao Qt Jambi Iniciando com o Qt Jambi Usando o Qt Jambi na IDE Eclipse Integrando Componentes do C++ com o Qt Jambi Apêndice D: Introdução ao C++ para Programadores Java e C# Introdução ao C++ Principais Diferenças da Linguagem Biblioteca Padrão do C++ Sobre os Autores Jasmin Blanchette Mark Summerfield Produção Índice
  • 5. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 5 Parte I: O Básico do Qt 1. Começando  Hello Qt  Fazendo Conexões  Alinhando Widgets  Usando a Documentação de Referência Este capítulo mostra como combinar C++ básico com a funcionalidade disponibilizada pelo Qt para criar algumas aplicações de interface gráfica pequenas. Este capítulo também introduz duas idéias chave do Qt: “signals e slots” e layouts. No Capítulo 2, iremos mais a fundo, e no Capítulo 3, começaremos a construir aplicações mais realísticas. Se você já conhece Java ou C# mas tem uma experiência limitada com C++, então é recomendado que você comece lendo a “Introdução ao C++” no Apêndice D. Hello Qt Vamos começar 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 definições das classes QApplication e QLabel. Para cada classe do Qt existe um arquivo header com o mesmo nome (e distinção entre maiúsculas e minúsculas) que contém a definição da classe.
  • 6. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 6 A linha 5 cria um objeto QApplication para gerenciar os recursos da aplicação no geral. O construtor de QApplication requer os argumentos argc e argv porque o Qt interpreta alguns argumentos de linha de comando próprios 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 gráfica. O termo vem da expressão “window gadget” e é equivalente a tanto “controle” como “container” na terminologia do Windows. Botões, menus, barras de rolagem e frames são exemplos de widgets. Widgets podem conter outros widgets; por exemplo, uma janela é, geralmente, um widget que contém um QMenuBar, algumas QToolBars, uma QStatusBar, e alguns outros widgets. A maioria das aplicações usa uma QMainWindow ou um QDialog como janela principal da aplicação, mas o Qt é tão flexível que qualquer widget pode ser uma janela. Neste exemplo, o widget QLabel é a janela da aplicação. A linha 7 torna a label visível. Widgets são criados, por padrão, como invisíveis para que possamos customizá-los antes de serem exibidos, deste modo evitando “flickering”. A linha 8 passa o controle da aplicação 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 ações do usuário como clicks do mouse ou então pressionamento de teclas. Ações do usuário geram eventos (também chamados de “mensagens”) para os quais o programa responde, geralmente executando uma ou mais funções. Por exemplo, quando o usuário clica em um widget, os eventos “pressionamento do botão do mouse” e “liberação do botão do mouse” são gerados. Neste ponto, aplicações gráficas diferem significativamente de programas BAT convencionais, nos quais praticamente só processam uma entrada, desenvolvem algum procedimento, e terminam sem interação humana. Por simplicidade, nós não nos preocupamos em chamar o delete para o objeto QLabel ao final da função main(). Este vazamento de memória (“memory leak”) é inofensivo num programa tão pequeno, já que a memória alocada será desalocada quando o programa terminar. Já é possível testar o programa na sua máquina. Ele deve se parecer com o mostrado na Figura 1.1. Primeiro você terá que instalar o Qt 4.3.2 (ou uma versão mais recente), este procedimento é explicado no Apêndice A. De agora em diante, vamos assumir que você tem uma cópia corretamente instalada do Qt e que o diretório bin está na sua variável PATH de ambiente. (No Windows isso é feito automaticamente pelo instalador do Qt) Você também precisará que o código deste programa esteja num arquivo hello.cpp num diretório chamado hello. Você mesmo pode escrever o arquivo hello.cpp ou copiá-lo dos exemplos que acompanham este livro, que está disponível em examples/chap01/hello/hello.cpp. (Todos os exemplos estão disponíveis no site do livro, http://www.informit.com/title/0132354160.) Figura 1.1 - Hello no Linux Do prompt de comando, vá até o diretório hello, e digite qmake –project
  • 7. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 7 para criar um arquivo projeto que é independente da plataforma, e depois digite qmake hello.pro para criar um arquivo “makefile” específico para a plataforma que está usando. (A ferramenta qmake é discutida em mais detalhes no Apêndice 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 botão fechar na barra de título da janela. Se você estiver usando o Windows e tiver instalado a versão Open Source do Qt e o compilador MinGW, você terá um atalho chamado “prompt de comando do Qt” que tem todas as variáveis de ambiente corretamente ajustadas. Se você conseguiu visualizar a janela então você pode compilar aplicações do Qt utilizando qmake e make como descritos anteriormente. Os executáveis são colocados na pasta “debug” ou “release” da aplicação (por exemplo, C:exampleschap01helloreleasehello.exe). Se você estiver utilizando o Microsoft Visual C++ com uma versão comercial do Qt, você utilizará o nmake ao invés 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 próximo 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 aplicação. Quando rodar, ela deve parecer com a Figura 1.2. Como este exemplo ilustra, é fácil diferenciar uma aplicação de interface de usuário Qt utilizando apenas uma formatação HTML. Figura 1.2: Uma label com formatação HTML básica
  • 8. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 8 Fazendo Conexões O segundo exemplo mostra como responder às ações do usuário. A aplicação consiste em um botão que o usuário pode clicar para sair. O código é muito similar ao exemplo anterior, com exceção do uso de um QPushButton no lugar de uma QLabel como nosso widget principal, e nós estamos conectando a ação do usuário (clique) a um bloco de código. O código desta aplicação está em examples/chap01/quit/quit.cpp; a aplicação em andamento é mostrada na Figura 1.3. Aqui está o conteúdo 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 aplicação que fecha Os widgets do Qt emitem sinais para indicar que uma ação de usuário ou uma mudança de estado ocorreu. [*] Por exemplo, QPushButton emite um sinal clicked() quando o usuário clica no botão. Um sinal pode se conectar com uma função (chamada de slot nesse contexto) para que quando o sinal for emitido, o slot seja executado automaticamente. No nosso exemplo, nós conectamos o sinal clicked() do botão com o slot quit() do objeto QApplication. As macros SIGNAL() e SLOT() fazem parte da sintaxe. [*] Sinais do Qt não tem nenhuma relação com sinais do Unix. Neste livro, estamos tratando somente dos sinais do Qt. Vamos construir a aplicação. Assumimos que você criou um diretório chamado quit contendo o arquivo quit.cpp. Rode o qmake no diretório 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 aplicação e rode-a. Se você clicar em Quit, ou pressionar a barra de espaço (que pressiona o botão), a aplicação terminará.
  • 9. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 9 Alinhando Widgets Nesta seção, 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 aplicação (mostrada na Figura 1.4) pergunta pela idade do usuário, a qual o usuário pode informar manipulando um spin box ou um slider. Figura 1.4 – A aplicação da idade A aplicação consiste em três widgets: um QSpinBox, um QSlider e um QWidget. O QWidget é a janela principal da aplicação. O QSpinBox e o QSlider são apresentados dentro da QWidget; eles são filhos de QWidget. Alternativamente, podemos dizer que QWidget é pai de QSpinBox e QSlider. O QWidget não tem pais porque está sendo usado como uma janela top-level. Os construtores de QWidget e de todas as suas subclasses tem QWidget * como parâmetro que especifica quem é o pai da widget em questão. Aqui está o código 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();
  • 10. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 10 24 return app.exec(); 25 } As linhas 8 e 9 preparam a QWidget que servirá como a janela principal da aplicação. Podemos chamar setWindowTitle() para escolher o texto que será exibido na barra de título da janela. As linhas 10 e 11 criam um QSpinBox e um QSlider, e as linhas 12 e 13 atribuem seus intervalos válidos. Podemos assumir que o usuário tem até 130 anos de idade. Poderíamos passar window para os construtores de QSpinBox e QSlider especificando que estes widgets devem ter window como pai deles, mas não é necessário 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 então emite um sinal valueChanged(int) porque o próprio valor mudou, ativando o slot setValue(int) do spin box. Mas nesse ponto, setValue(int) não emite nenhum sinal, já que o valor do spin box já é 35. Isso evita a recursão infinita. A Figura 1.5 ilustra a situação. Figura 1.5 – Mudando o valor de um widget, muda os dois
  • 11. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 11 Nas linhas 19 até 22, nós alinhamos o spin box e o slider usando um gerenciador de layouts. Este gerenciador é um objeto que define o tamanho e a posição dos widgets que estão sob sua responsabilidade. O Qt tem três 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 têm sido tirados no Linux, mas aplicações em Qt podem parecer nativas de cada plataforma suportada. O Qt consegue fazer isso emulando o “look and feel” de cada plataforma, ao invés de conter um kit de widgets de uma plataforma particular. Figura 1.6 – Estilos pré-definidos O estilo Plastique é o estilo padrão para aplicações Qt/X11 rodando sob o KDE, e o Cleanlooks é o padrão sob o GNOME. Estes estilos utilizam gradientes e “anti-aliasing”
  • 12. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 12  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 têm seu pai redefinido para o widget no qual o layout foi instalado, e por essa razão não temos que especificar um pai explícito quando construímos o widget que será colocado em um layout. Figura 1.7 – Os widgets e o layout da aplicação da idade Apesar de não termos escolhido a posição e o tamanho dos widgets explicitamente, o QSpinBox e o QSlider são dispostos visualmente de modo agradável de um lado até o outro. Isso ocorre porque QHBoxLayout automaticamente designa posições e tamanhos razoáveis para os widgets dos quais é responsável, baseado nas necessidades deles. Os gerenciadores de layouts nos privam da ocupação de posicionar, por puro código, os objetos na tela e garantem que a janela se redimensione suavemente. O modo apresentado por Qt para construir interfaces de usuário é simples de entender e é muito flexível. O procedimento mais comum que programadores Qt utilizam é instanciar os widgets necessários e depois definir suas propriedades conforme necessário. Programadores adicionam widgets aos layouts, que automaticamente cuidam do posicionamento e redimensionamento. O comportamento da interface de usuário é gerenciada conectando widgets uns aos outros usando o mecanismo de sinais e slots. para gerar um “look and feel” moderno. Usuários de aplicações Qt podem substituir os estilos padrão utilizando o comando –style na linha de comando. Por exemplo, para iniciar a aplicação 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 são visualizados nas plataformas nativas, já que dependem de dispositivos de tema de cada plataforma. Um estilo adicional chamado QtDotNet está disponível no Qt Solutions. Também é possível criar estilos customizados, como será explicado no Capítulo 19.
  • 13. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 13 Usando a Documentação de Referência A documentação de referência do Qt é uma ferramenta essencial para qualquer desenvolvedor. Ela cobre todas as classes e funções no Qt. Esse livro faz o uso de diversas classes e funções do Qt, mas não cobre todas elas e nem fornece todos os detalhes das que são mencionadas. Para tirar proveito máximo do Qt, você deve se familiarizar com a documentação do Qt o mais rápido possível. A documentação está disponível em HTML no diretório doc/html do Qt e pode ser lida através de qualquer browser. Você também pode usar o Qt Assistant, o browser de ajuda do Qt, que tem recursos poderosos de busca e indexação que o tornam mais rápido e fácil 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 seção “Referência API” na página inicial fornecem diferentes modos de navegar pelas classes de Qt. A página “Todas as classes” lista todas as classes na API do Qt. A página “Classes Principais” lista apenas as classes mais utilizadas de Qt. Como um exercício, procure as classes e as funções que utilizamos neste capítulo. Figura 1.8 – Documentação do Qt no Qt Assistant sob Windows Vista Note que funções herdadas são documentadas na classe base; por exemplo, QPushbutton não tem uma função própria show(), mas herda uma de QWidget. A Figura 1.9 mostra como as classes que vemos até agora se relacionam umas com as outras.
  • 14. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 14 Figura 1.9 – Árvore de herança para as classes de Qt vistas até agora A documentação de referência para a atual versão do Qt e para algumas versões mais recentes está disponível online em http://doc.trolltech.com/. Este site também tem artigos selecionados do Qt Quarterly, o newsletter dos programadores Qt enviado para todas as licenças comerciais. Este capítulo introduziu os conceitos chave de conexões signal-slot e layouts. Ele também começou a revelar a perspectiva total e consistente de orientação a objetos até a construção e uso de widgets. Se você procurar pela documentação do Qt, você encontrará uma uniformidade de exibição que a torna bem direta no que se diz respeito ao uso de novos widgets, e você também descobrirá que Qt escolheu cuidadosamente os nomes para funções, parâmetros, enums e assim por diante, que fazem com que programar em Qt se torne incrivelmente agradável e fácil. Os capítulos 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 básica de leitura, processamento e escrita de arquivos.
  • 15. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 15 2. Criando Dialogs  Herdando de QDialog  Signals e Slots a Fundo  Design Rápido de Dialogs  Modificando a Forma dos Dialogs  Dialogs Dinâmicos  Classes Nativas de Widgets e Dialogs Este capítulo vai te ensinar como criar caixas de diálogo utilizando Qt. Caixas de diálogo apresentam aos usuários opções e escolhas, e permitem que eles ajustem opções dos seus parâmetros preferidos e que façam suas escolhas. Eles são chamados de caixas de diálogo, ou apenas “dialogs”, porque eles fornecem os meios pelos quais os usuários “conversam” com as aplicações. A maioria das aplicações GUI (“graphics user interface”, ou interface gráfica de usuário) consiste em uma mainwindow com um menubar e uma toolbar, em conjunto com dezenas de dialogs que complementam a mainwindow. Também é possível criar dialogs que respondam diretamente às escolhas do usuário aplicando as ações necessárias (por exemplo, uma calculadora). Criaremos nosso primeiro dialog puramente por código 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 rápido (do que código puro) e faz com que seja fácil 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 própria. Fazendo isso, a tornamos independente, um componente encapsulado, com signals e slots próprios.
  • 16. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 16 Figura 2.1. A caixa de diálogo de busca. O código fonte está dividido em dois arquivos: finddialog.h e finddialog.cpp. Começaremos 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 múltiplos includes. A linha 3 inclui a definição 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 serão utilizadas na implementação do dialog (em finddialog.cpp). [*] Uma “foward declaration” diz ao compilador C++ que esta classe existe sem dar mais detalhes sobre a definição 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 começo da definição da classe é necessária para todas as classes que definem seus próprios signals e slots. [*] Foward declarations só podem ser utilizadas quando as variáveis forem ponteiros. O compilador não precisa, de inicio, de mais informações sobre a classe. Já que todos os ponteiros tem tamanho fixo: 4 bytes. O construtor de FindDialog é um exemplo típico de classes Qt. O parâmetro parent especifica o widget pai. O padrão para este parâmetro é um ponteiro nulo, significando que o widget não tem pai.
  • 17. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 17 13 signals: 14 void findNext(const QString &str, Qt::CaseSensitivity cs); 15 void findPrevious(const QString &str, Qt::CaseSensitivity cs); A seção signals declara dois sinais que o dialog emitirá quando o usuário clicar no botão “Find”. Se a opção “Search Backward” estiver selecionada, o dialog emite findPrevious() caso contrário, emite findNext(). A palavra-chave signals é, na verdade, uma macro. O pré-processador C++ o converte para padrões 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 seção privada da classe, declaramos dois slots. Para implementar os slots, precisaremos acessar a maioria dos widgets filhos do dialog, então mantemos ponteiros para eles também. A palavra-chave slots é, como signals, uma macro que se transforma em uma construção que C++ pode digerir. Para as variáveis private, usamos “foward declarations” das respectivas classes. Isso foi possível porque são todos ponteiros e não precisamos acessá-los no header, então o compilador não precisa de todas as definições da classe. Poderíamos ter incluído os includes (<QCheckBox>, <QLabel>, etc.), mas utilizando “foward declarations” quando possível, isso torna o tempo de compilação menor. Vamos para o arquivo da implementação da classe FindDialog, o finddialog.cpp: 1 #include <QtGui> 2 #include "finddialog.h" Primeiramente incluímos <QtGui>, um arquivo header que contém a definição das classes GUI do Qt. Qt consiste de vários módulos, cada um com sua própria biblioteca. Os módulos mais importantes são QtCore, QtGui, QtNetwork, QtOpenGL, QtScript, QtSql, QtSvg e QtXml. O header <QtGui> contém a definição de todas as classes que são parte dos módulos QtCore e QtGui. Incluir este header nos economiza a inclusão individual de cada classe do nosso dialog. No arquivo finddialog.h, ao invés de incluir <QDialog> e utilizar “foward declarations” para QCheckBox, QLabel, QLineEdit e QPushButton, poderíamos simplesmente ter incluído <QtGui>. Entretanto não é aconselhável incluir um arquivo header tão grande, especialmente em aplicações grandes.
  • 18. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 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 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 4, passamos o parâmetro parent para o construtor da classe base. Depois criamos os objetos filhos. A função tr() marca a string literal para futuras traduções para outras línguas. Esta função é declarada em QObject e em todas as classes que contém a macro Q_OBJECT. É um bom hábito cercar strings visíveis aos usuários com tr(), mesmo que você não tenha planos imediatos para traduzir sua aplicação para outras línguas. Traduções serão estudadas no Capítulo 18. Em strings literais, utilizamos o símbolo „&‟ para indicar teclas de atalho. Por exemplo, a linha 11 cria o botão Find, o qual o usuário pode ativar utilizando Alt+F nas plataformas que suportam teclas de atalho. O símbolo „&‟ também pode ser utilizado para controlar o foco: na linha 6 criamos uma label com a tecla de atalho (Alt+W), e na linha 8 nós definimos o lineedit como „companheiro‟ (buddy) da label. Um buddy é um widget que aceita o foco quando a tecla de atalho do outro é pressionada. Então quando o usuário pressiona Alt+W (atalho da label), o foco vai para o lineedit (buddy da label). Na linha 12, fazemos com que o botão Find seja o padrão chamando setDefault(true). O botão padrão é o botão que, quando o usuário pressiona Enter, é pressionado. Na linha 13, desabilitamos o botão Find. Quando um widget está desabilitado ele geralmente é mostrado em tons acinzentados e não responderá às interações do usuário. 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 usuário clicar no botão Find. O dialog se fecha quando o usuário clicar em Close. O slot close() é herdado de QWidget, e o seu comportamento padrão é esconder o widget de visualização (sem deletá-lo). Estudaremos o código para os slots enableFindButton() e findClicked() mais adiante. Já que QObject é um dos ancestrais do nosso dialog, então podemos omitir o prefixo „QObject::‟ das chamadas de connect(). 21 QHBoxLayout *topLeftLayout = new QHBoxLayout; 22 topLeftLayout->addWidget(label);
  • 19. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 19 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, nós alinhamos os widgets filhos utilizando gerenciadores de layout. Layouts podem conter ambos widgets e outros layouts. Misturando QHBoxLayouts, QVBoxLayout e QGridLayout, é possível 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 é responsável por toda a área do layout. Os outros três layouts são sub-layouts. A pequena „mola‟ na parte inferior direita da Figura 2.2. é um spacer (ou “stretch”). Ele usa o espaço vazio abaixo dos botões Find e Close, garantindo que esses botões ocupem o topo do layout em que estão. Figura 2.2. Os layouts do dialog de busca Um aspecto sutil de classes de gerenciamento de layouts é que não são widgets. Ao invés disso, são derivadas de QLayout. Que por sua vez é derivado de QObject. Na figura, widgets são representados por linhas sólidas e layouts são representados por linhas tracejadas para destacar a diferença entre eles. Durante a execução do programa, layouts são invisíveis. Quando sub-layouts são adicionados ao layout pai (linhas 23, 33 e 34), os sub-layouts têm 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 têm seus pais redefinidos como o dialog. A hierarquia resultante é mostrada na Figura 2.3. 36 setWindowTitle(tr("Find")); 37 setFixedHeight(sizeHint().height()); 38 }
  • 20. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 20 Figura 2.3. As relações de parentesco do dialog Finalmente, definimos o título a ser mostrado na barra de título e uma altura fixa para a janela, já que não existem widgets dentro do dialog que possam ocupar um espaço vertical significativo. A função QWidget::sizeHint() retorna o tamanho ideal do widget. Isso completa a revisão do construtor da classe FindDialog. Já que criamos os objetos e layouts através de „new‟, é razoável pensar que devemos deletar cada widget e layout com um „delete‟. Mas não é necessário, o Qt automaticamente deleta objetos filhos quando o pai é destruído, e todos os widgets e layouts do nosso dialog são descendentes do próprio 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 usuário clica no botão Find. Ele emite o sinal findPrevious() ou findNext(), dependendo da opção „Search Backward‟. A palavra-chave „emit‟ é específica do Qt; como outras extensões Qt ela é convertida em C++ padrão pelo pré- processador C++. O slot enableFindButton() é chamado sempre que o usuário muda o texto contido no lineedit. Isso ativa o botão se houver algum texto no lineedit, e desabilita caso contrário. Estes dois slots finalizam o dialog. Podemos, então, criar um main.cpp para testar nosso widget FindDialog:
  • 21. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 21 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 definição da classe FindDialog contém a macro Q_OBJECT, então 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 próxima seção). Para que o „moc‟ funcione corretamente é necessário colocar a definição da classe em um arquivo header, fora da implementação. O código gerado pelo moc inclui esse arquivo header e adiciona alguns códigos padrões do C++ por si próprio. Classes que utilizam a macro Q_OBJECT devem ser executadas pelo „moc‟. Isso não é um problema porque o qmake automaticamente adiciona as regras necessárias para o „makefile‟. Mas se você esquecer de gerar seu „makefile‟ usando qmake e o moc não tiver rodado, o linker reclamará dizendo que algumas funções foram declaradas mas não 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 saída do Visual C++ começa 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 aplicação. Agora, execute o programa. Se as teclas de atalho são 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 tabulação padrão, é a ordem na qual os widgets foram criados. Isso pode ser mudado usando QWidget::setTabOrder(). Forneça uma ordem razoável para a tecla tab e bons atalhos de teclado de forma que usuários que não querem (ou que não podem) usar um mouse sejam capazes de usar ao máximo a aplicação. Controle total sobre o teclado também é apreciado por digitadores rápidos. No Capítulo 3, nós usaremos o dialogo de busca numa aplicação real, e nós conectaremos os sinais findPrevious() e findNext() a alguns slots.
  • 22. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 22 Signals e Slots a Fundo O mecanismo de sinais e slots é fundamental para programação em Qt. Ele permite que o programador estabeleça um elo entre os objetos sem que os objetos saibam uns dos outros. Nós já conectamos alguns sinais e slots, declaramos nossos próprios sinais e slots, implementamos nossos slots e emitimos nossos sinais. Vamos dar uma olhada no mecanismo mais de perto. Slots são quase idênticos a funções membro ordinárias do C++. Elas podem ser virtuais, podem ser sobrecarregadas, podem ser publics, protecteds ou privates, podem ser diretamente chamadas como qualquer outra função membro do C++, e os seus parâmetros podem ser de qualquer tipo. A diferença é que um slot também pode ser conectado a um sinal, que no caso será chamado toda vez que o sinal for emitido. A estrutura da função connect() se dá da seguinte forma: connect(sender, SIGNAL(signal), receiver, SLOT(slot)); Onde „sender‟ e „receiver‟ são ponteiros para QObjects e „signal‟ e „slot‟ são assinaturas de funções sem nomes de parâmetros. As macros SIGNAL() e SLOT() essencialmente convertem seus argumentos para uma string. Nos exemplos que vimos até agora, nós sempre conectamos sinais diferentes com slots diferentes. Existem outras possibilidades a serem levadas em consideração.  Um sinal pode ser conectado a vários 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 são chamados um a um, numa ordem não especificada.  Vários 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 também é emitido. Além disso, conexões signal-signal são indistinguíveis de conexões signal-slot.
  • 23. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 23  Conexões podem ser removidas: disconnect(lcd, SIGNAL(overflow()), this, SLOT(handleMathError())); Isso é raramente necessário, porque o Qt automaticamente remove todas as conexões 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 parâmetros na mesma ordem: connect(ftp, SIGNAL(rawCommandReply(int, const QString &)), this, SLOT(processReply(int, const QString &))); Excepcionalmente, se um sinal tem mais parâmetros que o slot ao qual está conectado, os parâmetros adicionais são simplesmente ignorados. connect(ftp, SIGNAL(rawCommandReply(int, const QString &)), this, SLOT(checkErrorCode(int))); Se os tipos de parâmetros são incompatíveis, ou se o sinal ou slot não existirem, o Qt irá informar através de um warning em tempo de execução (se a aplicação foi construída no modo debug). Similarmente, o Qt irá lançar um warning se os nomes dos parâmetros 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 não é limitado a programação 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; };
  • 24. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 24 void Employee::setSalary(int newSalary) { if (newSalary != mySalary) { mySalary = newSalary; emit salaryChanged(mySalary); } } Perceba como o slot setSalary() é implementado. Nós emitimos o sinal salaryChanged() apenas se newSalary != mySalary. Isso garante que as conexões cíclicas não levem a loops infinitos. O Sistema Meta-Object do Qt Uma das maiores conquistas do Qt foi a extensão do C++ com um mecanismo de criação de componentes de software independentes que podem ser ligados sem nem saberem informações sobre o componente aos quais estão conectados. O mecanismo é chamado sistema meta-object e fornece dois serviços chave: signals- slots, e introspecção. A funcionalidade da introspecção é necessária para implementar signals e slots, e permite programadores obterem “informações meta” sobre sub-classes QObject em tempo de execução, incluindo a lista de sinais e slots suportados pelo objeto e nome da sua classe. O mecanismo também suporta propriedades (amplamente usadas pelo Qt Designer) e tradução de texto (para internacionalização), e estabelece as bases do módulo QtScript. A partir do Qt 4.2, propriedades podem ser adicionadas dinamicamente, um recurso que veremos em ação nos Capítulos 19 e 22. O C++ padrão não fornece suporte para as meta-informações dinâmicas que o sistema de meta-objeto de Qt precisa. O Qt resolve isso com uma ferramenta separada, o moc. Ele analisa as definições de Q_OBJECT e faz com que a informação fique disponível através de funções 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 funções de introspecção que devem ser implementadas em cada subclasse de QObject: metaObject(), tr(), qt_metacall(), entre outras.  A ferramenta moc gera implementações para as funções declaradas por Q_OBJECT e para todos os signals.  As funções membro de QObject (como connect() e disconnect() ) usam as funções de introspecção para fazer seus trabalhos. Tudo isso é feito automaticamente pelo qmake, moc e QObject, então você dificilmente terá que pensar nisso. Mas se estiver curioso você pode ler a documentação da classe QMetaObject e os códigos C++ gerados pelo moc para ver como a implementação funciona.
  • 25. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 25 Design Rápido de Dialogs O Qt foi planejado para ser agradável e intuitivo para o desenvolvimento de código a mão, e não é difícil encontrar programadores que desenvolvem suas aplicações inteiras puramente escrevendo código C++. Porém, muitos programadores preferem utilizar uma aproximação visual para desenvolver formulários, porque eles acham que este método é mais natural e rápido do que apenas código, e eles querem estar aptos a testar e mudar designs com mais rapidez e facilidade do que quando desenvolvidos com códigos puros. O Qt Designer expande as opções disponíveis aos programadores fornecendo uma capacidade visual de design. Qt Designer pode ser usado para desenvolver todos ou apenas alguns dos formulários da aplicação. Formulários que são criados utilizando o Qt Designer são convertidos em código C++, então o Qt Designer pode ser usado com uma variedade de ferramentas convencionais e não impõe especificações especiais ao compilador. Nessa seção, usaremos o Qt Designer para criar o diálogo “Ir para a célula” mostrado na Figura 2.4. Criar o dialog no Qt Designer ou por código 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 conexões signal/slots. 5. Implementar os próprios slots do dialog. Figura 2.4. O dialog de “Ir para célula”. 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 nós criaremos os botões „OK‟ e „Cancel‟ manualmente e mostraremos como é feito.) Você deve, agora, ter uma janela chamada „Untitled‟. Por padrão, a interface de usuário do Qt consiste em várias janelas „top-level‟. Se você preferir uma interface MDI (multiple document interface) com uma janela „top-window‟ e várias subjanelas, como mostrado na Figura 2.5, clique em Edit|Preferences e ajuste o modo de interface do usuário para „Docked Window‟.
  • 26. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 26 Figura 2.5. Qt Designer em modo „Docked Window‟ no Windows Vista O primeiro passo é criar widgets filhos e colocá-los no formulário. Criar uma label, um line editor, um spacer horizontal, e dois botões. 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 formulário. O spacer, que é invisível no formulário final, é mostrado no Qt Designer como uma pequena mola azul. Agora arraste a borda inferior do formulário pra encurtá-lo. Isso deveria produzir um formulário que é similar ao da Figura 2.6. Não gaste muito tempo posicionando os itens precisamente no formulário. Os gerenciadores de layouts vão posicioná-los de forma precisa posteriormente. Figura 2.6. O formulário 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 botão. Defina a propriedade objectName como “okButton”, a propriedade enabled para “false”, a propriedade text para “OK”, e a propriedade default para “true”.
  • 27. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 27 4. Clique no segundo botão. Defina a propriedade objectName para “cancelButton” e a propriedade text para “Cancel”. 5. Clique no fundo do formulário 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 edição que te permite escolher os Buddies. Depois, clique na tabela, mantenha o botão apertado e arraste a seta vermelha para o line Edit, e depois libere o botão. 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 edição de buddies clique em Edit|Edit Widgets. Figura 2.7 Formulário com as propriedades ajustadas O próximo passo é alinhar os widgets no formulário: 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 botões. Clique em Form|Lay Out Horizontally. 3. Clique no fundo do formulário para remover a seleção anterior de qualquer widget, depois clique em Form|Lay Out Vertically. 4. Clique em Form|Adjust Size para redimensionar o formulário para o seu tamanho preferencial. As linhas vermelhas mostradas no formulário mostram os layouts que foram criados, como é mostrado na Figura 2.8. Eles não são visíveis quando o formulário é executado. Figura 2.8. Formulário com Layouts.
  • 28. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 28 Agora clique em Edit|Edit Tab Order. Um número em um retângulo azul aparecerá próximo 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 edição 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 botão fechar na barra de título. Salve as alterações como gotocelldialog.ui em um diretório chamado gotocell, e crie um arquivo main.cpp no mesmo diretório 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 usuário gotocelldialog.ui e para gerar as regras apropriadas do makefile para chamar uic, o compilador de interfaces de usuário do Qt. A ferramenta uic converte o arquivo gotocelldialog.ui em código C++ e põe o resultado no arquivo ui_gotocelldialog.h. O arquivo ui_gotocelldialog.h gerado contém as definições para a classe Ui::GoToCellDialog, que é um equivalente C++ do gotocelldialog.ui. A classe declara variáveis membro que armazenam os layouts e widgets filhos do formulário, e uma função setupUi() que inicializa o formulário. A classe gerada se parece com isso:
  • 29. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 29 class Ui::GoToCellDialog { public: QLabel *label; QLineEdit *lineEdit; QSpacerItem *spacerItem; QPushButton *okButton; QPushButton *cancelButton; ... void setupUi(QWidget *widget) { ... } }; A classe gerada não tem nenhuma classe base. Quando utilizamos essa classe no main.cpp, nós criamos um QDialog e o passamos para setupUI(). Se você executar o programa agora, o diálogo vai funcionar, mas ele não funciona exatamente como queremos:  O botão OK está sempre desabilitado.  O botão Cancel não faz nada.  O line Edit aceita qualquer texto, ao invés de só aceitar posições validas de célula. Nós podemos fazer com que o diálogo funcione corretamente escrevendo algum código. 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 máxima de que qualquer problema do software pode ser resolvido simplesmente adicionando outra camada de meios indiretos). A convenção de nomeação é 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 código: #ifndef GOTOCELLDIALOG_H #define GOTOCELLDIALOG_H #include <QDialog> #include "ui_gotocelldialog.h" class GoToCellDialog : public QDialog, public Ui::GoToCellDialog { Q_OBJECT public: GoToCellDialog(QWidget *parent = 0); private slots: void on_lineEdit_textChanged(); }; #endif
  • 30. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 30 Aqui, utilizamos herança pública porque queremos acessar todos os widgets do dialog de fora do dialog. A implementação 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 formulário. Graças à herança múltipla, podemos acessar os membros de Ui::GoToCellDialog diretamente. Depois de criar a interface de usuário, setupUi() irá automaticamente conectar qualquer slot que siga a convenção de nome on_objectName_signalName() para o sinal de objectName correspondente. No nosso exemplo, isso significa que setupUi() irá estabelecer a seguinte conexão signal-slot: connect(lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(on_lineEdit_textChanged())); Também no construtor, nós criamos um validador (validator) para restringir o intervalo da entrada. O Qt fornece três classes internas do tipo validator: QIntValidator, QDoublrValidator, e QRegExpValidator. Aqui podemos usar um QRegExpValidator com a expressão regular “[A-Za-z][1-9][0-9]{0,2}”, que significa: Permita uma letra maiúscula ou minúscula, seguida de um digito entre 1 e 9, seguido de zero, 1, ou dois dígitos entre 0 e 9. (Para uma introdução à expressões regulares, veja a documentação da classe QRegExp.) Passando this para o construtor do QRegExpValidator, fazemos com que ele seja filho do objeto GoToCellDialog. Fazendo isso, não 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 nós 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 memórias, reduzindo o risco de vazamento de memória (memory leak). Os únicos objetos que devemos chamar delete são 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.
  • 31. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 31 Para widgets, o pai tem um significado adicional: Widgets filhos são mostrados dentro da área do pai. Quando deletamos o Widget pai, não somente os filhos são liberados da memória como também desaparecem da tela. Ao fim do construtor, nós conectamos o botão OK ao slot accept() do QDialog e o botão 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 nós usamos esse dialog, nós podemos usar o resultado para ver se o usuário clicou OK e atua de acordo. O slot on_lineEdit_textChanged() ativa ou desativa o botão OK, dependendo se o line edit contém uma localização válida de célula. 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 aplicação de novo. Digite “A12” no editor, e perceba que o botão OK se torna ativo. Tente digitar alguns textos aleatórios para ver como o validator funciona. Clique Cancel para fechar o dialog. O dialog funciona corretamente, mas para usuários do Mac, os botões estão um pouco diferentes. Escolhemos adicionar cada botão individualmente, para mostrar como era feito, mas nós deveríamos ter usado um QDialogButtonBox, um widget que contém os botões que especificamos e que os apresenta na forma correta para o sistema de janelas no qual a aplicação está sendo executada, como mostrado na Figura 2.10. Figura 2.10. O dialog „Ir para célula‟ no Windows Vista e no Mac. Para fazer com que o dialog use um QDialogButtonBox, nós devemos modificar ambos o design e o código. No Qt Designer, existem apenas quatro passos a tomar:
  • 32. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 32 1. Clique no formulário (não em nenhum dos widgets ou layouts) e depois clique em Form|Break Layout. 2. Selecione e delete os botões OK e Cancel, o spacer horizontal e o layout horizontal. 3. Arraste um “Button Box” para o formulário, abaixo da label de localização e do line Edit. 4. Clique no formulário e depois Form|Lay Out Vertically. Se nós estivéssemos fazendo apenas mudanças no design, como mudar o layout do dialog ou propriedades de widgets, nós estaríamos aptos a simplesmente reconstruir a aplicação. Mas nesse caso removemos alguns widgets e adicionamos novos widgets, e nestes casos devemos normalmente modificar o código também. As mudanças necessárias devem ser feitas no arquivo gotocelldialog.cpp. Aqui está a nova versão 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 versão anterior nós inicialmente desabilitamos o botão OK no Qt Designer. Nós não podemos fazer isso com um QDialogButtonBox, então nós fazemos isso no código, imediatamente depois da chamada setupUi(). A classe QDialogButtonBox tem um enum de botões padrão, e podemos usar isso para acessar botões particulares, neste caso o botão OK. Convenientemente, o nome padrão para um QDialogButtonBox do Qt Designer é buttonBox. Ambas as conexões são feitas a partir do Button Box ao invés de cada botão propriamente dito. O sinal accepted() é emitido quando o botão com a propriedade AcceptRole é clicado, e similarmente o sinal rejected() é emitido por um botão com a propriedade RejectRole. Por padrão, o botão QDialogButtonBox::Ok carrega a propriedade AcceptRole, e o botão QDialogButtonBox::Cancel carrega a propriedade RejectRole. Apenas mais uma mudança é necessária, 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 invés de se referir a um botão particular armazenado como variável membro, nós acessamos o botão OK do Button Box. Uma das facilidades do Qt Designer é que ele permite que programadores tenham grande liberdade para modificar seus próprios formulários sem serem forçados a mudar seus códigos. Quando você desenvolve um formulário puramente por C++, mudanças no design podem levar um tempo considerável. Com o Qt Designer, nenhum tempo é perdido já que o uic simplesmente refaz o código fonte de qualquer formulário que tenha mudado. A interface de
  • 33. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 33 usuário do dialog é salva em um arquivo .ui (um arquivo no formato XML), enquanto que funcionalidades próprias são implementadas derivando da classe gerada pelo uic. Modificando a Forma dos Dialogs Nós vimos como criar caixas de diálogo que sempre mostram os mesmos widgets sempre que são usados. Em alguns casos, é necessário que caixas de diálogo mudem suas formas. Os tipos mais comuns de caixas de diálogo que mudam suas formas são diálogos que se expandem e diálogos de múltiplas páginas. Ambos os tipos podem ser implementados no Qt, tanto por código como pelo Qt Designer. Diálogos que se expandem geralmente apresentam uma aparência simples mas têm um botão „ativável‟ que permite que o usuário alterne entre o diálogo simples e o diálogo expandido. Estes diálogos são comumente usados por aplicações que atingem tanto usuários casuais quanto avançados, escondendo as opções avançadas a menos que o usuário peça explicitamente para vê-las. Nesta seção, usaremos o Qt Designer para criar o diálogo de expansão mostrado na Figura 2.11. Figura 2.11. Caixa de diálogo de classificação nos modos simples e expandido. Este diálogo é um diálogo de classificação de uma aplicação de planilhas, onde o usuário pode selecionar uma ou várias colunas para que sejam classificadas. A versão simples do diálogo permite que ele escolha apenas uma chave de classificação, enquanto que a versão estendida fornece os meios para duas chaves extras. O botão „more‟ permite que o usuário alterne entre as versões. Criaremos o widget com sua versão expandida no Qt Designer, e esconderemos as chaves extras em tempo de execução conforme necessário. O diálogo parece complicado, mas é fácil fazê-lo no Qt Designer. O truque é fazer a primeira chave primeiro, depois duplicá-la duas vezes para obter as outras:
  • 34. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 34 1. Clique em File|New Form e escolha o modelo “Dialog com botões”. 2. Crie um botão OK e arraste para o canto superior direito do formulário. Mude a sua propriedade do objectName para “okButton” e defina sua propriedade default para “true”. 3. Crie um botão Cancel, e arraste-o para baixo do botão OK. Mude sua propriedade objectName para “cancelButton”. 4. Crie um spacer vertical e arraste-o para baixo do botão Cancel, depois crie um botão More, e arraste-o para baixo do spacer vertical. Mude sua propriedade objectName para “moreButton”, defina sua propriedade text para “&More”, e sua propriedade checkable para “true”. 5. Clique no botão OK, segure o Shift e clique no botão Cancel, no spacer vertical, no botão More e depois clique em Form|Lay Out Vertically. 6. Crie um group box, duas labels, duas comboboxes, e um spacer horizontal e coloque-os em qualquer lugar do formulário. 7. Arraste o canto inferior direito para aumentá-lo. Insira os outros widgets no groupbox e posicione-os aproximadamente como é mostrado na Figura 2.12 (a). 8. Arraste a borda direita do segundo combo box para fazê-lo, aproximadamente, duas vezes maior que o primeiro combobox. 9. Defina a propriedade title do group box para “&Primary Key”, a propriedade text da primeira label para “Column:”, e a propriedade text da segunda label para “Order:”. 10. Clique com o botão direito na primeira combobox e escolha Edit Items a partir do menu para editar os itens da combo box. Crie um item com o texto “None”. 11. Clique com o botão direito na segunda combo box e escolha Edit Items. Crie um item “Ascending” e outro “Descending”. 12. Clique na group box, Form|Lay Out in a Grid. Clique novamente no group box e depois Form|Adjust Size. Isso vai gerar o layout mostrado na Figura 2.12(b). Figura 2.12. Alinhando os widgets filhos em grid. Se um layout não ficar do jeitinho que você queria ou se você cometer um erro, você pode sempre clicar em Edit|Undo ou Form|Break Layout, depois reposicionar os widgets e tentar de novo. Vamos agora adicionar as chaves extras:
  • 35. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 35 1. Aumente a altura do diálogo 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 cópia dele (e de seu conteúdo) sobre o original. Arraste a cópia 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 padrão grid mostrado na Figura 2.13(a). 6. Clique no formulário para limpar possíveis seleções, clique em Form|Lay Out in a Grid. Agora arraste o canto inferior direito do formulário para cima e para esquerda para deixá-lo menor possível. O formulário 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 formulário em grid. O layout em grid resultante tem duas colunas e quarto linhas, totalizando oito células. O primeiro group box, o spacer vertical da esquerda, o segundo group box, e o terceiro group box, cada um ocupa uma única célula. O layout vertical contendo os botões OK, Cancel, e More ocupa duas células. Isso deixa duas células vazias na área inferior direita do diálogo. Se você não tem o mesmo resultado, desfaça o layout, reposicione os widgets, e tente de novo. Renomeie o formulário para “SortDialog” e mude o título da janela para “Sort”. Defina os nomes dos widgets filhos para aqueles da Figura 2.14.
  • 36. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 36 Figura 2.14. Nomeando os widgets Clique em Edit|Edit Tab Order. Clique em cada combo box de cima para baixo, nos botões OK, Cancel, e More. Clique em Edit|Edit Widgets para deixar o modo de edição de tabs. Agora que o formulário foi desenhado, estamos prontos para torná-lo funcional designando algumas conexões signals-slots. O Qt Designer nos permite que estabeleçamos conexões entre widgets que compartilham do mesmo formulário. Precisamos estabelecer duas delas. Clique em Edit|Edit Signals/Slots para entrar no modo de conexões do Qt Designer. Conexões são representadas por setas azuis entre os widgets do formulário, como é mostrado na Figura 2.15, e elas também são listadas na janela de edição de signals/slots do Qt Designer. Para estabelecer uma conexão entre dois widgets, clique no widget remetente e arraste a seta vermelha para o widget destinatário, e solte o botão do mouse. Isso vai fazer com que um diálogo seja exibido, permitindo que você escolha o sinal e o slot que pertencerão a conexão. Figura 2.15. Conectando os widgets
  • 37. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 37 A primeira conexão a ser feita é entre o botão okButton e o slot accept() do formulário. Arraste a seta vermelha do botão okButton para uma parte vazia do formulário, solte o botão para configurar a conexão pelo diálogo de configuração que será aberto, como mostrado na Figura 2.16. Escolha clicked() como sinal e accept() como slot, e clique OK. Figura 2.16. Diálogo de editor de conexões do Qt Designer Para a segunda conexão, arraste a seta vermelha do botão cancelButton para uma parte vazia do formulário, e no diálogo de configuração conecte o sinal clicked() ao slot reject() do formulário. A terceira conexão a ser estabelecida é entre o botão moreButton e o group box secondaryGroupBox. Arraste a seta vermelha entre estes widgets, então selecione o sinal toggled(bool) e o slot setVisible(bool). Por padrão, o Qt Designer não lista o slot setVisible(bool) na lista de slots, mas ele aparece se você habilitar a opção “Show all signals and slots”. A quarta e última conexão é entre o sinal toggled(bool) do botão moreButton e o slot setVisible(bool) do terceiro group box. Uma vez que as conexões foram estabelecidas, clique em Edit|Edit Widgets para deixar o modo de conexões. Salve o diálogo como sortdialog.ui em um diretório chamado sort. Para adicionar código ao formulário, nós usaremos o mesmo principio de herança múltipla que usamos para o diálogo “Go to Cell” na seção anterior. Primeiro, crie um arquivo sortdialog.h com o seguinte conteúdo: #ifndef SORTDIALOG_H #define SORTDIALOG_H #include <QDialog> #include "ui_sortdialog.h" class SortDialog : public QDialog, public Ui::SortDialog { Q_OBJECT
  • 38. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 38 public: SortDialog(QWidget *parent = 0); void setColumnRange(QChar first, QChar last); }; #endif Agora crie o sortdialog.cpp: 1 #include <QtGui> 2 #include "sortdialog.h" 3 SortDialog::SortDialog(QWidget *parent) 4 : QDialog(parent) 5 { 6 setupUi(this); 7 secondaryGroupBox->hide(); 8 tertiaryGroupBox->hide(); 9 layout()->setSizeConstraint(QLayout::SetFixedSize); 10 setColumnRange('A', 'Z'); 11 } 12 void SortDialog::setColumnRange(QChar first, QChar last) 13 { 14 primaryColumnCombo->clear(); 15 secondaryColumnCombo->clear(); 16 tertiaryColumnCombo->clear(); 17 secondaryColumnCombo->addItem(tr("None")); 18 tertiaryColumnCombo->addItem(tr("None")); 19 primaryColumnCombo->setMinimumSize( 20 secondaryColumnCombo->sizeHint()); 21 QChar ch = first; 22 while (ch <= last) { 23 primaryColumnCombo->addItem(QString(ch)); 24 secondaryColumnCombo->addItem(QString(ch)); 25 tertiaryColumnCombo->addItem(QString(ch)); 26 ch = ch.unicode() + 1; 27 } 28 } O construtor esconde as partes secundárias e terciárias do diálogo. Ele também define a propriedade sizeContraint do layout do formulário para QLayout::SetFixedSize, fazendo com que o diálogo se torne não redimensionável pelo usuário. O layout, então, assume a responsabilidade de redimensionar e dimensiona o diálogo automaticamente quando widgets são mostrados ou escondidos, garantindo que o diálogo será sempre mostrado no melhor tamanho. O slot setColumnRange() inicializa o conteúdo dos combo boxes baseado nas colunas selecionadas da planilha. Inserimos um item chamado “None” para as chaves (opcionais) secundária e terciária. As linhas 19 e 20 apresentam uma linguagem sutil de layout. A função QWidget::sizeHint() retorna o „tamanho ideal‟ do widget, que o sistema de layout tenta seguir. Isso explica porque
  • 39. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 39 diferentes tipos de widgets, ou widgets similares com conteúdos diferentes, podem ser designados com diferentes tamanhos pelo sistema de layout. Para comboboxes, isso significa que os comboboxes secundário e terciário, que contém “None”, acabam maiores que o primeiro combobox, que contém só entradas de letras individuais. Para evitar essa inconsistência, nós definimos o tamanho máximo da primeira combobox para o tamanho ideal do segundo combobox. Aqui está uma função teste main() que define o intervalo para incluir as colunas de „C‟ a „F‟ e depois mostra o diálogo: #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 diálogo de extensão. Como o exemplo mostra, este tipo de diálogo não é tão mais difícil de desenhar do que o diálogo plano: Tudo que precisamos era um botão de alternância, algumas conexões extras, e um layout não redimensionável. Em aplicações de produção, é bem comum que o botão de alternância tenha o texto “Advanced >>>” quando o diálog básico é exibido e “Advanced <<<” quando a extensão é mostrada. Isso é fácil de conseguir com Qt chamando setText() no QPushButton sempre que for clicado. O outro tipo comum de diálogos que mudam as formas, diálogos de múltiplas páginas, são até mais fáceis de criar em Qt, tanto por código ou com o Qt Designer. Tais diálogos podem ser construídos 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 página 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. Nós falaremos mais da classe QStackedWidget no Capítulo 6. Dialogs Dinâmicos Dialogs dinâmicos são aqueles que são criados em tempo de execução a partir de arquivos .ui produzidos no Qt Designer. Ao invés de converter o arquivo .ui para código C++ utilizando uic, nós podemos carregar o arquivo em tempo de execução usando a classe QUiLoader:
  • 40. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 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 função findChild<T>() é uma função membro template que retorna o objeto filho que corresponde com o nome e tipo de dados. Por causa de uma limitação do compilador, isso não está disponível para MSVC 6. Se você precisa usar o compilador MSVC 6, utilize a função 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 aplicação Qt, nós devemos adicionar esta linha ao arquivo .pro da aplicação: CONFIG += uitools Diálogos dinâmicos tornam possível mudar o layout de um formulário sem recompilar a aplicação. Eles podem também ser usados para criar aplicações “thin-client”, onde o executável meramente tem um formulário front-end interno e todos os outros formulários são criados quando necessário. Classes Nativas de Widgets e Dialogs O Qt fornece um conjunto completo de widgets nativos e diálogos comuns que atendem a maioria das situações. Nesta seção, apresentamos as imagens de quase todos eles. Alguns widgets especializados são adiados: Cobrimos widgets de mainwindows, como QMenuBar, QToolBar e QStatusBar no Capítulo 3, e nós cobrimos widgets relacionados ao layout, como QSplitter e QScrollArea no Capítulo 6. A maioria dos widgets nativos e diálogos são usados nos exemplos apresentados neste livro. Nas imagens mostradas nas Figuras 2.17 até 2.26, todos os widgets são mostrados usando o estilo Plastique. Figura 2.17. Botões do Qt
  • 41. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 41 Figura 2.18. Containers de página única do Qt Figura 2.19. Containers de múltiplas páginas do Qt Figura 2.20. Item views do Qt
  • 42. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 42 Figura 2.21. Widgets de exibição do Qt Figura 2.22. Widgets de entrada do Qt
  • 43. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 43 Figura 2.23. Diálogos de feedback do Qt Figura 2.24. Diálogos de fonte e cor do Qt Figura 2.25. Diálogos de impressão e arquivo do Qt
  • 44. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 44 Figura 2.26. Diálogo Qwizard do Qt O Qt oferece quatro tipos de "botões": QPushButton, QToolButton, QCheckBox e QRadioButton, eles são mostrados na Figura 2.17. QPushButton e QToolButton são mais comumente usados para iniciar uma ação quando clicados, mas eles também podem se comportar como botões de alternância (clique para afundar, clique para restaurar). QCheckBox pode ser usado para independentes opções on/off, enquanto QRadioButtons normalmente são mutuamente exclusivos. Widgets containers do Qt são widgets que contêm outros widgets. Eles são mostrados na Figura 2.18 e Figura 2.19. QFrame também 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 são widgets multi-página. Cada página é um widget filho, e as páginas são numeradas a partir de 0. Para QTabWidgets, tanto a forma como a posição das guias podem ser definidos. Os item views, mostrados na Figura 2.20, são 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 especificações 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 são documentadas em http://doc.trolltech.com/4.3/richtext-html-subset.html. O Qt oferece alguns widgets que são utilizados exclusivamente para exibição de informações, eles são 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 contrário de QLabel, ela fornece automaticamente as barras de rolagem quando necessário, e também fornece amplo suporte para teclado e mouse. O Qt Assistant 4.3 usa QTextBrowser para apresentar a documentação para o usuário. O Qt fornece diversos widgets para entrada de dados, como mostrado na Figura 2.22. QLineEdit pode restringir a sua entrada usando uma máscara de entrada, um validador, ou
  • 45. C++ GUI Programando com Qt4, Segunda Edição Tradução livre realizada pelos membros do Fórum QtBrasil www.qtbrasil.com 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 são totalmente integrados com a área de transferência. O Qt fornece uma caixa de mensagem versátil e um diálogo de erro que lembra quais mensagens mostrou, estes são mostrados na Figura 2.23. O progresso das operações demoradas pode ser indicado através da QProgressDialog ou usando a QProgressBar mostrado na Figura 2.21. QInputDialog é muito conveniente quando uma única linha de texto ou um número único é exigido do usuário. O Qt fornece o conjunto padrão de diálogos comuns que tornam mais fácil pedir ao usuário para selecionar uma cor, fonte, ou arquivo, ou para imprimir um documento. Estes são mostrados na Figura 2.24 e Figura 2.25. No Windows e no Mac OS X, o Qt usa os diálogos nativos, em vez de seus próprios diálogos comuns quando possível. As cores também podem ser escolhidas através de um dos widgets de seleção de cores do Qt Solutions, e fontes podem ser escolhidas usando QFontComboBox. Finalmente, QWizard fornece uma estrutura para a criação de wizards (também chamados de assistentes no Mac OS X). Wizards são úteis para tarefas complexas ou pouco freqüentes que os usuários podem ter dificuldade em aprender. Um exemplo de um assistente é mostrado na Figura 2.26. Muitas funcionalidades prontas para uso são fornecidas pelos widgets e diálogos 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 diálogos fornecidos com o Qt é adequado, um pode estar disponível a partir do Qt Solutions, ou de versões comerciais ou não comerciais de terceiros. O Qt Solutions oferece um conjunto de widgets adicionais, incluindo selecionadores de cores diferentes, um controle de botão giratório, menus de pizza, e um navegador de propriedade, bem como uma caixa de diálogo de cópia. Em algumas situações, pode ser desejável 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 Capítulo 5 explica como criar widgets personalizados.