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. Defining deeply nested widget hierarchies
Forum Updated to NodeBB v4.3 + New Features

Defining deeply nested widget hierarchies

Scheduled Pinned Locked Moved Unsolved General and Desktop
5 Posts 3 Posters 2.2k Views 2 Watching
  • 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.
  • S Offline
    S Offline
    Sewing
    wrote on last edited by
    #1

    Here I am wondering what is the correct way to go while constructing a MainWindow Gui with deeply nested Widget Elements.

    I used to subclass QWidget and populated it with layouts, built-in widgets and what have you.

    However, I found that propagating signals all the way up the gui hierarchy by means of dispatch function etc. is a nightmare. Also, if I would want to change certain properties of specific Widgets posteriori, e.g. the slider-range according to the size of some loaded data structure, I hit brick-walls due to private pointer members of widget elements and thus unreachable widget property functions.

    The alternative, (the way the designer handles things?), is to declare all widget members (pointers, etc.) in the top level Widget, where the entire layout is then defined as well. But I find this rather messy and it violates my modular construction of the Gui application quite considerably.

    I am wondering, what is the way to go ?

    How do you approach this in general?

    1 Reply Last reply
    0
    • mrjjM Offline
      mrjjM Offline
      mrjj
      Lifetime Qt Champion
      wrote on last edited by mrjj
      #2

      Hi
      Im not sure why you need to dispatch signals as you can connect
      to any public signal/slot across a widget tree.
      For the ability to alter ui->Widgets from outside, its normally
      best to provide access functions to do that - to not let all know
      about the private details.
      I also use signals to signals to surface ui->widgets signals to world.

      However, if you need , its possible to do

      class MainWindow : public QMainWindow {
        Q_OBJECT
      public:
        explicit MainWindow(QWidget* parent = 0);
        ~MainWindow();
        Ui::MainWindow* ui;
      private:
        //Ui::MainWindow *ui;
      };
      

      But since you care about modular design, i think you might need something else?

      1 Reply Last reply
      1
      • S Offline
        S Offline
        Sewing
        wrote on last edited by
        #3

        thank you for your reply, I appreciate it. I think I might not have stated my issue clear enough.

        Lets say I have the following code

        class GuiWindow : public QMainWindow {
          Q_OBJECT
        
         public:
          explicit GuiWindow(Widget* parent = nullptr) : QMainWindow{parent}{
              dock =  new QDockWidget{"Snapshots", this};
              mainCtrlWidget = new MainCtrlWidget{dock};
              dock->setWidget(mainCtrlWidget);
              addDockWidget(Qt::BottomDockWidgetArea, dock);
        
             label = new QLabel;
             QVBoxLayout *v = new QVBoxLayout;
             v->addWidget(b); 
             setLayout(v);
        }
        
          QDockWidget *dock;
          MainCtrlWidget *mainCtrlWidget;
          QLabel *label;
        };
        
        

        Now, MainCtrlWidget is also a QWidget according to

        
        class MainCtrlWidget : public QWidget {
          Q_OBJECT
        
         public:
          explicit MainCtrlWidget(QWidget* parent) : QWidget{parent}{
            QHBoxLayout *layout = new QHBoxLayout;
            QPusbButton *button = new QPushButton;
            layout->addWidget(button);
            setLayout(layout);
          }
        };
        

        Now the Pushbutton "button" is local to the MainCtrlWidget class, so how would I go about connecting this element with the QLabel in the top-level Gui Widget?

        kshegunovK 1 Reply Last reply
        0
        • mrjjM Offline
          mrjjM Offline
          mrjj
          Lifetime Qt Champion
          wrote on last edited by mrjj
          #4

          Hi
          There are varies ways, depending on what goal really is.

          My absolute favorite is new public signals

          So in MainCtrlWidget you define

          public signals:
          void LampON(); // some signal that describes the action/info this class provide

          Then internally , you do connect ( ui->button, clicked(), this, LampON)
          ( signal to signal. )

          Then from GuiWindow , you can connect the label to LampON

          This way, you do not bleed implementation details all over the program and the exposed signals are
          model after what the class supply of into to the world.

          If the need is to fiddle with the actual widget inside ui, for test or other purpose
          you can use findchildren on the parent and qobject_cast to get actual type.
          (this is normally not needed for a design, but can be useful)

          1 Reply Last reply
          1
          • S Sewing

            thank you for your reply, I appreciate it. I think I might not have stated my issue clear enough.

            Lets say I have the following code

            class GuiWindow : public QMainWindow {
              Q_OBJECT
            
             public:
              explicit GuiWindow(Widget* parent = nullptr) : QMainWindow{parent}{
                  dock =  new QDockWidget{"Snapshots", this};
                  mainCtrlWidget = new MainCtrlWidget{dock};
                  dock->setWidget(mainCtrlWidget);
                  addDockWidget(Qt::BottomDockWidgetArea, dock);
            
                 label = new QLabel;
                 QVBoxLayout *v = new QVBoxLayout;
                 v->addWidget(b); 
                 setLayout(v);
            }
            
              QDockWidget *dock;
              MainCtrlWidget *mainCtrlWidget;
              QLabel *label;
            };
            
            

            Now, MainCtrlWidget is also a QWidget according to

            
            class MainCtrlWidget : public QWidget {
              Q_OBJECT
            
             public:
              explicit MainCtrlWidget(QWidget* parent) : QWidget{parent}{
                QHBoxLayout *layout = new QHBoxLayout;
                QPusbButton *button = new QPushButton;
                layout->addWidget(button);
                setLayout(layout);
              }
            };
            

            Now the Pushbutton "button" is local to the MainCtrlWidget class, so how would I go about connecting this element with the QLabel in the top-level Gui Widget?

            kshegunovK Offline
            kshegunovK Offline
            kshegunov
            Moderators
            wrote on last edited by
            #5

            @Sewing said in Defining deeply nested widget hierarchies:

            Now the Pushbutton "button" is local to the MainCtrlWidget class, so how would I go about connecting this element with the QLabel in the top-level Gui Widget?

            There are 2 distinct approaches:

            1. You provide a fully self-contained widgets that have all their relevant slots and signals exposed (i.e. MainCtrlWidget exposes all the needed signals and slots from its children). Usually this involves delegating the signals and slots (what you describe in your original post).
            2. You don't subclass when you don't need to (and in your example above you don't need to) and you have a "controller" object/function that does all the connecting for you when creating everything. E.g.:
            QMainWindow mainWindow;
            
            QWidget * mainCtrlWidget = new QWidget();
            QHBoxLayout * layout = new QHBoxLayout(mainCtrlWidget);
            QPushButton * button = new QPushButton;
            layout->addWidget(button);
            
            dock->setWidget(mainCtrlWidget);
            mainWindow.addDockWidget(Qt::BottomDockWidgetArea, dock);
            
            QLabel * label = new QLabel;
            QVBoxLayout * mainLayout = new QVBoxLayout(&mainWindow);
            mainLayout->addWidget(label);
            

            As you see there's not one class derived here and you can connect the signals and slots of all objects at that point. This also works with designer forms, something akin to:

            QWidget * widget = new QWidget();
            Ui::SomeFormClass ui;
            ui.setupUi(widget);
            
            // Connect signals and slots at this point while `ui` is still available.
            

            Read and abide by the Qt Code of Conduct

            1 Reply Last reply
            4

            • Login

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