Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Struggling with basic class structure
QtWS25 Last Chance

Struggling with basic class structure

Scheduled Pinned Locked Moved Unsolved General and Desktop
7 Posts 4 Posters 282 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Y Offline
    Y Offline
    yannik131
    wrote on 5 Apr 2025, 12:34 last edited by
    #1

    Hello,

    I'm struggling with my project's class structure. Consider the following simplified UML diagram:

    mvc.png

    The main window has 2 widgets. The SettingsWidget has input fields and sends data to the PlotModel, which then sends data to the PlotWidget (custom widget using qcustomplot) for plotting. What I'm struggling with is

    • Which class should own the PlotModel: MainWindow, PlotWidget or a Singleton?
    • Who sets the callbacks between the model and the widgets? And in which function are they set? If PlotWidget owns PlotModel, setting the callbacks to SettingsWidget seems difficult
    • PlotModel derives from QObject. Is this correct?
    • Currently the SettingsWidget's elements are defined in MainWindow.ui and SettingsWidget has input fields as members and populates them with findChild. This is bad, right? Should all custom widgets have their own .ui file?

    I searched the documentation at https://doc.qt.io/qt-6/ but I'm not really sure where to start. Any advice?

    1 Reply Last reply
    0
    • C Online
      C Online
      Chris Kawa
      Lifetime Qt Champion
      wrote on 5 Apr 2025, 15:12 last edited by
      #2

      From what you're describing you've got 4 classes that should be kept separate and not depend on each other, other than a model interface. Each of them should be able to be created and work in separation i.e. a model doesn't require UI to exist and a UI displays empty space without a model, but is otherwise functional. You can look at Qt's own model view architecture for inspiration - models and views are independent and interchangeable and talk to each other only through an abstract interface. Similarly good UI is comprised of separate widgets that you can put in and take out without modifying other parts (apart from the parent that creates them). Each should be an independent entity.

      That being said SettingsWidget should be a separate class (and .ui) from MainWindow. PlotModel should know nothing about any other part of the system, PlotWidget and SettingsWidget would be independent classes that talk to the model via abstract interface (one mostly reading, the other mostly writing). So in pseudo code this should look something like this:

      // make separate objects
      mainWindow = new MainWindow;
      plotModel = new PlotModel;
      plotWidget = new PlotWidget;
      settingsWidget = new SettingsWidget;
      
      // connect views to the model
      plotWidget->setModel(plotModel); 
      settingsWidget->setModel(plotModel);
      
      // setup UI
      //addSubwindow is not a real thing. Could be a central widget or a dock, whatever you need
      mainWindow->addSubwindow(plotWidget);
      mainWindow->addSubwindow(settingsWidget);
      

      As to who should own all the objects and where that code exists - in a larger apps there's usually some overarching controlling object. In smaller projects MainWindow class often does the double duty of being both a window and that controlling object. It's not exactly the purest solution from design standpoint, but multiplying entities just for the sake of it is not either.
      If you want a separate controlling object you can always make it a stack allocated object in main(), like the QApplication instance. Or you could even subclass QApplication and make it be the controlling object. Up to you really.

      1 Reply Last reply
      3
      • Y Offline
        Y Offline
        yannik131
        wrote on 7 Apr 2025, 16:18 last edited by
        #3

        Thank you, that was helpful. I read the chapters on Models, Views and Delegates in https://doc.qt.io/qt-6/model-view-programming.html and will redesign my GUI according to these patterns.

        1 Reply Last reply
        0
        • S Offline
          S Offline
          SimonSchroeder
          wrote on 8 Apr 2025, 06:57 last edited by
          #4

          I mostly agree with @Chris-Kawa. However, instead of calling setModel() I would rather suggest that PlotWidget, PlotModel and SettingsWidget are just connected through signals and slots and don't hold pointers to each other (we're talking about Qt here). Most of the time I would just do the connects inside the constructor of MainWindow. If there are too many connects I might refactor the connects into a seperate function (e.g. init()) called from the MainWindow constructor. If you are going with a controlling object as @Chris-Kawa suggests, this would go in there. However, the Controller in MVC is just connecting signals and slots in Qt. This can be done in a single function and is more procedural than object oriented. I don't really see a point in creating a separate class for this, unless the Controller has more things to do.

          1 Reply Last reply
          1
          • P Offline
            P Offline
            Pl45m4
            wrote on 8 Apr 2025, 12:51 last edited by
            #5

            Hi @yannik131,

            if there is not much more complexity than your couple classes, you can simple let your main class (i.e. the QMainWindow) hold and manage everything else that is going on. Like @SimonSchroeder said above, you don't even need a controller or something.

            I would pick a hierarchy like this:

            • MainWindow
              • SettingsWidget (could be QDialog)
              • PlotWidget
                • PlotModel (here)
              • PlotModel (or here)

            QMainWindow as main entry point to your GUI. From there you can show your dialog to modify your data (PlotModel) and show/hide the actual plot. This model (and its raw data) can be stored in PlotWidget itself or also as member in your MainWindow.


            If debugging is the process of removing software bugs, then programming must be the process of putting them in.

            ~E. W. Dijkstra

            1 Reply Last reply
            0
            • C Online
              C Online
              Chris Kawa
              Lifetime Qt Champion
              wrote on 9 Apr 2025, 10:03 last edited by
              #6

              @SimonSchroeder I'd say it heavily depends on a use case. Connections are part of an event driven architecture - something happens and something else reacts to that. They are not really meant to be replacement for simple getters and setters, typical for a data model (think data(), setData() or parent() members of a model). Replacing a getter with a signal/slot connection is also particularly awkward, because you can only do it by passing a reference, but you don't really know how many slots will be connected to it and set it (if any). It also complicates further with connections across threads.

              QAbstractItemModel has around 40 functions as part of its interface. Depending on what a model actually does it might be ok or a terrible idea to replace that with connections. The overhead is maybe not large (especially with direct connections), but can become significant if the model is accessed frequently (think something like a logger and a view that plots some measurement realtime). A typical view in Qt's framework with moderate number of items in a model will make hundreds of calls to data() to get various aspects for displaying content. I wouldn't say replacing it with connects is a good idea. Also managing all of those connections can be really annoying.

              To be honest personally I'd much rather a setModel that sets a single pointer (you can store it in a QPointer if you want auto-nulling) than juggling 40 connections. I do recognize that it is a matter of preference though.

              S 1 Reply Last reply 30 days ago
              2
              • C Chris Kawa
                9 Apr 2025, 10:03

                @SimonSchroeder I'd say it heavily depends on a use case. Connections are part of an event driven architecture - something happens and something else reacts to that. They are not really meant to be replacement for simple getters and setters, typical for a data model (think data(), setData() or parent() members of a model). Replacing a getter with a signal/slot connection is also particularly awkward, because you can only do it by passing a reference, but you don't really know how many slots will be connected to it and set it (if any). It also complicates further with connections across threads.

                QAbstractItemModel has around 40 functions as part of its interface. Depending on what a model actually does it might be ok or a terrible idea to replace that with connections. The overhead is maybe not large (especially with direct connections), but can become significant if the model is accessed frequently (think something like a logger and a view that plots some measurement realtime). A typical view in Qt's framework with moderate number of items in a model will make hundreds of calls to data() to get various aspects for displaying content. I wouldn't say replacing it with connects is a good idea. Also managing all of those connections can be really annoying.

                To be honest personally I'd much rather a setModel that sets a single pointer (you can store it in a QPointer if you want auto-nulling) than juggling 40 connections. I do recognize that it is a matter of preference though.

                S Offline
                S Offline
                SimonSchroeder
                wrote 30 days ago last edited by
                #7

                @Chris-Kawa said in Struggling with basic class structure:

                They are not really meant to be replacement for simple getters and setters

                Agreed. You are right about the QAbstractItemModel. I was thinking more along the lines of simple UI elements connecting valueChanged(...) signals and setValue(...) slots or even QPushButton::pressed(). For those I advocate to just connect those signals and slots. E.g.SettingsWidget might connect the slots of individual UI elements to its own slots (like countChanged(int), nameChanged(QString), ...) which the MainWindow can then connect to the PlotModel.

                1 Reply Last reply
                0

                1/7

                5 Apr 2025, 12:34

                • Login

                • Login or register to search.
                1 out of 7
                • First post
                  1/7
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved