Posté le 19/03/2015 à 14:16Edité par Folco le 08/06/2015 à 23:09 Membre depuis le 18/06/2001, -26239 message
yop,

J'ai un QTableWidget qui contient un tab. Su ce tab (classe FormLadder), j'ai un bouton close, censé fermer son propre tab : http://www.mirari.fr/Wu33[img][/img]

Un clic sur ce bouton appelle une méthode de FormLadder :
void FormLadder::on_buttonLadderClose_clicked()
{
    controler->closeLadder(this);
}


MAIS !!!

Le controller appelé voudrait, entre autres, détruire ce FormLadder! Normal, yen a plus besoin. Mais si mon FormLadder est édtruit, comment la méthode on_buttonLadderClose_clicked() va-t-elle retourner fiablement ? Ca sera une méthode d'un objet devenu inexistant ><

Question : quelle est la bonne façon de s'y prendre ? Si je détruisais ce tab "de l'extérieur", ça poserait pas de problème, mais comment auto-détruire un objet et les données qui lui sont associées ?

Merci d'avance. smile
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 19/03/2015 à 22:33 Membre depuis le 10/06/2001, 40014 messages
Alors, la méthode elle-même n'est pas un problème, elle ne fait plus qu'un return (implicit) après l'appel à closeLadder, donc elle n'a plus besoin de l'objet détruit. Mais, attention attention, il est très dangereux d'effacer un QObject dans un slot, parce qu'il peut y avoir d'autres évènements en attente. Pour ça, QObject propose une méthode deleteLater, qui efface l'objet quand les évènements en cours ont été traîtés.
avatarMes news pour calculatrices TI: Ti-Gen (fr/en), MobiFiles (de)
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
Posté le 20/03/2015 à 06:25 Membre depuis le 18/06/2001, -26239 message
Parfait merci ! C'est exactement ça que je cherchais : The object will be deleted when control returns to the event loop. Je regardais hier s'il était possible de dériver QAplication pour surcharger, s'il était possible, l'event loop, et y insérer la destruction de ce foutu tab. En fait, le mécanisme existe déjà love
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 20/03/2015 à 23:39 Membre depuis le 18/06/2001, -26239 message
Si cette question vous a ultra-choqué ("comment il s'y prend comme une merde pour arriver à une problématique de ce genre ?!?!?"), n'hésitez pas à le dire. Bien que la fonction proposée par Kevin, que je subodorais et cherchais à implémenter, me satisfasse à 100%, je suis tout à fair preneur d'une solution avec un autre angle d'attaque. smile
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 21/03/2015 à 04:33 Membre depuis le 10/06/2001, 40014 messages
Ce type de bogue "use after free" est très courant dans les applications Qt, et la solution est toujours la même: remplacer delete par deleteLater. C'est exactement pour ça que cette méthode existe.
avatarMes news pour calculatrices TI: Ti-Gen (fr/en), MobiFiles (de)
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
Posté le 21/03/2015 à 19:24 Membre depuis le 18/06/2001, -26239 message
Qu'existe-t-il pour sérialiser ? Je ne voudrais sauver que des données de type de base C++, et des données Qt simples, du genre QString.

=> Bon, je crois que j'ai ma réponse : http://doc.qt.io/qt-5/qvariant.html
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 21/03/2015 à 23:20 Membre depuis le 10/06/2001, 40014 messages
Euh non, QVariant est pour le typage faible, pas pour la sérialisation. Tu peux aussi sérialiser un QVariant, mais il n'est normalement ni nécessaire, ni utile de passer par ça si tu connais le type des données à sérialiser.

La sérialisation se fait à travers QDataStream. Pour la plupart des classes Qt, la sérialisation est déjà implémentée, si tu veux sérialiser une classe que QDataStream ne connaît pas, tu peux implémenter ton propre surchargement des opérateurs << et >> (cf. "Reading and Writing Other Qt Classes" dans la documentation).
avatarMes news pour calculatrices TI: Ti-Gen (fr/en), MobiFiles (de)
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
Posté le 22/03/2015 à 00:18 Membre depuis le 18/06/2001, -26239 message
Ok, merci beaucoup. Je vais zyeuter tout ça. smile
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 22/03/2015 à 11:42Edité par Folco le 22/03/2015 à 15:59 Membre depuis le 18/06/2001, -26239 message
Mdr, il suffit de définir operator<< pour les classes perso, terminé c'est fini, c'est absolument génial cette classe, en 10 minutes j'ai implémenté la sérialisationde deux classes de données complexes grin

