2009-05-04 9 views
1

Voici un exemple de SpinBox qui écrit ses modifications dans les variables sous-jacentes. Le principal problème que j'ai est valueChanged est appelé quand le widget est construit. Y a-t-il une manière plus élégante de faire ceci? Je pense que c'est bizarre que j'ai connecté un widget à lui-même, mais valueChanged n'est pas virtuel.En Qt, comment implémenter un widget qui reste cohérent avec les variables du code

class ValueWriterInt: public QSpinBox { 
    Q_OBJECT 

public: 
    ValueWriterInt(vector<int*> const& value): myValue(value) { 
     QObject::connect(this, SIGNAL(valueChanged(int)), this, SLOT(valueChanged(int))); 
    } 
    ~ValueWriterInt() {} 

private slots: 
    void valueChanged(int new_value) { 
     for (auto it = myValue.begin(); it != myValue.end(); ++it) 
      **it = new_value; 
    } 

private: 
    vector<int*>  myValue; 
}; 

Répondre

1

Je ne vois rien de particulièrement bizarre à propos de la connexion d'un widget à lui-même. Avoir une seule méthode de détection et de réponse aux mises à jour de données semble être une bonne chose car vous avez moins de points de défaillance à vérifier lorsque vous déboguez. Dans votre cas spécifique, cela provoque un comportement indésirable, mais en général c'est une bonne solution. Maintenant, ayant exprimé l'opinion qu'une connexion réflexive n'est pas intrinsèquement inélégante, je vais suggérer une solution moins qu'élégante pour empêcher l'appel de valueChanged après construction. Vous pouvez avoir un drapeau pour déterminer si l'objet a été simplement construit et revenir tôt pour éviter que le code soit exécuté immédiatement après la construction. Dans votre exemple:

class ValueWriterInt: public QSpinBox { 
Q_OBJECT 

public: 
    ValueWriterInt(vector<int*> const& value): myValue(value), myAfterInit(true) { 
     QObject::connect(this, SIGNAL(valueChanged(int)), this, SLOT(valueChanged(int))); 
    } 
    ~ValueWriterInt() {} 

private slots: 
    void  valueChanged(int new_value) { 
     if (myAfterInit) { 
      myAfterInit = false; 
      return; 
     } 
     for (auto it = myValue.begin(); it != myValue.end(); ++it) 
       **it = new_value; 
    } 

private: 
    vector<int*>    myValue; 
    boolean      myAfterInit; 
}; 

Ce n'est pas trop mauvais d'une solution. Il vous donnera au moins le comportement désiré jusqu'à (et si) vous pouvez trouver une méthode plus élégante.

+0

Merci. C'est ce que j'ai fini par faire, mais il est extrêmement rassurant d'avoir une confirmation indépendante. valueChanged est appelé beaucoup plus souvent que je ne le pensais. Par exemple, l'appel de "setIndexWidget" entraîne l'appel de valueChanged sur le widget. Le bool aide là aussi. Merci encore! –

0

Alors, qu'essayez-vous d'accomplir ici? Yep, valueChanged n'est pas virtuel - pourquoi devrait-il être, vos objets devraient directement connecter leurs propres emplacements à tous les signaux auxquels ils veulent réagir, non?

+0

Les appels virtuels sont significativement plus efficaces que les signaux/emplacements. Cela n'a pas beaucoup d'importance pour tout ce qui est piloté par l'interface utilisateur. – MSalters

+0

J'essaye de construire un volet de paramètres, où les widgets personnalisés sur le volet vivent dans un arbre. Il s'avère être beaucoup plus difficile que je pensais ... –

0

Je ne vois pas d'autre alternative que d'utiliser des connexions SIGNAL-SLOT. Cependant, je voudrais changer le nom de l'emplacement, donc il n'a pas le même nom que le signal.

Il est intéressant de savoir comment l'emplacement est appelé même s'il n'y a pas encore de connexion. Je soupçonne que changer le nom de l'emplacement résoudra ce problème.

+0

Deux bons points. Merci. J'ai fini par changer le nom juste pour être sûr. Et, j'ai compris que le signal était appelé quand le widget était inséré dans l'arbre en utilisant setIndexWidget(). –

+0

C'est parfaitement bien si valueChanged (int) est appelé lors de la construction. C'est après tout ** un signal **, et non un slot. –

Questions connexes