Você está na página 1de 45

C++ GUI Programando com Qt4, Segunda Edio

Autores: Jasmin Blanchette e Mark Summerfield


1

Traduo por: Danilo Domingos, Arthur dos Santos Dias Reviso e edio por: Thiago Rossener Nogueira
qtbrasil.com

Viso Geral
O nico oficialmente publicado guia das melhores prticas para programao Qt 4.3 Usando o Qt da Trolltech possvel criar aplicaes C++ de alta performance que rodem em mquinas Windows, Linux/Unix, Mac OS X, e demais extenses Linux sem que seja necessrio fazer alteraes de cdigo. Agora, dois membros da Trolltech lhe oferecem este guia completo para que voc alcance resultados surpreendentes com a mais recente verso do Qt: Qt 4.3. Carregado com exemplos prticos, realistas e conselhos profundos, este o livro usado pela Trolltech para ensinar Qt para seus prprios novos funcionrios. Revisado e expandido constantemente, este livro nos revela os melhores padres atuais para se trabalhar com Qt para diversos usos, que vo desde implementao de arquiteturas de modelagem at o uso da engine grfica do Qt 4.3. Voc encontrar solues para diversas tarefas de desenvolvimento GUI, assim como tcnicas sofisticadas para sistemas com acesso a banco de dados, integrao com XML, uso de subclasses, composio, e muito mais. Seja voc um novo usurio de Qt, ou um usurio antigo que est aprendendo a nova verso, este livro certamente vai lhe ajudar a tirar vantagem de tudo que o Qt 4.3 capaz de fazer. Eis algumas novidades que encontraro neste livro: Atualizado completamente, com uma novssima cobertura de banco de dados, XML, e programao Qtopia. Cobertura de tudo que mudou do Qt 4.2 para 4.3, incluindo integrao com Windows Vista, suporte nativo a CSS para estilizao de aplicativos, e gerao de arquivos SVG. Captulos separados para assuntos relacionados a 2D e 3D, cobertura das novas classes de visualizao grfica do Qt 4.3, alm de uma cobertura total do QPainters OpenGL. Novos captulos a respeito de otimizao look-and-feel e sobre criao de scripts para aplicaes. Ilustra a arquitetura de visualizao e modelagem do Qt4, suporte a plugins, manuteno de layout, processamento de eventos, classes containers, e muito mais. Apresenta tcnicas avanadas vistas em nenhum outro livro - desde criao de plugins at interao com APIs nativas. Inclui um novo apndice de Qt Jambi, a nova verso Java do Qt.

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Tabela de Contedos Parte 1: Qt Bsico Captulo 1: Comeando Hello Qt Fazendo Conexes Alinhando Widgets Usando a Documentao de Referncia Captulo 2: Criando Dialogs Herdando de QDialog Signals e Slots a Fundo Design Rpido de Dialogs Modificando a Forma dos Dialogs Dialogs Dinmicos Classes Nativas de Widgets e Dialogs Captulo 3: Criando Janelas Principais Subclasse QMainWindow Criando Menus e Barras de Ferramentas Ajustando a Barra de Status Desenvolvendo o Menu Arquivo Usando Dialogs Armazenando Configuraes Documentos Mltiplos Misturar Telas Captulo 4: Implementao da Funcionalidade da Aplicao O Widget Central Subclasse QTableWidget Carregando e Salvando Implementao do Menu Editar Implementando os Outros Menus Subclasse QTableWidgetItem Captulo 5: Criando Widgets Customizveis Customizando Qt Widgets Subclasse QtWidget Integrando Widgets Customizveis com Qt Designer Buffering Duplo Parte II: Qt Intermedirio Captulo 6: Gerenciamento de Layout Modelando Widgets em um Form Layouts Empilhados Splitters reas Rolveis Janelas Dock e Barras de Ferramentas Interface de Documento Mltiplo Captulo 7: Processamento de Eventos Reimplementando Manipuladores de Eventos Instalando Filtros de Eventos Manter Respondendo durante Processamento Intensivo Captulo 8: Grficos 2D Pintando com QPainter Transformaes de Coordenadas de Sistema Renderizando em Alta-Qualidade com QImage Renderizando Itens Bsicos com Visualizadores de Grfico Imprimindo Captulo 9: Arrastar e Soltar Habilitando Arrastar e Soltar Suportando Tipos de Arrastar Personalizados Manipulao de Clipboard
Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


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

C++ GUI Programando com Qt4, Segunda Edio


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

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

Parte I: O Bsico do Qt
1. Comeando

Hello Qt Fazendo Conexes Alinhando Widgets Usando a Documentao de Referncia

Este captulo mostra como combinar C++ bsico com a funcionalidade disponibilizada pelo Qt para criar algumas aplicaes de interface grfica pequenas. Este captulo tambm introduz duas idias chave do Qt: signals e slots e layouts. No Captulo 2, iremos mais a fundo, e no Captulo 3, comearemos a construir aplicaes mais realsticas. Se voc j conhece Java ou C# mas tem uma experincia limitada com C++, ento recomendado que voc comece lendo a Introduo ao C++ no Apndice D.

Hello Qt
Vamos comear com um programa bem simples. Vamos estud-lo linha a linha e depois veremos como compil-lo e rod-lo. 1 #include <QApplication> 2 #include <QLabel> 3 int main(int argc, char *argv[]) 4 { 5 QApplication app(argc, argv); 6 QLabel *label = new QLabel("Hello Qt!"); 7 label->show(); 8 return app.exec(); 9 } As linhas 1 e 2 incluem as definies das classes QApplication e QLabel. Para cada classe do Qt existe um arquivo header com o mesmo nome (e distino entre maisculas e minsculas) que contm a definio da classe.
Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

