2017-01-27 2 views
1

Я столкнулся с довольно причудливой ошибкой - QAction::trigger вызвало появление диалогового окна блокировки, из-за чего мой сервер, который вызвал trigger, застрял (например, не смог обработать сигналы сокета до диалога был закрыт).Вызов слота асинхронно без подключения к нему с использованием явной строки кода

Я выяснил обходное решение. Подключить сигнал void triggerWorkaround() слот QAction::trigger с помощью Qt::QueuedConnection и я испускаю его:

QObject::connect(this, &HackClass::triggerWorkaround, targetAction_.data(), &QAction::trigger, Qt::QueuedConnection); 
emit triggerWorkaround(); 
QObject::disconnect(this, nullptr, targetAction_.data(), nullptr); 

Но это три строки коды запутанной. Есть ли какой-то непонятный способ сделать это? Я нашел QMetaObject::invokeMethod, но, откровенно говоря, это в 10 раз более запутанно, чем мое текущее решение. Кроме того, Я не хочу использовать имя метода как строку!

+0

Возможно, создайте отдельный поток для цикла событий сервера. – Velkan

ответ

2

Вы можете отделить, что в функцию QueuedInvoke так:

//overload for methods/slots 
//the slot gets invoked in the thread where the QObject lives 
template <typename Object, typename T> 
void QueuedInvoke(Object* object, T (Object::* f)()){ 
    QObject signalSource; 
    QObject::connect(&signalSource, &QObject::destroyed, 
        object, f, Qt::QueuedConnection); 
} 
//overload for functors 
//the functor gets invoked in the thread where the contextObject lives 
//or in the current thread if no contextObject is provided 
template <typename Func> 
void QueuedInvoke(Func&& f, QObject* contextObject = QAbstractEventDispatcher::instance()){ 
    QObject signalSource; 
    QObject::connect(&signalSource, &QObject::destroyed, 
        contextObject, std::forward<Func>(f), Qt::QueuedConnection); 
} 

Это будет использовать destroyed() сигнал, излучаемый из временного QObject размещать в очередь событие в цикл обработки событий. Слот/функтор фактически вызывается, когда цикл события обрабатывает это событие.

Таким образом, вместо 3-х строк, которые размещены, Вы можете использовать описанную выше функцию следующим образом:

QueuedInvoke(targetAction_.data(), &QAction::trigger); 

Мой ответ основан на this great answer о выполнении функтора в данной QThread. Вы можете обратиться к нему за дополнительной информацией.

+0

Я предполагаю, что это не будет работать для методов с аргументами ... –

+0

@ TomášZato, вы можете использовать лямбда-выражения, чтобы обойти это ограничение ... – Mike

+0

@ TomášZato, Чтобы запустить лямбда в определенном потоке, вы можете предоставить контекст 'QObject'. – Mike