Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Qt 4.3.0] Incompréhension à propos des slots et signaux

Rien ne se passe...

Sujet résolu
8 juin 2007 à 10:13:11

Salut à tous :p ,

Je suis encore débutant en C++ ;) , et il y a quelques jours, j'ai décidé de me lancer dans Qt, en parallèle à SDL, de façon à pouvoir faire des minis logiciels, ou editeurs(toujours plus sympa dans une GUI que que la console ^^ , ou via un .ini à modifier à la main).

En "luttant" :D quelques heures sur toute la doc (très complète d'ailleur) de Trolltech, et en m'inspirant des quelques tutos trouvés sur le net (attention aux changements radicaux par rapport aux versions antérieures :o ), j'ai réussi à monter une fenêtre, contenant tout ce que je voulais (apparence, disposition, etc).

Jusque là tout va bien, et bien que mon code manque d'organisation (je ne fais que tester pour le moment), je m'y retrouve à peut prêt.
Mon problème vient avec l'arrivée des slots et signaux (un peu bête de bloquer ici :p). Jusqu'à présent le(s) seul(s) slot(s) que j'ai réussi à faire fonctionner pour le moment est "SLOT(quit())".
J'ai voulu essayer d'autres slots, mais ce sans succès, rien ne sa passe, ni une erreur à la compilation, ni un bug plus tard, tout simplement rien... :euh:

Je sais que mon "problème" est probablement tout bête, mais voila un exemple, de façon à ce que vous puissiez m'éclairer à ce sujet. J'essaye ici d'afficher une valeur (ici, pour faire plus simple), ou un texte dans une barre de statut, lorsque l'on clique sur un bouton.

De manière générale, le signal doit fonctionner :p , et le slot que j'utilise est présent dans la doc pour un "QtLabel", alors devrait aussi? :

"void QLabel::setNum ( int num ) [slot]

Sets the label contents to plain text containing the textual representation of integer num. Any previous content is cleared. Does nothing if the integer's string representation is the same as the current contents of the label."


Pourtant lorsque je clique, rien ne se passe:

#include <QT/qapplication.h>
#include <QT/qwidget.h>
#include <QT/qpushbutton.h>
#include <QT/qframe.h>
#include <QT/qlabel.h>

int main( int argc, char *argv[] )
{
    /*Génération de la fenêtre parente et des éléments*/
    QApplication editeur(argc, argv);
    editeur.setStyle("plastique");

    QWidget fenetre;
    fenetre.setFixedSize(800,600);

    QLabel statut("Aucune opération en cours...",&fenetre);
    statut.setGeometry(10,570,641,21);
    statut.setFrameStyle(QFrame::Sunken | QFrame::Panel);

    /*Gestion des évenements*/
    QObject::connect(&nouveau, SIGNAL(clicked()), &statut, SLOT(setNum(10)));

    fenetre.show();

    /*Fin du programme*/
    return editeur.exec();
}

Avec un peu de chance, le problème sera évident à vos yeux ^^ (il l'est moins aux miens :colere2: ...).

Je vous remercie d'avance ;) !!


  • Partager sur Facebook
  • Partager sur Twitter
8 juin 2007 à 12:15:16

Bah déjà où declare-tu le bouton "Nouveau" ?
puis je pense que le probleme doit venir du "&statut" enlève le & pour voir.
Au pire tu fait une methode exprès pour :

QObject::connect(nouveau, SIGNAL(clicked()), this, SLOT(taMethode()));

  • Partager sur Facebook
  • Partager sur Twitter
8 juin 2007 à 12:18:02

Salut

tout d'abord tu peux lire la doc de l'assistant sur les signaux et slots: "Signals and Slots"

ensuite le problème dans ton cas viens déjà de la méthode QObject::connect(...)

tu as écrit:

QObject::connect(&nouveau, SIGNAL(clicked()), &statut, SLOT(setNum(10)));


si tu relis la doc tu verras qu'il a 2 problemes:

1) il faudrait écrire SLOT(setNum(int)) au lieu de SLOT(setNum(10))
2) tu ne peut pas lier un signal sans paramètre SIGNAL(clicked()) à un slot avec paramètre
SLOT(setNum(int))


