Você está na página 1de 11

Universidade Federal do Rio Grande do Norte

Prática de Algoritmos e Estrutura de Dados I

Rivaldo Rodrigues

Criando Interface com QT4

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 arraste­o 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 
redimensiona­lo. 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 referencia­lo 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 salva­la com o nome de “ 
myCalc” você pode optar por usar outro nome, só lembre de memoriza­lo 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 (lembre­se 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 usa­lo.
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/qt4­tutorial/my­first­qt­gui­application.html