Pais e Filhos, quer dizer, e Signals/Slots



Primeira Aplicação
ANTERIOR
Página Inicial Um Programa que Faz Alguma Coisa
PRÓXIMA


Criado em 26/09/2010 às 17:44

     



Esta página tratá mais informações sobre parentesco e como utilizar SIGNALs e SLOTs. Como já foi dito anteriormente, o conhecimento das classes do Qt é extremamente importante e, por esse motivo, a partir de agora sempre que eu chamar alguma diretiva #include colocarei um comentário ao lado mostrando todo o caminho de herança da classe, por exemplo: "#include <QApplication> //QObject-QCoreApplication-QApplication".

Vamos começar exemplificando o parentesco com a criação de um botão QPushButton dentro (filho) da nossa QLabel do exemplo anterior. Mas o botão será criado na heap, seguindo a recomendação da página anterior. O botão também é uma widget. Todas as widgets tem uma construtora com um parâmetro "(QWidget * parent = 0)". Este parâmetro serve para dizer "sua mãe/pai será..". Observe no Código 3 como o botão é criado:

Código 3. Criação de um botão, filho da label (main.cpp).
#include <QApplication>  //QObject-QCoreApplication-QApplication
#include <QLabel>        //QObject-QWidget-QFrame-QLabel
#include <QPushButton>	 //QObject-QWidget-QAbstractButton-QPushButton	

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

	QApplication app(argc, argv);
	
	QLabel textinho("Que mané Hello World oq!? Meu nome é Zé Pequeno!");
	textinho.resize(400,80);
	textinho.setAlignment(Qt::AlignCenter);
	
	QPushButton *botao = new QPushButton("Botão inutil", &textinho);

	textinho.show();
	app.exec();
}


É, um botão filho de uma label não é lá uma coisa muito útil, mas para exemplificar é o suficiente. Perceba as diretivas #include tanto para a QLabel quanto para o QPushButton, ambas vem das classes QObject-QWidget. Observe também que "textinho" é passado como parente do botão pelo endereço (&textinho), já que o parametro "QWidget * parent = 0" da construtora do botão é um ponteiro. Vamos dar uma olhadinha no resultado para este código:



Nossa label funciona, neste caso, como um container armazenando o botão. Note que o botão foi colocado no "local padrão" já que não especificamos nenhuma geometria para ele (canto superior esquerdo), e ao redimensionar a janela como mostrado na figura acima, o botão "tampa" um pedaço do texto da label. Essa é a forma que, geralmente, iremos dizer quem é mãe de quem. Vamos dar uma olhada nos passos envolvidos na execução do programa:

  • O programa inicia;
  • a label "textinho" é criada no Stack e é configurada;
  • o botão "botao" é criado na Heap, e sua mãe é "textinho";
  • a widget "textinho" é exibida e, junto com ela, seu filho botao;
  • o programa entra no loop de eventos;
  • ao fechar o programa, todas as variáveis declaradas na Stack serão deletadas;
  • no caso da variável "textinho", ela procura pelos filhos e os deleta automáticamente (botao);
  • "textinho" é deletada;
  • fim!
Já que estamos com um botão inútil, vamos fazer com que seja fechado ao clicar.


O Uso de Signals e Slots

Modifique o código 3 de acordo com o código abaixo adicionando uma conexão para o botão:

Código 4. "Conectando" o botão à alguma ação(main.cpp).
#include <QApplication>  //QObject-QCoreApplication-QApplication
#include <QLabel>        //QObject-QWidget-QFrame-QLabel
#include <QPushButton>	 //QObject-QWidget-QAbstractButton-QPushButton	

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

	QApplication app(argc, argv);
	
	QLabel textinho("Que mané Hello World oq!? Meu nome é Zé Pequeno!");
	textinho.resize(400,80);
	textinho.setAlignment(Qt::AlignCenter);
	
	QPushButton *botao = new QPushButton("Botão inutil", &textinho);
	QObject::connect(botao, SIGNAL(clicked()), botao, SLOT(close()));

	textinho.show();
	app.exec();
}


A função utilizada para conectar o botão a alguma ação (ou um widget a uma ação) está declarada dentro da classe QObject (a função pública e estática connect) por isso precisamos utilizar o operador de resolução de escopo "::". Poderiamos traduzir a linha "QObject::connect(botao, SIGNAL(clicked()), botao, SLOT(close()));" como: Ao clicar no widget sender "botão", feche o widget receiver "botão". Existem algumas propriedades importantes de SIGNALS/SLOTS, como por exemplo, parâmetros de cada um passados para o outro. Essas propriedades serão abordadas mais futuramente.


Mas então você pergunta:
E como vou saber quais funções podem "entrar" ali no slot? Eu posso criar uma??



Ao pesquisar sobre a classe QPushButton no Qt Assistant você encontra o seguinte:


Então estes são os "slots padrões" que podemos chamar quando o widget receiver for um botão. Você também pode criar um Slot, para isso basta você declará-lo como uma função dentro da sessão "public slots" de sua classe. A partir de agora além de declarar sessões public:, private:, protected:, você também declarará public slots:, por exemplo.

Com todos os conceitos mostrados até agora já podemos criar uma aplicação menos inútil! uma aplicação que realmente faça alguma coisa.





     


Primeira Aplicação
ANTERIOR
Página Inicial Um Programa que Faz Alguma Coisa
PRÓXIMA


Comentários: Pais e Filhos, quer dizer, e Signals/Slots

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: André
2012-01-31 16:22:39, disse:

Tudo bem Danilo.

Muito legal o site.

Mas estou com algumas dúvidas:

Como eu chamo um SLOT de uma classe diferente da qual eu estou trabalhando?
Por exemplo, no meu caso: Seja a classe ButtonMine, derivada de QPushButton, e eu queira acessar o SLOT buttonMineClicked() desta classe a partir da class MainWindow, como será a sintaxe do connect? Eu tentei assim:

ButtonMine *buttons [10][10];

...

connect(
buttons [i][j],
SIGNAL(clicked()),
this,
SLOT(buttons [i][j]->ButtonMineClicked()));

Mas não funciona.
Toda a parte de inicialização e "sets" está funcionando.

Outra coisa, é possível conectar SIGNAL e SLOT com assinaturas diferentes?

Desde já agradeço.
Nome: Danilo Domingos
2012-05-02 13:28:06, disse:

Olá André,

Você já tentou utilizar o connect dessa forma?:
connect(buttons[i][j], SIGNAL(clicked()), buttons[i][j], SLOT(ButtonMineClicked()));

Por assinatura você quer dizer o parâmetro do SIGNAL() e do SLOT()? Se sim, você não pode conectar SIGNALs e SLOTs com assinaturas diferentes. Se vc tem SIGNAL(int,int) então seu SLOT deverá ser SLOT(int,int).

Hoje quando eu chegar em casa vou fazer um exemplo e pensar melhor na sua primeira dúvida.