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.
Parte I: O Bsico do Qt
1. Comeando
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
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
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.
Fazendo Conexes
O segundo exemplo mostra como responder s aes do usurio. A aplicao consiste em um boto que o usurio pode clicar para sair. O cdigo muito similar ao exemplo anterior, com exceo do uso de um QPushButton no lugar de uma QLabel como nosso widget principal, e ns estamos conectando a ao do usurio (clique) a um bloco de cdigo. O cdigo desta aplicao est em examples/chap01/quit/quit.cpp; a aplicao em andamento mostrada na Figura 1.3. Aqui est o contedo do arquivo: 1 #include <QApplication> 2 #include <QPushButton> 3 int main(int argc, char *argv[]) 4 { 5 QApplication app(argc, argv); 6 QPushButton *button = new QPushButton("Quit"); 7 QObject::connect(button, SIGNAL(clicked()), 8 &app, SLOT(quit())); 9 button->show(); 10 return app.exec(); 11 } Figura 1.3 A aplicao que fecha
Os widgets do Qt emitem sinais para indicar que uma ao de usurio ou uma mudana de estado ocorreu. [*] Por exemplo, QPushButton emite um sinal clicked() quando o usurio clica no boto. Um sinal pode se conectar com uma funo (chamada de slot nesse contexto) para que quando o sinal for emitido, o slot seja executado automaticamente. No nosso exemplo, ns conectamos o sinal clicked() do boto com o slot quit() do objeto QApplication. As macros SIGNAL() e SLOT() fazem parte da sintaxe.
[*] Sinais do Qt no tem nenhuma relao com sinais do Unix. Neste livro, estamos tratando somente dos sinais do Qt.
Vamos construir a aplicao. Assumimos que voc criou um diretrio chamado quit contendo o arquivo quit.cpp. Rode o qmake no diretrio quit para gerar o arquivo projeto, e depois rode-o novamente para gerar o makefile, como segue: qmake -project qmake quit.pro Agora construa a aplicao e rode-a. Se voc clicar em Quit, ou pressionar a barra de espao (que pressiona o boto), a aplicao terminar.
Alinhando Widgets
Nesta seo, iremos criar um pequeno exemplo que demonstra como usar layouts para gerenciar a geometria dos widgets em uma janela e como usar sinais e slots para sincronizar dois widgets. A aplicao (mostrada na Figura 1.4) pergunta pela idade do usurio, a qual o usurio pode informar manipulando um spin box ou um slider.
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();
10
24 25 }
return app.exec();
As linhas 8 e 9 preparam a QWidget que servir como a janela principal da aplicao. Podemos chamar setWindowTitle() para escolher o texto que ser exibido na barra de ttulo da janela. As linhas 10 e 11 criam um QSpinBox e um QSlider, e as linhas 12 e 13 atribuem seus intervalos vlidos. Podemos assumir que o usurio tem at 130 anos de idade. Poderamos passar window para os construtores de QSpinBox e QSlider especificando que estes widgets devem ter window como pai deles, mas no necessrio porque o sistema de layout ir configurar isso sozinho e automaticamente atribuir o pai do spin box e do slider, como veremos a seguir. As duas chamadas QObject::connect() mostradas nas linhas 14 at 17 asseguram que o spin box e o slider estejam sincronizados para que eles sempre mostrem o mesmo valor. Sempre que o valor de um dos widgets mudar, o sinal valueChanged() de um deles ser emitido, e o slot setValue(int) do outro ser chamado com o novo valor. A linha 18 predefine o valor do spin box para 35. Quando isso acontece, o QSpinBox emite o sinal valueChanged(int) com um argumento do tipo int valendo 35. Esse argumento passado para o slot setValue(int) do QSlider, que ajusta o valor do slider para 35. O slider ento emite um sinal valueChanged(int) porque o prprio valor mudou, ativando o slot setValue(int) do spin box. Mas nesse ponto, setValue(int) no emite nenhum sinal, j que o valor do spin box j 35. Isso evita a recurso infinita. A Figura 1.5 ilustra a situao.
11
Estilos de Widgets
Os screenshots que vimos at agora tm sido tirados no Linux, mas aplicaes em Qt podem parecer nativas de cada plataforma suportada. O Qt consegue fazer isso emulando o look and feel de cada plataforma, ao invs de conter um kit de widgets de uma plataforma particular. Figura 1.6 Estilos pr-definidos
O estilo Plastique o estilo padro para aplicaes Qt/X11 rodando sob o KDE, e o Cleanlooks o padro sob o GNOME. Estes estilos utilizam gradientes e anti-aliasing
12
para gerar um look and feel moderno. Usurios de aplicaes Qt podem substituir os estilos padro utilizando o comando style na linha de comando. Por exemplo, para iniciar a aplicao de idade acima utilizando o estilo Motif sob X11, simplesmente digite o comando: ./age -style motif Diferente dos outros estilos, Windows XP, Windows Vista, e Mac apenas so visualizados nas plataformas nativas, j que dependem de dispositivos de tema de cada plataforma. Um estilo adicional chamado QtDotNet est disponvel no Qt Solutions. Tambm possvel criar estilos customizados, como ser explicado no Captulo 19.
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.
13
Note que funes herdadas so documentadas na classe base; por exemplo, QPushbutton no tem uma funo prpria show(), mas herda uma de QWidget. A Figura 1.9 mostra como as classes que vemos at agora se relacionam umas com as outras.
A documentao de referncia para a atual verso do Qt e para algumas verses mais recentes est disponvel online em http://doc.trolltech.com/. Este site tambm tem artigos selecionados do Qt Quarterly, o newsletter dos programadores Qt enviado para todas as licenas comerciais. Este captulo introduziu os conceitos chave de conexes signal-slot e layouts. Ele tambm comeou a revelar a perspectiva total e consistente de orientao a objetos at a construo e uso de widgets. Se voc procurar pela documentao do Qt, voc encontrar uma uniformidade de exibio que a torna bem direta no que se diz respeito ao uso de novos widgets, e voc tambm descobrir que Qt escolheu cuidadosamente os nomes para funes, parmetros, enums e assim por diante, que fazem com que programar em Qt se torne incrivelmente agradvel e fcil. Os captulos seguintes da Parte I se apoiam nos fundamentos aqui abordados, mostrando como criar uma GUI completa com menus, toolbars, janelas de documentos, status bars, e dialogs, em conjunto com a funcionalidade bsica de leitura, processamento e escrita de arquivos.
15
2. Criando Dialogs
Herdando de QDialog 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.
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.
17
13 signals: 14 void findNext(const QString &str, Qt::CaseSensitivity cs); 15 void findPrevious(const QString &str, Qt::CaseSensitivity cs); A seo signals declara dois sinais que o dialog emitir quando o usurio clicar no boto Find. Se a opo Search Backward estiver selecionada, o dialog emite findPrevious() caso contrrio, emite findNext(). A palavra-chave signals , na verdade, uma macro. O pr-processador C++ o converte para padres C++ antes que o compilador veja. Qt::CaseSensitivity um enum que pode assumir os valores Qt::CaseSensitive (um) e Qt::CaseInsensitive (zero). 16 private slots: 17 void findClicked(); 18 void enableFindButton(const QString &text); 19 private: 20 QLabel *label; 21 QLineEdit *lineEdit; 22 QCheckBox *caseCheckBox; 23 QCheckBox *backwardCheckBox; 24 QPushButton *findButton; 25 QPushButton *closeButton; 26 }; 27 #endif Na seo privada da classe, declaramos dois slots. Para implementar os slots, precisaremos acessar a maioria dos widgets filhos do dialog, ento mantemos ponteiros para eles tambm. A palavra-chave slots , como signals, uma macro que se transforma em uma construo que C++ pode digerir. Para as variveis private, usamos foward declarations das respectivas classes. Isso foi possvel porque so todos ponteiros e no precisamos acess-los no header, ento o compilador no precisa de todas as definies da classe. Poderamos ter includo os includes (<QCheckBox>, <QLabel>, etc.), mas utilizando foward declarations quando possvel, isso torna o tempo de compilao menor. Vamos para o arquivo da implementao da classe FindDialog, o finddialog.cpp: 1 #include <QtGui> 2 #include "finddialog.h" Primeiramente inclumos <QtGui>, um arquivo header que contm a definio das classes GUI do Qt. Qt consiste de vrios mdulos, cada um com sua prpria biblioteca. Os mdulos mais importantes so QtCore, QtGui, QtNetwork, QtOpenGL, QtScript, QtSql, QtSvg e QtXml. O header <QtGui> contm a definio de todas as classes que so parte dos mdulos QtCore e QtGui. Incluir este header nos economiza a incluso individual de cada classe do nosso dialog. No arquivo finddialog.h, ao invs de incluir <QDialog> e utilizar foward declarations para QCheckBox, QLabel, QLineEdit e QPushButton, poderamos simplesmente ter includo <QtGui>. Entretanto no aconselhvel incluir um arquivo header to grande, especialmente em aplicaes grandes.
18
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);
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());
20
Finalmente, definimos o ttulo a ser mostrado na barra de ttulo e uma altura fixa para a janela, j que no existem widgets dentro do dialog que possam ocupar um espao vertical significativo. A funo QWidget::sizeHint() retorna o tamanho ideal do widget. Isso completa a reviso do construtor da classe FindDialog. J que criamos os objetos e layouts atravs de new, razovel pensar que devemos deletar cada widget e layout com um delete. Mas no necessrio, o Qt automaticamente deleta objetos filhos quando o pai destrudo, e todos os widgets e layouts do nosso dialog so descendentes do prprio dialog. Agora, vamos definir os slots do dialog: 39 void FindDialog::findClicked() 40 { 41 QString text = lineEdit->text(); 42 Qt::CaseSensitivity cs = 43 caseCheckBox->isChecked() ? Qt::CaseSensitive 44 : Qt::CaseInsensitive; 45 if (backwardCheckBox->isChecked()) { 46 emit findPrevious(text, cs); 47 } else { 48 emit findNext(text, cs); 49 } 50 } 51 void FindDialog::enableFindButton(const QString &text) 52 { 53 findButton->setEnabled(!text.isEmpty()); 54 } O slot findClicked() chamado quando o usurio clica no boto Find. Ele emite o sinal findPrevious() ou findNext(), dependendo da opo Search Backward. A palavra-chave emit especfica do Qt; como outras extenses Qt ela convertida em C++ padro pelo prprocessador C++. O slot enableFindButton() chamado sempre que o usurio muda o texto contido no lineedit. Isso ativa o boto se houver algum texto no lineedit, e desabilita caso contrrio. Estes dois slots finalizam o dialog. Podemos, ento, criar um main.cpp para testar nosso widget FindDialog:
2 #include "finddialog.h" 3 int main(int argc, char *argv[]) 4 { 5 QApplication app(argc, argv); 6 FindDialog *dialog = new FindDialog; 7 dialog->show(); 8 return app.exec(); 9 }
Para compilar o programa, utilize qmake como de usual. Uma vez que a definio da classe FindDialog contm a macro Q_OBJECT, ento o makefile gerado pelo qmake incluir regras especiais para executar o moc, o meta-object compiler do Qt. (O sistema meta-object ser estudado na prxima seo). Para que o moc funcione corretamente necessrio colocar a definio da classe em um arquivo header, fora da implementao. O cdigo gerado pelo moc inclui esse arquivo header e adiciona alguns cdigos padres do C++ por si prprio. Classes que utilizam a macro Q_OBJECT devem ser executadas pelo moc. Isso no um problema porque o qmake automaticamente adiciona as regras necessrias para o makefile. Mas se voc esquecer de gerar seu makefile usando qmake e o moc no tiver rodado, o linker reclamar dizendo que algumas funes foram declaradas mas no implementadas. As mensagens podem ser relativamente obscuras. O GCC produz mensagens de erro desse tipo: finddialog.o: In function `FindDialog::tr(char const*, char const*)': /usr/lib/qt/src/corelib/global/qglobal.h:1430: undefined reference to `FindDialog::staticMetaObject'
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.
22
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.
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; };
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.
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.
25
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.
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
27
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.
28
Para visualizar o dialog, clique em Form|Preview. Note a ordem dos tabs que voc predefiniu pressionando Tab repetidamente. Feche o dialog utilizando o boto fechar na barra de ttulo. Salve as alteraes como gotocelldialog.ui em um diretrio chamado gotocell, e crie um arquivo main.cpp no mesmo diretrio utilizando um editor de texto: #include <QApplication> #include <QDialog> #include "ui_gotocelldialog.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Ui::GoToCellDialog ui; QDialog *dialog = new QDialog; ui.setupUi(dialog); dialog->show(); return app.exec(); }
Agora execute o qmake para criar um arquivo .pro e um makefile (qmake project; qmake gotocell.pro). A ferramenta qmake inteligente o bastante para detectar o arquivo de interface do usurio gotocelldialog.ui e para gerar as regras apropriadas do makefile para chamar uic, o compilador de interfaces de usurio do Qt. A ferramenta uic converte o arquivo gotocelldialog.ui em cdigo C++ e pe o resultado no arquivo ui_gotocelldialog.h. O arquivo ui_gotocelldialog.h gerado contm as definies para a classe Ui::GoToCellDialog, que um equivalente C++ do gotocelldialog.ui. A classe declara variveis membro que armazenam os layouts e widgets filhos do formulrio, e uma funo setupUi() que inicializa o formulrio. A classe gerada se parece com isso:
29
Ns podemos fazer com que o dilogo funcione corretamente escrevendo algum cdigo. O jeito mais organizado de fazer isso criando uma classe que derivada de ambos QDialog e Ui::GoToCellDialog e que implemente a funcionalidade faltante (deste modo provando a mxima de que qualquer problema do software pode ser resolvido simplesmente adicionando outra camada de meios indiretos). A conveno de nomeao dar o mesmo nome da classe gerada pelo o uic mas sem o prefixo Ui::. Usando um editor de texto, crie um arquivo chamado gotocelldialog.h que contenha o seguinte cdigo: #ifndef GOTOCELLDIALOG_H #define GOTOCELLDIALOG_H #include <QDialog> #include "ui_gotocelldialog.h" class GoToCellDialog : public QDialog, public Ui::GoToCellDialog { Q_OBJECT public: GoToCellDialog(QWidget *parent = 0); private slots: void on_lineEdit_textChanged(); }; #endif
30
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.
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.
Para fazer com que o dialog use um QDialogButtonBox, ns devemos modificar ambos o design e o cdigo. No Qt Designer, existem apenas quatro passos a tomar:
32
33
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:
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).
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
35
O layout em grid resultante tem duas colunas e quarto linhas, totalizando oito clulas. O primeiro group box, o spacer vertical da esquerda, o segundo group box, e o terceiro group box, cada um ocupa uma nica clula. O layout vertical contendo os botes OK, Cancel, e More ocupa duas clulas. Isso deixa duas clulas vazias na rea inferior direita do dilogo. Se voc no tem o mesmo resultado, desfaa o layout, reposicione os widgets, e tente de novo. Renomeie o formulrio para SortDialog e mude o ttulo da janela para Sort. Defina os nomes dos widgets filhos para aqueles da Figura 2.14.
Clique em Edit|Edit Tab Order. Clique em cada combo box de cima para baixo, nos botes OK, Cancel, e More. Clique em Edit|Edit Widgets para deixar o modo de edio de tabs. Agora que o formulrio foi desenhado, estamos prontos para torn-lo funcional designando algumas conexes signals-slots. O Qt Designer nos permite que estabeleamos conexes entre widgets que compartilham do mesmo formulrio. Precisamos estabelecer duas delas. Clique em Edit|Edit Signals/Slots para entrar no modo de conexes do Qt Designer. Conexes so representadas por setas azuis entre os widgets do formulrio, como mostrado na Figura 2.15, e elas tambm so listadas na janela de edio de signals/slots do Qt Designer. Para estabelecer uma conexo entre dois widgets, clique no widget remetente e arraste a seta vermelha para o widget destinatrio, e solte o boto do mouse. Isso vai fazer com que um dilogo seja exibido, permitindo que voc escolha o sinal e o slot que pertencero a conexo. Figura 2.15. Conectando os widgets
37
Para a segunda conexo, arraste a seta vermelha do boto cancelButton para uma parte vazia do formulrio, e no dilogo de configurao conecte o sinal clicked() ao slot reject() do formulrio. A terceira conexo a ser estabelecida entre o boto moreButton e o group box secondaryGroupBox. Arraste a seta vermelha entre estes widgets, ento selecione o sinal toggled(bool) e o slot setVisible(bool). Por padro, o Qt Designer no lista o slot setVisible(bool) na lista de slots, mas ele aparece se voc habilitar a opo Show all signals and slots. A quarta e ltima conexo entre o sinal toggled(bool) do boto moreButton e o slot setVisible(bool) do terceiro group box. Uma vez que as conexes foram estabelecidas, clique em Edit|Edit Widgets para deixar o modo de conexes. Salve o dilogo como sortdialog.ui em um diretrio chamado sort. Para adicionar cdigo ao formulrio, ns usaremos o mesmo principio de herana mltipla que usamos para o dilogo Go to Cell na seo anterior. Primeiro, crie um arquivo sortdialog.h com o seguinte contedo: #ifndef SORTDIALOG_H #define SORTDIALOG_H #include <QDialog> #include "ui_sortdialog.h" class SortDialog : public QDialog, public Ui::SortDialog { Q_OBJECT
Traduo livre realizada pelos membros do Frum QtBrasil www.qtbrasil.com
38
public: SortDialog(QWidget *parent = 0); void setColumnRange(QChar first, QChar last); }; #endif Agora crie o sortdialog.cpp: 1 #include <QtGui> 2 #include "sortdialog.h" 3 SortDialog::SortDialog(QWidget *parent) 4 : QDialog(parent) 5 { 6 setupUi(this); 7 8 9 10 11 } secondaryGroupBox->hide(); tertiaryGroupBox->hide(); layout()->setSizeConstraint(QLayout::SetFixedSize); setColumnRange('A', 'Z');
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
39
Dialogs Dinmicos
Dialogs dinmicos so aqueles que so criados em tempo de execuo a partir de arquivos .ui produzidos no Qt Designer. Ao invs de converter o arquivo .ui para cdigo C++ utilizando uic, ns podemos carregar o arquivo em tempo de execuo usando a classe QUiLoader:
40
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
45