簡體   English   中英

如何從非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工作時(工作人員當前正忙於對它的調用)在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM