Escolar Documentos
Profissional Documentos
Cultura Documentos
Revista qt2
Revista qt2
Aplicaes Hbridas
Tutorial QML
revistaqt.com
ndice
5 Qt + PHP parte 2
Continuao do tutorial sobre desenvolvimento de aplicaes hbridas (Desktop + Web) usando Qt e PHP.
35 Estilo de codificao Qt
41 Tutorial Qml
57 Caixa de Entrada
Respostas a e-mails de leitores.
Carssimosleitores,
Hunstrsmeses,quandoresolvicriarumarevistasobreoQt eujsabiaqueserianoserianadafcil. Pra comear esta seria a minha primeira experincia como editoreprapiorareuestavasozinhonessaempreitada. Com o tempo que sobrava de um emprego em tempo integral e uma famlia numerosa, eu ia escrevendo e como tambm era a minha primeira experincia como diagramador, ia apanhando do BrOffice Draw (programa queusoparaeditararevista).DomeuentusiasmocomoQt vinhaaestmulodequeeuprecisavaparacontinuar. Comapenas24pginas,aprimeiraediodaRevistaQtfoi publicada no dia 8 de setembro deste ano. Eram poucos e umtantoinseguros,maseramosmeusprimeirospassosno sentidodaminhaideia. Dois meses e muito trabalho depois, aqui estou eu de novo, destavezescrevendooeditorialdasegundaediodaRevista Qt, que passa a ter editorias definidas, uma diagramao ligeiramente melhorada continua sendo feita por mim :) e comomesmoobjetivo:compartilharconhecimentosobreQt. Seguindo orientaes do meu amigo Pierre Freire, criei editorias, de acordo com a naturezadecadaartigoaserpublicado. EstasseroasprimeiraseditoriasdaRevistaQt: Iniciar EstaeditoriaserdedicadaaartigosparainiciantesemQt.Sej existisse na primeira edio, os artigos: Apresentando o Qt, Instalao do Qt SDK e Al Qt Creator estariam nesta editoria,porrequereremumconhecimentomuitobsicodoQt.
Laboratrio Artigoscomumnvelmaisaltodecomplexidadeouqueexijam maiores conhecimentos dos leitores sero publicados nesta editoria.OartigoQt+PHPparte1daprimeiraedioum exemplodeartigodestaeditoria.
VersoBrasileira fato: existe pouca documentao sobre Qt em portugus disponvel. No entanto,existe um bom material disponvelem ingls. Nesta editoria sero publicadas tradues da documentaodoQt.
CaixadeEntrada Nesta editoria sero publicados os emails dos leitores, enviados para revistaqt@gmail.com, com as respectivas respostasdadaspeloeditor. Notcias Sendo uma publicao bimestral, se fosse publicar tudo o que acontece precisaramos de uma centena de pginas para notcias. Ento, apenas notcias relevantes para estudantes ou profissionaisdeQtseroconsideradasparaestaeditoria Geek&Poke As charges de Oliver Widder ganham umaseoespecficanarevista. Alm destas, existem planos para outras editorias, como uma que apresente cases de aplicaodoQt. Encerrando este tutorial, agradeo pelas crticas e mensagens de apoio que tenho recebidodesdeolanamentodaprimeiraediodarevista. Umgrandeabrao. AndrLuizdeOliveiraVasconcelos editor
Qt + PHP parte 2
Por: Andr Vasconcelos alovasconcelos@gmail.com
Continuaodotutorialsobredesenvolvimentodeaplicaeshbridas Desktop+PHP
Na primeira parte deste tutorial, vimos um pequeno exemplo de aplicao hbrida Desktop + PHP. A partir de agora passamos a ver um exemplo mais complexo, utilizando o Zend Framework no servidor. Como os tutoriais publicados nesta seo da revista Laboratrio sero voltados aos programadores mais experientes no vamos nos deter em aspectos bsicos de programao Qt ou PHP. Para esta segunda parte, precisaremos do Zend Framework, que pode ser obtido no endereo: http://framework.zend.com/download/latest O motivo de adotar o Zend Framework neste projeto apenas um: simplificar o desenvolvimento do lado servidor da nossa aplicao. Isto porque o ZF (vamos cham-lo assim daqui pra frente) possui uma srie de classes prontas para usar . Como usaremos apenas alguns componentes bsicos do ZF, podemos utilizar a verso minimal. Alm do ZF, vamos precisar do MySQL instalado na mquina que vamos usar como servidor. O MySQL pode ser obtido no endereo: http://dev.mysql.com/downloads/ Obviamente, como a parte servidora de nossa aplicao ser desenvolvida em PHP, precisamos tambm do Apache e do PHP 5 instalados no servidor. A minha plataforma de desenvolvimento a seguinte:
phpapp
ZF Aplicao PHP com ZF
HTTP
Interface em Qt
A aplicao desenvolvida nesta parte do tutorial carrega dados a partir de um servidor e mostra em um Grid. Os dados ficam em um banco MySQL e so lidos por uma aplicao em PHP disponvel no servidor. A interface da nossa aplicao feita em Qt faz uma requisio aplicao em PHP no servidor, e apresenta o resultado. Teremos um boto para fazer nova requisio ao servidor e atualizar as informaes no Grid. Do lado servidor temos um programa em PHP com ZF que recebe o nome de uma classe e o nome de um mtodo, executa o mtodo e retorna o resultado como um XML.
Como diria Jack, o Estripador: vamos por partes. Comecemos pela criao do banco de dados da aplicao:
CREATEDATABASE`teste`DEFAULTCHARACTERSETlatin1COLLATElatin1_swedish_ci; CREATEDATABASE`teste`DEFAULTCHARACTERSETlatin1COLLATElatin1_swedish_ci;
Agora que temos o banco de dados vamos criao do lado servidor da nossa aplicao em PHP. O documentRoot do Apache em minha mquina aponta para o diretrio /home/vasconcelos/Projetos/www. Se voc no faz ideia do que seja documentRoot, recomendo que procure na Internet por um tutorial de instalao e configurao do Apache. Estando no diretrio correspondente ao documentRoot do Apache, crie um diretrio chamado phpapp:
A seguir vamos criar dentro do diretrio de nossa aplicao um diretrio chamado Classes, onde ficaro os arquivos com os cdigos das classes da mesma:
$ cd phpapp $ cd phpapp $ mkdir Classes $ mkdir Classes
Como esta aplicao far uso do ZF, vamos criar em seu diretrio um link simblico para o diretrio contendo as bibliotecas do cara (o ZF).
$ ln -s ../ZendFramework-1.10.8-minimal/library/Zend Zend $ ln -s ../ZendFramework-1.10.8-minimal/library/Zend Zend
No meu caso, o diretrio contendo o ZF ZendFramework-1.10.8-minimal e fica no mesmo nvel do diretrio da aplicao. Substitua a referncia na criao do link de acordo com o nome do diretrio e a localizao do ZF no seu servidor.
Agora que temos o diretrio de nossa aplicao e um link para o diretrio com as bilbiotecas do ZF criados, vamos escrever o cdigo PHP para ela, comeando pelo arquivo index.php, que dever ser criado no diretrio da aplicao phpapp.
www.revistaqt.com www.twitter.com/revistaqt
[8] RevistaQt Novembro/Dezembro-2010
<?php <?php // index.php // index.php // Include para o Servidor Rest do Zend Framework // Include para o Servidor Rest do Zend Framework require_once('Zend/Rest/Server.php'); require_once('Zend/Rest/Server.php'); // Nome da classe que est sendo requisitada // Nome da classe que est sendo requisitada $className = $_GET['class']; $className = $_GET['class']; // Include para definio da classe requisitada // Include para definio da classe requisitada require_once("Classes/{$className}.php"); require_once("Classes/{$className}.php"); // Instancia servidor Rest // Instancia servidor Rest $server = new Zend_Rest_Server(); $server = new Zend_Rest_Server(); // Seta o nome da classe // Seta o nome da classe $server->setClass($className); $server->setClass($className); // Processa a requisio // Processa a requisio $server->handle(); $server->handle();
No quadro acima temos todo o cdigo do arquivo index.php. Como mencionei no incio desta parte do tutorial, a adoo do ZF simplificou muito o trabalho. A classe Zend_Rest_Server faz toda a mgica acontecer. O Rest Server recebe uma requisio para execuo de um mtodo em uma determinada classe e retorna o resultado. Nosso prximo passo ser criar uma classe para conexo ao banco de dados. Antes de continuarmos, quero fazer algumas observaes. A finalidade deste exemplo demonstrar a abordagem de aplicaes hbridas (Qt + PHP), no servir de base para uma aplicao real. Aqui no estou preocupado com o tratamento de erros, por exemplo. Observe que no index.php no est sendo tratada a situao de inexistncia do arquivo correspondente classe que esteja sendo requisitada ao servidor. A classe de conexo que vamos criar a seguir tambm no possuir tratamento de erros e servir apenas para executar queries. Crie um arquivo chamado Conexao.php no diretrio Classes da aplicao.
<?php <?php // Classes/Conexao.php // Classes/Conexao.php require_once('Zend/Db.php'); require_once('Zend/Db.php'); // Definio da classe de conexo com o banco de dados // Definio da classe de conexo com o banco de dados class Conexao { class Conexao { private $db; // Recurso de conexo com o banco de dados private $db; // Recurso de conexo com o banco de dados static private $instancia; // Instncia esttica de Conexao static private $instancia; // Instncia esttica de Conexao // Mtodo pblico para conectar ao banco de dados // Mtodo pblico para conectar ao banco de dados public function conecta() public function conecta() { { // Conecta ao banco de dados // Conecta ao banco de dados $db = Zend_Db::factory('Pdo_Mysql', array( $db = Zend_Db::factory('Pdo_Mysql', array( 'host' => 'localhost', // servidor 'host' => 'localhost', // servidor 'username' => 'root', // usurio 'username' => 'root', // usurio 'password' => 'margrande', // senha 'password' => 'margrande', // senha 'dbname' => 'teste', // banco de dados 'dbname' => 'teste', // banco de dados 'charset' => 'utf8' // codificao 'charset' => 'utf8' // codificao )); )); $this->db = $db; $this->db = $db; } } // Mtodo esttico para retornar ou instanciar uma nova conexo // Mtodo esttico para retornar ou instanciar uma nova conexo static public function getConexao(){ static public function getConexao(){ if (!isset(self::$instancia)) { if (!isset(self::$instancia)) { $c = __CLASS__; $c = __CLASS__; self::$instancia = new $c; self::$instancia = new $c; } } return self::$instancia; return self::$instancia; } } // Mtodo para execuo de Queries SQL // Mtodo para execuo de Queries SQL public function executaQuery($sql) public function executaQuery($sql) { { if(!is_resource($this->db)){ if(!is_resource($this->db)){ $this->conecta(); $this->conecta(); } } return $this->db->fetchAll($sql); return $this->db->fetchAll($sql); } } }
Esta classe de conexo usa o Design Pattern conhecido como Singleton. Mais informaes sobre o assunto podem ser encontradas em http://pt.wikipedia.org/wiki/Singleton.
Para concluir a parte servidora desta aplicao falta apenas criar a classe que ser requisitada pelo programa em Qt.
<?php <?php // Classes/ListaEstado.php // Classes/ListaEstado.php class ListaEstado { class ListaEstado { public function retorna() { public function retorna() { include_once1('Classes/Conexao.php'); include_once1('Classes/Conexao.php'); $db = Conexao::getConexao(); $db = Conexao::getConexao(); return $db->executaQuery("SELECT return $db->executaQuery("SELECT id_estado, id_estado, sigla, sigla, nome nome FROM FROM estado"); estado"); } } } }
isso. Para testar acesse a aplicao pelo browser, passando na url os argumentos class e method, como mostra a figura abaixo:
O resultado apresentado depender do browser que voc estiver utilizando. O Firefox apresenta o XML retornado pela aplicao como mostra a prxima figura.
O Chrome suprime a exibio das tags XML, exibindo apenas os valores retornados. Se voc selecionar a opo exibir cdigo fonte da pgina (ou View page source), ver o XML completo.
Agora que o servidor est pronto, vamos criar a parte cliente da nossa aplicao em Qt. Como j foi esclarecido tanto no Editorial, como no incio desta parte do tutorial, a editoria Laboratrio (da qual o presente artigo faz parte) dedicada queles com mais experincia em Qt. Sero abordados aqui, tpicos um pouco mais avanados e que vo portanto requerer do leitor o conhecimento bsico de Qt. Usando o Qt Creator, crie um projeto chamado QtPHP, tendo sua classe principal chamada QtPHP. Quem tiver dvidas sobre como criar uma aplicao em Qt, pode consultar o artigo Al, Qt Creator publicado na primeira edio da Revista Qt. Com um projeto com o nome de QtPHP criado, vamos crio da interface (bem simples) da aplicao. Arraste para a janela da aplicao um componente QpushButton. Troque sua propriedade objectName para btnAtualizar e sua propriedade text para Atualizar.
Arraste um componente QtableWidget para a janela da aplicao. Coloque um componente Spacer entre o boto Atualizar e a borda da janela, como mostrado abaixo.
Usando o menu de contexto da janela de nossa aplicao (boto direito do mouse), selecione a opo Layout Layout in a Grid.
Com a interface da nossa aplicao desenhada, podemos passar ao cdigo-fonte, mas antes vamos a uma breve descrio de seu funcionamento.
enviarRequisicao
QU rl
QNetworkRequest tratarResultado
A base do nosso programa so os slots enviarRequisicao e tratarResultado. O primeiro, utiliza um objeto do tipo QNetworkRequest para enviar ao servidor uma requisio http. No caso desta aplicao, a requisio ser:
http://localhost/phpapp/?class=ListaEstado&method=retorna http://localhost/phpapp/?class=ListaEstado&method=retorna
O slot enviarRequisicao monta uma URL que submetida atravs de um objeto do tipo QNetworkRequest pelo mtodo get de um objeto QNetworkAccessManager. O signal finished do objeto QNetworkAccessManager ser conectado ao slot tratarResultado que receber um objeto do tipo QNetworkReply com o resultado da requisio feita ao servidor. O slot tratarResultado processar o XML recebido como resposta do servidor, preenchendo o grid QTableWidget que colocamos na interface do programa.
a ost sp Re
Internet
Nosso programa utilizar os mdulos QtNetwork e QtXml, portanto, edite o arquivo qtPHP.pro e altere a linha:
QT QT += core gui += core gui
para
QT QT
O cdigo da funo main, no arquivo main.cpp no apresenta qualquer alterao em relao ao criado pelo Qt Creator, como vemos a seguir:
#include <QtGui/QApplication> #include <QtGui/QApplication> #include "qtphp.h" #include "qtphp.h" int main(int argc, char *argv[]) { int main(int argc, char *argv[]) { QApplication a(argc, argv); QApplication a(argc, argv); QtPHP w; QtPHP w; w.show(); w.show(); return a.exec(); return a.exec(); } }
Agora edite o arquivo qtphp.h para que seu contedo seja igual ao mostrado na listagem abaixo:
#ifndef QTPHP_H #ifndef QTPHP_H #define QTPHP_H #define QTPHP_H #include <QMainWindow> #include <QMainWindow> #include <QNetworkAccessManager> #include <QNetworkAccessManager> #include <QNetworkRequest> #include <QNetworkRequest> #include <QNetworkReply> #include <QNetworkReply> #include <QMessageBox> #include <QMessageBox> #include <QdomDocument> #include <QdomDocument> #include <QTimer> #include <QTimer> namespace Ui { namespace Ui { class QtPHP; class QtPHP; } } class QtPHP : public QMainWindow { class QtPHP : public QMainWindow { Q_OBJECT Q_OBJECT public: public: explicit QtPHP(QWidget *parent = 0); explicit ~QtPHP(); QtPHP(QWidget *parent = 0); ~QtPHP(); private slots: private slots: void enviarRequisicao(); void enviarRequisicao(); void tratarResultado(QNetworkReply * resposta); void tratarResultado(QNetworkReply * resposta); private: private: Ui::QtPHP *ui; Ui::QtPHP *ui; QNetworkAccessManager * requisicaoRede; QNetworkAccessManager * requisicaoRede; }; }; #endif // QTPHP_H #endif // QTPHP_H
As linhas em destaque (cor vermelha) no cdigo acima referem-se quelas que devem ser includas em relao ao arquivo originalmente criado pelo Qt Creator. Temos a incluso das definies das classes que usaremos no programa, dos prottipos dos slots enviarRequisicao e tratarResultado e do atributo requisicaoRede.
RevistaQt Novembro/Dezembro-2010 [15] 15]
Bom, agora vamos parte mais importante deste programa. A implementao, propriamente dita, da classe QtPHP, no arquivo qtphp.cpp. Como o cdigo um mais extenso (pouco mais de cem linhas), vamos ver cada parte dele separadamente. Comeando pelos includes feitos para o header da classe e para o header da classe correspondente interface grfica.
#include "qtphp.h" #include "qtphp.h" #include "ui_qtphp.h" #include "ui_qtphp.h"
As linhas em destaque (cor vermelha) foram includas no mtodo construtor originalmente criado pelo Qt Creator. Primeiro temos a instanciao de um objeto do QNetworkAccessManager que o responsvel neste caso pela comunicao entre nosso programa em Qt e a aplicao Web. Este objeto um atributo da classe QtPHP, de modo que esteja acessvel em todos os mtodos da mesma. Se no fosse um atributo da classe, precisaramos passar por referncia a todos os mtodos que precisam utiliz-lo. Como temos um boto, chamado btnAtualizar que dever executar uma requisio ao servidor, conectamos o signal clicked do mesmo ao slot enviarRequisicao da nossa classe. Quando ocorrer uma requisio, o objeto QNetworkAccessManager aguarda pela resposta do servidor e emite um signal finished quando isto ocorrer. Para que nosso programa saiba que a requisio foi atendida e reaja resposta, conectamos o signal finished do objeto QNetworkAccessManager ao slot tratarResultado, passando ao mesmo um ponteiro para um objeto do tipo QNetworkReply. [16] RevistaQt Novembro/Dezembro-2010 16]
A seguir temos a configurao do objeto QTableWidget que exibir a lista de estados obtida do servidor. Estamos setando o nmero de colunas para trs (3) e ocultando o header vertical, ou seja, a coluna mostrada esquerda da tabela com a numerao das linhas. Continuando, setamos o cabealho (header) do objeto QTableWidget, com Id para a primeira coluna, Sigla para a segunda coluna e Nome para a terceira. Agora vem um macete publicado por Mark Summerfield em seu livro Advanced Qt Programming da Prentice Hall. Observe a utilizao de uma chamada ao mtodo esttico singleShot da classe QTimer para chamar o mtodo enviarRequisicao. A ideia de colocar a chamada ao mtodo enviarRequisicao no mtodo construtor era de que, ao executar o programa, a lista de estados seja automaticamente carregada e exibida, sem que o usurio tenha que clicar no boto Atualizar. At a tudo bem, mas porque no coloquei no final do mtodo construtor simplesmente uma chamada ao mtodo enviarRequisicao? De acordo com Mark, deve-se limitar ao construtor, chamadas a mtodos que estejam relacionados criao do objeto. A chamada ao mtodo de carga da lista de estados pressupe que a janela de nossa aplicao esteja pronta. Chamadas diretas a mtodos do objeto que est sendo construdo so consideradas inseguras, porque no existe a garantia de que o objeto esteja pronto durante a execuo do construtor. Assim, Mark recomenda o uso de uma chamada ao mtodo esttico singleShot de QTimer com zero como argumento correspondente ao intervalo, como foi feito aqui:
QTimer::singleShot(0, this, SLOT(enviarRequisicao()));} QTimer::singleShot(0, this, SLOT(enviarRequisicao()));}
Com esta instruo estamos executando em zero milissegundos (imediatamente, portanto), no objeto this o slot enviarRequisicao. Esta prtica garante que a execuo ocorrer apenas quando o objeto correspondente a nossa aplicao esteja pronta. Nenhuma alterao foi implementada no mtodo destrutor da classe criado pelo Qt Creator, como visto a seguir:
/** /** * @brief Destrutor * */ @brief Destrutor */ QtPHP::~QtPHP() { QtPHP::~QtPHP() { delete ui; delete ui; } }
O prximo mtodo da nossa classe o enviarRequisicao, que um slot privado da classe QtPHP, para que possa ser conectado ao signal clicked do boto Atualizar.
void QtPHP::enviarRequisicao() { void QtPHP::enviarRequisicao() { ui->tableWidget->setRowCount(0); ui->tableWidget->setRowCount(0); ui->tableWidget->clearContents(); ui->tableWidget->clearContents(); // Monta a URL para requisio dos dados ao servidor // Monta a URL para requisio dos dados ao servidor QString url = "http://localhost/phpapp/?class=ListaEstado&method=retorna"; QString url = "http://localhost/phpapp/?class=ListaEstado&method=retorna"; // Executa a requisio ao servidor // Executa a requisio ao servidor requisicaoRede->get(QNetworkRequest(QUrl(url))); requisicaoRede->get(QNetworkRequest(QUrl(url))); } }
As duas primeiras linhas do slot enviarRequisicao, servem para apagar o contedo do objeto tableWidget, que exibir a lista de estados carregada do servidor. Desta forma, quando o usurio clicar no boto Atualizar, a nova lista carregada substituir a anterior. A prxima instruo no mtodo a montagem da URL que ser submetida ao servidor. Aqui foi utilizado um objeto do tipo QString para armazenar o endereo. A ltima instruo do mtodo usa o mtodo get do atributo requisicaoRede que um QNetworkAccessManager. O mtodo get de QNetworkAccessManager recebe um objeto QNetworkRequest, o qual como o prprio nome indica, uma requisio de rede. A requisio retornar ao QNetworkAccessManager um ponteiro para um objeto QNetworkReply, que receber o resultado de tal requisio. Quando a resposta for recebida pelo objeto QNetworkAccessManager, este emitir um signal finished. que foi conectado l no construtor com o prximo e ltimo mtodo de nossa classe: o slot tratarResultado. Como o cdigo de tratarResultado maior e o responsvel pela apresentao do resultado de nosso programa, vamos listar o seu cdigo por blocos:
void QtPHP::tratarResultado(QNetworkReply * resposta) { void QtPHP::tratarResultado(QNetworkReply * resposta) { // Verifica se houve erro na resposta // Verifica se houve erro na resposta if(resposta->error() != QNetworkReply::NoError){ if(resposta->error() != QNetworkReply::NoError){ QMessageBox::critical(this, "Erro", QMessageBox::critical(this, "Erro", "No foi possvel recuperar dados do servidor"); "No foi possvel recuperar dados do servidor"); return; return; } }
O slot tratarResultado recebe como argumento um ponteiro para um objeto do tipo QNetworkReply passado para ele pelo objeto QNetworkAccessManager no momento em que o signal finished for emitido (lembre-se de que no construtor da classe QtPHP, conectamos o signal finished do objeto requisicaoRede que um QNetworkAccessManager ao slot tratarResultado). O primeiro passo em tratarResultado verificar se ocorreu erro na requisio feita ao servidor. Para isso verificamos se o resultado da chamada ao mtodo error do objeto resposta diferente de QNetworkReply:NoError. Caso tenha ocorrido um erro, o programa emite uma mensagem informando ao usurio e retorna. A resposta recebida do servidor ser um XML com a seguinte estrutura:
<ListaEstado generator="zend" version="1.0"> <ListaEstado generator="zend" version="1.0"> <retorna> <retorna> <key_0> <key_0> <id_estado>1</id_estado> <id_estado>1</id_estado> <sigla>AM</sigla> <sigla>AM</sigla> <nome>Amazonas</nome> <nome>Amazonas</nome> </key_0> </key_0> ... ... <key_25> <key_25> <id_estado>26</id_estado> <id_estado>26</id_estado> <sigla>AP</sigla> <sigla>AP</sigla> <nome>Amap</nome> <nome>Amap</nome> </key_25> </key_25> <status>success</status> <status>success</status> </retorna> </retorna> </ListaEstado> </ListaEstado>
Na primeira linha temos a tag raiz do nosso XML, identificando nesse caso o nome da classe que foi executada para emisso da resposta ListaEstado. Os atributos generator e version indicam respectivamente quem gerou o XML e qual a verso. A prxima tag do XML tem o nome do mtodo executado retorna. Em seguida, temos para cada um dos registros retornados a tag key_n, onde n representa o nmero sequencial do registro, comeando por zero (0). Para cada registro, temos trs tags indicando os nomes dos campos retornados, a saber: <id_estado> <sigla> <nome> O valor contido em nas tags acima o contedo do registro propriamente dito.
// Cria objeto DOM para tratamento do XML de resposta e // Cria objeto resposta pode ser atribuda ao este objeto // verifica se a DOM para tratamento do XML de resposta e // verifica se a QDomDocument doc; resposta pode ser atribuda ao este objeto QDomDocument doc; if(!doc.setContent(resposta)){ if(!doc.setContent(resposta)){ QMessageBox::critical(this,"Erro","Erro tratando resultado"); QMessageBox::critical(this,"Erro","Erro tratando resultado"); return; return; } }
No prximo passo, caso no tenha ocorrido um erro no retorno da requisio do servidor, temos a criao de um objeto do tipo QDomDocument que ser utilizado para tratamento do XML retornado. Na atribuio do contedo ao objeto QDomDocument verificamos se ocorreu erro. Se a resposta do servidor no puder ser atribuda ao objeto QDomDocument, o programa emite uma mensagem ao usurio e retorna. Com o XML da resposta carregado no objeto QDomDocument podemos usar suas facilidades para navegar pelas tags do documento.
// Verifica se o retorno foi gerado pela classe ListaEstado // Verifica se o = doc.documentElement(); QDomElement classe retorno foi gerado pela classe ListaEstado QDomElement classe = "ListaEstado"){ if(classe.tagName() != doc.documentElement(); if(classe.tagName() != "ListaEstado"){ QmessageBox::critical(this,"Erro", QmessageBox::critical(this,"Erro", no da classe ListaEstado"); "O XML recebido "O XML recebido no da classe ListaEstado"); return; return; } }
Neste trecho do cdigo, utilizamos um objeto QDomElement para armazenar o primeiro elemento do documento DOM. Se o nome da tag do primeiro elemento do XML recebido do servidor no for ListaEstado, o programa avisa ao usurio e retorna.
// N correspondente ao nome do mtodo - retorna // N correspondente ao nome do mtodo QDomNode metodo = classe.firstChild(); - retorna QDomNode metodo = classe.firstChild();
Em seguida o primeiro filho do elemento ListaEstado atribuido a um objeto QDomNode. A tag filha de ListaEstado em nosso XML retorna, que corresponde ao nome do mtodo executado pelo servidor.
// N correspondente ao registro // N correspondente ao registro QDomNode registro = metodo.firstChild(); QDomNode registro = metodo.firstChild();
O primeiro filho da tag retorna, lida no passo anterior, corresponde ao primeiro registro retornado pela consulta.
// N correspondente ao status - o ltimo // N correspondente ao status - o ltimo QDomNode status = metodo.lastChild(); QDomNode status = metodo.lastChild(); if(status.toElement().text() != "success"){ if(status.toElement().text() != "success"){ QMessageBox::critical(this,"Erro","O servidor retornou erro"); QMessageBox::critical(this,"Erro","O servidor retornou erro"); return; return; } }
Antes de comear a navegar pelos registros, temos a leitura do ltimo filho da tag retorna, que corresponde ao status da execuo do comando. Caso o texto deste ltimo elemento seja diferente de success, significa que ocorreu um erro. Neste caso, o programa avisa ao usurio e retorna.
// Percorre os registros // Percorre os registros int linha = 0; int linha = 0; while(!registro.isNull() && registro != status){ while(!registro.isNull() && registro != status){ ui->tableWidget->insertRow(linha); ui->tableWidget->insertRow(linha); QDomNode campo = registro.firstChild(); QDomNode int coluna campo = registro.firstChild(); = 0; int coluna = 0; // Percorre os campos // Percorre os campos while(!campo.isNull()){ while(!campo.isNull()){ QTableWidgetItem * item = new QTableWidgetItem(campo.toElement().text()); QTableWidgetItem * item = new coluna, item); ui->tableWidget->setItem(linha, QTableWidgetItem(campo.toElement().text()); ui->tableWidget->setItem(linha, coluna, item); coluna++; coluna++; campo = campo.nextSibling(); campo = campo.nextSibling(); } } linha++; linha++; registro = registro.nextSibling(); registro = registro.nextSibling(); } } }
Se a execuo do programa chegou a este ponto, s falta percorrer a lista de registros e popular o QTableWidget da nossa aplicao com os dados. Neste trecho do cdigo, o primeiro loop while percorre registro, at que seja o final desde que no seja o registro de status. Como cada campo de um registro um filho seu, temos um segundo loop para percorrer os filhos de cada registro e setar a linha/coluna correspondente no QTableWidget com o contedo do campo. Para navegar entre os itens de um elemento do DOM, usamos o mtodo nextSibling. A seguir, a listagem completa do slot tratarResultado.
void QtPHP::tratarResultado(QNetworkReply * resposta) { void QtPHP::tratarResultado(QNetworkReply * resposta) { // Verifica se houve erro na resposta // Verifica se houve erro na resposta if(resposta->error() != QNetworkReply::NoError){ if(resposta->error() != QNetworkReply::NoError){ QMessageBox::critical(this, "Erro", QMessageBox::critical(this, "Erro", "No foi possvel recuperar dados do servidor"); "No foi possvel recuperar dados do servidor"); return; return; } } // Cria objeto DOM para tratamento do XML de resposta e // Cria objeto resposta pode ser atribuda ao este objeto // verifica se a DOM para tratamento do XML de resposta e // verifica se a QDomDocument doc; resposta pode ser atribuda ao este objeto QDomDocument doc; if(!doc.setContent(resposta)){ if(!doc.setContent(resposta)){ QMessageBox::critical(this,"Erro","Erro tratando resultado"); QMessageBox::critical(this,"Erro","Erro tratando resultado"); return; return; } } // Verifica se o retorno foi gerado pela classe ListaEstado // Verifica se o = doc.documentElement(); QDomElement classe retorno foi gerado pela classe ListaEstado QDomElement classe = "ListaEstado"){ if(classe.tagName() != doc.documentElement(); if(classe.tagName() != "ListaEstado"){ QMessageBox::critical(this,"Erro", QMessageBox::critical(this,"Erro", "O XML recebido no da classe ListaEstado"); "O XML recebido no da classe ListaEstado"); return; return; } } // N correspondente ao nome do mtodo - retorna // N correspondente ao nome do mtodo QDomNode metodo = classe.firstChild(); - retorna QDomNode metodo = classe.firstChild(); // N correspondente ao registro // N correspondente ao registro QDomNode registro = metodo.firstChild(); QDomNode registro = metodo.firstChild(); // N correspondente ao status - o ltimo // N correspondente ao status - o ltimo QDomNode status = metodo.lastChild(); QDomNode status = metodo.lastChild(); if(status.toElement().text() != "success"){ if(status.toElement().text() != "success"){ QMessageBox::critical(this,"Erro","O servidor retornou erro"); QMessageBox::critical(this,"Erro","O servidor retornou erro"); return; return; } } // Percorre os registros // Percorre os registros int linha = 0; int linha = 0; while(!registro.isNull() && registro != status){ while(!registro.isNull() && registro != status){ ui->tableWidget->insertRow(linha); ui->tableWidget->insertRow(linha); QDomNode campo = registro.firstChild(); QDomNode int coluna campo = registro.firstChild(); = 0; int coluna = 0; // Percorre os campos // Percorre os campos while(!campo.isNull()){ while(!campo.isNull()){ QTableWidgetItem * item = new QTableWidgetItem(campo.toElement().text()); QTableWidgetItem * item = new coluna, item); ui->tableWidget->setItem(linha, QTableWidgetItem(campo.toElement().text()); ui->tableWidget->setItem(linha, coluna, item); coluna++; coluna++; campo = campo.nextSibling(); campo = campo.nextSibling(); } } linha++; linha++; registro = registro.nextSibling(); registro = registro.nextSibling(); } } } }
A explicao sobre o funcionamento deste programa no foi feita linha a linha, mas para aqueles com alguma experincia em Qt, os comentrios colocados no cdigo-fonte j devem ajudar bastante. A mesma observao vale para a parte PHP desta aplicao.
Comentando um dia desses sobre aplicaes hbridas Qt + PHP com um amigo, ele questionou: no poderamos fazer a parte servidora tambm em Qt, usando CGI? Verdade poderamos. Mas fazer a parte servidora usando a dupla PHP / Zend Framework facilita muito o trabalho. No precisamos nos preocupar com detalhes da conexo com o banco de dados ou com a formatao do resultado em XML. comum encontrar programadores especialistas em uma ferramenta, querendo utiliz-la para tudo aquilo que pretendam fazer. Sempre uso o seguinte exemplo para ilustrar esta situao: Imagine um trabalhador que possui um excelente conjunto de chaves de fenda. Vrios tamanhos, torques, modelos, etc. - uma maravilha... Mas se tentar colocar um prego, um martelo seria mais til do que todo o seu conjunto de chaves. A escolha da ferramenta deve ser feita de acordo com o trabalho a ser feito. Ok, eu admito - t parecendo coisa de livro de auto-ajuda, mas se tem uma coisa que os meus vinte e poucos anos de programao me ensinaram que no existe ferramenta definitiva. Na prxima edio continuamos com mais exemplos de aplicaes hbridas, utilizando Qt e PHP. Um grande abrao.
http://geekandpoke.typepad.com
Nestetutorialiremosaprenderacomoinstalarumambientede desenvolvimentocomQTnoMacOSX. Com o crescimento da Apple no mercado, tem se tornado muito comum o uso de notebooks e desktops da empresa de Cupertino por usurios e empresas, com isto a demanda por novos aplicativos tem crescido bastanteeestenovofiloparaosprogramadoresestaapenascomeando. OobjetivodestetutorialabordarainstalaodoSDK(KitdeDesenvolvimentodaQTparaMacOS),outras informaesoslinksabaixopoderoajudarbastante.
http://www.revistaqt.com http://qt.nokia.com
1.2Voctemagoraaopodeusaraversocomercialoulgpl(livre),nonossotutorialestamosbaixandoa versolgpl,conformeaimagemabaixo:
1.3Casoodownloadnocomece,cliquenolink,conformeafigura:
1.4Avelocidadedodownloadvaidependerdasuabandalarga,agoraaordemesperar.
2.1Ateladoinstaladorapareceeoprocessoseinicia.
2.2Teladeboasvindascomalgumasinformaessobreoproduto.
2.3UmreadmecominformaessobreaversaodoQTeinformaesemgeral,podemosseguiremfrente.
2.4Informaessobreolicenciamentodosoftware,casotenhainteresseleiaesigaemfrente.
2.5 Esta janela, quer uma confirmao se voc aceita os termos da licena clique emAgreecaso voc concordeemusar.
2.6Oinstaladorirmostrarasunidadesdediscoeoespaodisponvel,eoespaoqueainstalaodoQT vaiocuparnodisco.
2.7Sequisermudarolocaldeinstalao.Notutorialdeixamosnopadro.
2.8 Como esta instalando um software, por motivos de segurana o Mac Os vai solicitar o seu usurio e senhadoadministrador.
2.9Oprocessodeinstalaofoiiniciado,agoraesperar.
2.10Sevocchegouaesteponto,significaqueoQTfoiinstaladocomsucessonoseucomputador.
DentrodapastaDeveloperselecioneApplications,agoraentrenapastaQT.
CliquenoQtCreatorparaconheceraIDEdedesenvolvimento.
3.2OQtCreatoraIDEdedesenvolvimentooficial.
Chegamosaofinaldestetutorial,ondeabordamosainstalaodasferramentasdedesenvolvimentoparaMac. Oprximopassoagoraoseu,estudar,pesquisareconhecerestefascinantemundodoQT.
EstilodecodificaoQT
Esta umatraduo livredodocumento QtCodingStylecomalgumasconvenesutilizadasno desenvolvimento do Qt propriamente dito. Tratase de uma pequena lista de recomendaes queles que queiram participar ativamente do projeto, baixando os fontes do Qt e criando novas classes, novos mdulos, etc. Achei interessante reproduzir aqui como sugesto de estilo. Vamos aotexto:
Paraponteirosoureferncias,sempreuseumnicoespaoentreotipoeocaracter'*'ou'&'*, masnenhumespaoentreo*ou&eonomedavarivel.
Nouseespaodepoisdeumcast. Eviteconverses(casts)noestilodeCquandopossvel.
Chaves
Comoregrabsica,achavedaesquerdavemnamesmalinhadocomeodadeclarao:
Exceo:Implementaesdefunesedeclaraesdeclassessempretmachaveesquerdano comeodeumanovalinha:
Usechavesquandoocorpodeumadeclaraocondicionalcontivermaisdeumalinha,ou quandocontiverapenasumalinhaquesejaumpoucomaiscomplexa
//Errado if(address.isEmpty()){ returnfalse; } for(inti=0;i<10;++i){ qDebug("%i",i); } //Correto if(address.isEmpty()) returnfalse; for(inti=0;i<10;++i) qDebug("%i",i);
Exceo1:Usechavestambmseadeclaraocontivervriaslinhas
Exceo2:Usechavestambmemblocosifthenelsecasooblocodecdigodoifoudoelse tenhamaisdeumalinha
//Errado if(address.isEmpty()) returnfalse; else{ qDebug("%s",qPrintable(address)); ++it; } //Correto if(address.isEmpty()){ returnfalse; }else{ qDebug("%s",qPrintable(address)); ++it; } //Errado if(a) if(b) ... else ... //Correto if(a){ if(b) ... else ... }
Usechavesquandoocorpodeumadeclaraoforvazia
Parnteses
Useparntesesparaagruparexpresses:
switch(myEnum){ caseValue1: doSomething(); break; caseValue2: doSomethingElse(); //fallthrough default: defaultHandling(); break; } Quebrasdelinhas
Sintaselivreparaquebrarumaregraseestafizeroseucdigoparecerruim.
No dia 18 de novembro, a Nokia ir realizar um webinar em portugus sobre o desenvolvimento de apliaes em Qt para dispositivos com Symbian. J no dia 9 de dezembro, ser a vez de um webinar sobre desenvolvimento de interfaces grficas de usurios com Qt 4.7 e Qt Quick, tambm em portugus. Para inscrever-se no webinar sobre Qt para dispositivos Symbian, acesse: http://forumnokia.emea.acrobat.com/e93667679/event/registration.html Para inscrever-se no webinar sobre desenvolvimento de interfaces grficas de usurios com QT 4.7 e Qt Quick, acesse: http://forumnokia.emea.acrobat.com/e60819127/event/registration.html
Mais uma da srie Verso Brasileira. Desta vez trago uma traduo do QML Tutorial disponvel no endereo http://doc.qt.nokia.com/4.7-snapshot/qml-tutorial.html. O Tutorial QML est dividido em trs partes. De lambuja, a traduo de mais dois tutoriais relacionados ao Tutorial QML. Um sobre layouts baseados em ncoras (Anchor-based) e outro sobre a linguagem QML. Vamos l...
Tutorial QML
Este tutorial traz uma introduo ao QML, a linguagem de marcao para o Qt Quick. Ele no cobre todos os aspectos; a nfase no ensino dos princpios fundamentais, e os recursos so apresentados medida em que sejam necessrios. Atravs dos diferentes passos deste tutorial ns aprenderemos sobre os tipos bsicos, criaremos nosso prprio componente QML com propriedades e sinais (signals), e criaremos uma animao simples com a ajuda dos estados (states) e transies (transitions). O primeiro captulo comea com um programa "Hello world!" mnimo e o captulo seguinte apresenta novos conceitos. O cdigo fonte do tutorial pode ser encontrado no diretrio: $QTDIR/examples/declarative/tutorials/helloworld onde $QTDIR corresponde ao diretrio no qual voc instalou o SDK do Qt 4.7. Captulos do tutorial: 1. Tipos bsicos 2. Componentes QML 3. Estados (States) e transies (Transitions)
Aqui est o cdigo QML da aplicao: import QtQuick 1.0 import QtQuick 1.0 Rectangle { Rectangle { id: page id: page width: 500; height: 200 width: 500; height: 200 color: "lightgray" color: "lightgray" Text { Text { helloText id: id: "Hello world!" text: helloText text: y: 30 "Hello world!" y: 30 anchors.horizontalCenter: page.horizontalCenter anchors.horizontalCenter: page.horizontalCenter font.pointSize: 24; font.bold: true font.pointSize: 24; font.bold: true } } } }
Elemento Rectangle
Rectangle { Rectangle { id: page id: page width: 500; height: 200 width: 500; height: 200 color: "lightgray" color: "lightgray" Declaramos um elemento raiz do tipo Rectangle. Este um dos blocos de construo bsicos que voc pode usar para criar uma aplicao em QML. Ns atribuimos um id para poder fazer referncia ao mesmo mais tarde. Neste caso, ns o chamamos de "page". Ns tambm setamos as propriedades width (tamanho), height (altura) e color (cor). O elemento Rectangle contm muitas outras propriedades (como x e y), mas estes so deixados com seus valores default.
Elemento Text
Text { Text { helloText id: id: "Hello world!" text: helloText text: y: 30 "Hello world!" y: 30 anchors.horizontalCenter: page.horizontalCenter anchors.horizontalCenter: page.horizontalCenter font.pointSize: 24; font.bold: true font.pointSize: 24; font.bold: true } }
Adicionamos um elemento Text como filho do elemento raiz Rectangle que exibe o texto "Hello world!". A propriedade y usada para posicionar o texto verticalmente a 30 pixels do topo de seu pai. A propriedade anchors.horizontalCenter refere-se centralizao horizontal de um elemento. Neste caso, especificamos que nosso elemento Text deve ser centralizado horizontalmente no elemento page (veja Layout baseado em ncora "Anchor-based Layout"). As propriedades font.pointSize e font.bold so relativas s fontes e usam a notao de ponto.
Visualizando o exemplo
Para ver o que voc criou, execute a ferramenta de visualizao QML (localizada no diretrio bin do SDK do Qt) com o nome do arquivo como primeiro argumento. Por exemplo, para executar o exemplo completo do Tutorial 1 a partir do local de instalao, voc deveria digitar:
bin/qmlviewer $QTDIR/examples/declarative/tutorials/helloworld/tutorial1.qml
Nosso seletor de cores feito de seis clulas com diferentes cores. Para evitar escrever o mesmo cdigo vrias vezes para cada clula, criamos um novo componente Cell. Um componente proporciona uma forma de definir um novo tipo que podemos reutilizar em outros arquivos QML. Um componente QML como uma caixa preta e interage com o mundo exterior atravs de propriedades, sinais (signals) e funes e geralmente definido em seu prprio arquivo QML. (Para mais detalhes veja a seo "Definindo novos componentes"). O nome do arquivo do componente deve sempre comear com uma letra maiscula. Aqui est o cdigo QML do arquivo Cell.qml: import QtQuick 1.0 import QtQuick 1.0 Item { Item { container id: id: container property alias cellColor: rectangle.color property alias cellColor: rectangle.color signal clicked(color cellColor) signal clicked(color cellColor) width: 40; height: 25 width: 40; height: 25 Rectangle { Rectangle { id: rectangle id: rectangle border.color: "white" border.color: "white" anchors.fill: parent anchors.fill: parent } } MouseArea { MouseArea { anchors.fill: parent anchors.fill: parent onClicked: container.clicked(container.cellColor) onClicked: container.clicked(container.cellColor) } } } }
O elemento raiz do nosso componente um Item com o id container. Um Item o elemento visual mais bsico em QML e frequentemente usado com um container para outros elementos. property alias cellColor: rectangle.color property alias cellColor: rectangle.color Declaramos uma propriedade cellColor. Esta propriedade acessvel de fora do nosso componente, o que nos permite instanciar as clulas com diferentes cores. Esta propriedade apenas um apelido (alias) para uma propriedade existente - a propriedade color de um retngulo que compe a clula (veja Adicionando novas propriedades). signal clicked(color cellColor) signal clicked(color cellColor) Ns precisamos que nosso componente tenha tambm um signal que chamaremos de clicked com um parmetro do tipo color. Usaremos este signal para mudar a cor do texto no arquivo QML principal mais tarde. Rectangle { Rectangle { rectangle id: id: rectangle border.color: "white" border.color: "white" anchors.fill: parent anchors.fill: parent } } Nosso componente cell basicamente um retngulo colorido com o id rectangle. A propriedade anchors.fill uma forma conveniente de atribuir o tamanho de um elemento. Neste caso, o retngulo ter o mesmo tamanho de seu pai (veja Layout baseado em ncora "Anchor-based Layout"). MouseArea { MouseAreaanchors.fill: parent { anchors.fill: parent onClicked: container.clicked(container.cellColor) onClicked: container.clicked(container.cellColor) } }
Para mudar a cor do texto quando clicar em uma clula, criamos um elemento MouseArea com o mesmo tamanho de seu pai. Um MouseArea define um signal chamado clicked. Quando o signal disparado precisamos emitir nosso prprio signal clicked com a cor como parmetro;
Criamos o seletor de cores colocando 6 clulas com diferentes cores em uma tabela. Cell { cellColor: "red"; onClicked: helloText.color = cellColor } Cell { cellColor: "red"; onClicked: helloText.color = cellColor } Quando o signal clicked de nossa clula disparada, precisamos atribuir a cor do texto para a cellColor passada como seu parmetro. Podemos reagir a qualquer signal do componente atravs de uma propriedade de nome "onSignalName" (veja Manipuladores de sinais).
Passo a passo
states: State { states: "down"; when: mouseArea.pressed == true name: State { name: "down"; { target: helloText; y: 160; rotation: 180; color: "red" } PropertyChanges when: mouseArea.pressed == true PropertyChanges { target: helloText; y: 160; rotation: 180; color: "red" } } }
Primeiro ns criamos um novo state para nosso elemento text. Este state ser ativado quando o MouseArea for pressionado e desativado quando for solto. O state down inclui um conjunto de mudanas de propriedades em relao ao state default (os itens como so inicialmente definidos no QML). Especificamente, ns setamos a propriedade y do texto para 160, a rotao para 180 e a cor para vermelho.
transitions: Transition { transitions: Transition { reversible: true from: ""; to: "down"; from: ""; to: "down"; reversible: true ParallelAnimation { ParallelAnimation { NumberAnimation { properties: "y,rotation" NumberAnimation { properties: "y,rotation" duration: 500 duration: 500 easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad } } ColorAnimation { duration: 500 } ColorAnimation { duration: 500 } } } } }
Como no queremos que o texto aparea na base da tela instantaneamente, mas ao invs disse mova-se suavemente, adicionamos uma transition entre os dois states. As propriedades from e to definem os states entre os quais a transition vai ser executada. Nesse caso, queremos uma transition do state default oara nosso state down. Como queremos que a mesma transition seja executada ao contrrio quando voltando do state down para o state default, setamos a propriedade reversible para true. Isto equivale a escrever as duas transitions separadamente. O elemento ParallelAnimation garante que os dois tipos de animao (number e color) comecem ao mesmo tempo. Podeos tambm execut-las (as animaes) uma aps a outra usando SequentialAnimation ao invs de ParallelAnimation. Para mais detalhes sobre states e transitions, veja States QML e o exemplo de states e transitions.
Neste caso, a borda esquerda de rect2 vinculada borda direita de rect1, produzindo o seguinte: O sistema de ancoragem tambm permite que voc especifique margens e deslocamentos. Margens especificam a quantidade de espao deixado para o lado de fora de um item, enquanto deslocamentos permitem que voc manipule o posicionamento usando as linhas centrais de ancoragem. Observe que margens especificadas usando o sistema de ancoragem tem significado apenas para ncoras; elas no tem qualquer efeito quando usando outros layouts ou posicionamento absoluto. O seguinte exemplo especifica uma margem esquerda:
Rectangle { id: rect1; ... } Rectangle id: rect1; ... } Rectangle { {id: rect2; anchors.left: rect1.right; anchors.leftMargin: 5; ... } Rectangle { id: rect2; anchors.left: rect1.right; anchors.leftMargin: 5; ... }
Neste caso, a margem de 5 pixels reservada para a esquerda de rect2, produzindo o seguinte: Voc pode especificar ncoras mltiplas. Por exemplo:
Rectangle { id: rect1; ... } Rectangle id: rect1; Rectangle { {id: rect2; ... } Rectangle { id: rect2; rect1.right; anchors.left: anchors.left: rect1.right; anchors.top: rect1.bottom; ... anchors.top: rect1.bottom; ... } }
Especificando mltiplas ncoras horizontais ou verticais voc pode controlar o tamanho de um item. Por exemplo:
Rectangle { id: rect1; x: 0; ... } Rectangle id: rect1; x: 0; ... } Rectangle { {id: rect2 Rectangle { id: rect2 anchors.left: rect1.right anchors.left: rect1.right anchors.right: rect3.left anchors.right: rect3.left ... ... } } Rectangle { id: rect3; x: 150; ... } Rectangle { id: rect3; x: 150; ... }
Limitaes
Por razes de performance, voc s pode ancorar um item ao seus irmos e pais diretos. Por exemplo, a segunte ncora pode ser considerada invlida e produziria uma advertncia:
Item { Item group1 id: { id: group1 Rectangle { id: rect1; ... } } Rectangle { id: rect1; ... } } Item { Item group2 id: { id: group2 Rectangle { id: rect2; anchors.left: rect1.right; ... } } Rectangle { id: rect2; anchors.left: rect1.right; ... } }
A sua empresa trabalha com Qt? Compartilhe sua experincia com nossos leitores. Envie um e-mail para revistaqt@gmail.com.
[50] RevistaQt Novembro/Dezembro-2010 50]
Objetos so especificados pelo seu tipo, seguido por um par de chaves. Tipos de objetos sempre comeam com uma letra maiscula. No exemplo acim, existem dois objetos, um Rectangle e um Image. Entre as chaves, podemos especificar informaes sobre o objeto, como suas propriedades. Propriedades so especificadas como propriedade: valor. No exemplo acima, podemos ver que Image possui uma propriedade chamada source, qual foi atribuido o valor "pics/logo.png". A propriedade e seus valores so separadas por uma dois pontos. Propriedades podem ser especificadas uma por linha:
Rectangle { Rectangle { 100 width: width: 100 height: 100 height: 100 } }
Quando mltiplos pares propriedade/valor so especificados em uma nica linha, eles devem ser separados por um ponto e vrgula. A declarao import importa o mdulo Qt, que contm todos os elementos padro do QML. Sem esta declarao import, os elementos Rectangle e Image no estariam disponveis
Expresses
Alm de atribuir valores s propriedades, voc pode tambm atribuir expresses escritas em Javascript.
Rotation { Rotation {360 * 3 angle: angle: 360 * 3 } }
Estas expresses podem incluir referncias a outros objetos e propriedades, caso em que um vnculo estabelecido: quando o valor da expresso muda, a propriedade qual a expresso foi atribuda automaticamente atualizada para aquele valor.
Item { Item { { Text Text { text1 id: id: "Hello World" text: text1 text: "Hello World" } } Text { Text { text2 id: id: text1.text text: text2 text: text1.text } } } }
No exemplo acima, o objeto text2 mostrar o mesmo texto do objeto text1. Se text1 mudar, text2 automaticamente alterado para o mesmo valor. Observe que para referir-se a outros objetos, usamos os valores de seus ids (veja abaixo mais informaes sobre a propriedade id).
Comentrios QML
Comentar em QML semelhante ao JavaScript. * Comentrios de nica linha comeam com // e terminam no final da linha * Comentrios multilinhas comeam com /* e terminam com */ Comentrios so ignorados pelo engine. Eles so teis para explicar o que voc est fazendo; para referncia futura ou para outros que leiam seus arquivos QML. Comentrios tambm podem ser usados para evitar a execuo de cdigo, o que s vezes til para rastrear problemas.
Text { Text text: "Hello world!" { text: "Hello //opacity: 0.5 world!" //opacity: 0.5 } }
No exemplo acima, o objeto Text ser sua opacidade normal, posto que a linha opacity: 0.5 foi transformada em um comentrio.
Tipos de propriedades
QML suporta propriedades de muitos tipos (veja Tipos bsicos QML). Os tipos bsicos incluem int, real, bool, string, color e lists.
Item { Item {10.5 x: x: ... 10.5 ... state: "details" state: "details" focus: true focus: true } } // uma propriedade 'real' // uma propriedade 'real' // uma propriedade 'string' // uma propriedade 'string' // uma propriedade 'bool' // uma propriedade 'bool'
Propriedades QML so o que conhecido como type-safe. Isto , elas apenas permitem atribuir um valor que combine com o tipo da propriedade. Por exemplo, a propriedade x do item um real, e se voc tentar atribuir uma string a ela, voc obter um erro.
Item { Item {"hello" // ilegal! x: x: "hello" // ilegal! } }
A propriedade id
Cada objeto pode receber uma propriedade especial e nica chamada id. Nenhum outro objeto dentro do mesmo documento QML pode ter o mesmo valor de id. Atribuir um id permite que o objeto seja referido por outros objetos e scripts. O primeiro elemento Rectangle abaixo tem um id, "myRect". O segundo elemento Rectangle define seu prprio tamanho (width) por referncia a myRect.width, o que significa que ele ter o mesmo valor de width que o primeiro elemento Rectangle.
Item { Item { Rectangle { Rectangle { id: myRect id: myRect width: 100 width: 100 height: 100 height: 100 } } Rectangle { Rectangle myRect.width width: { width: myRect.width height: 200 height: 200 } } } }
Observe que um id deve comear com uma letra minscula ou um underscore e no pode conter outros caracteres que no sejam letras, nmeros e underscores.
Propriedades List
Propriedades List parecem com isso:
Item { Item { children: [ children:{}, Image [ Image Text {} {}, Text {} ] ] } }
A lista encerrada entre colchetes, com uma vrgula separando os elementos da lista. Em casos onde voc esteja atribuindo um nico item lista, voc pode omitir os colchetes:
Image { Image { children: Rectangle {} children: Rectangle {} } }
Propriedades Default
Cada tipo de objeto pode especificar uma de suas listas ou propriedades de objeto como sua propriedade default. Se a propriedade foi declarada como propriedade default, a tag da propriedade pode ser omitida. Por exemplo, este cdigo:
State { State { changes: [ changes: [ PropertyChanges {}, PropertyChanges {}, PropertyChanges {} PropertyChanges {} ] ] } }
Propriedades agrupadas
Em alguns casos, propriedades formam um grupo lgico e usam um ponto ou notao agrupada para demonstrar isso. Propriedades agrupadas pode ser escritas assim:
Text { Text { font.pixelSize: 12 font.pixelSize: font.bold: true 12 font.bold: true } }
ou assim:
Text { Text { { pixelSize: 12; bold: true } font font { pixelSize: 12; bold: true } } }
Propriedades anexadas
Alguns objetos anexam propriedades a outro objeto. Propriedades anexadas so da forma Tipo.propriedade, onde Tipo o tipo de elemento que anexa a propriedade. Por exemplo:
Component { Component { id: myDelegate id: myDelegate Text { Text { text: "Hello" text: "Hello" color: ListView.isCurrentItem ? "red" : "blue" color: ListView.isCurrentItem ? "red" : "blue" } } } } ListView { ListView { delegate: myDelegate delegate: myDelegate } }
O elemento ListView anexa a propriedade ListView.isCurrentItem para cada delegate que ele cria. Outro exemplo de propriedade anexada o elemento Keys que anexa propriedades para manipulao de teclas pressionadas para um item visual, por exemplo:
Item { Item focus: true { focus: true Keys.onSelectPressed: console.log("Selected") Keys.onSelectPressed: console.log("Selected") } }
Todo manipulador de sinais comea com "on". Alguns manipuladores de sinais incluem um parmetro opcional, por exemplo o manipulador do sinal onPressed de MouseArea tem um parmetro mouse:
MouseArea { MouseArea { acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton onPressed: if (mouse.button == Qt.RightButton) onPressed: ifconsole.log("Boto Qt.RightButton) (mouse.button == direito do mouse pressionado") console.log("Boto direito do mouse pressionado") } }
Resposta do editor:
verdade, Crlisson, eu at publiquei um pedido pblico de desculpas com a explicao na segunda-feira (dia 20): http://revistaqt.blogspot.com/2010/09/mea-culpa.html A primeira edio foi bem limitada mesmo, porque tive que fazer tudo sozinho. At as charges liberadas pelo Oliver da Geek and Poke eu tive que editar no Gimp pra traduzir o texto... :) No tenho muita habilidade com a diagramao tambm. A idia que outros se empolguem e participem do projeto. Com relao ao Android, existe um "port" do Qt para ele (http://gitorious.org/~taipan/qt/android-lighthouse), mas no um projeto da Nokia. Um abrao e muito obrigado.
Resposta do editor:
Oi Eduardo. Voc tem razo sobre a qualidade das imagens. Minha idia foi reduzir a quantidade de pginas para aqueles que (como eu) preferissem imprimir a revista, mas no final das contas, olhando a verso impressa, algumas imagens no ficaram boas mesmo. Vou melhorar isso na prxima edio, "espalhando" um pouco mais o contedo. Nesta primeira edio, acabei fazendo tudo sozinho e escaparam alguns detalhes. Preciso muito desse tipo de retorno, para ir melhorando a revista. Um grande abrao, Eduardo.
A histria comea com um programador e sua aplicao em Qt pronta e testada. O prximo passo distribuir a aplicao, provavelmente disponibilizando-a para download em algum servidor Web. Moleza! No dia seguinte, nosso heri recebe o e-mail de algum que fez o download do arquivo, mas ao tentar executar... nada! O usurio seguiu as instrues e deu permisso de leitura para o arquivo, mas ao tentar executar, recebeu a seguinte mensagem: error while loading shared libraries: libQtGui.so.4: cannot open shared object file: No such file or directory Estamos diante da tpica situao de na minha mquina funciona . Acontece que na mquina de desenvolvimento funciona tudo porque normalmente temos um trilho de bibliotecas instaladas nela. O Qt nos d duas opes de compilao de nossas aplicaes: esttica e dinmica. Para que possamos utilizar a compilao esttica, o prprio Qt tem que ter sido compilado estaticamente. Acreditem... esta no a mais simples das tarefas. Alm de levar muitas horas pra compilar o Qt estaticamente, existem muitas dependncias. Com a compulao esttica, temos a gerao de um executvel muito maior do que o gerado com a compilao dinmica, porm com tudo embutido nele. Se o programador da nossa historinha tivesse usado esta forma de compilao, o executvel disponibilizado para download teria funcionado. O compilao default do Qt a dinmica. Com a compilao dinmica temos executveis menores, porque as bibliotecas utilizadas no so includas. Durante a execuo dos programas, estes devem acessar arquivos externos correspondentes s bibliotecas necessrias. No caso do nosso desenvolvedor frustrado, a aplicao est reclamando que no conseguiu achar o arquivo libQtGui.so.4 que contm a biblioteca QtGui usada pelas aplicaes em Qt quando inclumos o mdulo gui no projeto, ou seja, em toda e qualquer aplicao com interface grfica desenvolvida em Qt. E tem mais... (parafraseando a Polishop) o programa interrompe a execuo na primeira biblioteca que no localiza. Ento na verdade, faltam mais arquivos do que o libQtGui.so.4. Neste artigo veremos como montar um pacote com tudo que uma aplicao nossa em Qt precisa para ser executada no Linux. Em edies futuras veremos como proceder para outras plataformas. [58] RevistaQt Novembro/Dezembro-2010 58]
Para este artigo, vamos utilizar o programa Al, Mundo! publicado na primeira edio da Revista Qt. Nosso primeiro passo ser descobrir quais so as bilbliotecas utilizadas pelo executvel de nossa aplicao, com o utilitrio ldd:
33 bibliotecas pra um Al, Mundo!? o preo que pagamos pelas facilidades que o Qt nos proporciona. Mas no se desespere (ainda...) porque muitas destas bibliotecas esto presentes na instalao de qualquer distribuio atual de Linux. O resultado do utilitrio ldd em seu computador pode ser diferente do apresentado aqui, dependendo da sua distribuio Linux e da verso de Qt que esteja utilizando. Eu uso o Ubuntu 10.10 com o Qt 4.7 instalado via Synaptic. Para testar a instalao de minhas aplicaes em Qt, instalei uma mquina virtual Ubuntu rodando no Virtual Box. Esta mquina virtual uma instalao limpa do Ubuntu sem as bibliotecas de desenvolvimento adicionais. Dessa forma, ela funciona como a mquina de um usurio que no seja programador.
RevistaQt Novembro/Dezembro-2010 [59] 59]
A princpio podemos nos preocupar apenas com as bibliotecas do Qt, ento o ldd pode ser executado em conjunto com o grep para filtrar apenas os arquivos que pertenam ao Qt:
Agora que sabemos de quais bibliotecas o programa AloMundo precisa para rodar, vamos copiar estes arquivos, juntamente com o arquivo executvel AloMundo para um diretrio chamado AloMundoLinux que usaremos para distribuir a aplicao. Para indicar a localizao das bilbiotecas, usamos devemos setar a varivel de ambiente LD_LIBRARY_PATH antes de executar o programa. Agora vem o macete retirado do diretrio do Google Earth: um script utilizado para setar a varivel de ambiente e chamar o executvel. Este script dever estar no diretrio AloMundoLinux.
#!/bin/sh # #!/bin/sh ## Agente SAA # # Agente SAA # FindPath() { FindPath() { fullpath="`echo $1 | grep /`" fullpath="`echo $1 | grep /`" if [ "$fullpath" = "" ]; then if oIFS="$IFS" [ "$fullpath" = "" ]; then oIFS="$IFS" IFS=: IFS=: for path in $PATH for [ -x "$path/$1" ]; then do if path in $PATH do if if -x "$path" = "" ]; then [ [ "$path/$1" ]; then if path="." = "" ]; then [ "$path" path="." fi fi fullpath="$path/$1" fullpath="$path/$1" break break fi done fi done IFS="$oIFS" IFS="$oIFS" fi fi if [ "$fullpath" = "" ]; then if fullpath="$1" = "" ]; then [ "$fullpath" fullpath="$1" fi fi # Is the sed/ls magic portable? # Is the sed/ls magic portable? if [ -L "$fullpath" ]; then if #fullpath="`ls -l ]; then [ -L "$fullpath" "$fullpath" | awk '{print $11}'`" #fullpath="`ls -l "$fullpath" | awk '{print $11}'`" fullpath=`ls -l "$fullpath" |sed -e 's/.* -> //' |sed -e 's/\*//'` fullpath=`ls -l "$fullpath" |sed -e 's/.* -> //' |sed -e 's/\*//'` fi fi dirname $fullpath dirname $fullpath } } CPATH="`FindPath $0`" CPATH="`FindPath $0`" LD_LIBRARY_PATH=.:${CPATH} LD_LIBRARY_PATH=.:${CPATH} export LD_LIBRARY_PATH export LD_LIBRARY_PATH cd "${CPATH}/" cd "${CPATH}/" exec "./AloMundo" "$@" exec "./AloMundo" "$@"
Ainda no acabou... no caso do nosso pequeno AloMundo, no utilizamos imagens, apenas um label com o texto Al, Mundo!, mas para aplicaes onde sejam utilizadas imagens, devemos incluir os plugins para tratamento dos formatos utilizados. Os plugins dos formatos de imagens ficam no diretrio qt/plugins/imageformats a partir do diretrio onde esteja instalado o Qt. Digamos que sua aplicao utilize imagens do tipo jpeg. Nesse caso voc deve criar no diretrio de sua aplicao um diretrio chamado imageformats e copie para ele o arquivo qt/plugins/imageformats/libqjpeg.so para ele. Com os arquivos da aplicao presentes no diretrio AloMundoLinux, basta gerar um pacote, compactando-o. Pode-se utilizar, por exemplo, o utilitrio tar para isso: tar cvfz AloMundoLinux.tgz AloMundoLinux Agora s baixar o arquivo na mquina cliente, descompactar e executar a aplicao atravs do script start. Caso a execuo reclame da ausncia de outra biblioteca, basta inclu-la no diretrio AloMundoLinux e gerar o pacote novamente. Uma vantagem da abordagem de compilao dinmica a possibilidade de atualizar as bibliotecas sem atualizar as aplicaes. Ok, voc pode a essa altura estar imaginando: se eu tiver 10 aplicaes em Qt terei em cada uma delas uma cpia das bibliotecas utilizadas? No necessariamente. Voc pode adotar como regra, a criao de um diretrio na mquina do cliente para armazenar as bibliotecas e utilizar este diretrio no seu script start. Alguns fabricantes de software usam a estratgia de criar um diretrio com o seu nome e dentro deste diretrio instalar seus produtos. Neste caso, o script start setar a varivel LD_LIBRARY_PATH para apontar para o diretrio compartilhado onde estaro as bibliotecas. At a prxima.
Um excelente material sobre Qt encontra-se disponvel no site de Um excelente material sobre Qt encontra-se disponvel no site de Antnio Mrcio A. Menezes. Slides de seu mini-curso e o cdigo-fonte Antnio Mrcio A. Menezes. Slides de seu mini-curso e o cdigo-fonte utilizado. Imperdvel para estudantes ou profissionais de Qt. utilizado. Imperdvel para estudantes ou profissionais de Qt. O mini-curso est disponvel em: O mini-curso est disponvel em: http://antoniomenezes.net/?tag=mini-curso-c-qt http://antoniomenezes.net/?tag=mini-curso-c-qt
Edio 2 - Novembro-Dezembro-2010
Editor Andr Luiz de O. Vasconcelos Cartoons Oliver Widder (Geek & Poke) Colaboradores Pierre Andrade Freire Rogrio Etsuo Yamamaru
A revista e os aplicativos nela publicados foram criados utilizando o Linux Ubuntu, verso 10.10.
A Revista Qt foi criada e convertida para PDF no BrOffice.org Draw, verso 3.2.1.
As imagens capturadas das telas presentes na Revista Qt foram obtidas atravs do KSnaphot, verso 0.8.1.
O tratamento de imagens (como a traduo das charges do Geek & Poke) foi feito atravs do Gimp, verso 2.6.10.