Professional Documents
Culture Documents
Prática de Algoritmos e Estrutura de Dados I
Rivaldo Rodrigues
Introdução
Quando construímos um programa geralmente incluímos no mesmo diversas instruções de
saída para que, a partir de um terminal, possamos ter uma indicação do funcionamento do mesmo.
Em aplicações mais complexas e profissionais o programador pode optar por construir uma
interface gráfica que ira permitir que o usuário interaja com o programa de forma mais amigável e
intuitiva.
Este tutorial visa apresentar a ferramenta QT4 e mostrar os passos necessários para
construirmos um interface básica. Embora o QT4 esteja disponível para diversas plataformas iremos
nos focar na distribuição para linux.
Os diversos aspectos para se utilizar o QT4 serão mostrados a medida que formos progredindo
no tutorial onde, ao completarmos o processo, teremos criado a interface para uma calculadora
simples.
A Ferramenta Designer
A primeira etapa para a criação da interface é "desenhar" a tela de interação com o usuário.
Para isso o QT4 dispõe da ferramenta designer que consiste em um ambiente onde se pode
inserir os componentes para sua interface de forma visual.
Vamos iniciar o assistente digitando o seguinte comando no terminal:
```
$ designer
```
Provavelmente você irá se deparar com uma série de janelas soltas e uma caixa de dialogo
onde é possível escolher o tipo da nossa janela principal. Clique em Widget. Um widget consiste em
uma janela simples (inicialmente vazia) com algumas opções que nos são bastante conhecidas, como
é o caso do botão para minimizar e fechar a janela.
Agora vamos por a casa em ordem agrupando todas essas janelas. Para isso clique no menu
Edit>User>Interface Mode em seguida escolha Docked Window.
Vamos começar a construir a nossa interface propriamente dita. Primeiramente, vamos dar
uma olhada na aba Object Inspector que se encontra no canto superior direito. Essa aba será de
extrema importância na construção da nossa interface, e nela onde se encontram os objetos (widgets)
inseridos.
Ate o momento apenas um objeto é mostrado, ele corresponde a nossa janela principal
(também conhecida como form).
Vamos colocar um nome mais sugestivo a nossa janela. Clique com o botão direito em
qualquer lugar da janela e em seguida em change objectName digite "qtCalc" e pressione Ok. Note
que o nome correspondente ao nosso formulário foi trocado na guia Object Inspector.
Outra guia de extrema importância é a guia Property Editor que também se encontra no lado
direito logo abaixo do Object Inspector. Essa guia nos mostra as diversas propriedades que pode ser
modificadas no nosso objeto atualmente selecionado (no casso a nossa janela). Não nos deteremos a
um estudo formal das opções presente nesta guia pois viso deixar este tutorial o mais prático e
objetivo possível sem falar que são muitas opções.
Algumas opção porem, são comuns a diversos objetos como é o caso da opção para
determinar o tamanho, fonte e o nome do objeto.
Na opção windowTitle vamos inserir o nome que queremos que apareça na barra principal da
nossa janela. Clique no campo ao lado de windowTitle e digite um título criativo para a sua aplicação.
Ilustração 1: Tela do Designer. Em destaque o Object Inspector e o Property
Editor.
Feito isso, vamos começar a inserir os componentes da nossa interface. No lado esquerdo
existe uma aba chamada Widget Box, lá você encontra disponível os principais componentes para a
criação de uma interface.
Vamos começar inserindo o teclado numérico para nossa calculadora. Clique em Push Button
e arrasteo da guia ate a sua janela, feito isso um botão de tamanho e texto padrão deverá aparecer na
sua janela e uma referência a ele no Object Inpector.
Clique no botão recém inserido e as bordas do mesmo aparecerão em destaque nos permitindo
redimensionalo. Escolha um tamanho coerente com a nossa janela. Você também pode movimentar o
seu botão para a posição que achar conveniente, para isso, basta clicar e arrastar o botão para a nova
posição.
Feito isso, vamos identificar o nosso botão assim como fizemos como a janela. Clique com o
botão esquerdo do mouse no nosso botão e selecione Change objectName em seguida digite um nome
que caracterize o seu botão para que seja fácil referencialo mais tarde, sugiro que seja algo do tipo
"pushButton_1". Clique novamente no botão em seguida em Change text e insira o texto que deve
aparecer no botão (no caso "1"). Você pode ainda obter o mesmo efeito modificando a opção text no
Property Editor onde também é possível modificar a fonte e o tamanho do texto.
Proceda de forma análoga para construir os outros botões do teclado da sua calculadora. Sua
interface devera se parecer com a da figura a baixo.
Ilustração 2: Teclado Numérico
Agora vamos inserir o painel da nossa calculadora, para isso, vamos fazer uso do componente
Line Edit. Insira um Line Edit acima do teclado numérico e modifique o nome para “resultArea”, você
também optar por inserir um texto padrão usando o Change text, um zero cairia bem como texto
padrão.
Bem, agora que estamos satisfeito com a nossa interface vamos salvala com o nome de “
myCalc” você pode optar por usar outro nome, só lembre de memorizalo pois o mesmo será usado
mais a frente.
Adicionado Funções aos componentes
Agora que terminamos a nossa interface, vamos adicionar a funcionalidade referente a cada
um dos nossos componentes. Para isso crie um arquivo arquivo .h com o mesmo nome que você usou
quando salvou a interface (no caso myCalc.h).
Copie o seguinte código para o arquivo.
...
#ifndef QTCALC_H
#define QTCALC_H
#include "ui_myCalc.h"
#include <string>
using std::string;
class Calc : public QWidget, private Ui::qtCalc
{
Q_OBJECT
public:
Calc( QWidget *parent = 0 );
public slots:
void clear();
void igualClick();
void digitClick();
void operationClick();
private:
string str;
char opCod;
int op1, op2;
};
#endif
...
Vamos analisar o que cada parte do código significa.
...
#include "ui_myCalc.h"
...
Provavelmente você deve estar achando estranho o fato de termos incluído um arquivo que não
existe. Pois bem, nossa interface se encontra no arquivo "myCalc.ui" (formato XML), durante o
processo de compilação do nosso projeto esse arquivo será convertido para um arquivo ".h"
correspondente o qual nos previamente incluirmos.
...
class Calc : public QWidget, private Ui::qtCalc
...
Aqui nos definimos a nossa classe Calc que deve chamar por herança as classes QWidget (nos
possibilita o uso dos componentes widget) e a classe criada para nossa janela (note que ela possui o
mesmo nome que demos a janela).
...
Q_OBJECT
...
Esta é uma macro própria do QT4 que nos permite utilizar algumas definições necessários
como sinais e slots (veremos mais sobre sinais e slots no decorrer do texto).
...
public:
Calc(QWidget *parent = 0);
....
Este é o construtor da nossa classe, o parâmetros parent é opcional, de fato ele não tem efeito
na nossa classe já que temos apenas uma janela. Tal parâmetro serve para informar que existe outras
janelas ou diálogos associados a esta. Vamos nos contentar em deixar deste jeito por enquanto.
...
public slots:
void clear();
void igualClick();
void digitClick ();
void operationClick();
...
Aqui nos definimos algumas funções membro da classe chamadas slots. Slots são funções que
serão associados a um objeto da nossa interface e chamando quando o mesmo receber um sinal
(signal).
Agora vamos criar um arquivos .cpp onde ficará a implementação das funções aqui
apresentadas (lembrese de que deve ser usado o mesmo nome do arquivo .h no arquivos .cpp).
...
#include <QtGui>
#include “qtCalc.h”
...
Aqui nos incluímos a declaração da nossa interface (construída no passo anterior) e a classe
QGui que nos possibilitar usar diversas outras classes do QT4 como QString,QFileDialog etc.
...
Calc::Calc( QWidget *parent )
: str( "" ), opCod( '0' )
{
setupUi(this); // this sets up GUI
// signals/slots mechanism in action
connect( pushButton_CE, SIGNAL( clicked() ), this, SLOT( clear() ) );
connect( pushButton_Igual, SIGNAL( clicked() ), this, SLOT( igualClick() ) );
connect( pushButton_0, SIGNAL( clicked() ), this, SLOT( digitClick() ) );
connect( pushButton_1, SIGNAL( clicked() ), this, SLOT( digitClick() ) );
connect( pushButton_2, SIGNAL( clicked() ), this, SLOT( digitClick() ) );
connect( pushButton_3, SIGNAL( clicked() ), this, SLOT( digitClick() ) );
connect( pushButton_4, SIGNAL( clicked() ), this, SLOT( digitClick() ) );
connect( pushButton_5, SIGNAL( clicked() ), this, SLOT( digitClick() ) );
connect( pushButton_6, SIGNAL( clicked() ), this, SLOT( digitClick() ) );
connect( pushButton_7, SIGNAL( clicked() ), this, SLOT( digitClick() ) );
connect( pushButton_8, SIGNAL( clicked() ), this, SLOT( digitClick() ) );
connect( pushButton_9, SIGNAL( clicked() ), this, SLOT( digitClick() ) );
connect( pushButton_Soma, SIGNAL( clicked() ), this, SLOT( operationClick() ) );
connect( pushButton_Sub, SIGNAL( clicked() ), this, SLOT( operationClick() ) );
connect( pushButton_Div, SIGNAL( clicked() ), this, SLOT( operationClick() ) );
connect( pushButton_Mult, SIGNAL( clicked() ), this, SLOT( operationClick() ) );
connect( pushButton_Exp, SIGNAL( clicked() ), this, SLOT( operationClick() ) );
connect( pushButton_Mod, SIGNAL( clicked() ), this, SLOT( operationClick() ) );
}
...
Aqui se encontra o nosso construtor, ele é bastante extenso pelo fato de termos um grande
numero de objetos na nossa janela, pois é nele onde faremos a conexão entre o sinal recebido e a
função que será chamada.
A primeira coisa a se fazer é iniciar a nossa janela com o comando setupUi , lembre se que
nossa classe chama por herança a classe da nossa janela, ou seja, ela também é uma janela, o que nos
leva ao comando this.
Chegou a hora de adicionarmos funcionalidade a cada um dos nossos botões. Vamos analisar
o procedimento para o pushButton_1 , o procedimento para os demais se da de forma analogia.
...
connect( pushButton_1, SIGNAL( clicked() ), this, SLOT( digitClick() ) );
...
A instrução connect indica que queremos fazer uma conexão entre o objeto (primeiro
argumento) um sinal (segundo argumento), uma janela( terceiro argumento) e um slot (quarto
argumento).
Nosso procedimento indica que o pushButton_1 quando receber um sinal de clicado na nossa
janela invocará uma função definida nos slots e chamada digitClick.
Simples não? Proceda da mesma forma para os demais botões, todos que forem números vão
receber a função digitClick como slot, os botões CE e = irão receber as funções clear e igualClick
respectivamente, por fim, todos os nosso operados vão receber a função operationClick. Confira o seu
resultado com o código completo que foi mostrado acima.
Agora basta construir a lógica de cada função e nosso trabalho estará praticamente terminado.
Antes de começar vamos fazer algumas considerações importantes. Cada objeto que constitui
a nossa interface dispõe de funções próprias para sua manipulação, o conjuntos de funções é tão
extensa (se não mais) que o conjunto de propriedade. Assim sendo, vamos nos deter a apenas alguma
funções que serão apresentadas a medida que implementamos os nossos slots.
Vamos começar pela função clear implementada como segue:
...
void Calc::clear()
{
resultArea>clear();
resultArea>setText( "0" );
str = "";
opCod = '0';
}
...
No código acima, resultArea se refere ao nosso Line Edit (se este foi o nome que você deu ao
mesmo) e o método clear (próprio dos Line Editsi) é usado para limpar o conteúdo presente na área
de texto. Já o método setText é usado para inserir um texto no mesmo.
A nossa função clear dispõe da lógica necessários para reiniciar a nossa calculadora.
...
void Calc::digitClick ()
{
QPushButton *clickedButton = qobject_cast<QPushButton *>( sender() );
if ( clickedButton == pushButton_0 && str == "" )
;
else
str += clickedButton>text().toStdString();
resultArea>setText( QString::fromStdString( str ) );
}
...
O nosso próximo slot trata os dígitos do teclado numérico. Inicialmente usamos o operador
qobject_cast que tem por função transformar um tipo qualquer no tipo indicado entre < e > . O tipo
indicado (QPushButton *) indica que queremos que ele transforme o nosso dado entre parênteses (no
caso sender, uma referência ao objeto que enviou o sinal ao qual esse slot esta conectado) em um
ponteiro para um QpushButton o qual será atribuindo na variável clickedButton.
Feito isso, podemos manipular o clickedButton como se estivéssemos manipulando
diretamente o objeto responsável pelo sinal.
Uma comparação é feita para saber se o objeto que enviou o sinal foi o botão zero, afim de
evitarmos imprimir um numero desnecessários de zeros a esquerda.
A instrução após a comparação pega o texto contido no botão (metodo text() ) e acrescenta a
nossa string. Como str é uma string padrão do C++ e o QT4 trabalha com sua própria string
(QString) devemos, antes de fazer a atribuição, converter o texto presente no botão para uma string
convencional. A class Qstring possui um método chamado toStdString que nos possibilita fazer isso
então vamos usalo.
A próxima etapa a se fazer é apresentar a nova string ao usuário. Para isso usamos o método já
conhecido (setText) no entanto, como foi tido anteriormente os objetos do QT4 usam a classe QString
sendo assim, vamos aplicar uma conversão no sentido inverso ao que fizemos anteriormente
utilizando o metodo static da classe QString fromStdString que recebe uma string convencional e nos
retorna uma QString.
...
void Calc::operationClick()
{
QPushButton *clickedButton = qobject_cast<QPushButton *>( sender() );
if( opCod == '0' )
{
string res = clickedButton>text().toStdString();
opCod = res[0];
istringstream temp( str );
temp >> op1;
str = "";
}
}
...
Bem, não a muito o que se explicar aqui visto que usamos basicamente os que já foi discutido
anteriormente. Fora isso, tudo faz parte da nossa lógica de programação para extrairmos o texto
presente no botão pegarmos o char que o caracteriza e armazenarmos na variavel OpCod ao mesmo
tempo que usamos uma istringstram para retirar o valor inteiro contido atualmente na string para que
este não seja perdido e possa ser utilizado mais adiante no calculo.
...
void Calc::igualClick()
{
if ( str.length() > 256)
resultArea>setText( "Caracter limit exceded" );
else
{
istringstream temp ( str );
temp >> op2;
QString res;
bool valid = true;
switch( opCod )
{
case '+':
res.setNum( op1 + op2 );
break;
case '':
res.setNum( op1 + op2 );
break;
case '*':
res.setNum( op1 * op2 );
break;
case '/':
res.setNum( op1 / op2 );
break;
case '^':
res.setNum( pow(op1, op2) );
break;
case '%':
res.setNum(op1 & op2);
break;
default:
valid = false;
}
if( !valid )
resultArea>setText("Erro: Invalid Operator.");
else
resultArea>setText( res );
str = "";
opCod = '0';
}
}
...
Essa é nossa ultima função e também a mais simples de todas. Basicamente o que fizemos é o
que se espera que seja feito quando o botão de igual for pressionado.
Extraímos o segundo operando da nossa string em seguida fazemos um teste no nosso
operador e aplicamos a ação correspondente ao mesmo. Caso o operador presente não seja um
operador valido uma mensagem de erro será mostrada, caso contrario mostraremos o resultado.
Simples. Pois bem, nossa calculadora é bastante limita mas como nossa intenção aqui e
apresentar a construção da interface creio que nosso objetivo foi comprido.
Compilação e execução
Estamos a poucos passos que vermos o nosso programa funcionando, falta agora criarmos um
arquivos contendo a função main que iniciará nossa aplicação.
Digite o código abaixo e salve como main.cpp.
...
#include <QApplication>
#include "qtCalc.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Calc *dialog = new Calc();
dialog>show();
return app.exec();
}
...
O que fazemos aqui é criar um objeto da nossa classe (no caso a janela) e utilizamos o método
show para iniciar sua exibição.
Agora podemos compilar o nosso projeto. O QT4 dispõe de comandos próprios para a
compilação. Navegue pelo terminal ate a pasta onde se encontram os arquivos e digite:
...
$qmake project
$qmake
$make
...
Se tudo ocorrer corretamente o arquivo devera ser compilado e receberá o mesmo nome da
pasta onde se encontra.
Bem, você acaba de aprender o essencial sobre como criar interfaces com QT4, agora é só
usar da criatividade para construir suas proporias interfaces. Esperto ter ajudado.
Referências
http://doc.trolltech.com/4.2/
http://sector.ynet.sk/qt4tutorial/myfirstqtguiapplication.html