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