Defining deeply nested widget hierarchies



  • 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?


  • Qt Champions 2016

    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?



  • 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?


  • Qt Champions 2016

    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)


  • Qt Champions 2016

    @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.
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.