A linha 5 cria um objeto QApplication para gerenciar os recursos da aplicao no geral. O construtor de QApplication requer os argumentos argc e argv porque o Qt interpreta alguns argumentos de linha de comando prprios do Qt. A linha 6 cria um widget QLabel que mostra o texto Hello Qt!. No Qt e na terminologia Unix, um widget um elemento visual numa interface grfica. O termo vem da expresso window gadget e equivalente a tanto controle como container na terminologia do Windows. Botes, menus, barras de rolagem e frames so exemplos de widgets. Widgets podem conter outros widgets; por exemplo, uma janela , geralmente, um widget que contm um QMenuBar, algumas QToolBars, uma QStatusBar, e alguns outros widgets. A maioria das aplicaes usa uma QMainWindow ou um QDialog como janela principal da aplicao, mas o Qt to flexvel que qualquer widget pode ser uma janela. Neste exemplo, o widget QLabel a janela da aplicao. A linha 7 torna a label visvel. Widgets so criados, por padro, como invisveis para que possamos customiz-los antes de serem exibidos, deste modo evitando flickering. A linha 8 passa o controle da aplicao para o Qt. Neste ponto, o programa entra no chamado loop de eventos. Imagine o loop de eventos como um modo de espera onde o programa espera por aes do usurio como clicks do mouse ou ento pressionamento de teclas. Aes do usurio geram eventos (tambm chamados de mensagens) para os quais o programa responde, geralmente executando uma ou mais funes. Por exemplo, quando o usurio clica em um widget, os eventos pressionamento do boto do mouse e liberao do boto do mouse so gerados. Neste ponto, aplicaes grficas diferem significativamente de programas BAT convencionais, nos quais praticamente s processam uma entrada, desenvolvem algum procedimento, e terminam sem interao humana. Por simplicidade, ns no nos preocupamos em chamar o delete para o objeto QLabel ao final da funo main(). Este vazamento de memria (memory leak) inofensivo num programa to pequeno, j que a memria alocada ser desalocada quando o programa terminar. J possvel testar o programa na sua mquina. Ele deve se parecer com o mostrado na Figura 1.1. Primeiro voc ter que instalar o Qt 4.3.2 (ou uma verso mais recente), este procedimento explicado no Apndice A. De agora em diante, vamos assumir que voc tem uma cpia corretamente instalada do Qt e que o diretrio bin est na sua varivel PATH de ambiente. (No Windows isso feito automaticamente pelo instalador do Qt) Voc tambm precisar que o cdigo deste programa esteja num arquivo hello.cpp num diretrio chamado hello. Voc mesmo pode escrever o arquivo hello.cpp ou copi-lo dos exemplos que acompanham este livro, que est disponvel em examples/chap01/hello/hello.cpp. (Todos os exemplos esto disponveis no site do livro, http://www.informit.com/title/0132354160.) Figura 1.1 - Hello no Linux

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


Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

para criar um arquivo projeto que independente da plataforma, e depois digite qmake hello.pro para criar um arquivo makefile especfico para a plataforma que est usando. (A ferramenta qmake discutida em mais detalhes no Apndice B.) Digite make para construir o programa. Rode-o digitando hello no Windows, ./hello no Unix, e open hello.app no Mac. Para terminar o programa, clique no boto fechar na barra de ttulo da janela. Se voc estiver usando o Windows e tiver instalado a verso Open Source do Qt e o compilador MinGW, voc ter um atalho chamado prompt de comando do Qt que tem todas as variveis de ambiente corretamente ajustadas. Se voc conseguiu visualizar a janela ento voc pode compilar aplicaes do Qt utilizando qmake e make como descritos anteriormente. Os executveis so colocados na pasta debug ou release da aplicao (por exemplo, C:\examples\chap01\hello\release\hello.exe). Se voc estiver utilizando o Microsoft Visual C++ com uma verso comercial do Qt, voc utilizar o nmake ao invs de make. Alternativamente, voc pode criar um arquivo projeto do Visual Studio a partir do arquivo hello.cpp digitando qmake -tp vc hello.pro e compilando o programa no Visual Studio. Se voc estiver usando o Xcode no Mac, voc pode gerar um projeto Xcode usando o comando qmake -spec macx-xcode hello.pro

Antes de irmos para o prximo exemplo vamos nos divertir um pouco: Substitua a linha QLabel *label = new QLabel("Hello Qt!"); por QLabel *label = new QLabel("<h2><i>Hello</i> " "<font color=red>Qt!</font></h2>"); E recompile a aplicao. Quando rodar, ela deve parecer com a Figura 1.2. Como este exemplo ilustra, fcil diferenciar uma aplicao de interface de usurio Qt utilizando apenas uma formatao HTML.

Figura 1.2: Uma label com formatao HTML bsica

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

Fazendo Conexes
O segundo exemplo mostra como responder s aes do usurio. A aplicao consiste em um boto que o usurio pode clicar para sair. O cdigo muito similar ao exemplo anterior, com exceo do uso de um QPushButton no lugar de uma QLabel como nosso widget principal, e ns estamos conectando a ao do usurio (clique) a um bloco de cdigo. O cdigo desta aplicao est em examples/chap01/quit/quit.cpp; a aplicao em andamento mostrada na Figura 1.3. Aqui est o contedo do arquivo: 1 #include <QApplication> 2 #include <QPushButton> 3 int main(int argc, char *argv[]) 4 { 5 QApplication app(argc, argv); 6 QPushButton *button = new QPushButton("Quit"); 7 QObject::connect(button, SIGNAL(clicked()), 8 &app, SLOT(quit())); 9 button->show(); 10 return app.exec(); 11 } Figura 1.3 A aplicao que fecha

Os widgets do Qt emitem sinais para indicar que uma ao de usurio ou uma mudana de estado ocorreu. [*] Por exemplo, QPushButton emite um sinal clicked() quando o usurio clica no boto. Um sinal pode se conectar com uma funo (chamada de slot nesse contexto) para que quando o sinal for emitido, o slot seja executado automaticamente. No nosso exemplo, ns conectamos o sinal clicked() do boto com o slot quit() do objeto QApplication. As macros SIGNAL() e SLOT() fazem parte da sintaxe.
[*] Sinais do Qt no tem nenhuma relao com sinais do Unix. Neste livro, estamos tratando somente dos sinais do Qt.

Vamos construir a aplicao. Assumimos que voc criou um diretrio chamado quit contendo o arquivo quit.cpp. Rode o qmake no diretrio quit para gerar o arquivo projeto, e depois rode-o novamente para gerar o makefile, como segue: qmake -project qmake quit.pro Agora construa a aplicao e rode-a. Se voc clicar em Quit, ou pressionar a barra de espao (que pressiona o boto), a aplicao terminar.

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

Alinhando Widgets
Nesta seo, iremos criar um pequeno exemplo que demonstra como usar layouts para gerenciar a geometria dos widgets em uma janela e como usar sinais e slots para sincronizar dois widgets. A aplicao (mostrada na Figura 1.4) pergunta pela idade do usurio, a qual o usurio pode informar manipulando um spin box ou um slider.

Figura 1.4 A aplicao da idade

A aplicao consiste em trs widgets: um QSpinBox, um QSlider e um QWidget. O QWidget a janela principal da aplicao. O QSpinBox e o QSlider so apresentados dentro da QWidget; eles so filhos de QWidget. Alternativamente, podemos dizer que QWidget pai de QSpinBox e QSlider. O QWidget no tem pais porque est sendo usado como uma janela top-level. Os construtores de QWidget e de todas as suas subclasses tem QWidget * como parmetro que especifica quem o pai da widget em questo. Aqui est o cdigo fonte: 1 2 3 4 #include #include #include #include <QApplication> <QHBoxLayout> <QSlider> <QSpinBox>

5 int main(int argc, char *argv[]) 6 { 7 QApplication app(argc, argv); 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 QWidget *window = new QWidget; window->setWindowTitle("Enter Your Age"); QSpinBox *spinBox = new QSpinBox; QSlider *slider = new QSlider(Qt::Horizontal); spinBox->setRange(0, 130); slider->setRange(0, 130); QObject::connect(spinBox, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int))); QObject::connect(slider, SIGNAL(valueChanged(int)), spinBox, SLOT(setValue(int))); spinBox->setValue(35); QHBoxLayout *layout = new QHBoxLayout; layout->addWidget(spinBox); layout->addWidget(slider); window->setLayout(layout); window->show();

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

10

24 25 }

return app.exec();

As linhas 8 e 9 preparam a QWidget que servir como a janela principal da aplicao. Podemos chamar setWindowTitle() para escolher o texto que ser exibido na barra de ttulo da janela. As linhas 10 e 11 criam um QSpinBox e um QSlider, e as linhas 12 e 13 atribuem seus intervalos vlidos. Podemos assumir que o usurio tem at 130 anos de idade. Poderamos passar window para os construtores de QSpinBox e QSlider especificando que estes widgets devem ter window como pai deles, mas no necessrio porque o sistema de layout ir configurar isso sozinho e automaticamente atribuir o pai do spin box e do slider, como veremos a seguir. As duas chamadas QObject::connect() mostradas nas linhas 14 at 17 asseguram que o spin box e o slider estejam sincronizados para que eles sempre mostrem o mesmo valor. Sempre que o valor de um dos widgets mudar, o sinal valueChanged() de um deles ser emitido, e o slot setValue(int) do outro ser chamado com o novo valor. A linha 18 predefine o valor do spin box para 35. Quando isso acontece, o QSpinBox emite o sinal valueChanged(int) com um argumento do tipo int valendo 35. Esse argumento passado para o slot setValue(int) do QSlider, que ajusta o valor do slider para 35. O slider ento emite um sinal valueChanged(int) porque o prprio valor mudou, ativando o slot setValue(int) do spin box. Mas nesse ponto, setValue(int) no emite nenhum sinal, j que o valor do spin box j 35. Isso evita a recurso infinita. A Figura 1.5 ilustra a situao.

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

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Nas linhas 19 at 22, ns alinhamos o spin box e o slider usando um gerenciador de layouts. Este gerenciador um objeto que define o tamanho e a posio dos widgets que esto sob sua responsabilidade. O Qt tem trs tipos principais de gerenciadores de layouts: QHBoxLayout alinha os widgets horizontalmente da esquerda para a direita (da direita para a esquerda para algumas culturas). QVBoxLayout alinha os widgets verticalmente de cima para baixo.

