QT: Фоновый поток обновляющий поток UI

У меня есть фоновый поток, и поток называет некоторые методы, которые обновляют 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.
}

Вы знаете то, что продолжается или что я делаю неправильно? или возможно, кто-то может предложить, чтобы я другой подход имел дело со своей проблемой новичка?

Заранее спасибо,

Ernesto

9
задан ebasconp 3 March 2010 в 18:14
поделиться

1 ответ

Я сам не использовал invokeMethod () , но для этого я обычно просто использую сигналы и слоты.Например, вы можете создать сигнал как член класса B , который подключен к слоту в классе 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) может return до вызова функции слота, что делает невозможным получение готового возвращаемого значения).

Фактически вы можете выполнить это соединение где угодно, если у вас есть указатели на объект типа A и объект типа B . Это делает сигналы и слоты очень гибкими, поскольку вы можете полностью отделить A от B , но при этом позволить им обмениваться данными через сигналы и слоты. Например:

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 , но они могут связываться через тонкий четко определенный канал.

10
ответ дан 3 November 2019 в 01:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: