Tipos de Janelas do Qt



Um Programa que Faz Alguma Coisa
ANTERIOR
Página Inicial O Poder Gráfico do Qt Designer
PRÓXIMA


Criado em 28/09/2010 às 16:40

     



Nesta página, falarei um pouquinho sobre os tipos de "janelas" que encontramos no Qt. Também falarei sobre "separação" do seu código para uma melhor organização. Se você abrir o Qt Creator ou o Qt Designer você terá que escolher logo de cara, qual é o template (modelo) que você usará. Tente você mesmo, você verá três opções basicamente:
  • MainWindow
  • Dialog
  • Widget



Eu diria que no nível de complexidade, nós poderíamos organizá-los do mais simples para o mais complexo da seguinte forma: Widget, Dialog, MainWindow. Nada mais justo que começarmos pelo mais simples.

Você já conheçeu as Widgets das páginas anteriores, QLabel, QPushButton, QLineEdit. Você viu até um caso em que um botão estava dentro de uma label. Nesse caso, será que não poderíamos pegar a label, e seu filho botão, e chamá-los de uma unica widget? Tipo uma nova classe(widget) chamada QLabotao! Sim, nós poderíamos, e desse modo podemos criar nossas proprias widgets, compostas por outras widgets. Isso será exemplificado mais adiante.

E o Dialog? O Dialog é uma janela que tem como objetivo pegar/receber informações de escolha do usuário. Exemplos de dialogs: Janela de tipo de fonte a ser usada num editor de texto, janela de abertura de arquivo, janela de salvamento de arquivo, janela de cores. Geralmente dialogs servem como auxílio à tarefas de uma janela principal e tem dois botões, o aceitar e o cancelar.



Enfim, MainWindows são janelas principais do programa. É a janela que manda no programa, ela chama dialogs diversas vezes e quando é fechada o programa acaba. Ela tem mais algumas propriedades como statusbar, toolbars, docked windows entre outras..



Para criarmos novas Widgets, novos Dialogs ou novos MainWindows nós vamos, inicialmente, criar classes que herdam daquelas. Então é importante saber que herdaremos nossas novas classes das já existentes:
  • QObject-QWidget
  • QObject-QWidget-QDialog
  • QObject-QWidget-QMainWindow
Veja que o proprio caminho de heranças sugere que as classes mais diferenciadas QDialog e QMainWindow sejam mais complicadinhas que a QWidget.

Figura Esquemática 1. Classes do Qt que já vimos até agora (Heranças).



Criando Nossa Widget

Você perceberá que ao fazer nossas próprias coisas (widgets, dialogs ou mainwindows), é sempre bom dividir nossa fonte em arquivos header e arquivos source, com isso o código fica mais organizado e entendivel. Vejamos então, um exemplo de uma Widget criada por nós, seguido do comentário do código. Mas antes, o resultado:



Código 6. Código source principal(main.cpp).
#include <QApplication> 	//QObject-QCoreApplication-QApplication
#include "nossawidget.h"	//"QObject-QWidget-"nossawidget

int main(int argc, char * argv[])
{

	QApplication app(argc, argv);
	
	NossaWidget janela;

	janela.show();
	
	return app.exec();
}


Tudo começa na função main (Código 6), onde criamos a nossa classe do tipo NossaWidget, o que acontece nesse momento? a construtora da nossa classe é chamada! Construtora essa que tem seu protótipo dentro do header "nossawidget.h"(Código 7) e sua implementação dentro do arquivo source "nossawidget.cpp"(Código 8, implementados abaixo)

Código 7. Header da nossa classe(nossawidget.h).
#ifndef NOSSAWIDGET_H
#define NOSSAWIDGET_H

#include <QWidget>			//QObject-QWidget

class NossaWidget : public QWidget
{
	public:
                NossaWidget(QWidget *parent = 0);	//protótipo da função construtora
};
#endif


Perceba que nosso header está "protegido contra duplicação" nas diretivas #ifndef/#define/#endif (senão estiver definida, defina, fim do if), precisamos incluir a classe QWidget porque nossa classe vai vir dela. O parâmetro da nossa construtora é inicializado com o valor zero porque, como vamos chamá-la do main, podemos criá-la sem parâmetros e não será filha de ninguém.

Código 8. Source da nossa classe(nossawidget.cpp).
#include <QLabel>           //QObject-QWidget-QFrame-QLabel
#include <QPushButton>      //QObject-QWidget-QAbstractButton-QPushButton
#include <QVBoxLayout>      //QObject-QLayout-QBoxLayout-QVBoxLayout
#include <QHBoxLayout>      //QObject-QLayout-QBoxLayout-QHBoxLayout
#include <QLineEdit>        //QObject-QWidget-QLineEdit
#include "nossawidget.h"    //Para ele saber de quem você está falando

NossaWidget::NossaWidget(QWidget *parent) : QWidget (parent)
{

        QLabel *label = new QLabel("Insira o seu Nome:");
	QPushButton *botao = new QPushButton("Ok");
        QLineEdit *linha = new QLineEdit;

        QVBoxLayout *layoutV = new QVBoxLayout(this);
        QHBoxLayout *layoutH = new QHBoxLayout();

        layoutH->addWidget(label);
        layoutH->addWidget(linha);
        
	layoutV->addLayout(layoutH);
        layoutV->addWidget(botao);
		
	QObject::connect(botao, SIGNAL(clicked()), this, SLOT(close()));
}


No arquivo source da nossa widget, 3 widgets e 2 layouts são criados e o botão é conectado. Você já é capaz de entender a suruba dos layouts ali sozinho(a) mas, para judar, dê uma olhada na figura abaixo:



A linhas da figura acima representam:variável "janela" do main.cpp, Layout Vertical da nossa classe aplicado a quem o chamou (this = variável janela, do main.cpp) e Layout Horizontal da nossa clase. O "this" ali ta dizendo: O layout vertical vai ser aplicado a quem chamou a construtora (variável janela, no main), Quando for clicado, o botão vai dar um "close()" em quem o chamou (variável janela, do main.cpp).


Criando Nosso Dialog

Para fazer um dialog diferente dos padrões (como o de abertura de arquivo, ou até algumas mensagens de notificação), o processo é o mesmo mas existe uma diferença sutil nas conexões dos botões de um Dialog. Acompanhe o código do mesmo exemplo da Widget para um Dialog:

Código 9. Arquivo source principal(main.cpp).
#include <QApplication> 	//QObject-QCoreApplication-QApplication
#include "nossodialog.h"	//"QObject-QWidget-QDialog-"nossodialog

int main(int argc, char * argv[])
{

	QApplication app(argc, argv);
	
	NossoDialog dialog;

	dialog.show();
	
	return app.exec();
}


Código 10. Header do nosso dialog(nossodialog.h).
#ifndef NOSSODIALOG_H
#define NOSSODIALOG_H

#include <QDialog>			//QObject-QWidget-QDialog

class NossoDialog : public QDialog
{
	public:
                NossoDialog(QWidget *parent = 0);	//protótipo da função construtora
};
#endif


Já aproveitando o balanço do busão vou mostrar, na implementação do source code do nosso dialog, o uso do layout grid (QGridLayout). Você já viu que o QHBoxLayout organiza as widgets horizontalmente e que a QVBoxLayout organiza as widgets verticalmente. O layout em grid considera um esquema de linhas e colunas, como numa matriz, acompanhe abaixo:

Código 11. Arquivo source do nosso dialog(nossodialog.cpp).
#include <QLabel>           //QObject-QWidget-QFrame-QLabel
#include <QPushButton>      //QObject-QWidget-QAbstractButton-QPushButton
#include <QGridLayout>      //QObject-QLayout-QGridLayout
#include <QLineEdit>        //QObject-QWidget-QLineEdit
#include "nossodialog.h"    //Para ele saber de quem você está falando

NossoDialog::NossoDialog(QWidget *parent) : QDialog (parent)
{

        QLabel *label = new QLabel("Insira o seu Nome:");
        QPushButton *botaoOk = new QPushButton("Ok");
        QPushButton *botaoCan = new QPushButton("Cancelar");
        QLineEdit *linha = new QLineEdit;

        QGridLayout *layoutGrid = new QGridLayout(this);

        layoutGrid->addWidget(label, 0, 0); //Linha 0, Coluna 0
        layoutGrid->addWidget(linha, 0, 1); //Linha 0, Coluna 1
        layoutGrid->addWidget(botaoOk, 1, 0); //Linha 1, Coluna 0
        layoutGrid->addWidget(botaoCan, 1, 1); //Linha 1, Coluna 1


        QObject::connect(botaoOk, SIGNAL(clicked()), this, SLOT(accept()));
        QObject::connect(botaoCan, SIGNAL(clicked()), this, SLOT(reject()));
}



