Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QtPlugin: connect or redirect stdout / stdcerr



  • My full application is composed by:
    a) A Qt GUI main application
    b) A set of custom plugins (shared libraries with Qt interfaces + GUI) that are loaded inside the main application in run-time.

    I would like to connect these plugins stdout / stdcerr to a QPlainTextEdit component located in my main application.

    I did something like this using QProcess here, and works good:
    https://forum.qt.io/topic/109682/qprocess-not-reading-only-std-cerr/3

    // Topic example connecting stdout of QProcess:
    connect(_process, &QProcess::readyReadStandardOutput, [&]() {
        auto data = _process->readAllStandardOutput();
        ui->console_txt->appendPlainText(data);
    });
    

    Following this topic above, I think that somehow I have to connect the readyReadStandardOutput plugin method to my ui->qPlainTextEdit->appendPlainText(data);

    Of course, my plugin class / interface don't have these readyReadStandardOutput and readyReadStandardError QProcess methods.

    Looking this topic, I would like to apply the same connect idea but replacing the QProcess by my own "shared library" (plugins with Qt interface).

    Here is my plugin header interface (API):

    #ifndef PLUGIN_API_H
    #define PLUGIN_API_H
    
    #include <QString>
    #include <QDebug>
    #include <QJsonObject>
    #include <QObject>
    
    class Plugin_API : public QObject
    {
        Q_OBJECT
    public:
        virtual ~Plugin_API() = default;
    
        virtual QJsonObject get_data(void) = 0;
        virtual void open_ui(const QJsonObject ui_data) = 0;
        virtual void run(const int job_id) = 0;
    
        // ===== SIGNALS ===== //
        virtual void send_msg(const QJsonObject msg) = 0;
    };
    
    // Declare our interface:
    Q_DECLARE_INTERFACE(Plugin_API, "com.lamar.plugin")
    
    #endif // PLUGIN_API_H
    

    Below is one plugin example header that is using the PLUGIN_API interface above:

    #ifndef ANALYSIS_X_H
    #define ANALYSIS_X_H
    
    #include <QObject>
    #include <QtPlugin>
    
    #include <QJsonDocument>
    #include <QJsonArray>
    #include <QJsonObject>
    #include <QFile>
    #include <QByteArray>
    
    #include "analysis_x_global.h"
    #include "plugin_api.h"
    #include "dialog.h"
    
    class ANALYSIS_XSHARED_EXPORT Analysis_x: public Plugin_API
    {
        Q_OBJECT
        Q_PLUGIN_METADATA(IID "com.lamar.plugin")
        Q_INTERFACES(Plugin_API)
    
    public:
        explicit Analysis_x(QObject* parent = nullptr);
        ~Analysis_x() override;
    
        QJsonObject get_data(void) override;
        void open_ui(const QJsonObject ui_data) override;
        void run(const int step_id) override;
    
    private:
        QJsonObject _data;
        Dialog _ui;
    
    signals:
        void send_msg(const QJsonObject msg) override;
    
    public slots:
        void save_ui(QJsonObject updated_ui);
    };
    
    #endif // ANALYSIS_X_H
    

    How can I connect the plugin stdout/stdcerr to the QPlainTextEdit in the main Qt GUI application?

    Here are some related Qt topics:
    https://forum.qt.io/topic/22538/solved-qt-capture-stdout
    https://wiki.qt.io/Plugins
    https://doc.qt.io/qt-5/qtplugin.html


  • Lifetime Qt Champion

    It's the std::out and std::err of your application that are going to be used.

    See this stack overflow answer of a way to capture it.


  • Lifetime Qt Champion

    Hi,

    If you using Qt logging facilities, then use a message handler.


  • Lifetime Qt Champion

    Hi
    Just so i understand fully.
    The plugins runs "things" with QProcess and you want to send the results to MainWindow ?
    Like you show
    // Topic example connecting stdout of QProcess:
    connect(_process, &QProcess::readyReadStandardOutput, & {
    auto data = _process->readAllStandardOutput();
    ui->console_txt->appendPlainText(data);
    });

    just that ui->console_txt is in main and you cant do that directly or where does
    stdout / stdcerr come into play ?

    first i though you wanted to capture std::cout but then realized you were talking about QProcess.



  • @SGaist thank you for your response.
    I don't know Qt Logging Class.
    Is that, right?
    https://doc.qt.io/qt-5/qmessagelogger.html

    Please, could you give me a little example about how to use this message handler?



  • @mrjj No...
    My old example is using QProcess...and it works good!

    Now, I would like to do the same idea with my custom plugin classes.
    These plugins are NOT QProcess. They are QtPlugin (shared library with GUI).

    So I would like to know how can I connect the plugin stdout/stdcerr to the QPlainTextEdit located in my main application.


  • Lifetime Qt Champion

    @fem_dev
    Hi
    Sorry I don't understand
    what stdout/stdcerr
    you mean when its a plugin. (and you run nothing in Qprocess)

    What is it you want capture and send to QPlainTextEdit ?

    Do you mean cout ? printf ? cerr ?
    Can you give an example ?

    Anyway, i assume you mean messages of some sort
    and qDebug is excellent for that.
    All messages from plugins could go to same place and be shown on screen.

    About the message handler
    https://doc.qt.io/qt-5/qtglobal.html#qInstallMessageHandler

    example
    https://stackoverflow.com/questions/4954140/how-to-redirect-qdebug-qwarning-qcritical-etc-output



  • @mrjj Thank you, for your quick response. I will try to explain this better.

    Forget completely the QProcess. I'm not using it any more.
    The QProcess example above was only a conceptual idea of what I really want to do at this point.

    In this image below I did a abstract example of what I want to do:
    Plugin stdout connect.png

    Explanation:

    1. When the "Open Plugin X GUI" button was clicked, I call the PLUGIN_API interface method called open_ui().
      So, the plugin GUI is showed in the screen as a separated window.
      At this moment, I have 2 windows in my screen:
      a) Main Application
      b) Plugin X

    2. Inside que Plugin X GUI, I have a button. If I click this button, I trigger an action, I mean, a Plugin X internal method called: button_clicked()

    3. The PluginX::button_clicked() uses Standard Output and Standard Error (std::cout and std::cerr)

    4. I would like to see these outputs from Plugin X std::cout and std::cerr in the QPlainTextEdit located inside the Main Application GUI.
      So, every time that the user trigger the PluginX::button_clicked() method, I want to see these 2 messages in the QPlainTextEdit:

    Plugin X: Button A clicked
    Plugin X: Error example
    

    I known that I can do it using signals and slots, but I would like to do that connecting/capturing the std::cout and std::cerr because of software design reasons.

    Is this possible? How can I do it?

    Thank you again,


  • Lifetime Qt Champion

    It's the std::out and std::err of your application that are going to be used.

    See this stack overflow answer of a way to capture it.



  • You should know that your plugin does not have its own output. Since it is part of the main application it will share its output. @SGaist proposed the right solution. But you should know that the output will be mixed between your plugin and the regular application. It will not be the same as your previous experiment with a QProcess. If you want to separate those you need to use something else for output. Since you know that it should show up in the text edit, you could write your own stream operator which will update the text edit. Then use your new stream operator.



  • @SimonSchroeder thank you! I will think about that!


Log in to reply