11

Estilos de Widgets
Os screenshots que vimos at agora tm sido tirados no Linux, mas aplicaes em Qt podem parecer nativas de cada plataforma suportada. O Qt consegue fazer isso emulando o look and feel de cada plataforma, ao invs de conter um kit de widgets de uma plataforma particular. Figura 1.6 Estilos pr-definidos

O estilo Plastique o estilo padro para aplicaes Qt/X11 rodando sob o KDE, e o Cleanlooks o padro sob o GNOME. Estes estilos utilizam gradientes e anti-aliasing

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

12

para gerar um look and feel moderno. Usurios de aplicaes Qt podem substituir os estilos padro utilizando o comando style na linha de comando. Por exemplo, para iniciar a aplicao de idade acima utilizando o estilo Motif sob X11, simplesmente digite o comando: ./age -style motif Diferente dos outros estilos, Windows XP, Windows Vista, e Mac apenas so visualizados nas plataformas nativas, j que dependem de dispositivos de tema de cada plataforma. Um estilo adicional chamado QtDotNet est disponvel no Qt Solutions. Tambm possvel criar estilos customizados, como ser explicado no Captulo 19.

QGridLayout alinha os widgets em um grid.

A chamada de QWidget::setLayout() na linha 22 instala o gerenciador na janela. Mas na verdade, o QSpinBox e o QSlider tm seu pai redefinido para o widget no qual o layout foi instalado, e por essa razo no temos que especificar um pai explcito quando construmos o widget que ser colocado em um layout. Figura 1.7 Os widgets e o layout da aplicao da idade

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

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

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

13

Usando a Documentao de Referncia


A documentao de referncia do Qt uma ferramenta essencial para qualquer desenvolvedor. Ela cobre todas as classes e funes no Qt. Esse livro faz o uso de diversas classes e funes do Qt, mas no cobre todas elas e nem fornece todos os detalhes das que so mencionadas. Para tirar proveito mximo do Qt, voc deve se familiarizar com a documentao do Qt o mais rpido possvel. A documentao est disponvel em HTML no diretrio doc/html do Qt e pode ser lida atravs de qualquer browser. Voc tambm pode usar o Qt Assistant, o browser de ajuda do Qt, que tem recursos poderosos de busca e indexao que o tornam mais rpido e fcil comparado com um web browser. Para iniciar o Qt Assistant, clique em Qt by Trolltech v4.x.x|Assistant no Windows, digite assistant na linha de comando no Unix, ou d um duplo-clique em Assistant na busca do Mac. Os links na seo Referncia API na pgina inicial fornecem diferentes modos de navegar pelas classes de Qt. A pgina Todas as classes lista todas as classes na API do Qt. A pgina Classes Principais lista apenas as classes mais utilizadas de Qt. Como um exerccio, procure as classes e as funes que utilizamos neste captulo. Figura 1.8 Documentao do Qt no Qt Assistant sob Windows Vista

Note que funes herdadas so documentadas na classe base; por exemplo, QPushbutton no tem uma funo prpria show(), mas herda uma de QWidget. A Figura 1.9 mostra como as classes que vemos at agora se relacionam umas com as outras.

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


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

A documentao de referncia para a atual verso do Qt e para algumas verses mais recentes est disponvel online em http://doc.trolltech.com/. Este site tambm tem artigos selecionados do Qt Quarterly, o newsletter dos programadores Qt enviado para todas as licenas comerciais. Este captulo introduziu os conceitos chave de conexes signal-slot e layouts. Ele tambm comeou a revelar a perspectiva total e consistente de orientao a objetos at a construo e uso de widgets. Se voc procurar pela documentao do Qt, voc encontrar uma uniformidade de exibio que a torna bem direta no que se diz respeito ao uso de novos widgets, e voc tambm descobrir que Qt escolheu cuidadosamente os nomes para funes, parmetros, enums e assim por diante, que fazem com que programar em Qt se torne incrivelmente agradvel e fcil. Os captulos seguintes da Parte I se apoiam nos fundamentos aqui abordados, mostrando como criar uma GUI completa com menus, toolbars, janelas de documentos, status bars, e dialogs, em conjunto com a funcionalidade bsica de leitura, processamento e escrita de arquivos.

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

15

2. Criando Dialogs

Herdando de QDialog Signals e Slots a Fundo Design Rpido de Dialogs Modificando a Forma dos Dialogs Dialogs Dinmicos Classes Nativas de Widgets e Dialogs

Este captulo vai te ensinar como criar caixas de dilogo utilizando Qt. Caixas de dilogo apresentam aos usurios opes e escolhas, e permitem que eles ajustem opes dos seus parmetros preferidos e que faam suas escolhas. Eles so chamados de caixas de dilogo, ou apenas dialogs, porque eles fornecem os meios pelos quais os usurios conversam com as aplicaes. A maioria das aplicaes GUI (graphics user interface, ou interface grfica de usurio) consiste em uma mainwindow com um menubar e uma toolbar, em conjunto com dezenas de dialogs que complementam a mainwindow. Tambm possvel criar dialogs que respondam diretamente s escolhas do usurio aplicando as aes necessrias (por exemplo, uma calculadora). Criaremos nosso primeiro dialog puramente por cdigo e mostraremos como funciona. Depois veremos como criar dialogs pelo Qt Designer, a ferramenta visual de design do Qt. Utilizar o Qt Designer um jeito muito mais rpido (do que cdigo puro) e faz com que seja fcil testar designs diferentes e at mesmo modificar designs j existentes no futuro.

Herdando de QDialog
Nosso primeiro exemplo um dialog de busca, escrito totalmente em C++. Ele mostrado na Figura 2.1. Vamos implementar o dialog como uma classe prpria. Fazendo isso, a tornamos independente, um componente encapsulado, com signals e slots prprios.

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Figura 2.1. A caixa de dilogo de busca.
16

O cdigo fonte est dividido em dois Comearemos pelo header (finddialog.h): 1 #ifndef FINDDIALOG_H 2 #define FINDDIALOG_H 3 #include <QDialog> 4 5 6 7 class class class class QCheckBox; QLabel; QLineEdit; QPushButton;

arquivos:

finddialog.h

finddialog.cpp.

As linhas 1 e 2 (e 27) protegem o header contra mltiplos includes. A linha 3 inclui a definio de QDialog, a classe base para dialogs em Qt. QDialog derivado de QWidget. A linha 4 at 7 apresenta foward declarations das classes de Qt que sero utilizadas na implementao do dialog (em finddialog.cpp). [*] Uma foward declaration diz ao compilador C++ que esta classe existe sem dar mais detalhes sobre a definio da classe (normalmente localizada no header da classe). Voltaremos a falar disso em breve. Depois, definimos FindDialog como uma subclasse de QDialog: 8 class FindDialog : public QDialog 9 { 10 Q_OBJECT 11 public: 12 FindDialog(QWidget *parent = 0); A macro Q_OBJECT no comeo da definio da classe necessria para todas as classes que definem seus prprios signals e slots. [*] Foward declarations s podem ser utilizadas quando as variveis forem ponteiros. O compilador no precisa, de inicio, de mais informaes sobre a classe. J que todos os ponteiros tem tamanho fixo: 4 bytes. O construtor de FindDialog um exemplo tpico de classes Qt. O parmetro parent especifica o widget pai. O padro para este parmetro um ponteiro nulo, significando que o widget no tem pai.

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

17

13 signals: 14 void findNext(const QString &str, Qt::CaseSensitivity cs); 15 void findPrevious(const QString &str, Qt::CaseSensitivity cs); A seo signals declara dois sinais que o dialog emitir quando o usurio clicar no boto Find. Se a opo Search Backward estiver selecionada, o dialog emite findPrevious() caso contrrio, emite findNext(). A palavra-chave signals , na verdade, uma macro. O pr-processador C++ o converte para padres C++ antes que o compilador veja. Qt::CaseSensitivity um enum que pode assumir os valores Qt::CaseSensitive (um) e Qt::CaseInsensitive (zero). 16 private slots: 17 void findClicked(); 18 void enableFindButton(const QString &text); 19 private: 20 QLabel *label; 21 QLineEdit *lineEdit; 22 QCheckBox *caseCheckBox; 23 QCheckBox *backwardCheckBox; 24 QPushButton *findButton; 25 QPushButton *closeButton; 26 }; 27 #endif Na seo privada da classe, declaramos dois slots. Para implementar os slots, precisaremos acessar a maioria dos widgets filhos do dialog, ento mantemos ponteiros para eles tambm. A palavra-chave slots , como signals, uma macro que se transforma em uma construo que C++ pode digerir. Para as variveis private, usamos foward declarations das respectivas classes. Isso foi possvel porque so todos ponteiros e no precisamos acess-los no header, ento o compilador no precisa de todas as definies da classe. Poderamos ter includo os includes (<QCheckBox>, <QLabel>, etc.), mas utilizando foward declarations quando possvel, isso torna o tempo de compilao menor. Vamos para o arquivo da implementao da classe FindDialog, o finddialog.cpp: 1 #include <QtGui> 2 #include "finddialog.h" Primeiramente inclumos <QtGui>, um arquivo header que contm a definio das classes GUI do Qt. Qt consiste de vrios mdulos, cada um com sua prpria biblioteca. Os mdulos mais importantes so QtCore, QtGui, QtNetwork, QtOpenGL, QtScript, QtSql, QtSvg e QtXml. O header <QtGui> contm a definio de todas as classes que so parte dos mdulos QtCore e QtGui. Incluir este header nos economiza a incluso individual de cada classe do nosso dialog. No arquivo finddialog.h, ao invs de incluir <QDialog> e utilizar foward declarations para QCheckBox, QLabel, QLineEdit e QPushButton, poderamos simplesmente ter includo <QtGui>. Entretanto no aconselhvel incluir um arquivo header to grande, especialmente em aplicaes grandes.

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


3 FindDialog::FindDialog(QWidget *parent) 4 : QDialog(parent) 5 { 6 label = new QLabel(tr("Find &what:")); 7 lineEdit = new QLineEdit; 8 label->setBuddy(lineEdit); 9 10 11 12 13 14 caseCheckBox = new QCheckBox(tr("Match &case")); backwardCheckBox = new QCheckBox(tr("Search &backward")); findButton = new QPushButton(tr("&Find")); findButton->setDefault(true); findButton->setEnabled(false); closeButton = new QPushButton(tr("Close"));

18

Na linha 4, passamos o parmetro parent para o construtor da classe base. Depois criamos os objetos filhos. A funo tr() marca a string literal para futuras tradues para outras lnguas. Esta funo declarada em QObject e em todas as classes que contm a macro Q_OBJECT. um bom hbito cercar strings visveis aos usurios com tr(), mesmo que voc no tenha planos imediatos para traduzir sua aplicao para outras lnguas. Tradues sero estudadas no Captulo 18. Em strings literais, utilizamos o smbolo & para indicar teclas de atalho. Por exemplo, a linha 11 cria o boto Find, o qual o usurio pode ativar utilizando Alt+F nas plataformas que suportam teclas de atalho. O smbolo & tambm pode ser utilizado para controlar o foco: na linha 6 criamos uma label com a tecla de atalho (Alt+W), e na linha 8 ns definimos o lineedit como companheiro (buddy) da label. Um buddy um widget que aceita o foco quando a tecla de atalho do outro pressionada. Ento quando o usurio pressiona Alt+W (atalho da label), o foco vai para o lineedit (buddy da label). Na linha 12, fazemos com que o boto Find seja o padro chamando setDefault(true). O boto padro o boto que, quando o usurio pressiona Enter, pressionado. Na linha 13, desabilitamos o boto Find. Quando um widget est desabilitado ele geralmente mostrado em tons acinzentados e no responder s interaes do usurio. 15 16 17 18 19 20 connect(lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(enableFindButton(const QString &))); connect(findButton, SIGNAL(clicked()), this, SLOT(findClicked())); connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));

O slot privado enableFindButton(const QString &) chamado sempre que o texto do lineedit mudar. O slot privado findClicked() chamado quando o usurio clicar no boto Find. O dialog se fecha quando o usurio clicar em Close. O slot close() herdado de QWidget, e o seu comportamento padro esconder o widget de visualizao (sem delet-lo). Estudaremos o cdigo para os slots enableFindButton() e findClicked() mais adiante. J que QObject um dos ancestrais do nosso dialog, ento podemos omitir o prefixo QObject:: das chamadas de connect(). 21 22 QHBoxLayout *topLeftLayout = new QHBoxLayout; topLeftLayout->addWidget(label);

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


23
19

topLeftLayout->addWidget(lineEdit); QVBoxLayout *leftLayout = new QVBoxLayout; leftLayout->addLayout(topLeftLayout); leftLayout->addWidget(caseCheckBox); leftLayout->addWidget(backwardCheckBox); QVBoxLayout *rightLayout = new QVBoxLayout; rightLayout->addWidget(findButton); rightLayout->addWidget(closeButton); rightLayout->addStretch(); QHBoxLayout *mainLayout = new QHBoxLayout; mainLayout->addLayout(leftLayout); mainLayout->addLayout(rightLayout); setLayout(mainLayout);

24 25 26 27 28 29 30 31 32 33 34 35

Depois disso, ns alinhamos os widgets filhos utilizando gerenciadores de layout. Layouts podem conter ambos widgets e outros layouts. Misturando QHBoxLayouts, QVBoxLayout e QGridLayout, possvel gerar dialogs bem sofisticados. Para nosso dialog, usaremos dois QHBoxLayout e dois QVBoxLayout, como mostrados na Figura 2.2. O layout externo o principal; ele instalado no FindDialog na linha 35 e responsvel por toda a rea do layout. Os outros trs layouts so sub-layouts. A pequena mola na parte inferior direita da Figura 2.2. um spacer (ou stretch). Ele usa o espao vazio abaixo dos botes Find e Close, garantindo que esses botes ocupem o topo do layout em que esto. Figura 2.2. Os layouts do dialog de busca

Um aspecto sutil de classes de gerenciamento de layouts que no so widgets. Ao invs disso, so derivadas de QLayout. Que por sua vez derivado de QObject. Na figura, widgets so representados por linhas slidas e layouts so representados por linhas tracejadas para destacar a diferena entre eles. Durante a execuo do programa, layouts so invisveis. Quando sub-layouts so adicionados ao layout pai (linhas 23, 33 e 34), os sub-layouts tm seus pais redefinidos. Da, quando o layout principal instalado no dialog (linha 35), ele se torna filho do dialog e todos os widgets dentro dos layouts tm seus pais redefinidos como o dialog. A hierarquia resultante mostrada na Figura 2.3. 36 37 38 } setWindowTitle(tr("Find")); setFixedHeight(sizeHint().height());

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

20

Figura 2.3. As relaes de parentesco do dialog

Finalmente, definimos o ttulo a ser mostrado na barra de ttulo e uma altura fixa para a janela, j que no existem widgets dentro do dialog que possam ocupar um espao vertical significativo. A funo QWidget::sizeHint() retorna o tamanho ideal do widget. Isso completa a reviso do construtor da classe FindDialog. J que criamos os objetos e layouts atravs de new, razovel pensar que devemos deletar cada widget e layout com um delete. Mas no necessrio, o Qt automaticamente deleta objetos filhos quando o pai destrudo, e todos os widgets e layouts do nosso dialog so descendentes do prprio dialog. Agora, vamos definir os slots do dialog: 39 void FindDialog::findClicked() 40 { 41 QString text = lineEdit->text(); 42 Qt::CaseSensitivity cs = 43 caseCheckBox->isChecked() ? Qt::CaseSensitive 44 : Qt::CaseInsensitive; 45 if (backwardCheckBox->isChecked()) { 46 emit findPrevious(text, cs); 47 } else { 48 emit findNext(text, cs); 49 } 50 } 51 void FindDialog::enableFindButton(const QString &text) 52 { 53 findButton->setEnabled(!text.isEmpty()); 54 } O slot findClicked() chamado quando o usurio clica no boto Find. Ele emite o sinal findPrevious() ou findNext(), dependendo da opo Search Backward. A palavra-chave emit especfica do Qt; como outras extenses Qt ela convertida em C++ padro pelo prprocessador C++. O slot enableFindButton() chamado sempre que o usurio muda o texto contido no lineedit. Isso ativa o boto se houver algum texto no lineedit, e desabilita caso contrrio. Estes dois slots finalizam o dialog. Podemos, ento, criar um main.cpp para testar nosso widget FindDialog:

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


1 #include <QApplication>
21

2 #include "finddialog.h" 3 int main(int argc, char *argv[]) 4 { 5 QApplication app(argc, argv); 6 FindDialog *dialog = new FindDialog; 7 dialog->show(); 8 return app.exec(); 9 }

Para compilar o programa, utilize qmake como de usual. Uma vez que a definio da classe FindDialog contm a macro Q_OBJECT, ento o makefile gerado pelo qmake incluir regras especiais para executar o moc, o meta-object compiler do Qt. (O sistema meta-object ser estudado na prxima seo). Para que o moc funcione corretamente necessrio colocar a definio da classe em um arquivo header, fora da implementao. O cdigo gerado pelo moc inclui esse arquivo header e adiciona alguns cdigos padres do C++ por si prprio. Classes que utilizam a macro Q_OBJECT devem ser executadas pelo moc. Isso no um problema porque o qmake automaticamente adiciona as regras necessrias para o makefile. Mas se voc esquecer de gerar seu makefile usando qmake e o moc no tiver rodado, o linker reclamar dizendo que algumas funes foram declaradas mas no implementadas. As mensagens podem ser relativamente obscuras. O GCC produz mensagens de erro desse tipo: finddialog.o: In function `FindDialog::tr(char const*, char const*)': /usr/lib/qt/src/corelib/global/qglobal.h:1430: undefined reference to `FindDialog::staticMetaObject'

A sada do Visual C++ comea assim: finddialog.obj : error LNK2001: unresolved external symbol "public:~virtual int __thiscall MyClass::qt_metacall(enum QMetaObject ::Call,int,void * *)"

Se isso acontecer com voc algum dia, execute o qmake de novo para atualizar o arquivo makefile, e reconstrua a aplicao. Agora, execute o programa. Se as teclas de atalho so exibidas em sua plataforma, verifique se as teclas de atalho Alt+W, Alt+C, Alt+B, e Alt+F acionam o comportamento correto. Pressione a tecla tab para navegar pelos widgets com o teclado. A ordem de tabulao padro, a ordem na qual os widgets foram criados. Isso pode ser mudado usando QWidget::setTabOrder(). Fornea uma ordem razovel para a tecla tab e bons atalhos de teclado de forma que usurios que no querem (ou que no podem) usar um mouse sejam capazes de usar ao mximo a aplicao. Controle total sobre o teclado tambm apreciado por digitadores rpidos. No Captulo 3, ns usaremos o dialogo de busca numa aplicao real, e ns conectaremos os sinais findPrevious() e findNext() a alguns slots.

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

22

Signals e Slots a Fundo


O mecanismo de sinais e slots fundamental para programao em Qt. Ele permite que o programador estabelea um elo entre os objetos sem que os objetos saibam uns dos outros. Ns j conectamos alguns sinais e slots, declaramos nossos prprios sinais e slots, implementamos nossos slots e emitimos nossos sinais. Vamos dar uma olhada no mecanismo mais de perto. Slots so quase idnticos a funes membro ordinrias do C++. Elas podem ser virtuais, podem ser sobrecarregadas, podem ser publics, protecteds ou privates, podem ser diretamente chamadas como qualquer outra funo membro do C++, e os seus parmetros podem ser de qualquer tipo. A diferena que um slot tambm pode ser conectado a um sinal, que no caso ser chamado toda vez que o sinal for emitido. A estrutura da funo connect() se d da seguinte forma: connect(sender, SIGNAL(signal), receiver, SLOT(slot));

Onde sender e receiver so ponteiros para QObjects e signal e slot so assinaturas de funes sem nomes de parmetros. As macros SIGNAL() e SLOT() essencialmente convertem seus argumentos para uma string. Nos exemplos que vimos at agora, ns sempre conectamos sinais diferentes com slots diferentes. Existem outras possibilidades a serem levadas em considerao.

Um sinal pode ser conectado a vrios slots: connect(slider, SIGNAL(valueChanged(int)), spinBox, SLOT(setValue(int))); connect(slider, SIGNAL(valueChanged(int)), this, SLOT(updateStatusBarIndicator(int))); Quando o sinal emitido, os slots so chamados um a um, numa ordem no especificada. Vrios sinais podem ser conectados ao mesmo slot: connect(lcd, SIGNAL(overflow()), this, SLOT(handleMathError())); connect(calculator, SIGNAL(divisionByZero()), this, SLOT(handleMathError())); Quando qualquer um dos sinais for emitido, o slot chamado. Um sinal pode ser conectado a outro sinal: connect(lineEdit, SIGNAL(textChanged(const QString &)), this, SIGNAL(updateRecord(const QString &))); Quando o primeiro sinal emitido, o segundo sinal tambm emitido. Alm disso, conexes signal-signal so indistinguveis de conexes signal-slot.

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

23

Conexes podem ser removidas: disconnect(lcd, SIGNAL(overflow()), this, SLOT(handleMathError())); Isso raramente necessrio, porque o Qt automaticamente remove todas as conexes envolvendo um objeto quando ele deletado.

Para conectar um sinal a um slot com sucesso (ou outro signal), eles precisam ter os mesmos tipos de parmetros na mesma ordem: connect(ftp, SIGNAL(rawCommandReply(int, const QString &)), this, SLOT(processReply(int, const QString &)));

Excepcionalmente, se um sinal tem mais parmetros que o slot ao qual est conectado, os parmetros adicionais so simplesmente ignorados. connect(ftp, SIGNAL(rawCommandReply(int, const QString &)), this, SLOT(checkErrorCode(int)));

Se os tipos de parmetros so incompatveis, ou se o sinal ou slot no existirem, o Qt ir informar atravs de um warning em tempo de execuo (se a aplicao foi construda no modo debug). Similarmente, o Qt ir lanar um warning se os nomes dos parmetros estiverem inseridos nas assinaturas do sinal ou do slot. At agora, apenas utilizamos sinais e slots com widgets. Mas o mecanismo implementado para QObject e no limitado a programao GUI. O mecanismo pode ser usado por qualquer subclasse de QObject: class Employee : public QObject { Q_OBJECT public: Employee() { mySalary = 0; } int salary() const { return mySalary; } public slots: void setSalary(int newSalary); signals: void salaryChanged(int newSalary); private: int mySalary; };

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

24

O Sistema Meta-Object do Qt
Uma das maiores conquistas do Qt foi a extenso do C++ com um mecanismo de criao de componentes de software independentes que podem ser ligados sem nem saberem informaes sobre o componente aos quais esto conectados. O mecanismo chamado sistema meta-object e fornece dois servios chave: signalsslots, e introspeco. A funcionalidade da introspeco necessria para implementar signals e slots, e permite programadores obterem informaes meta sobre sub-classes QObject em tempo de execuo, incluindo a lista de sinais e slots suportados pelo objeto e nome da sua classe. O mecanismo tambm suporta propriedades (amplamente usadas pelo Qt Designer) e traduo de texto (para internacionalizao), e estabelece as bases do mdulo QtScript. A partir do Qt 4.2, propriedades podem ser adicionadas dinamicamente, um recurso que veremos em ao nos Captulos 19 e 22. O C++ padro no fornece suporte para as meta-informaes dinmicas que o sistema de meta-objeto de Qt precisa. O Qt resolve isso com uma ferramenta separada, o moc. Ele analisa as definies de Q_OBJECT e faz com que a informao fique disponvel atravs de funes C++. J que o moc implementa toda a sua funcionalidade usando C++ puro, o sistema meta-object funciona com qualquer compilador C++. O mecanismo funciona da seguinte forma: A macro Q_OBJECT declara algumas funes de introspeco que devem ser implementadas em cada subclasse de QObject: metaObject(), tr(), qt_metacall(), entre outras. A ferramenta moc gera implementaes para as funes declaradas por Q_OBJECT e para todos os signals. As funes membro de QObject (como connect() e disconnect() ) usam as funes de introspeco para fazer seus trabalhos.

Tudo isso feito automaticamente pelo qmake, moc e QObject, ento voc dificilmente ter que pensar nisso. Mas se estiver curioso voc pode ler a documentao da classe QMetaObject e os cdigos C++ gerados pelo moc para ver como a implementao funciona.

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

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

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

25

Design Rpido de Dialogs


O Qt foi planejado para ser agradvel e intuitivo para o desenvolvimento de cdigo a mo, e no difcil encontrar programadores que desenvolvem suas aplicaes inteiras puramente escrevendo cdigo C++. Porm, muitos programadores preferem utilizar uma aproximao visual para desenvolver formulrios, porque eles acham que este mtodo mais natural e rpido do que apenas cdigo, e eles querem estar aptos a testar e mudar designs com mais rapidez e facilidade do que quando desenvolvidos com cdigos puros. O Qt Designer expande as opes disponveis aos programadores fornecendo uma capacidade visual de design. Qt Designer pode ser usado para desenvolver todos ou apenas alguns dos formulrios da aplicao. Formulrios que so criados utilizando o Qt Designer so convertidos em cdigo C++, ento o Qt Designer pode ser usado com uma variedade de ferramentas convencionais e no impe especificaes especiais ao compilador. Nessa seo, usaremos o Qt Designer para criar o dilogo Ir para a clula mostrado na Figura 2.4. Criar o dialog no Qt Designer ou por cdigo sempre envolve alguns passos fundamentais: 1. Criar e inicializar widgets filhos. 2. Coloc-los em um layout. 3. Atribuir a ordem dos tabs. 4. Estabelecer conexes signal/slots. 5. Implementar os prprios slots do dialog. Figura 2.4. O dialog de Ir para clula.

Para iniciar o Qt Designer, clique em Qt by Trolltech v4.x.y|Designer no menu Iniciar no Windows, digite designer na linha de comando do Unix, ou d um duplo-clique em Designer no Mac OS X Finder. Quando o Qt Designer iniciar, ele ir mostrar uma lista de templates. Clique no template Widget e depois clique em Create. (O template Dialog with Buttons Bottom pode parecer tentador, mas para esse exemplo ns criaremos os botes OK e Cancel manualmente e mostraremos como feito.) Voc deve, agora, ter uma janela chamada Untitled. Por padro, a interface de usurio do Qt consiste em vrias janelas top-level. Se voc preferir uma interface MDI (multiple document interface) com uma janela top-window e vrias subjanelas, como mostrado na Figura 2.5, clique em Edit|Preferences e ajuste o modo de interface do usurio para Docked Window.

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


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

O primeiro passo criar widgets filhos e coloc-los no formulrio. Criar uma label, um line editor, um spacer horizontal, e dois botes. Para cada item, arraste o nome ou o cone da caixa de widgets do Qt Designer e solte-o aproximadamente onde ele deveria estar no formulrio. O spacer, que invisvel no formulrio final, mostrado no Qt Designer como uma pequena mola azul. Agora arraste a borda inferior do formulrio pra encurt-lo. Isso deveria produzir um formulrio que similar ao da Figura 2.6. No gaste muito tempo posicionando os itens precisamente no formulrio. Os gerenciadores de layouts vo posicion-los de forma precisa posteriormente. Figura 2.6. O formulrio com alguns widgets

Utilizando o editor de propriedades do Qt Designer ajuste as propriedades de cada widget: 1. Clique na label TextLabel. Certifique-se de que a propriedade objectName dela seja label e mude a propriedade text para &Cell Location:. 2. Clique no line editor. Certifique-se de que a propriedade objectName seja lineEdit. 3. Clique no primeiro boto. Defina a propriedade objectName como okButton, a propriedade enabled para false, a propriedade text para OK, e a propriedade default para true.
Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


4. Clique no segundo boto. Defina a propriedade objectName para cancelButton e a propriedade text para Cancel. 5. Clique no fundo do formulrio para selecion-lo. Ajuste a propriedade objectName para GoToCellDialog e a propriedade windowTitle para Go to Cell. Todos os widgets parecem bem, exceto pela label que mostra &Cell Location. Escolha Edit|Edit Buddies para entrar em um modo especial de edio que te permite escolher os Buddies. Depois, clique na tabela, mantenha o boto apertado e arraste a seta vermelha para o line Edit, e depois libere o boto. A label deveria exibir, agora, o texto Cell Location, como mostrado na Figura 2.7 e tem o line Edit como seu buddy. Para deixar o modo de edio de buddies clique em Edit|Edit Widgets.

27

Figura 2.7 Formulrio com as propriedades ajustadas

O prximo passo alinhar os widgets no formulrio: 1. Clique na label Cell Location, pressione a tecla Shift e clique no line Edit para selecionar os dois widgets. Clique em Form|Lay Out Horizontally. 2. Clique no spacer, segure o Shift e clique em ambos os botes. Clique em Form|Lay Out Horizontally. 3. Clique no fundo do formulrio para remover a seleo anterior de qualquer widget, depois clique em Form|Lay Out Vertically. 4. Clique em Form|Adjust Size para redimensionar o formulrio para o seu tamanho preferencial. As linhas vermelhas mostradas no formulrio mostram os layouts que foram criados, como mostrado na Figura 2.8. Eles no so visveis quando o formulrio executado. Figura 2.8. Formulrio com Layouts.

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Agora clique em Edit|Edit Tab Order. Um nmero em um retngulo azul aparecer prximo de cada widget que possa admitir foco, como mostrado na Figura 2.9. Clique em cada widget para escolher a ordem de cada um, depois clique em Edit|Edit Widgets para deixar o modo de edio de tabs.

28

Figura 2.9. Definindo a ordem do tab.

Para visualizar o dialog, clique em Form|Preview. Note a ordem dos tabs que voc predefiniu pressionando Tab repetidamente. Feche o dialog utilizando o boto fechar na barra de ttulo. Salve as alteraes como gotocelldialog.ui em um diretrio chamado gotocell, e crie um arquivo main.cpp no mesmo diretrio utilizando um editor de texto: #include <QApplication> #include <QDialog> #include "ui_gotocelldialog.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Ui::GoToCellDialog ui; QDialog *dialog = new QDialog; ui.setupUi(dialog); dialog->show(); return app.exec(); }

Agora execute o qmake para criar um arquivo .pro e um makefile (qmake project; qmake gotocell.pro). A ferramenta qmake inteligente o bastante para detectar o arquivo de interface do usurio gotocelldialog.ui e para gerar as regras apropriadas do makefile para chamar uic, o compilador de interfaces de usurio do Qt. A ferramenta uic converte o arquivo gotocelldialog.ui em cdigo C++ e pe o resultado no arquivo ui_gotocelldialog.h. O arquivo ui_gotocelldialog.h gerado contm as definies para a classe Ui::GoToCellDialog, que um equivalente C++ do gotocelldialog.ui. A classe declara variveis membro que armazenam os layouts e widgets filhos do formulrio, e uma funo setupUi() que inicializa o formulrio. A classe gerada se parece com isso:

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


