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

Shared Library + UI: Accessing the UI elements



  • I would like to develop a shared library that contains a window and UI elements.

    So, I created:
    a) A Qt shared library project called myLib
    b) A plugin interface (abstract class) called Plugin_API
    c) Inherit the plugin interface in the MyLib class

    Here is the Plugin_API.h

    #ifndef PLUGIN_API_H
    #define PLUGIN_API_H
    
    #include <QtPlugin>
    #include <QString>
    
    class Plugin_API : public QObject
    {
        Q_OBJECT
    
    public:
        virtual ~Plugin_API() = default;
        virtual void showUI(void) = 0;
        virtual void test(void) = 0;
    
    signals:
        void sendString(QString string);
    };
    
    Q_DECLARE_INTERFACE(Plugin_API, "com.lamar.plugin")
    
    #endif // PLUGIN_API_H
    

    Here is the MyLib Class definition:

    #ifndef MYLIB_H
    #define MYLIB_H
    
    #include <QObject>
    #include <QString>
    
    #include "myLib_global.h"
    #include "plugin_api.h"
    
    class MYLIB_EXPORT MyLib : public Plugin_API
    {
        Q_OBJECT
        Q_PLUGIN_METADATA(IID "com.lamar.plugin")
        Q_INTERFACES(Plugin_API)
    
    public:
        explicit MyLib(QObject* parent = nullptr);
    
        void test() override;
        void showUI() override;
    };
    
    #endif // MYLIB_H
    

    Finally, here is the MyLib implementation file:

    #include "mylib.h"
    
    MyLib::MyLib(QObject* parent)
    {
    
    }
    
    void MyLib::test()
    {
        
    }
    
    void MyLib::showUI()
    {
        
    }
    

    Now, I would like to add a GUI window in this MyLib class. So, add a *.ui file.
    My question is: How can I add a *.ui file to this MyLib class and be able to access all UI elements like this:

    void MyLib::showUI()
    {
        ui->show(); // Open the UI Window
    
        // Access to the UI elements:
        ui->myButton->setText("Test Button");
        ui->myLabel->setText("Test Label");
    }
    

    Before I asked this question, I was creating a new Qt Designer Form Class and get 3 new files:

    • my_ui_class.h
    • my_ui_class.cpp
    • my_ui_class.ui

    After that, I was creating a My_UI_Class instance inside a MyLib method, like:

    #include "my_ui_class.h"
    
    void MyLib::showUI()
    {
        My_UI_Class ui;
    
        ui.setModal(true);
        ui.exec();    
    }
    

    The problem with this way is: MyLib doesn't have direct access to the UI elements and the UI events/signals like on_btn_clicked().

    So, I think that should be a better way to add a UI to a shared library (in compile time).

    Could you help me?

    Thank you,


  • Lifetime Qt Champion

    @fem_dev
    Hi
    Ah.
    Well you could just make its
    Ui::My_UI_Class *ui;
    public if you want to skip adding access functions to My_UI_Class.


  • Lifetime Qt Champion

    Hi
    Im not sure i understand.
    Dont mylib have access to the UI elements via
    My_UI_Class ui; ?
    Like normal when you create a Qt Designer Form Class ?



  • @mrjj said in Shared Library + UI: Accessing the UI elements:

    Dont mylib have access to the UI elements via
    My_UI_Class ui; ?

    In this example below...I don't think so...

    #include "my_ui_class.h"
    
    void MyLib::showUI()
    {
        My_UI_Class ui;
    
        // ITS NOT POSSIBLE TO DO THAT:
        ui.myLabel.setText("This is a test");
    
        ui.setModal(true);
        ui.exec();    
    }
    

    Is there a way do access ui elements inside this MyLib method above?


  • Lifetime Qt Champion

    @fem_dev
    But then its not a normal UI struct thing ?
    Can you show how its defined as it should be able to work 100% like
    in a normal form.



  • @mrjj said in Shared Library + UI: Accessing the UI elements:

    But then its not a normal UI struct thing ?

    Sorry, I believe I am not able to express myself well.

    My point is this:
    When I create a new project from a shared library using the Qt Creator IDE, by default, that project does not create any *.ui files associated with that library. I'm going to call this project MyLib.

    So, if it is desired that this shared library has a graphical interface (like a regular form, with buttons, labels, ets ...) it is necessary to manually add a *.ui file to this project.

    My question is: How should I proceed to add this *.ui file so that I can access all the graphic elements within the methods of the main class (MyLib).

    Below is an example of how I would like to access graphics without having to create any intermediate objects (QWidget or QDialog):

    void MyLib::someMethod()
    {
        ui->myLabel->setText("This is a test"); 
    }
    

    How the class MyLib can have a private member like:

    Ui::MyLib *ui;
    

    Did I get to express myself better? Is it possible?


  • Qt Champions 2019

    @fem_dev said in Shared Library + UI: Accessing the UI elements:

    it is necessary to manually add a *.ui file to this project.

    No, it's not. You can simply use the wizard to add a ui class to your lib project.
    Also I'm not sure why anybody else except the class should have access to the internal ui variable.


  • Lifetime Qt Champion

    Hi
    No its not possible to directly add UI files to a LIB as its not a
    QObject and cannot send signals etc
    so it has to be via a QWidget
    So just add
    my_ui_class.h
    my_ui_class.cpp
    my_ui_class.ui
    to the project and
    use my_ui_class in the lib.



  • @mrjj said in Shared Library + UI: Accessing the UI elements:

    use my_ui_class in the lib.

    Ok...I got the main idea.

    @jsulm said in Shared Library + UI: Accessing the UI elements:

    Also I'm not sure why anybody else except the class should have access to the internal ui variable.

    Let me explain my doubt:

    Suppose I do it again the previous way, that is, adding the above 3 files to the MyLib project using the Qt Designer Form Class:

    • my_ui_class.h
    • my_ui_class.cpp
    • my_ui_class.ui

    So, I got this:

    #include "my_ui_class.h"
    
    void MyLib::showUI()
    {
        My_UI_Class ui;
    
        ui.setModal(true);
        ui.exec();    
    }
    

    When I click on any interface button, a signal is sent from the GUI to the UI class and it receives that signal in a slot called on_btn_clicked().

    However, I would like to receive this signal within some method in the MyLib class. This has many uses for me like:

    • Communicate the plugin UI with the Main App via Plugin_API interface
    • Allocate memory for the process to be done
    • Open / close other components
      etc...

    How do I get the on_btn_clicked () signal coming from the graphical interface to a MyLib class slot?


  • Lifetime Qt Champion

    @fem_dev
    Well you can try to make MyLib a QObject and see if that works.

    #include <QObject>
    
    class MYLIB_EXPORT Mylib : public QObject
    {
        Q_OBJECT
    
    public:
        Mylib();
    };
    

    Then it should be able to send and receive signals.

    Im not sure if we get an issues with the event loop but try it and see.



  • @mrjj said in Shared Library + UI: Accessing the UI elements:

    Well you can try to make MyLib a QObject and see if that works.

    thank you...
    Well, many large applications use shared libraries that contain the GUI.
    I would like to know what is the best or "canonical" way to create a shared library + GUI and how get the access of the GUI data inside of the "myLib".

    Is this way correct? Is this the standard way?

    // STEP 0: Create a `My_UI_Class` `private member` inside of `myLib` class 
    class MYLIB_EXPORT MyLib : public Plugin_API
    {
        Q_OBJECT
        Q_PLUGIN_METADATA(IID "com.lamar.plugin")
        Q_INTERFACES(Plugin_API)
    ...
    private:
        My_UI_Class _my_ui;
    }
    

    // STEP 1: From myLib call a `My_UI_Class` method to modify a UI parameter
    
    #include "my_ui_class.h"
    
    void MyLib::someMethod()
    {
        _my_ui->setX(100)
    }
    

    // STEP 2: Now, inside the `My_UI_Class` method, I have acccess to the `ui` elements
    void My_UI_Class::setX(int x)
    {
        ui->mybtn->setText(x);
    }
    

    In this example above, I have to do 2 steps to modify the UI element. Is this the correct / best way to do that?
    Or there is a short-cut way to access and modify the UI elements direct from myLib methods?


  • Lifetime Qt Champion

    Hi
    If Plugin_API inherits QObejct then yes it might work.

    The normal way is to expose QWidgets to the outside world and not have the actual lib
    be sort of a Widget itself since its by nature not visual.
    And yes, keep My_UI_Class _my_ui; private and provide access functions to the widgets
    instead of allowing direct access as that creates a tight coupling with the users of the widgets
    and internal structure. (which is unwanted)

    You never showed what you have inside My_UI_Class so i cant comment on

    • Or there is a short-cut way to access and modify the UI elements direct from myLib methods?


  • @mrjj said in Shared Library + UI: Accessing the UI elements:

    You never showed what you have inside My_UI_Class

    It is just a regular QDialog class.
    I add some buttons and labels using Qt Designer.

    #ifndef MY_UI_CLASS_H
    #define MY_UI_CLASS_H
    
    #include <QDialog>
    
    namespace Ui {
    class My_UI_Class;
    }
    
    class My_UI_Class : public QDialog
    {
        Q_OBJECT
    
    public:
        explicit My_UI_Class(QWidget *parent = nullptr);
        ~My_UI_Class();
    
    private:
        Ui::My_UI_Class *ui;
    };
    
    #endif // MY_UI_CLASS_H
    

    #include "my_ui_class.h"
    #include "ui_my_ui_class.h"
    
    My_UI_Class::My_UI_Class(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::My_UI_Class)
    {
        ui->setupUi(this);
    }
    
    My_UI_Class::~My_UI_Class()
    {
        delete ui;
    }
    


  • Lifetime Qt Champion

    @fem_dev
    Hi
    Ah.
    Well you could just make its
    Ui::My_UI_Class *ui;
    public if you want to skip adding access functions to My_UI_Class.


Log in to reply