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

Decouple the graphical user interface from logic (MVC/3-Layer)?



  • Hey,

    I started a software development project because I want to learn more aboutthe software development process and Qt seems to be suitable for this project. For summing up:

    I want to develop a GUI with QWidget. Using this GUI, a user can search for and connect to Bluetooth Low Energy devices. I also have a developer board that sends certain sensor data. After the user has connected to this device, the data is sent to the application in real time. With QCustomplot, this data is plotted on two charts. There is also a ListWidget in which this data is also displayed. The user also has the option of selecting a folder in which this data is to be saved.

    Now I thought that I would create a class BluetoothLE, which contains all functions with which devices can be searched, a connection established and services and characteristics can be selected.
    I would then create a second class "DataContainer" that receives the raw data with help of the BluetoothLE class from the sensor and converts it so that it can be plotted.
    Then I would create a third class "plotter", which prepares the plots (title, axis labeling, etc.). This class then receives the data from the DataContainer and plots it on the UI.

    So my UI Class would contain the Slots (button clicked, selected and so on). And in these slots I would then access the functions I need. For example, when the user clicks search for devices, the "Discover Devices" function is called in the BluetoothLE class and the devices are sent to a list widget.

    The question is, does it make sense to choose an architecture pattern (MVC / Layer) or is that a decoupling? I have never worked with it before therefore I don't know how to start. At this moment I have every Logic in the mainwindow.ui because I wanted to see if it works and yeah it does.

    In this post someone wrote this:

    class MyWidget : public QWidget
    {
        Q_OBJECT
    
    public:
        MyWidget(QWidget * parent = Q_NULLPTR)
            : QWidget(parent)
        {
            ui.setupUi(this);
            // Make connections, etc.
        }
    
    private:
        Ui::MyWidgetForm ui;
    };
    

    But why should I have a class my widget? The widgets that I create on my UI I created with Drag and Drop and my MainWindow.ui is like this

    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    


  • I cannot tell you what is the right or wrong way to decouple your data in your program but both examples of realizing the UI are valid. I prefer the first approach because it works better in the inheritance model of OO. MyWidget becomes a specialization of QWidget that is more generic and easier to reuse than directly adding your UI code to MainWindow.


  • Lifetime Qt Champion

    Hi
    One of the "dangers" handling all signals directly in MainWindow is that it becomes
    huge and very intermixed.

    So your plan to have a data class and a view class is a good idea and if you have code like

    void MainWindow::on_pushButton_2_released()
    {
    dataclass.DoSomthing();
    }

    So the GUI does no actual data processing but that is kept in the appropriate classes you will have an ok design;

    If you have a Widget where you use lots of signals, its often a good idea to subclass it and handle the signals in the class as else you get tons of code in MainWindow and that makes it hard to reuse the logic.
    The promote feature in Creator makes this very painless as you can still Design with the std. widgets, but at
    runtime it's your subclass that is running.
    That allows the Widget to be more self contained and more reusable since it comes with signals connected and all.

    In other cases where it's just a few slots and such, it's fine just to have it in MainWindow without it becoming a mess.



  • @mrjj Thank you very much.
    Do you think it would fit here if I use the Modwel view controller pattern here? Because in my application, the data that is to be displayed is shown once in a list, and each in a diagram (I have 2 diagrams on the user interface) and they all use the same data

    dc233f2c-1bf3-4776-9083-afaa154980bb-image.png


  • Lifetime Qt Champion

    Hi,

    Yes it does.

    You should also take a look at Qt's model view programming chapter. It shows your use case implemented with Qt's classes.



  • @SGaist Thank you for your advice, I have already read the documentation but there is something that I do not understand. In my example, I would use a QStackedWidget that navigates thorugh device list, services list and characteristics list. For these 3 Lists I would create a ListView. Now after choosing the characteristic I have 3 views.

    The fitrst view show the whole numeric values that come every second (i.e. x,y,z coordinates of acceleration and x,y,z coordinates of gyroscope data)
    The second view is a plot (made with 3d party library QCustomplot) which only plots the x,y,z-coordinates of acceleration
    The third view is another plot which only plots the x,y,z-coordinates of gyroscope data

    So for example I have a a function getWholeData(), a function getAccelerationData() which uses the getWholeData() function to only pick the acceleration and one getGyroscopeData().

    My problem is now: For the plots one normally uses a normal "Widget" from the Containers of the QtCreator - there is nothing like "WidgetView" like for lists (ListWidget and ListView). How is it possible to use here the Model/View Pattern?


  • Lifetime Qt Champion

    You can create custom views if you want. See the Chart Example