2012-12-29 2 views
1

J'utilise Qt5 où j'implémente un thread en passant le worker QObject à une instance de QThread par moveToThread(). Ma mise en œuvre ressemble à ceci ..Qt: Signal/Slot ne fonctionnant pas après que QObject ait été déplacé vers un thread différent

Worker.h

class worker : public QObject 
{ 
    Q_OBJECT 
public: 
    explicit worker(QObject *parent = 0); 
    bool IsWorkRunning(); 
    void MoveObjectToThread(); 

signal: 
    void SignalToObj_mainThreadGUI(); 

public slots: 
    void do_Work(); 
    void StopWork(); 
    void StartWork(); 

private: 
    void Sleep(); 
    QThread *workerthread;  
    volatile bool running,stopped; 
}; 

Worker.cpp

worker::worker(QObject *parent) : 
    QObject(parent),stopped(false),running(false) 
{ 
} 

void worker::do_Work() 
{ 
    running = true; 
    while(!stopped) 
    { 
     if(running) 
     { 
     emit SignalToObj_mainThreadGUI(); 
     workerthread->msleep(20); 
     } 
    } 
} 

void worker::StopWork() 
{ 
    running = false; 
} 

void worker::StartWork() 
{ 
    running = true; 
} 

bool worker::IsWorkRunning() 
{ 
    return running; 
} 

void MoveObjectToThread() 
{ 
    workerthread = new QThread; 
    QObject::connect(workerthread,SIGNAL(started()),this,SLOT(do_Work())); 

    this->moveToThread(workerthread); 

    workerthread->start(); 
} 

mainwindow.h

namespace Ui { 
class MainWindow; 
} 

class MainWindow : public QMainWindow 
{ 
    Q_OBJECT 

public: 
    explicit MainWindow(QWidget *parent = 0); 
    ~MainWindow(); 

signals: 
    void Startwork_mainwindow(); 
    void Stopwork_mainwindow(); 

public slots: 

private slots: 
    void on_pushButton_push_to_start_clicked(); 

    void on_pushButton_push_to_stop_clicked(); 

private: 

    Ui::MainWindow *ui; 
    worker myWorker; 
    bool work_started; 

}; 

mainwindow.cpp

MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent),work_started(false), 
    ui(new Ui::MainWindow) 
{ 
    ui->setupUi(this); 

    QObject::connect(this,SIGNAL(Startwork_mainwindow()),&myWorker,SLOT(StartWork())); 
    QObject::connect(this,SIGNAL(Stopwork_mainwindow()),&myWorker,SLOT(StopWork())); 
} 

MainWindow::~MainWindow() 
{ 
    delete ui; 
} 

void MainWindow::on_pushButton_push_to_start_clicked() 
{ 
    if(!work_started) 
    { 
     myWorker.MoveObjectToThread(); 
     work_started = true; 
    } 

    if(!myWorker.IsWorkRunning()) 
     emit this->Startwork_mainwindow(); 
} 

void MainWindow::on_pushButton_push_to_stop_clicked() 
{ 
    if(myWorker.IsWorkRunning()) 
     emit this->Stopwork_mainwindow(); 
} 

ne sais pas pourquoi les deux paires signal/emplacement suivant ne marche pas semble fonctionner

QObject::connect(this,SIGNAL(Startwork_mainwindow()),&myWorker,SLOT(StartWork())); 
QObject::connect(this,SIGNAL(Stopwork_mainwindow()),&myWorker,SLOT(StopWork())); 

En conséquence, je ne peux pas démarrer ou arrêter le fil une fois que la fente do_Work() est déclenchée par started() le signal de l'objet QThread. Juste pour référence ce poste de la mine est une continuation de mon précédent post here described aperçu .Tout sera utile ... Merci

+0

Avez-vous essayé de passer au fil avant d'effectuer l'une des connexions de signal? Comme juste après l'avoir fait? Votre boucle externe ne tourne-t-elle pas aussi follement dans votre thread quand elle ne tourne pas? Peut-être qu'il a besoin d'un sommeil aussi bien pour aider le planificateur. – jdi

+0

Au lieu d'utiliser 'moveToThread', je réimplémenter' QThread'. C'est plus facile à suivre, et je pense que c'est moins sujette aux erreurs. Et lorsque vous utilisez 'QObject :: connect' du thread principal vers un autre thread, ne vous connectez pas à un autre thread en utilisant' AutoConnect', utilisez ['QueuedConnection'] (http://qt-project.org/doc/qt- 4.8/qt.html # ConnectionType-enum) à la place. – phyatt

+0

et si j'utilise Qt :: Directconnection? et certains où dans les forums je lis le sous-classement QThread n'est pas une bonne pratique ... et Qt5 a rendu public beaucoup de fonctions privées statiques en raison de ce paradigme d'utilisation –

Répondre

2

Dans votre définition de classe MainWindow, essayez de changer worker myWorker-worker * myWorker. En outre, je ferais comme d'autres l'ont suggéré et déplacer le fil en dehors de la classe worker. Le constructeur MainWindow devient quelque chose comme ceci:

MainWindow::MainWindow(QWidget *parent) 
    : QMainWindow(parent) 
    , work_started(false) 
    , ui(new Ui::MainWindow) 
    , myWorker(new worker()) 
{ 
    // NOTE: myWorker is created without a parent on purpose. 
    // Qt won't change the thread affinity of an obj with a parent 

    ui->setupUi(this); 

    connect(this, SIGNAL(Startwork_mainwindow()), myWorker, SLOT(StartWork())); 
    connect(this, SIGNAL(Stopwork_mainwindow()), myWorker, SLOT(StopWork())); 

    QThread * thread = new QThread(); 
    // delete the worker obj whenever this obj is destroyed 
    connect(this, SIGNAL(destroyed()), myWorker, SLOT(deleteLater())); 
    // stop the thread whenever the worker is destroyed 
    connect(myWorker, SIGNAL(destroyed()), thread, SLOT(quit())); 
    // clean up the thread 
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 
    myWorker->moveToThread(thread); 
    thread->start(); 
} 

Bien sûr, vous n'avez pas besoin de la méthode worker::MoveObjectToThread() plus. En outre, la méthode worker::IsWorkRunning() n'est pas vraiment sûre d'appeler à partir de MainWindow. Vous ne rencontrerez probablement aucun problème avec cet exemple spécifique, mais cela vous causera certainement de la peine lorsque les choses deviendront plus complexes. Au lieu de cela, ajoutez un signal workFinished() ou quelque chose de similaire et écoutez-le dans la classe MainWindow.

Le signal Startwork_mainwindow() démarre le travail. Comme vous ne fournissez pas de type de connexion dans vos appels à connect, Qt utilisera QueuedConnection lorsque vous modifiez l'affinité de thread (moveToThread). Fondamentalement, myWorker est dans un thread avec sa propre boucle d'événements. L'appel d'un emplacement à l'aide de Qt::QueuedConnection envoie un événement à cette boucle d'événements qui met en file d'attente la méthode de l'emplacement. Il s'exécutera chaque fois que la boucle de l'événement arrivera à destination.

Questions connexes