2009-07-20 5 views
3

Je voudrais savoir lequel de ce qui suit est la bonne façon de faire chose avec signal/slot dans Qt. J'ai besoin d'un moyen d'avoir plusieurs instances d'un dialogue, par exemple A et B Et je dois dire A pour imprimer "A" et B pour imprimer "B" à partir d'un fil différent. Donc, je crois que je besoin de quelque chose comme soit:Qt signal à l'emplacement de l'objet spécifique

OPTION 1)A->print("A") et B->print("B")

ou est-il préférable de le faire:

OPTION 2)emit print("A") et emit print("B") et utiliser d'une manière que je ne sais pas si seulement A attraper le "A" et seulement B attraper le "B".

j'ai eu l'option 1 travail comme celui-ci:

class myClass : public QMainWindow 
{ 
    Q_OBJECT 

public: 
    myClass (QWidget *parent = 0, Qt::WFlags flags = 0); 
    ~myClass(); 
    void doPrint(char* text) 
    { 
     emit mySignal(text); 
    } 
private: 
    Ui::myClass ui; 

public slots: 
    void newLog(char* msg); 

signals: 
    void mySignal(char* msg); 
}; 

myClass::myClass(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags) 
{ 
    ui.setupUi(this); 
    connect(this, SIGNAL(mySignal(char*)), this, SLOT(newLog(char*))); 
} 

void myClass::newLog(char* msg) 
{ 
    ui.textEdit->append(msg); 
} 

et tout ce que je dois faire est:

myClass* instanceA = new myClass(); 
myClass* instanceB = new myClass(); 
instanceA->doPrint("A"); 
instanceB->doPrint("B"); 

est ce droit?

Merci!

+0

Entre Nous allez du côté opposé de votre question. Dans quel cas vous pouvez vous sentir à l'aise avec l'option 2?Peut-on dire un exemple où le deuxième cas a un avantage si la seule chose que vous voulez est d'imprimer "A" et "B"? – Narek

Répondre

1

Dans cet exemple simplifié, je pense que vous êtes sur le bon chemin avec l'option 1. Cependant, ce serait encore mieux si vous n'aviez pas besoin de la méthode doPrint(), ce qui éliminerait également le besoin du signal mySignal (à moins au myClass). Au lieu de cela, je suggère héritant vos fils de QThread si le sont pas déjà, et de faire quelque chose comme ceci:

class myThread : public QThread 
{ 
    Q_OBJECT 

public: 
    myThread (QWidget *parent = 0) : QThread(parent) {} 
    ~myThread() {} 
    void run(char* text) 
    { 
     emit mySignal(text); 
    } 

signals: 
    void mySignal(char* msg); 
}; 

Ensuite, vous devez faire quelque chose comme ceci:

myClass* instanceA = new myClass(); 
myThread* threadA = new myThread(); 
connect(threadA, SIGNAL(mySignal(char*)), instanceA, SLOT(newLog(char*)), Qt::QueuedConnection); 
threadA->run("A"); 

Il est évident que, dans la plupart code non-exemple, vous ne passeriez pas la chaîne dans l'exécution, mais plutôt générer des chaînes à exécuter que threadA est en cours d'exécution. L'avantage est que cela garde les considérations de thread sur myClass, et vous avez seulement besoin de penser à eux où ils sont connectés. D'un autre côté, vous introduisez moins de dépendances dans les threads, car ils n'ont pas besoin de connaître myClass pour pouvoir se connecter.

+1

Veuillez arrêter de diffuser cette information erronée à propos de Qt :: QueuedConnection étant nécessaire dans ce cas. Ce n'est plus le cas, pour les trois dernières versions de Qt. –

+1

@mmutz, je l'ai fait dans mon exemple pour assurer le type de connexion, basé sur http://doc.trolltech.com/4.5/threads.html#signals-and-slots-across-threads qui stipule en partie "QThread les objets résident dans le thread où l'objet a été créé - pas dans le thread créé lors de l'appel de QThread :: run() Il est généralement dangereux de fournir des slots dans votre sous-classe QThread. " Cependant, je vois maintenant que "vous pouvez émettre en toute sécurité des signaux à partir de votre implémentation de QThread :: run() ...", ce que j'avais précédemment manqué. Quoi qu'il en soit, spécifier le type de connexion ne nuit à rien que je puisse voir. –

2

Étant donné que votre emplacement est dans un autre thread, vous devez utiliser le système Meta-Object pour appeler la méthode de manière asynchrone. La bonne façon de le faire est d'utiliser QMetaObject::invokeMethod

NE PAS sous-classer QThread et remplacer la méthode d'exécution. Pour plus de détails sur ce sujet, voir: http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/

void otherClass::printTo(myClass* instance, char* text) 
{ 
    QMetaObject::invokeMethod(instance,  // pointer to a QObject 
           "doPrint",  // member name (no parameters here) 
           Qt::QueuedConnection,  // connection type 
           Q_ARG(char*, text));  // parameters 
} 

void myClass::doPrint(char* text) 
{ 
    ui.textEdit->append(text); 
} 

myClass* instanceA = new myClass(); 
myClass* instanceB = new myClass(); 
printTo(instanceA, "A"); 
printTo(instanceB, "B"); 

Si le type char * n'a pas été enregistré avec le système de méta-objet encore, le font avec Q_DECLARE_METATYPE(char*);

alors:

qRegisterMetaType<char*>("charPtr");