class Ui::GoToCellDialog { public: QLabel *label; QLineEdit *lineEdit; QSpacerItem *spacerItem; QPushButton *okButton; QPushButton *cancelButton; ... void setupUi(QWidget *widget) { ... } }; A classe gerada no tem nenhuma classe base. Quando utilizamos essa classe no main.cpp, ns criamos um QDialog e o passamos para setupUI(). Se voc executar o programa agora, o dilogo vai funcionar, mas ele no funciona exatamente como queremos: O boto OK est sempre desabilitado. O boto Cancel no faz nada. O line Edit aceita qualquer texto, ao invs de s aceitar posies validas de clula.

29

Ns podemos fazer com que o dilogo funcione corretamente escrevendo algum cdigo. O jeito mais organizado de fazer isso criando uma classe que derivada de ambos QDialog e Ui::GoToCellDialog e que implemente a funcionalidade faltante (deste modo provando a mxima de que qualquer problema do software pode ser resolvido simplesmente adicionando outra camada de meios indiretos). A conveno de nomeao dar o mesmo nome da classe gerada pelo o uic mas sem o prefixo Ui::. Usando um editor de texto, crie um arquivo chamado gotocelldialog.h que contenha o seguinte cdigo: #ifndef GOTOCELLDIALOG_H #define GOTOCELLDIALOG_H #include <QDialog> #include "ui_gotocelldialog.h" class GoToCellDialog : public QDialog, public Ui::GoToCellDialog { Q_OBJECT public: GoToCellDialog(QWidget *parent = 0); private slots: void on_lineEdit_textChanged(); }; #endif

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Aqui, utilizamos herana pblica porque queremos acessar todos os widgets do dialog de fora do dialog. A implementao pertence ao arquivo gotocelldialog.cpp: #include <QtGui> #include "gotocelldialog.h" GoToCellDialog::GoToCellDialog(QWidget *parent) : QDialog(parent) { setupUi(this); QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}"); lineEdit->setValidator(new QRegExpValidator(regExp, this)); connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); } void GoToCellDialog::on_lineEdit_textChanged() { okButton->setEnabled(lineEdit->hasAcceptableInput()); }

30

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

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

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Para widgets, o pai tem um significado adicional: Widgets filhos so mostrados dentro da rea do pai. Quando deletamos o Widget pai, no somente os filhos so liberados da memria como tambm desaparecem da tela. Ao fim do construtor, ns conectamos o boto OK ao slot accept() do QDialog e o boto Cancel ao slot reject(). Ambos os slots fecham o dialog, mas accept() define o valor de resultado do dialog para QDialog::Accepted (que 1), e o reject() define o resultado para QDialog::Rejected (que 0). Quando ns usamos esse dialog, ns podemos usar o resultado para ver se o usurio clicou OK e atua de acordo. O slot on_lineEdit_textChanged() ativa ou desativa o boto OK, dependendo se o line edit contm uma localizao vlida de clula. QLineEdit::hasAcceptableInput() usa o validador que escolhemos no construtor. Isso completa o dialog. Podemos agora reescrever o arquivo main.cpp para us-lo: #include <QApplication> #include "gotocelldialog.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); GoToCellDialog *dialog = new GoToCellDialog; dialog->show(); return app.exec(); }

31

Construa o arquivo gotocell.pro usando qmake project (j que adicionamos arquivos fonte ao projeto), execute qmake gotocell.pro para atualizar o makefile, depois construa e execute a aplicao de novo. Digite A12 no editor, e perceba que o boto OK se torna ativo. Tente digitar alguns textos aleatrios para ver como o validator funciona. Clique Cancel para fechar o dialog. O dialog funciona corretamente, mas para usurios do Mac, os botes esto um pouco diferentes. Escolhemos adicionar cada boto individualmente, para mostrar como era feito, mas ns deveramos ter usado um QDialogButtonBox, um widget que contm os botes que especificamos e que os apresenta na forma correta para o sistema de janelas no qual a aplicao est sendo executada, como mostrado na Figura 2.10.

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

Para fazer com que o dialog use um QDialogButtonBox, ns devemos modificar ambos o design e o cdigo. No Qt Designer, existem apenas quatro passos a tomar:

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


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

32

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


usurio do dialog salva em um arquivo .ui (um arquivo no formato XML), enquanto que funcionalidades prprias so implementadas derivando da classe gerada pelo uic.

33

Modificando a Forma dos Dialogs


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

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

Este dilogo um dilogo de classificao de uma aplicao de planilhas, onde o usurio pode selecionar uma ou vrias colunas para que sejam classificadas. A verso simples do dilogo permite que ele escolha apenas uma chave de classificao, enquanto que a verso estendida fornece os meios para duas chaves extras. O boto more permite que o usurio alterne entre as verses. Criaremos o widget com sua verso expandida no Qt Designer, e esconderemos as chaves extras em tempo de execuo conforme necessrio. O dilogo parece complicado, mas fcil faz-lo no Qt Designer. O truque fazer a primeira chave primeiro, depois duplic-la duas vezes para obter as outras:

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


1. Clique em File|New Form e escolha o modelo Dialog com botes.
34

2. Crie um boto OK e arraste para o canto superior direito do formulrio. Mude a sua propriedade do objectName para okButton e defina sua propriedade default para true. 3. Crie um boto Cancel, e arraste-o para baixo do boto OK. Mude sua propriedade objectName para cancelButton. 4. Crie um spacer vertical e arraste-o para baixo do boto Cancel, depois crie um boto 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 boto OK, segure o Shift e clique no boto Cancel, no spacer vertical, no boto 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 formulrio. 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 boto 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 boto 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 no 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:
Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


1. Aumente a altura do dilogo para que ele seja capaz de armazenar as outras duas chaves. 2. Segure o Ctrl (Alt no Mac), clique e arraste o primeiro group box para criar uma cpia dele (e de seu contedo) sobre o original. Arraste a cpia para baixo do original, ainda segurando o Ctrl (ou Alt). Repita esse processo para criar um terceiro group box, arrastando-o para baixo do segundo. 3. Mude as propriedades title deles para &Seconday Key e &Tertiary Key. 4. Crie um spacer vertical e coloque-o entre o primeiro e o segundo group box. 5. Organize os widgets no padro grid mostrado na Figura 2.13(a). 6. Clique no formulrio para limpar possveis selees, clique em Form|Lay Out in a Grid. Agora arraste o canto inferior direito do formulrio para cima e para esquerda para deix-lo menor possvel. O formulrio deveria se parecer com a Figura 2.13(b). 7. Ajuste a propriedade sizeHint dos dois spacers verticais para [20,0].

35

Figura 2.13. Alinhando os widgets do formulrio em grid.

O layout em grid resultante tem duas colunas e quarto linhas, totalizando oito clulas. O primeiro group box, o spacer vertical da esquerda, o segundo group box, e o terceiro group box, cada um ocupa uma nica clula. O layout vertical contendo os botes OK, Cancel, e More ocupa duas clulas. Isso deixa duas clulas vazias na rea inferior direita do dilogo. Se voc no tem o mesmo resultado, desfaa o layout, reposicione os widgets, e tente de novo. Renomeie o formulrio para SortDialog e mude o ttulo da janela para Sort. Defina os nomes dos widgets filhos para aqueles da Figura 2.14.

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Figura 2.14. Nomeando os widgets
36

Clique em Edit|Edit Tab Order. Clique em cada combo box de cima para baixo, nos botes OK, Cancel, e More. Clique em Edit|Edit Widgets para deixar o modo de edio de tabs. Agora que o formulrio foi desenhado, estamos prontos para torn-lo funcional designando algumas conexes signals-slots. O Qt Designer nos permite que estabeleamos conexes entre widgets que compartilham do mesmo formulrio. Precisamos estabelecer duas delas. Clique em Edit|Edit Signals/Slots para entrar no modo de conexes do Qt Designer. Conexes so representadas por setas azuis entre os widgets do formulrio, como mostrado na Figura 2.15, e elas tambm so listadas na janela de edio de signals/slots do Qt Designer. Para estabelecer uma conexo entre dois widgets, clique no widget remetente e arraste a seta vermelha para o widget destinatrio, e solte o boto do mouse. Isso vai fazer com que um dilogo seja exibido, permitindo que voc escolha o sinal e o slot que pertencero a conexo. Figura 2.15. Conectando os widgets

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


A primeira conexo a ser feita entre o boto okButton e o slot accept() do formulrio. Arraste a seta vermelha do boto okButton para uma parte vazia do formulrio, solte o boto para configurar a conexo pelo dilogo de configurao que ser aberto, como mostrado na Figura 2.16. Escolha clicked() como sinal e accept() como slot, e clique OK. Figura 2.16. Dilogo de editor de conexes do Qt Designer

37

Para a segunda conexo, arraste a seta vermelha do boto cancelButton para uma parte vazia do formulrio, e no dilogo de configurao conecte o sinal clicked() ao slot reject() do formulrio. A terceira conexo a ser estabelecida entre o boto moreButton e o group box secondaryGroupBox. Arraste a seta vermelha entre estes widgets, ento selecione o sinal toggled(bool) e o slot setVisible(bool). Por padro, o Qt Designer no lista o slot setVisible(bool) na lista de slots, mas ele aparece se voc habilitar a opo Show all signals and slots. A quarta e ltima conexo entre o sinal toggled(bool) do boto moreButton e o slot setVisible(bool) do terceiro group box. Uma vez que as conexes foram estabelecidas, clique em Edit|Edit Widgets para deixar o modo de conexes. Salve o dilogo como sortdialog.ui em um diretrio chamado sort. Para adicionar cdigo ao formulrio, ns usaremos o mesmo principio de herana mltipla que usamos para o dilogo Go to Cell na seo anterior. Primeiro, crie um arquivo sortdialog.h com o seguinte contedo: #ifndef SORTDIALOG_H #define SORTDIALOG_H #include <QDialog> #include "ui_sortdialog.h" class SortDialog : public QDialog, public Ui::SortDialog { Q_OBJECT
Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio

38

public: SortDialog(QWidget *parent = 0); void setColumnRange(QChar first, QChar last); }; #endif Agora crie o sortdialog.cpp: 1 #include <QtGui> 2 #include "sortdialog.h" 3 SortDialog::SortDialog(QWidget *parent) 4 : QDialog(parent) 5 { 6 setupUi(this); 7 8 9 10 11 } secondaryGroupBox->hide(); tertiaryGroupBox->hide(); layout()->setSizeConstraint(QLayout::SetFixedSize); setColumnRange('A', 'Z');

12 void SortDialog::setColumnRange(QChar first, QChar last) 13 { 14 primaryColumnCombo->clear(); 15 secondaryColumnCombo->clear(); 16 tertiaryColumnCombo->clear(); 17 18 19 20 21 22 23 24 25 26 27 28 } secondaryColumnCombo->addItem(tr("None")); tertiaryColumnCombo->addItem(tr("None")); primaryColumnCombo->setMinimumSize( secondaryColumnCombo->sizeHint()); QChar ch = first; while (ch <= last) { primaryColumnCombo->addItem(QString(ch)); secondaryColumnCombo->addItem(QString(ch)); tertiaryColumnCombo->addItem(QString(ch)); ch = ch.unicode() + 1; }

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

C++ GUI Programando com Qt4, Segunda Edio


diferentes tipos de widgets, ou widgets similares com contedos diferentes, podem ser designados com diferentes tamanhos pelo sistema de layout. Para comboboxes, isso significa que os comboboxes secundrio e tercirio, que contm None, acabam maiores que o primeiro combobox, que contm s entradas de letras individuais. Para evitar essa inconsistncia, ns definimos o tamanho mximo da primeira combobox para o tamanho ideal do segundo combobox. Aqui est uma funo teste main() que define o intervalo para incluir as colunas de C a F e depois mostra o dilogo: #include <QApplication> #include "sortdialog.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); SortDialog *dialog = new SortDialog; dialog->setColumnRange('C', 'F'); dialog->show(); return app.exec(); } Isso completa o dilogo de extenso. Como o exemplo mostra, este tipo de dilogo no to mais difcil de desenhar do que o dilogo plano: Tudo que precisamos era um boto de alternncia, algumas conexes extras, e um layout no redimensionvel. Em aplicaes de produo, bem comum que o boto de alternncia tenha o texto Advanced >>> quando o dilog bsico exibido e Advanced <<< quando a extenso mostrada. Isso fcil de conseguir com Qt chamando setText() no QPushButton sempre que for clicado. O outro tipo comum de dilogos que mudam as formas, dilogos de mltiplas pginas, so at mais fceis de criar em Qt, tanto por cdigo ou com o Qt Designer. Tais dilogos podem ser construdos de diferentes maneiras: Um QTabWidget pode ser usado. Ele fornece uma tab bar que controla um QStackedWidget interno. Um QListWidget e um QStackWidget podem ser usados em conjunto, com o item atual do QListWidget determinando qual pgina o QStackedWidget mostra, conectando o sinal QListWidget::currentRowChanged() ao slot QStackWidget::setCurrentIndex(). Um QTreeWidget pode ser usado com um QStackedWidget num modo similar ao QListWidget.

39

Ns falaremos mais da classe QStackedWidget no Captulo 6.

Dialogs Dinmicos
Dialogs dinmicos so aqueles que so criados em tempo de execuo a partir de arquivos .ui produzidos no Qt Designer. Ao invs de converter o arquivo .ui para cdigo C++ utilizando uic, ns podemos carregar o arquivo em tempo de execuo usando a classe QUiLoader:

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


QUiLoader uiLoader; QFile file("sortdialog.ui"); QWidget *sortDialog = uiLoader.load(&file); if (sortDialog) { ... } Podemos acessar os widgets filhos utilizando QObject::findChild<T>(): QComboBox *primaryColumnCombo = sortDialog->findChild<QComboBox *>("primaryColumnCombo"); if (primaryColumnCombo) { ... } A funo findChild<T>() uma funo membro template que retorna o objeto filho que corresponde com o nome e tipo de dados. Por causa de uma limitao do compilador, isso no est disponvel para MSVC 6. Se voc precisa usar o compilador MSVC 6, utilize a funo global qFindChild<T>(), que funciona essencialmente da mesma forma. A classe QUiLoader est localizada em uma biblioteca separada. Para usar QUiLoader a partir de uma aplicao Qt, ns devemos adicionar esta linha ao arquivo .pro da aplicao: CONFIG += uitools Dilogos dinmicos tornam possvel mudar o layout de um formulrio sem recompilar a aplicao. Eles podem tambm ser usados para criar aplicaes thin-client, onde o executvel meramente tem um formulrio front-end interno e todos os outros formulrios so criados quando necessrio.

40

Classes Nativas de Widgets e Dialogs


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

Figura 2.17. Botes do Qt

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Figura 2.18. Containers de pgina nica do Qt
41

Figura 2.19. Containers de mltiplas pginas do Qt

Figura 2.20. Item views do Qt

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Figura 2.21. Widgets de exibio do Qt
42

Figura 2.22. Widgets de entrada do Qt

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Figura 2.23. Dilogos de feedback do Qt
43

Figura 2.24. Dilogos de fonte e cor do Qt

Figura 2.25. Dilogos de impresso e arquivo do Qt

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com

C++ GUI Programando com Qt4, Segunda Edio


Figura 2.26. Dilogo Qwizard do Qt
44

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

C++ GUI Programando com Qt4, Segunda Edio


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

45

Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com