不能发出QThread的信号 [英] Can not emit QThread's signals

查看:324
本文介绍了不能发出QThread的信号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

QT 5.1.0rc2,msvc 2010,Microsoft Visual Studio 2010

QT 5.1.0rc2 , msvc 2010 , Microsoft Visual Studio 2010

它是Qt 4.8.4,msvc 2008的工作代码

It is working code on Qt 4.8.4 , msvc 2008

我有编译错误

#if defined( HANDLE_PROCESSING_IN_MAIN_THREAD )
    if(QThread::currentThread() != this)
        emit started();
#endif
    inherited::run();

#if defined( HANDLE_PROCESSING_IN_MAIN_THREAD )
    if(QThread::currentThread() != this)
      emit finished();
#endif




错误C2660:'QThread :: started ':函数不接受0个参数

错误C2660:'QThread :: finished':函数不接受0个参数

error C2660: 'QThread::started' : function does not take 0 arguments
error C2660: 'QThread::finished' : function does not take 0 arguments


$ b b

在QThread中我看到了

In QThread i have seen

Q_SIGNALS:
    void started(
#if !defined(Q_QDOC)
      QPrivateSignal
#endif
    );
    void finished(
#if !defined(Q_QDOC)
      QPrivateSignal
#endif
    );

当我定义Q_QDOC我在QT源中有很多错误。

when I defined Q_QDOC I got many errors in QT sources.

QPrivateSignal是在宏Q_OBJECT中定义的空结构

QPrivateSignal is empty structure that defined in macro Q_OBJECT

需要一个不影响应用程序体系结构的解决方案, .8.4

Need a solution that does not affect the architecture of the application, as to be backward compatible with Qt4.8.4

有些想法?

推荐答案

自动。

您尝试使用预处理器来处理代码的两种变体:在gui线程或专用线程中处理。

You're trying to use preprocessor to handle two variants of the code: processing in the gui thread or a dedicated thread. Qt provides a very easy way of dealing with it.


  1. 在一个类中实现你的处理功能,派生自 QObject 。你也可以在重新实现的 event()方法中,如果你更容易通过发布事件而不是调用槽来开始处理。

  1. Implement your processing functionality in a slot in a class deriving from QObject. You could also do it in the reimplemented event() method if it's easier for you to start processing by posting an event rather than invoking a slot.

如果你想让对象的槽在不同的线程中运行,使用 moveToThread()方法。

If you want your object's slots to run in a different thread, use the moveToThread() method.

您不需要从 QThread 派生。其默认实现 run()旋转本地事件循环。

You don't need to derive from QThread. Its default implementation of run() spins a local event loop.

与生存在GUI线程中兼容,它必须以小块进行处理并放弃控制,以使GUI不会停顿。

If you want your object to be compatible with living in the GUI thread, it must do its processing in small chunks and relinquish control so that the GUI doesn't stall.

下面是一个完整的示例,演示如何在GUI或单独的线程中启动worker对象,如何在线程之间安全移动它。

Below is a complete example that demonstrates how you can start the worker object in either GUI or a separate thread, and how you can safely move it between threads.

main.cpp

#include <QApplication>
#include <QVBoxLayout>
#include <QPushButton>
#include <QThread>
#include <QBasicTimer>
#include <QElapsedTimer>
#include <QLabel>
#include <QDebug>

class Helper : private QThread {
public:
    using QThread::usleep;
};

class Worker : public QObject {
    Q_OBJECT
    int m_counter;
    bool m_busy;
    QBasicTimer m_timer;
    void timerEvent(QTimerEvent * ev);
public:
    Worker(QObject *parent = 0) : QObject(parent), m_busy(false) {}
    Q_SLOT void start() {
        if (m_busy) return;
        m_counter = 0;
        m_busy = true;
        m_timer.start(0, this);
    }
    Q_SIGNAL void done();
    Q_SIGNAL void progress(int);
    // must be called from within the working thread, so we wrap it in a slot
    Q_INVOKABLE void moveToThread(QThread *t) { QObject::moveToThread(t); }
};

void Worker::timerEvent(QTimerEvent * ev)
{
    const int busyTime = 50; // [ms] - longest amount of time to stay busy
    const int testFactor = 128; // number of iterations between time tests
    const int maxCounter = 10000;
    if (ev->timerId() != m_timer.timerId()) return;

    QElapsedTimer t;
    t.start();
    while (1) {
        // do some "work"
        Helper::usleep(100);
        m_counter ++;
        // exit when the work is done
        if (m_counter > maxCounter) {
            emit progress(100);
            emit done();
            m_busy = false;
            break;
        }
        // exit when we're done with a timed "chunk" of work
        // Note: QElapsedTimer::elapsed() may be expensive, so we call it once every testFactor iterations
        if ((m_counter % testFactor) == 1 && t.elapsed() > busyTime) {
            emit progress(m_counter*100/maxCounter);
            break;
        }
    }
}

class Window : public QWidget {
    Q_OBJECT
    QLabel *m_label;
    QThread *m_thread;
    QObject *m_worker;
    Q_SIGNAL void start();
    Q_SLOT void showProgress(int p) { m_label->setText(QString("%1 %").arg(p)); }
    void moveWorkerToThread(QThread *thread) {
        qDebug() << QMetaObject::invokeMethod(m_worker, "moveToThread", Q_ARG(QThread*, thread));
    }
    Q_SLOT void on_startGUI_clicked() {
        moveWorkerToThread(qApp->thread());
        emit start();
    }
    Q_SLOT void on_startWorker_clicked() {
        moveWorkerToThread(m_thread);
        emit start();
    }
public:
    Window(QWidget *parent = 0, Qt::WindowFlags f = 0) :
        QWidget(parent, f), m_label(new QLabel), m_thread(new QThread(this)), m_worker(new Worker)
    {
        QVBoxLayout * l = new QVBoxLayout(this);
        QPushButton * btn;
        btn = new QPushButton("Start in GUI Thread");
        btn->setObjectName("startGUI");
        l->addWidget(btn);
        btn = new QPushButton("Start in Worker Thread");
        btn->setObjectName("startWorker");
        l->addWidget(btn);
        l->addWidget(m_label);
        connect(m_worker, SIGNAL(progress(int)), SLOT(showProgress(int)));
        m_worker->connect(this, SIGNAL(start()), SLOT(start()));
        m_thread->start();
        QMetaObject::connectSlotsByName(this);
    }
    ~Window() {
        m_thread->quit();
        m_thread->wait();
        delete m_worker;
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    qRegisterMetaType<QThread*>("QThread*"); // for invokeMethod to work
    Window w;
    w.show();
    return a.exec();
}

#include "main.moc"

这篇关于不能发出QThread的信号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