deux solutions possibles:
1) chois des signaux et slots compatibles au niveau des paramètres
mais il n'y a pas toujours ceux que tu veux

2) développe ta propre classe MyQLabel qui hérite de QLabel
ajoute une méthode MyQLabel::OnClick() qui appelle setNum(10)
et fait:

QObject::connect(&nouveau, SIGNAL(clicked()), &statut, SLOT(OnClicked());



Astuce: tu peux aussi afficher la valeur de retour de QObject::connect(...)
qui renvoie true/false en fonction du résultat du conenct(...)

Bon courage!
  • Partager sur Facebook
  • Partager sur Twitter
8 juin 2007 à 12:52:25

Merci pour vos réponses ;) .

En effet, je parcourais la doc à l'instant et je viens de me rendre compte que l'appel de "setNum" avec pour paramètre une valeur ou une variable est interdite.
Donc si j'ai bien compris, il faut que je me créé mon propre Label, avec des méthodes compatibles au niveau des paramètres :) ?

Je vais essayer tout ça et vous tiendrais au courant, en tout cas merci encore ;) !!

PS: UltimAKnighT, autant pour moi :p , j'ai oublié de copier la déclaration de "nouveau" quand j'ai posté mon code ^^ .
  • Partager sur Facebook
  • Partager sur Twitter
8 juin 2007 à 16:57:40

Ouais de toute façcon j'ai raconter des conneries :)
Jviens de m'en rendre compte. J'ai regarder la doc ^^ désolé :)
  • Partager sur Facebook
  • Partager sur Twitter
8 juin 2007 à 17:25:20

