A organização de Qt (Especial de Natal)



O Porder do Qt Designer
ANTERIOR
Página Inicial Compilando com Qt Creator
PRÓXIMA


Criado em 22/12/2010 às 14:13

     



Antes de dar continuidade ao exemplo da página anterior, vamos dar uma estudada na estrutura de organização que o próprio Qt oferece.

Se você compilou o exemplo da página anterior (e nomeou o projeto como "lanchonete.pro") então ao acessar a pasta do seu projeto você deve encontrar a seguinte configuração:
- Uma pasta "imagens" com dois arquivos: "coquerin.png" e "resource.qrc".
- "dialog.h"
- "dialog.cpp"
- "dialog.ui"
- "main.cpp"
- "lanchonete.pro"

Na página anterior nós praticamente só alteramos o arquivo "dialog.ui" (ui = user interface). Abra o seu projeto e vamos observar estes arquivos de dentro do Qt Creator.

Assim que você reabrir o Qt Creator, uma janela de boas vindas será exibida e você tem dois caminhos para abrir o arquivo "lanchonete.pro":
- No menu, File, open file or project.
- Escolher o seu projeto na lista de projetos recentes, se ele ainda estiver lá.



Ao abrir o projeto, perceba que os arquivos envolvidos no projeto estão exibidos no lado esquerdo sob o painel "Projects". O Próprio Qt Creator já organiza os arquivos em pastas. São elas:
- Forms
Aqui ficarão todos os formulários que você desenvolver no Qt Designer. Sejam eles dialogs, widgets, mainwindows, qualquer formulário.
- Headers
Aqui ficarão todos os arquivos header (.h) envolvidos no seu projeto.
- Resources
Aqui ficarão todos os arquivos resource (.qrc) que você utilizar na sua aplicação, e é por aqui que você edita os itens contidos no seu arquivo resource.
- Source
Aqui ficarão todas as implementações de seus headers (.cpp).
Eventualmente existirão mais pastas além destas, mas essas são as principais.

Para sair do modo de edição de formulário, e editar estes arquivos basta clicar em EDIT na barra de ferramentas da esquerda.



Mas se eu só criei o formulário, como os arquivos
dialog.h e dialog.cpp já estão ai?



Essa pergunta é comum entre os iniciantes de Qt. Lembra quando você criou o arquivo pela primeira vez, quando escolheu o tipo de janela que sua aplicação usaria? Nós escolhemos QDialog e o nomeamos de "dialog". Aqui está a prova!



O proprio Qt já cria os arquivos dialog.h e dialog.cpp. Mas ele cria ainda mais do que isso:

Quando você fez o formulário dialog.ui, o Qt de alguma forma traduziu tudo o que você desenhou para C++ através da UIC (User Interface Compiler), e colocou o resultado no arquivo ui_dialog.h onde está definida a classe Ui_Dialog. Esse arquivo (ui_dialog.h) é gerado automaticamente sempre que você compilar o programa. Ui_Dialog é uma classe cheia de variáveis membro (se você desenhou uma label, tem QLabel, se vc desenhou 3 botões, tem 3 QPushButton), e uma função que as inicializa (que não é a construtora). Essa função que inicializa as variáveis é necessária. Vamos supor que você tenha criado uma QLabel com o texto "cebolinha" no Qt Creator (Qt Designer). Então dentro do arquivo ui_dialog.h (gerado pelo Qt no momento da compilação) você terá em algum lugar a linha "QLabel * nomeQvcDeuPraEla;" (onde nomeQvcDeuPraEla é o nome inserido no campo objectName do Property Editor). Seria muito legal se ela já tivesse sido inicializada nessa própria linha ("= new QLabel("cebolinha");"). Mas membros de classe não podem ser inicializados quando são declarados a não ser que isso seja feito por uma função. Normalmente essa função é a construtora mas nesse caso existe uma função especial, a "void setupUi(QDialog *Dialog)". É ela que vai fazer "nomeQvcDeuPraEla = new QLabel("cebolinha");".

Figura Esquemática 1. Esquema de representação, vá lendo e olhando para a figura.


Dentro do arquivo ui_dialog.h criado pelo Qt automaticamente, ele cria uma segunda classe dentro de um namespace chamado Ui, logo depois de terminar a classe Ui_Dialog:

Fragmento de código 1. ui_dialog.h, o arquivo que é gerado automáticamente.
class Ui_Dialog
{
...  // Widgets e setupUI
}
namespace Ui {
	class Dialog: public Ui_Dialog {};
} // namespace Ui

