首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >不能发出QThread信号

不能发出QThread信号
EN

Stack Overflow用户
提问于 2013-09-06 08:33:45
回答 1查看 2.9K关注 0票数 1

QT 5.1.0rc2,msvc 2010,2010

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

我的编译错误在

代码语言:javascript
复制
#if defined( HANDLE_PROCESSING_IN_MAIN_THREAD )
    if(QThread::currentThread() != this)
        emit started();
#endif
    inherited::run();

代码语言:javascript
复制
#if defined( HANDLE_PROCESSING_IN_MAIN_THREAD )
    if(QThread::currentThread() != this)
      emit finished();
#endif

错误C2660:'QThread::started‘:function不接受0参数 错误C2660:'QThread::finished‘:function不接受0参数

我在QThread上见过

代码语言:javascript
复制
Q_SIGNALS:
    void started(
#if !defined(Q_QDOC)
      QPrivateSignal
#endif
    );
    void finished(
#if !defined(Q_QDOC)
      QPrivateSignal
#endif
    );

当我定义Q_QDOC时,我在QT源代码中得到了许多错误。

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

需要不影响应用程序体系结构的解决方案,如向后兼容Qt4.8.4

一些想法?

EN

回答 1

Stack Overflow用户

发布于 2013-09-06 09:38:05

线程的信号会自动发出。你不应该手动发射它们。

您正在尝试使用预处理器来处理代码的两个变体: gui线程中的处理或专用线程中的处理。Qt提供了一种非常简单的处理方法。

  1. 在派生自QObject的类中的槽中实现处理功能。如果通过投递事件而不是调用插槽来开始处理,您也可以在重新实现的event()方法中这样做。
  2. 如果希望在不同的线程中运行对象的槽,请使用moveToThread()方法。
  3. 您不需要从QThread派生。它的默认run()实现会旋转一个本地事件循环。
  4. 如果您希望您的对象与GUI线程中的对象兼容,那么它必须以小块的形式进行处理,并放弃控制,这样GUI就不会停止。

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

代码语言:javascript
复制
// https://github.com/KubaO/stackoverflown/tree/master/questions/qobject-thread-18653347
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif

/// See http://stackoverflow.com/a/40382821/1329652
bool isSafe(QObject * obj) {
   Q_ASSERT(obj->thread() || qApp && qApp->thread() == QThread::currentThread());
   auto thread = obj->thread() ? obj->thread() : qApp->thread();
   return thread == QThread::currentThread();
}

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

class Worker : public QObject {
   Q_OBJECT
   int m_counter;
   QBasicTimer m_timer;
   void timerEvent(QTimerEvent * ev) override;
public:
   Worker(QObject *parent = nullptr) : QObject(parent) {}
   /// This method is thread-safe.
   Q_SLOT void start() {
      if (!isSafe(this)) return (void)QMetaObject::invokeMethod(this, "start");
      if (m_timer.isActive()) return;
      m_counter = 0;
      m_timer.start(0, this);
   }
   /// This method is thread-safe.
   Q_INVOKABLE void startInThread(QObject *targetThread) {
      if (!isSafe(this)) return (void)QMetaObject::invokeMethod(this, "startInThread", Q_ARG(QObject*, targetThread));
      QObject::moveToThread(qobject_cast<QThread*>(targetThread));
      start();
   }
   Q_SIGNAL void done();
   Q_SIGNAL void progress(int percent, bool inGuiThread);
};

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 = 30000;
   if (ev->timerId() != m_timer.timerId()) return;

   const auto inGuiThread = []{ return QThread::currentThread() == qApp->thread(); };
   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, inGuiThread());
         emit done();
         m_timer.stop();
         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) == 0 && t.elapsed() > busyTime) {
         emit progress(m_counter*100/maxCounter, inGuiThread());
         break;
      }
   }
}

class Window : public QWidget {
   Q_OBJECT
   QVBoxLayout m_layout{this};
   QPushButton m_startGUI{"Start in GUI Thread"};
   QPushButton m_startWorker{"Start in Worker Thread"};
   QLabel m_label;
   QThread m_thread{this};
   Worker m_worker;

   Q_SLOT void showProgress(int p, bool inGuiThread) {
      m_label.setText(QString("%1 % in %2 thread")
                      .arg(p).arg(inGuiThread ? "gui" : "worker"));
   }
   Q_SLOT void on_startGUI_clicked() {
      m_worker.startInThread(qApp->thread());
   }
   Q_SLOT void on_startWorker_clicked() {
      m_worker.startInThread(&m_thread);
   }
public:
   Window(QWidget *parent = {}, Qt::WindowFlags f = {}) : QWidget(parent, f) {
      m_layout.addWidget(&m_startGUI);
      m_layout.addWidget(&m_startWorker);
      m_layout.addWidget(&m_label);
      m_thread.start();
      connect(&m_worker, SIGNAL(progress(int,bool)), SLOT(showProgress(int,bool)));
      connect(&m_startGUI, SIGNAL(clicked(bool)), SLOT(on_startGUI_clicked()));
      connect(&m_startWorker, SIGNAL(clicked(bool)), SLOT(on_startWorker_clicked()));
   }
   ~Window() {
      m_thread.quit();
      m_thread.wait();
   }
};

int main(int argc, char *argv[])
{
   QApplication a(argc, argv);
   Window w;
   w.show();
   return a.exec();
}

#include "main.moc"
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18653347

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档