(bon par contre, j'ai trouvé commenté générer automagiquement les getters/setters qu'après avoir fini ça, donc j'aurais probablement pu mettre 3 minutes au lieu de 10 trigic)
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 22/03/2015 à 15:27 Membre depuis le 10/06/2001, 40014 messages
Tu vas aussi avoir besoin de operator>> si tu veux récupérer les données que tu as écrites. smile
avatarMes news pour calculatrices TI: Ti-Gen (fr/en), MobiFiles (de)
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
Posté le 22/03/2015 à 15:59 Membre depuis le 18/06/2001, -26239 message
Oui tout à fait, je l'ai pas encore écrit mais ça me semble tout aussi simple.
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 22/03/2015 à 16:19 Membre depuis le 10/06/2001, 40014 messages
Effectivement.
avatarMes news pour calculatrices TI: Ti-Gen (fr/en), MobiFiles (de)
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
Posté le 24/03/2015 à 20:06Edité par Folco le 08/06/2015 à 23:09 Membre depuis le 18/06/2001, -26239 message
J'ai des soucis récurrents avec QTableWidget.

Entre autres, les labels horizontaux (les titres de colonnes) qui doivent hériter de la classe Shrödinger.
Voici mon code :
LadderUi::LadderUi(QWidget* parent) :
    QWidget(parent),
    ui(new Ui::LadderUi)
{
    ui->setupUi(this);

    // Create and set the columns titles
    labels << "Name" << "Race" << "Score" << "Victories" << "Defeats";
    ui->tableLadder->setHorizontalHeaderLabels(labels);
}

Rien de sorcier. Tout le reste est paramétré dans Designer, sauf les titres des colonnes, car dans le constructeur ça les fait apparaitre de temps en temps.

Un screen de Designer puisqu'on en parle : sZyO

Et le résultat sur l'appli : lwtn

On voit une ligne de données rentrée dans le tableau, mais nulle trace des colonnes.

Il s'agit d'un "fork" d'un de mes projets, ce code-là n'a pas changé, et "avant ça marchait". Je ne sais plus ce que j'avais fait pour que ça marche d'ailleurs, j'avais ramé, mais j'avais fini par y arriver.

Que faire ?
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 24/03/2015 à 20:25 Membre depuis le 18/06/2001, -26239 message
Un test case minimaliste qui reproduit le problème : http://www.mirari.fr/M5rn
Windows 7, Qt 5.4.1, MinGW 32 bits bundlé avec Creator.

Meme résultat sous Debian testing (Jessie), Qt 5.3.2.

Ca doit etre moi qui rate un truc sad
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 25/03/2015 à 00:14 Membre depuis le 10/06/2001, 40014 messages
Dans ton fichier ladderui.ui, je vois:
       <attribute name="horizontalHeaderVisible">
        <bool>false</bool>
       </attribute>
avatarMes news pour calculatrices TI: Ti-Gen (fr/en), MobiFiles (de)
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
Posté le 25/03/2015 à 06:24 Membre depuis le 18/06/2001, -26239 message
Oui, j'ai fini par voir ça. Et c'est bien là que ça déconne, comme le montrent mes screens, parce qu'après avoir joué avec les checkboxs de Designer, j'ai réussi à faire réapparaitre les labels.

J'en conclus que :
- Designer est buggué sur ce point
- la doc est trompeuse, car elle laisse penser que définir les labels les fait apparaitre : The simplest way to create the headers is to supply a list of strings to the setHorizontalHeaderLabels() and setVerticalHeaderLabels() functions.

Et je n'ai pas trouvé de méthode setVisible() pour les labels, alors que c'est paramétrable (théoriquement) dans Designer : Header::horizontalHeaderVisible: No documentation available.

Enfin c'est pas très grave, mais je sais pas trop où reporter.
Par contre, si tu veux le faire, je suis sûr qu'on écoute plus un mainteneur de KDE de longue date qu'un inconnu au bataillon cheeky
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 26/03/2015 à 06:28Edité par Folco le 08/06/2015 à 23:10 Membre depuis le 18/06/2001, -26239 message
@Kevin -> suite à ta réponse, un objet défini comme ça :
class Ladder: public QObject
{
    public:
        Ladder(QString name);
        ~Ladder();
        ...
        
    private:
        Q_DISABLE_COPY(Ladder)
        ...
};

alloué sur le heap, sans autre héritage, et qui utilise deleteLater(), c'est pas un problème ?

Sinon, après la problématique à laquelle répond deleteLater(), on se retrouve avec une autre : comment faire pour détruire sans souci quelque chose qui contient un QWidget ?

J'espère que comme ça, ça marche.
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 26/03/2015 à 11:35 Membre depuis le 10/06/2001, 40014 messages
Folco (./17) :
@Kevin -> suite à ta réponse, un objet défini comme ça :
class Ladder: public QObject
…
alloué sur le heap, sans autre héritage, et qui utilise deleteLater(), c'est pas un problème ?

Je ne vois aucun problème là.
Sinon, après la problématique à laquelle répond deleteLater(), on se retrouve avec une autre : comment faire pour détruire sans souci quelque chose qui contient un QWidget ?

Un objet ne doit jamais contenir un QWidget, mais seulement un pointeur QWidget *. Comme ça, si ton QWidget est une fenêtre (donc n'a pas de parent), tu peux utiliser deleteLater sur le QWidget * dans ton destructeur, sinon le mieux est de ne pas y toucher (il sera détruit automatiquement quand le widget parent le sera).
avatarMes news pour calculatrices TI: Ti-Gen (fr/en), MobiFiles (de)
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
Posté le 26/03/2015 à 15:18 Membre depuis le 18/06/2001, -26239 message
Ok, merci.

Bug reporté ici : https://bugreports.qt.io/browse/QTCREATORBUG-14189
On va mesurer le temps de réaction/correction. cheeky
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 26/03/2015 à 18:26 Membre depuis le 18/06/2001, -26239 message
J'ai cherché sans succès une méthode de Q(Core)Application qui permette de broadcaster un event à tous les QObject créés par l'application.
Ca permettrait aux objets qui le souhaitent de s'enregistrer élégamment les uns auprès des autres, sans variable globale. Ca existe ?
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 26/03/2015 à 18:41 Membre depuis le 10/06/2001, 40014 messages
Émettre un signal auquel les objets intéressés peuvent se connecter (avec un slot), ça ne te suffit pas?
avatarMes news pour calculatrices TI: Ti-Gen (fr/en), MobiFiles (de)
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
Posté le 26/03/2015 à 19:52 Membre depuis le 18/06/2001, -26239 message
Ca demande que l'émetteur connaisse l'adresse des destinataires. Idéalement, j'aurais aimé éviter. Je vais totu simplement procéder autrement, merci.
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 26/03/2015 à 23:29 Membre depuis le 10/06/2001, 40014 messages
Dans mon idée, c'est aux destinataires de se connecter au signal de l'émetteur. (C'est comme ça que fonctionnent les signaux et slots Qt normalement.) Ainsi, l'émetteur "connaît" les destinataires dans le sens où il y a une liste des connections quelque part dans les membres privés de QObject, mais c'est géré à l'intérieur de Qt, ton code ne doit pas s'en occuper.

Mais peut-être qu'avec un exemple, je verrais mieux ce que tu veux faire?
avatarMes news pour calculatrices TI: Ti-Gen (fr/en), MobiFiles (de)
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
Posté le 27/03/2015 à 21:03Edité par Folco le 08/06/2015 à 23:10 Membre depuis le 18/06/2001, -26239 message
Bon, je m'y suis pris complètement autrement, d'une façon certainement plus Qt-compliant. J'essaye de me plier à la philosophie du truc.

pwic, j'ai un souci avec QCloseEvent, ou la manière dont on ferme une fenêtre. J'ai lu (et reeeelu) le tutorial d'une simple application, je ne vois pas ce qui cloche, et pourtant...
// Post a close event, which will cause MainWindow::closeEvent() to be called later
void MainWindow::on_buttonQuit_clicked()
{               
    // The event loop takes the ownership of the event and frees it
    qApp->postEvent(this, new QCloseEvent;
}


Donc dans ma MainWindow, j'ai un bonton "quit" qui est censé quitter, en postant un QCloseEvent. Ca a l'air tellement simplissime que je ne vois pas ce qui cloche.
Je ne trifouille pas les flags de la mainwindow, je ne redirige rien vers ci ou ça, donc je ne sais pas vers où chercher ><

Une idée stp ?
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 27/03/2015 à 22:21 Membre depuis le 10/06/2001, 40014 messages
Normalement, on utilise QCoreApplication::quit() pour quitter l'application.
avatarMes news pour calculatrices TI: Ti-Gen (fr/en), MobiFiles (de)
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
Posté le 27/03/2015 à 22:28Edité par Folco le 08/06/2015 à 23:10 Membre depuis le 18/06/2001, -26239 message
Ok, mais je ne vois pas ce qui ne marche pas ><
Et je ne veux pas fermer comme ça, vu que je veux intercepter le close event :
void MainWindow::closeEvent(QCloseEvent* event)
{
    if (!controller->closeAll())
    {
        event->ignore();
    }
}


Même quand je vire le bloc if(), et que je fait un event->accept(), ça ne fait rien. Je dois faire un close() pour que ça fonctionne. Pourtant, l'exemple d'ici montre une surdéfinition de closeEvent qui n'en fait pas plus :
void MainWindow::closeEvent(QCloseEvent *event)
{
    if (maybeSave()) {
        writeSettings();
        event->accept();
    } else {
        event->ignore();
    }
}

Et j'ai tracé l'exécution, l'event est bien envoyé quand je clique sur mon bouton.
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 28/03/2015 à 01:53 Membre depuis le 10/06/2001, 40014 messages
Il faut appeler close() et ce sera Qt qui activera ton closeEvent et réagira en conséquence. Poster directement le QCloseEvent ne sert à rien, c'est seulement le mécanisme pour accepter ou rejeter la fermeture, mais la réception de l'évènement ne ferme rien, la logique est dans la méthode close.
avatarMes news pour calculatrices TI: Ti-Gen (fr/en), MobiFiles (de)
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité
Posté le 28/03/2015 à 09:32 Membre depuis le 18/06/2001, -26239 message
Ok, je comprends le mécanisme alors. Donc mon bouton doit juste appeler close(), et mon closeEvent() custom acceptera ou rejetera l'event.

Mais alors, quel intéret de pouvoir générer un poster un event s'il est "inactif" ? C'est dommage, parce que je trouve ça très élégant de générer des events dans un programme basé sur l'évènementiel...

Merci en tout cas, tu me débloques sur ce point. smile
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 28/03/2015 à 12:27 Membre depuis le 18/06/2001, -26239 message
Bon ben non seulement j'ai compris, mais en plus ça marche du tonerre maintenant, eventClose() permet d'intercepter la fermeture de l'application par le WM, et de l'annuler au besoin, c'est absolument parfait love. Comme les vrais, quoi tripo
Merci encore happy
avatar<<< Kernel Extremist©®™ >>>
Feel the power of (int16) !
Posté le 28/03/2015 à 17:35 Membre depuis le 10/06/2001, 40014 messages
Folco (./28) :
Mais alors, quel intéret de pouvoir générer un poster un event s'il est "inactif" ? C'est dommage, parce que je trouve ça très élégant de générer des events dans un programme basé sur l'évènementiel...

L'évènementiel de Qt passe principalement par les signaux et les slots. Le système des events sert essentiellement pour les évènements issus du système, et postEvent n'est utile que très rarement (pour simuler par exemple un appui d'une touche).
avatarMes news pour calculatrices TI: Ti-Gen (fr/en), MobiFiles (de)
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité