[英]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工作時(工作人員當前正忙於對它的調用)在GUI中出現一條消息。做東西())。
我希望該庫保持與Qt無關,因此我不願意向Cruncher添加信號和插槽。 是否有其他方法可以使它在不是Qt類時向GUI提供反饋以報告其工作?
我正在考慮創建一個QTimer,它會在Worker運行時以固定的時間間隔輪詢Cruncher的某些“狀態”和“ errorMsg”成員,但這似乎非常不理想。
我發布自己的答案,因為盡管我接受了@Nim的建議,但我希望答案更加冗長,因此如果有人應該遇到相同的問題,則答案會更有用。
我在庫中創建了消息調度程序的框架:
// doesn't need to know about Qt
class MessagePort
{
public:
virtual void message(std::string msg) = 0;
};
接下來,我將此對象的句柄添加到Cruncher,並通過偶爾調用message()來添加doStuff():
// 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
反應,則可以使用一些共享的QAtomicInt
變量或類似的標記作為標志,輔助線程在方便時進行檢查。 仍然需要輪詢的稍微復雜一點的方法是,使用互斥鎖保護共享的數據結構。 與該方向通信的更復雜方式將涉及某種消息隊列(就像Qt在向該方向發出信號時在主線程的事件循環中使用的那樣)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.