É importantíssimo frisar o modo com que um dialog é encerrado: Clicando no botão OK, ou CANCELAR. Enviando a mensagem de volta (para sua MainWindow) ACCEPTED ou REJECTED. Abaixo está uma representação do layout grid:



O uso dos layouts foi para simples demonstração, você pode usar o Layour que quiser. A criação de MainWindows vai ficar para páginas posteriores porque envolve outros conceitos. Calma que jájá faremos exemplos graficamente!, é importante saber oque acontece behind the scenes.

Por hoje é só pessoal!


Exercicio 2

Crie uma classe derivada de uma QLineEdit ("MeuLineEdit"). Desenvolva uma função construtora para sua classe de forma que ela seja inicializada com um texto inicial, sem usar a construtora própria para isso ( MeuLineEdit linha("não vale")).
Que membro você escolheu para fazer essa alteração? (Use o Qt Assistant)


     


Um Programa que Faz Alguma Coisa
ANTERIOR
Página Inicial O Poder Gráfico do Qt Designer
PRÓXIMA


Comentários: Tipos de Janelas do Qt

Se você tiver alguma sugestão ou dúvida, por favor, preencha o formulário abaixo. O seu comentário só será adicionado após uma verifição do conteúdo.



Nome*:

Email*:

Mensagem*:


Nome: Carlos André
2011-02-22 15:06:43, disse:

No exercício 2, para colocar o texto inicial....usei o construtor sobrecarregado (dentro da implementação do construtor da minha classe):


QLineEdit ( const QString & contents, QWidget * parent = 0 )


podia ser assim?
Nome: Danilo Domingos
2011-02-23 13:59:08, disse:

Olá Carlos,
Você pode usar o construtor padrão da QLineEdit (como você fez) da seguinte forma:

class MeuLineEdit : public QLineEdit
{
public:
MeuLineEdit(const QString &contents);
};

MeuLineEdit::MeuLineEdit(const QString &contents) : QLineEdit(contents)
{ }


e no main simplesmente chamar
MeuLineEdit linha("Texto inicial");
linha.show();

Dessa forma a sua construtora só manda o argumento string para a construtora da mãe e dps disso não faz nada.

----------------

Mas também dá para fazer de um jeito que não usa a construtora padrão da QLineEdit que aceita uma string. Que seria apenas fazendo

class MeuLineEdit : public QLineEdit
{
public:
MeuLineEdit(); //construtora que não recebe argumento
};

MeuLineEdit::MeuLineEdit() : QLineEdit()
{
this->setText("Texto inicial");
}


e no main simplesmente chamar
MeuLineEdit linha;
linha.show();

Na vedade ambos os jeitos passam pelas 2 possiveis construtoras de QLineEdit, mas o objetivo é fazer as pessoas verem que um slot (setText) pode ser chamado de qualquer lugar, não necessariamente do SIGNAL.
O exercício não tem MUITO a ver com janelas, mas é bom pra familiarizar a pessoa com QT ASSISTANT e tal
Nome: ztwdRegDdlZvPH
2012-08-25 19:09:28, disse:

Welcome to the world of Qt.I wondered why you were tirnyg such an old version of Qt (4.3.3) but I assume that's a type as you mention 4.6.0.You could have avoided all of the issues above by downloading the free MSVC integration plugin (LGLP). It allows you to set environment variables and provides wizards for creating Qt projects with all the libraries, post build steps etc setup for you. It's well worth it. There is no-need to do any of this stuff your self (although in MSVC, you still have to add libraries to the linker if you decide to use the GL or test modules later etc).The biggest problem with Qt+MSVC is that that libraries came built with the free MinGW and the symbols were not compatible (there is a GUI tool called CuteBuilder to automate this process). So the whole thing had to be rebuilt using nmake. But as of 4.6, Qt now provide an installer with MSVC 2008 binaries pre-built.
Nome: marcos souza
2012-09-02 02:43:12, disse:

meu velho, não sei nem se vc vai ler isso

mas a sua explicação foi a melhor até agora, vc tem mais tutoriais de qt pela net?

valeu
Nome: Danilo Domingos
2012-12-11 17:56:45, disse:

Olá Marcos, obrigado.
Eu pretendo continuar sim, mas no momento ando ocupado. Quando tiver mais tempo vou continuar com os tutoriais.