我的目标是使用Qt的DBus绑定创建一个库.
我尝试创建一个Qt应用程序而不在主线程中启动QEventLoop(由QCoreApplication类提供).
这是一个简约的应用程序示例,使用QT-4.6.2版本正常工作但使用QT-4.8或更高版本阻止内省.
DBusHandler.hpp
#pragma once
#include <iostream>
#include <QtCore/QThread>
#include <QtCore/QtCore>
#include <QtDBus/QDBusInterface>
class DBusHandler : public QThread
{
Q_OBJECT;
private:
void run(void)
{
QDBusConnection connection = QDBusConnection::sessionBus();
connection.registerService("my.qdbus.example");
connection.registerObject("/", this, QDBusConnection::ExportAllSlots);
exec();
}
public:
DBusHandler(void) {}
virtual ~DBusHandler(void) {}
void stop(void)
{
QDBusConnection connection = QDBusConnection::sessionBus();
connection.unregisterObject("/");
connection.unregisterService("my.qdbus.example");
connection.disconnectFromBus(connection.name());
QThread::quit();
}
public slots:
void remoteCall(QByteArray message)
{
std::cout << "Message size: " << message.size() << std::endl;
}
};
Run Code Online (Sandbox Code Playgroud)
main.cpp中
#include "DBusHandler.hpp"
int …Run Code Online (Sandbox Code Playgroud) 我怀疑应该如何使用QEventLoop.我有两段代码,它们都适合我(获取Web资源下载).
第一:
QNetworkAccessManager *manager = new QNetworkAccessManager( this );
QNetworkRequest request;
request.setUrl(QUrl(url));
request.setRawHeader("User-Agent", "Mozilla Firefox");
connect(manager, SIGNAL(finished(QNetworkReply*)),this,SLOT(replyFinished(QNetworkReply*)));
manager->get( request ) ;
QEventLoop loop;
connect(manager, SIGNAL(finished(QNetworkReply*)),&loop, SLOT(quit()));
loop.exec();
Run Code Online (Sandbox Code Playgroud)
第二个:
QNetworkAccessManager *manager = new QNetworkAccessManager( this );
QNetworkRequest request;
request.setUrl(QUrl(url));
request.setRawHeader("User-Agent", "Mozilla Firefox");
manager->get( request ) ;
QEventLoop loop;
connect(manager, SIGNAL(finished(QNetworkReply*)),this, SLOT(replyFinished(QNetworkReply*)));
loop.exec();
Run Code Online (Sandbox Code Playgroud)
我想知道的是我应该使用哪一个.我的意思是,在信号被激活后,事件循环是否在第二个中退出?或者我必须quit()像第一个一样打电话?我在某个地方找到了第二个解决方案,但它对我来说似乎不合适所以我将其修改为第一段代码.
我决定在我的一个脚本中添加一个GUI.该脚本是一个简单的Web scraper.我决定使用工作线程作为下载和解析数据可能需要一段时间.我决定使用PySide,但我对Qt的了解非常有限.
由于脚本应该在遇到验证码时等待用户输入,我决定它应该等到QLineEdit发生火灾returnPressed然后将其内容发送到工作线程,以便它可以发送它进行验证.这应该比忙碌更好 - 等待按下返回键.
似乎等待信号并不像我想象的那样直截了当,在搜索了一段时间后,我遇到了几个类似于此的解决方案.跨线程的信令和工作线程中的本地事件循环使我的解决方案有点复杂.
经过几个小时的修补后,它仍然无法正常工作.
应该发生什么:
QEventLoop通过调用开始self.loop.exec_()QEventLoop通过调用loop.quit()在一个工作线程,其经由连接槽self.line_edit.returnPressed.connect(self.worker.stop_waiting)在所述main_window类怎么了:
...往上看...
退出QEventLoop不起作用.调用后self.loop.isRunning()返回.返回,因此线程在奇怪的情况下似乎没有死亡.线程仍然停在线上.因此,即使事件循环告诉我它不再运行,线程也会执行事件循环.Falseexit()self.isRunningTrueself.loop.exec_()
GUI响应工作线程类的插槽.我可以看到文本beeing发送到工作线程,事件循环的状态和线程本身,但在上面提到的行执行后没有任何内容.
代码有点复杂,因此我添加了一些伪代码-python-mix而忽略了不重要的:
class MainWindow(...):
# couldn't find a way to send the text with the returnPressed signal, so I
# added a helper signal, seems to work though. Doesn't work in the
# constructor, might be a PySide bug? …Run Code Online (Sandbox Code Playgroud) 我想创建一个基于其构建的库,QTcpServer并QTcpSocket用于在其main函数中没有事件循环的程序中(因为Qt事件循环是阻塞的,并且不能为所需的实时操作提供足够的时序分辨率).
我希望通过在类中创建本地事件循环来解决这个问题,但除非我app->exec()首先调用main函数,否则它们似乎不起作用.有没有办法创建本地事件循环并允许在线程内进行信号/插槽通信而无需应用程序级事件循环?
我已经看过有没有办法在没有QApplication :: exec()的情况下使用Qt?但答案没有帮助,因为似乎解决方案添加了本地事件循环但不删除应用程序循环.
我的Qt应用程序的主窗口是一个普通的QMainWindow子类.在那个窗口我有几个按钮; 每个clicked插槽的信号都连接自己的插槽,每个插槽创建一个不同的插槽QDialog:
void onButtonA_clicked()
{
MyADialog* dialog = new MyADialog(this);
dialog->exec();
delete dialog;
}
Run Code Online (Sandbox Code Playgroud)
我一直在读这篇文章:https://wiki.qt.io/Threads_Events_QObjects#Events_and_the_event_loop和作者说
你永远不应该阻止事件循环
哪个让我担心; exec是一个阻塞函数,所以根据他所说的(他的例子Worker::doWork做了很多工作,需要一些时间来完成)我的代码阻止了事件循环,但我没有注意到任何暗示这一点; 相反,主窗口似乎表现正常,并且当我更改代码以使用该show()方法时没有区别.
我阻止了事件循环吗?我应该在这里使用不同的方法吗?
我的问题是一般性的,与 QT 中QEventLoop类的使用有关。我对此有两个主要问题。
问题1)它在QT内部如何工作(我主要关心的是为什么QEventLoop对象的执行不会阻塞QT应用程序主循环 - [编辑3]最后一条评论不正确,请参阅下面的答案)。
详情请参阅下文。
问题2)除了阻塞之外还有其他目的吗?看来我只能遇到QEventLoop用于等待目的的例子。
可以用于其他目的吗?就像我们可以想象将特定事件的处理从主应用程序循环委托给本地 QEventLoop 吗?(不确定这个问题是否有意义)
问题1)的展开:
我对 QT 主事件循环基本工作原理的理解如下。应用程序主事件循环(QCoreApplication::exec() )从队列中获取QEvent “E”,并将其分派到它决定事件应前往的QObject “A”(例如,事件的位置和 Z 值)如果按下鼠标左键则为QWidget ) 。如果我们假设对象“A”正在使用事件“E”,则调用该对象的事件方法(还有其他便利方法和事件过滤器,但我们假设事件方法处理我们案例中的事件) - 一些处理与对象“A”相关的事件发生在这里 - 并返回 true。然后,QT主事件循环开始处理队列中的下一个事件,依此类推。
但是,如果对象“A”的事件方法的调用中存在某些阻塞,我希望主应用程序循环被阻塞,因为它等待接收者(对象“A”)的事件方法返回。 ..
例如,如果事件的处理最终调用对象“A”的方法,我们在其中创建一个永远不会退出的本地QEventLoop,我的期望是整个应用程序停止并且不再处理任何事件,直到本地QEventLoop退出,对象“A”的事件方法返回。
否则,这是不正确的,因为我可以看到本地QEventLoop没有阻止应用程序主事件循环...
有人可以让我更深入地了解本地QEventLoop如何工作吗?
[编辑3]参见下面的答案,本地事件循环处理事件
---- 编辑 1 ----
如果我不清楚,我很抱歉,这实际上很难用语言解释,所以下面是一个小代码片段,以更好地说明我的问题 1。
主窗口.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public …Run Code Online (Sandbox Code Playgroud) 我正在编写一个DLL,它被另一个应用程序用作插件,并希望利用Qt的能力.
我已经设置,编译和运行所有类,但没有发出任何信号.所以似乎没有QEventLoop.
尝试1:
我将我的主类修改为子类QThread而不是QObject,并在run()中创建一个QEventLoop,连接所有信号/槽,并执行该线程.
但它没有说没有QApplication就没有QEventLoop.
尝试2:
我修改了主类(仍然继承了QThraed)而不是实例化QCoreApplication,连接所有信号/槽,然后执行应用程序.
警告说QApplication不是在main()线程中创建的,仍然不会发出信号.
我不确定该怎么做.我显然无法在将使用我的插件的应用程序中创建QCoreApplication,并且我无法在没有插件的情况下发出信号.
我已经包含了一个简单的(并且可怕写的)测试应用程序,它应该说明我的问题:
任何帮助,将不胜感激!
main.cpp中:
#include <iostream>
#include "ThreadThing.h"
using namespace std;
int main(int argc, char *argv[])
{
cout << "Main: " << 1 << endl;
ThreadThing thing1;
cout << "Main: " << 2 << endl;
thing1.testStart();
cout << "Main: " << 3 << endl;
thing1.testEnd();
cout << "Main: " << 4 << endl;
thing1.wait(-1);
cout << "Main: " << 5 << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
ThreadThing.h:
#ifndef THREADTHING_H
#define THREADTHING_H
#include <QThread> …Run Code Online (Sandbox Code Playgroud) // Example class
class A : public QObject
{
Q_OBJECT
void fun() {
Timer::SingleShot(10, timerSlot); //rough code
}
public slot:
void timerSlot();
}
auto a = SharedPointer<A>(new A);
a->fun();
a->reset(); // a deleted
Run Code Online (Sandbox Code Playgroud)
在这种情况下删除a并触发计时器后,它会执行timerSlot()吗?我得到了一次非常罕见的崩溃,并且不确定是不是因为这个逻辑中有些可疑.
我正在浏览链接
\n\n\n\n我对一些说法感到困惑。在第一个链接中,它说
\n\n\n\n\nQThread 中的所有函数都是编写的,旨在从创建线程调用,而不是从 QThread 启动的线程调用。
\n
虽然它建议使用moveToThread将对象移动到新线程,而不是子类化QThread。我的问题是:
run方法调用的默认实现exec,会创建一个事件循环,当使用 改变对象的线程关联性moveToThread时,所有的操作slots都会在新线程中执行,而不是在创建线程上执行,这与前面提到的预期用途相矛盾相矛盾。我错过了什么吗?
第二个问题:
\n\n在第三个链接中说
\n\n\n\n\n事件队列属于线程而不是事件循环,并且它\xe2\x80\x99被该线程中运行的所有事件循环共享。
\n
我的问题是单个线程中如何可以有多个事件循环?我的理解是,事件循环通过事件队列循环,直到exit/terminate被调用,并处理每个event到达该队列的事件。如果这是真的,一个循环将永远不会结束(除非 exit/terminate被调用),另一个循环如何开始?任何演示它的示例代码都将受到高度赞赏。
qeventloop ×9
qt ×9
c++ ×6
event-loop ×2
blocking ×1
dbus ×1
dll ×1
pyside ×1
python ×1
qapplication ×1
qobject ×1
qt5 ×1
qthread ×1
qtimer ×1
qtnetwork ×1