J'ai dérivé le QLabel :p , et j'ai fais un nouveau constructeur, ainsi qu'un "public slots" ;) , de façon à pouvoir fonctionner avec le signal "clicked()".
Voici mon nouveau code (j'ai tout mis sur le même fichier pour le moment):

#include <Qapplication>
#include <QLabel>
#include <QPushButton>
#include <QScrollBar>
#include <QGroupBox>
#include <QObject>

class MonLabel : public QLabel
{
    Q_OBJECT

public:
    MonLabel(const QString&,QWidget*);

public slots:
    void Valeur();
};

MonLabel::MonLabel(const QString &text,QWidget *parent = 0)
    : QLabel(text,parent)
{
    //Rien à faire
}

void MonLabel::Valeur()
{
    this->setText("Nouveau");
}


int main( int argc, char *argv[] )
{
    /*Génération de la fenêtre et le Widget parent*/
    QApplication editeur(argc, argv);
    editeur.setStyle("plastique");

    QWidget fenetre;
    fenetre.setFixedSize(800,600);

    /*Création des boutons*/
    QPushButton nouveau("Nouveau", &fenetre);
    nouveau.setGeometry(0,0,100,20);

    MonLabel *statut= new MonLabel("Aucune opération en cours...",&fenetre);
    statut->setGeometry(10,570,641,21);
    statut->setFrameStyle(QFrame::Sunken | QFrame::Panel);

    QObject::connect(&nouveau, SIGNAL(clicked()), statut, SLOT(Valeur()));

    fenetre.show();

    /*Fin du programme*/
    return editeur.exec();
}


Seulement ça ne fonctionne pas encore :colere2: , et ce probablement à cause de quelque chose plus embêtant que le code: l'installation de Qt 4.3.0 . A la compilation, je reçois ce message:

Running pre-build step: Console application
qt-prebuild : running
qt-prebuild : scan started
qt-prebuild : scan completed
Switching to target: default
Linking executable: Editeur_de_niveau.exe

.objs\editeur_main.o:editeur_main.cpp:(.text+0x176): undefined reference to `vtable for MonLabel'
.objs\editeur_main.o:editeur_main.cpp:(.text+0x182): undefined reference to `vtable for MonLabel'
.objs\editeur_main.o:editeur_main.cpp:(.text+0x25e): undefined reference to `vtable for MonLabel'
.objs\editeur_main.o:editeur_main.cpp:(.text+0x26a): undefined reference to `vtable for MonLabel'
collect2: ld returned 1 exit status
Process terminated with status 1 (0 minutes, 0 seconds)
 


J'ai cherché un peu sur le net, et les forums pour essayer d'en trouver la raison, et visiblement ça vient de moc, avec l'ajout du macro Q_OBJECT. J'ai à peut prêt tout testé de ce qui était proposé, et ce qui a marché pour la plupart, ne fais rien du tout chez moi.
Dans mon cas, je n'ai pas non plus de headers, donc le moc ne devrait pas être necessaire??

De plus, j'ai essayé (pour être sur) en mettant ma classe dans un header, et le constructeur ainsi que le slot sur un autre fichier .cpp. Là, qt-prebuild s'est occupé de lancer le moc et de me "créer" le fichier (dumoins d'après le log), seulement une fois que je vais dans le repertoire pour y chercher mon moc_monlabel.cpp, il n'y a rien du tout o_O ...

J'ai suivit quasiment à la lettre (mis à part quelques différences en raison des versions: 4.2.3 <=> 4.3.0), le tutorial ici présent: http://www.siteduzero.com/tuto-3-14605-1-qt-installation-sous-windows-avec-codeblocks.html, mais rien n'y fait, je n'arrive pas à compiler mon code, et reçois bêtement ce ce message :euh: ...

J'ai lu aussi que sous Code Blocks (IDE que j'utilises), Qt est assez problématique, et j'ai testé pour le moment uniquement sous Windows (me posera peut être moins de problème sous Kubuntu). Si vous avez réussi à la faire fonctionner correctement, je vous serais reconnaissant de me dire comment :p . Peut être faut-il que je telecharge une version de Qt antérieure, et mieu supportée par C::B :o ?
  • Partager sur Facebook
  • Partager sur Twitter
8 juin 2007 à 22:59:24

23h00... quelques heures de travail acharné ^^ ...

Plus sérieusement :p , j'ai réussi à régler mon problème, ça marche nickel à présent.
Merci à tous ;) !!

Cependant, je ne sais pas trop comment j'ai fais pour le faire fonctionner :-°(au moins ça marche). J'ai complètement reconfiguré mon template QT de A à Z (j'avais du loupé quelque chose :o ).
La liaison avec qt-prebuild.exe se fait sans problème, et cette fois-ci le fichier moc_***.cpp est bien créé :p .

De plus, j'ai déplacé ma nouvelle classe MyLabel dans un header à part ^^ , car sinon, apparament, ça ne fonctionne pas non plus o_O ? Si quelqu'un d'ailleur pourrait m'éclairer à ce sujet, et me justifier pourquoi je ne peux pas avoir de définition de classe dans un .cpp ?

En tout cas, merci pour votre aide ;) !
  • Partager sur Facebook
  • Partager sur Twitter
8 juin 2007 à 23:02:19

ce problème n'apparait que lorsque ta classe contient des slots/signals donc la macro Q_OBJECT car çà génère un moc_***.cpp, mais tu peux mettre la déclaration dans un .cpp si tu rajoutes dans ton fichier (à la fin) un truc du genre :
#include "ta_class.moc"
  • Partager sur Facebook
  • Partager sur Twitter
8 juin 2007 à 23:55:17

Merci ;) !
C'est à présent un peu plus clair :p pour moi, tout cette affaire.
Je vais donc pouvoir commencer/continuer mon apprentissage de Qt :-°:D .
  • Partager sur Facebook
  • Partager sur Twitter