Qt:后台线程刷新UI线程

时间:2010-03-04 04:14:17

标签: c++ qt4

我有一个后台线程,线程调用一些更新UI的方法(为了显示进度条并在文本区域显示其他信息)。

如果我修改了一些UI窗口小部件值,则会引发“无法向不同线程拥有的对象发送事件”断言错误。

在论坛上,我看到我可以使用QMetaObject :: invokeMethod方法但是如果我传递Qt :: DirectConnection标志它实际上会引发上面显示的相同错误,它就可以工作。

如果我使用Qt :: QueuedConnection或Qt :: AutoConnection,则invokeMethod返回false。

我的代码与此类似:

·H:

class A : public QMainWindow
{
  Q_OBJECT

  QProgressBar* pb;

  public slots:
    bool m(bool, int);
};

class B
{
  A* a;

  public:
    void handleEvent();
};


.cpp:

bool A::m(bool x, int y)
{
  pb->setValue(y);
  return x;
}

void B::handleEvent()
{
  //a->m(true, 12); //raises an assertion error

  bool r;
  //bool ret = QMetaObject::invokeMethod(a, "m", Qt::DirectConnection, Q_RETURN_ARG(bool, r), Q_ARG(bool, true), Q_ARG(int, 12)); //raises the same assertion error error

  bool ret = QMetaObject::invokeMethod(a, "m", Qt::AutoConnection, Q_RETURN_ARG(bool, r), Q_ARG(bool, true), Q_ARG(int, 12)); //is ignored and ret contains false.
}

你知道发生了什么事或我做错了什么吗?或者,有人可以建议我另一种方法来处理我的新手问题吗?

提前致谢,

埃内斯托

1 个答案:

答案 0 :(得分:10)

我自己没有使用invokeMethod(),但为了做到这一点,我通常只使用信号和插槽。例如,您可以创建一个class B成员的信号,该信号连接到class A中用于更新进度的插槽:

class B : public QObject
{
    Q_OBJECT

    A* a;

signals:
    void update_signal(bool, int);

public:
    void handleEvent();
};

B::B()
{
    //assuming a already points to the correct place...
    connect(this, SIGNAL(update_signal(bool,int), 
            a, SLOT(m(bool,int)), Qt::QueuedConnection);
}

void B::handleEvent()
{
    emit update_signal(true, 12);
}
在这种情况下,

A::m()必须返回void,但这不是问题,因为在使用排队连接时,无论如何都无法获得返回值,因为调用是异步的(emit update_signal(true,12)可能在之前返回调用slot函数使得无法准备好返回值。

只要您指向类型为A的对象和类型为B的对象,就可以在任何地方实际执行此连接。这使得信号和插槽非常灵活,因为您可以完全将AB分离,但仍允许它们通过信号和插槽进行通信。例如:

class B : public QObject
{
    Q_OBJECT

signals:
    void update_signal(bool, int);

public:
    void handleEvent();
};

void B::handleEvent()
{
    emit update_signal(true, 12);
}

class A : public QMainWindow
{
    Q_OBJECT

    QProgressBar* pb;

    public slots:
        void m(bool, int);
};

void A::m(bool x, int y)
{
    pb->setValue(y);
}

int main()
{
    A* a = new A();
    B* b = new B();

    QObject::connect(b, SIGNAL(update_signal(bool, int)),
            a, SLOT(m(bool, int)), Qt::QueuedConnection);

    //...
}

在这种情况下,b不必存储指针或了解a的任何信息,但他们可以通过精心定义的精确频道进行通信。