如何从非Qt C++库类向Qt GUI提供反馈
How can I provide feedback from a non-Qt C++ library class to a Qt GUI?
我正在为一些计算密集型任务(机器视觉)开发C++类库。
// I am a part of a Qt-agnostic library
class Cruncher
{
/* ... */
public:
void doStuff();
};
然后有一个使用该库的Qt GUI。我正在创建一个工人线程来调用库中的重载例程:
// I am a part of a Qt-based GUI which utilizes the library
class Worker : public QThread
{
/* ... */
protected:
virtual void run()
{
/* ... */
Cruncher c;
for (int i = 0; i < count; ++i)
c.doStuff(); // takes some time, and while it's working
// it should communicate status changes which should
// become visible in the GUI
}
};
现在在doStuff()中发生了很多事情,我想在不等待doStuff)返回的情况下向用户提供一些关于正在发生的事情的反馈。首先,也许有一些比每次调用doStuff()后将仪表增加一步更精细的进度报告。此外,doStuff()可能会遇到非关键故障,这使它可以继续部分工作,但我希望在Cruncher工作时(Worker当前正忙于调用doStuff)出现这种情况时,GUI中会显示一条消息。
我希望库保持Qt独立,所以我不愿意向Cruncher添加信号和插槽。当它不是Qt类时,有其他方法可以让它向GUI提供反馈以报告它的工作吗?
我曾考虑创建一个QTimer,在Worker运行时,它会以固定的时间间隔轮询Cruncher的一些"status"answers"errorMsg"成员,但这似乎是非常次优的。
我发布了自己的答案,因为尽管我接受了@Nim的建议,但我希望答案更详细一点,因此如果有人遇到同样的问题,答案会更有用。
我在库中创建了一个消息调度器的框架:
// doesn't need to know about Qt
class MessagePort
{
public:
virtual void message(std::string msg) = 0;
};
接下来,我向Cruncher添加了这个对象的句柄,并添加了doStuff(),偶尔调用message():
// now with Super Cow powers!
class Cruncher
{
protected:
MessagePort *msgPort_;
public:
Cruncher(MessagePort *msgPort) : msgPort_(msgPort) {}
void doStuff()
{
while(...)
{
/*...*/
msgPort_->message("Foo caused an overload in Bar!");
}
}
};
最后,我使用所有必要的Qt优点在GUI中制作了MessagePort的实现:
class CruncherMsgCallback : public QObject, public MessagePort
{
Q_OBJECT
public:
CruncherMsgCallback() : QObject(), MessagePort()
{
connect(this, SIGNAL(messageSignal(const QString &)),
GUI, SLOT(messageShow(const QString &)),
Qt::QueuedConnection);
}
virtual void message(std::string msg)
{
emit messageSignal(QString::fromStdString(msg));
}
signals:
void messageSignal(const QString &msg);
};
最后,当Worker创建Cruncher的实例时,它还会为其提供一个指向工作MessagePort的指针:
class Worker
{
protected:
virtual void run()
{
CruncherMsgCallback msgC;
Cruncher c(&msgC); // &msgC works as a pointer to a
// generic MessagePort by upcasting
c.doStuff(); // Cruncher can send messages to the GUI
// from inside doStuff()
}
};
使用回调函数(类)等,并在构建过程中传入。你需要报告的事情,通过回调报告。
您可以安全地从run()
方法发出信号,我认为这是将信息从工作线程传递到主线程的最佳方式。只需将信号添加到您的QThread子类中(如果您不确定QThread线程是如何工作的,请避免添加插槽)。
最好将来自这些信号的连接显式排队,以避免出现问题。虽然默认情况下,自动连接类型也应该起作用,并发出排队信号,但我认为在这种情况下最好是显式的。实际上,直接信号也应该这样工作,但你必须自己照顾线程安全,而不是让Qt为你处理它,而且你不能连接到使用任何QtGui类的插槽,这些类只在主线程中工作,所以最好坚持排队连接。
要将简单信息传递给run()
方法,如果不需要立即反应,可以使用一些共享的QAtomicInt
变量或类似的东西作为标志,工作线程在方便时会检查这些标志。稍微复杂一点的方法,仍然需要轮询,是拥有共享的数据结构,您可以用互斥锁来保护它。与该方向通信的更复杂的方式将涉及某种消息队列(就像Qt在主线程的事件循环中使用的那样,当您向该方向发出信号时)。
- Qt GUI使用Qfiledialogbox和qlabel显示视频,这是我的代码
- 试图打开并读取一个.txt文件,但它从原始文件中删除了实际文本(Qt GUI C++
- 是否可以在QT GUI应用程序中处理事件时播放加载动画指示器?
- 从其他std ::线程更新QT GUI
- 无法使用 Visual Studio 2010 和 Qt 版本 4.8.0 创建"Qt Gui Application"
- "hijacking" 给定根 QWidget* 的 Qt gui
- 尽管有线程,Qt GUI 仍挂起
- C++ Qt GUI update
- 在QT GUI中创建一个全局对象
- 在已经运行的C 控制台应用程序上实现QT GUI
- QT GUI最简单的方法可以从另一堂课访问MainWindow
- 通过Qt-tcp套接字更改Qt-GUI
- ROS-Qt GUI - 如何分发线程
- 由于线程问题,Qt-Gui没有更新
- 为Python逻辑创建一个C++Qt Gui
- Qt GUI应用程序在与GUI交互时停止实时进程
- 如何在C 中制作QT GUI应用,而不会内存泄漏
- 如何将QT GUI应用程序的版本打印到主机上
- 使用由Eclipse中的Qt设计器创建的Qt GUI
- Qt Gui 应用程序部署