Teoricamente era pro header de Ui::Dialog estar ali dentro daquelas chaves vazias ({}). É como se o Creator falasse: "Até aqui é o procedimento padrão, a partir daqui o usuário que defina o cabeçalho desta classe (Ui::Dialog), inclusive em outro arquivo, porque nesse aqui ninguem põe a mão!!". Então, já que você não quer arranjar briga com o Qt Creator, este header é escrito em um arquivo separado, que é o dialog.h. Então, no exato momento as duas classes tem os mesmos membros (caixinha de surpresas). Só que Ui::Dialog está dentro do namespace Ui comparada com Ui_Dialog.

Dentro de dialog.h você encontra um ponteiro private chamado ui (minusculo) do tipo Ui::Dialog que provavelmente apontará para todos aqueles itens que você criou no Qt Designer, que pertecem originalmente à classe Ui_Dialog, que foram herdadas para Ui::Dialog. E o arquivo source (dialog.cpp) implementa a construtora (que chama setupUi).

Então, no exato momento a diferença entre as classes é que Ui::Dialog tem um ponteiro *ui e uma construtora, Ui_Dialog não.

Essa é uma forma muito inteligente de organizar os arquivos header, e os formulários criados pelo programador. Deste modo, você pode alterar o seu arquivo ".ui" que no final das contas a caixinha de surpresas já vai estar atualizada dentro de "dialog.h". Sempre que você mudar o arquivo ".ui" um novo ui_dialog.h vai ser gerado (sempre que compilar). Automaticamente o dialog.h já vai estar atualizado com a caixinha de surpresas.
A partir da caixinha de surpresas, do ponteiro ui, e da construtora, o Qt diz: "dai pra baixo faz o que você quiser com o que você criou". Pode criar signals, slots, qualquer coisa. No arquivo ".cpp" o ponteiro já é inicializado logo após a herança (new ui::Dialog):

Fragmento de código 2. dialog.cpp, a implementação "restante" da classe Dialog.
Dialog::Dialog(QWidget *parent)
		: QDialog(parent)
		, ui(new ui::Dialog)
	{
		ui->setupUi(this);
	}


A construtora está dizendo: "Aplique aquela roupa que o usuário projetou no Qt Creator (Qt Designer) em this". Mas quem é "this"? this é o objeto (obrigatoriamente do tipo Dialog) que chamou essa construtora. Ou seja, lá do main.cpp.

Figura Esquemática 2.


No momento que o objeto "w" é criado, a construtora de QDialog é chamada (cria a janela e suas características), depois a construtora de Dialog (cria cada membro que você desenhou - item a), que usa setupUi para imprimir o teu desenho na janela criada pela construtora de QDialog (b). O diálogo é exibido, o programa entra no loop de eventos (c).

Feito isso, faça o seguinte:



Vai tomar um café. Por que isso é complicadinho de entender. Releia o texto com calma se não entendeu.

Para confirmar seu entendimento, confira o código do arquivo ui_dialog.h. Ele está disponível na pasta "lanchonete-build-desktop" ( uma pasta anterior ao root do programa), lá você consegue eliminar muitas dúvidas. Esse diretório tem as pastas "Release" e "Debug" que vão conter os executáveis das respectivas versões. Esse diretório é chamado de "Shadow build directory".
...
...
...
5 minutos depois do café: Então é isso, a organização de Qt com relação aos headers e source files que tenham sido criados em conjunto com o formulário ".ui". No Creator você encontra meios de modificar o modo com que se dá essa herança. Mas para quem está começando, esse jeito ajuda muito.
ATENÇÃO: Para classes que implementam seus proprios signals/slots, ou seja, que tenham o macro Q_OBJECT, é obrigatório a separação em headers e source files. Caso contrário, o MOC (Meta Object Compiler) não funcionará. Para outras classes, acredito que não haja problemas em criar um único arquivo header. Mas eu, particularmente, mantenho o padrão de headers e source files do Qt.
ATENÇÃO 2: Se você tiver de editar o formulário, pelo arquivo ui_nomedaclasse.h que não vai ser né! Porque ele é sobrescrito sempre que há uma compilação. Deve ser até por isso que os caras resolveram mandar esse arquivo pra fora da pasta root do projeto. Pra ninguem achar que mudando as coisas lá, vai mudar no formulário, porque não vai.

Na próxima página, vamos dar vida à lanchonete criando nossos próprios signals e slots e brincando de abrir outros dialogs a partir do principal.


     


O Porder do Qt Designer
ANTERIOR
Página Inicial Compilando com Qt Creator
PRÓXIMA


Comentários: A organização de Qt (Especial de Natal)

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: Bruno
2012-11-06 10:14:45, disse:

Olá;

Cara eu não entendi uma coisa, a classe Dialog quando está no arquivo ui_dialog.h herda da classe ui_dialog e no arquivo dialogo.h ela herda do QDialog ou seja ela herdou de duas classes diferentes, isso é permitido. Cara essa dúvida está corredo minha mente responde ai xD valeu...