Qt Widgets Alignment
-
Hi. I have a question about widgets and layout alignment.
I have a QDialog, where I put one external Widget, containing QLabel and QLineEdit.
Next I want to put my own Widget and align it to QLineEdit inside external Widget.
I added picture, where you can see imaginary green alignment line.
So the code without layouts is like this:#include <QDialog> #include <QCheckBox> #include "ExternalWidget.h" public MyDialog : QDialog { public: MyDialog() { auto *external = new ExternalWidget(); // widget with QLabel and QLineEdit auto *myWidget = new QCheckBox(); // how to align myWidget by second widget in external? } }
Using QFormLayout didn't work out, but may be I'm missing something.
Please help, thank you. -
Well I think you have to monitor the size change of the label. So consider using event filter, but that will require you to save the pointers as member variables.
Here's what I've tried:MyDialog() { ... label->installEventFilter(this); auto margins = hBox->contentsMargins(); margins.setLeft(external->layout()->contentsMargins().left()); // make hBox's left margin the same as external's layout hBox->setContentsMargins(margins); // also try to make hBox having the spacing, but somehow seem not working, still need to add the spacing value in eventFilter hBox->setSpacing(external->layout()->spacing()); } protected: bool eventFilter(QObject *watched, QEvent *event) { if(event->type() == QEvent::Resize && watched == label) { QResizeEvent* re = (QResizeEvent*)event; spacer->changeSize(re->size().width() + external->layout()->spacing(), 0, QSizePolicy::Fixed, QSizePolicy::Ignored); } return QDialog::eventFilter(obj, event); }
Or don't use a spacer, just set the hBox's left margin:
MyDialog() { ... label->installEventFilter(this); } protected: bool eventFilter(QObject *watched, QEvent *event) { if(event->type() == QEvent::Resize && watched == label) { QResizeEvent* re = (QResizeEvent*)event; auto margins = hBox->contentsMargins(); margins.setLeft(external->layout()->contentsMargins().left() + re->size().width() + external->layout()->spacing()); hBox->setContentsMargins(margins); } return QDialog::eventFilter(obj, event); }
I also tried only adding myWidget without a QHBoxLayout, but it seems that contentsMargins is not working on QCheckBox.
-
Hi and welcome to the forum :)
@SWest said in Qt Widgets Alignment:
Next I want to put my own Widget and align it to QLineEdit inside external Widget.
I added picture, where you can see imaginary green alignment line.The line is not straight :))
(but I think it's clear what you mean)It's not that easy, because your
ExternalWidget
has margins and the layout items ofExternalWidget
's own layout are treated different from these which are one layer above them (yourQCheckBox
a.k.amyWidget
)From the top of my head:
You can try to put everything in a vertical (QVBoxLayout
) layout and then let yourmyWidget
only populate half of the row.
Or you can placemyWidget
in a layout with a spacer to which you assign the samesizePolicy
as the label inExernalWidget
and then check the result.Maybe there's an even easier way I cannot think about right now
-
@Pl45m4
Thank you very much for your answer.
First suggestion with half of the row is not suitable in my case.
But second with spacer is interesting. I tried to add spacer as in the following code:MyDialog() { auto *main = new QVBoxLayout(this); auto *external = new ExternalWidget(); main->addWidget(external); auto *hBox = new QHBoxLayout(); main->addLayout(hBox); QLabel *label = external->label(); // let's assume this method exists QSizePolicy labelPolicy = label->sizePolicy(); auto *spacer = new QSpacerItem(label->width(), label->height(), labelPolicy.horizontalPolicy(), labelPolicy.verticalPolicy()); hBox->addItem(spacer); auto *myWidget = new QCheckBox(); hBox->addWidget(myWidget); }
But it didn't work accurate. It aligned with some spacing before myWidget. Also it expanded dialog, but this is not important.
May be I did something incorrectly?
Also I tried to:hBox->setSpacing(0); int spacing = externalWidget->layout()->spacing(); auto *spacer = new QSpacerItem(label->width() - spacing, label->height(), labelPolicy.horizontalPolicy(), labelPolicy.verticalPolicy());
It somehow changed nothing
-
@SWest
I presume you are aware it will always be tricky to align robustly because you want to treat the label and widget separately for your purpose while it is supplied to you as a single composite widget holding both of these in a layout, which really is not designed for you to do what you want here. If you could handle them separately, or even (entirely depending on what the implementation of that widget does) pull out the label and lineedit from it and place them yourself it would be much easier to align. -
Well I think you have to monitor the size change of the label. So consider using event filter, but that will require you to save the pointers as member variables.
Here's what I've tried:MyDialog() { ... label->installEventFilter(this); auto margins = hBox->contentsMargins(); margins.setLeft(external->layout()->contentsMargins().left()); // make hBox's left margin the same as external's layout hBox->setContentsMargins(margins); // also try to make hBox having the spacing, but somehow seem not working, still need to add the spacing value in eventFilter hBox->setSpacing(external->layout()->spacing()); } protected: bool eventFilter(QObject *watched, QEvent *event) { if(event->type() == QEvent::Resize && watched == label) { QResizeEvent* re = (QResizeEvent*)event; spacer->changeSize(re->size().width() + external->layout()->spacing(), 0, QSizePolicy::Fixed, QSizePolicy::Ignored); } return QDialog::eventFilter(obj, event); }
Or don't use a spacer, just set the hBox's left margin:
MyDialog() { ... label->installEventFilter(this); } protected: bool eventFilter(QObject *watched, QEvent *event) { if(event->type() == QEvent::Resize && watched == label) { QResizeEvent* re = (QResizeEvent*)event; auto margins = hBox->contentsMargins(); margins.setLeft(external->layout()->contentsMargins().left() + re->size().width() + external->layout()->spacing()); hBox->setContentsMargins(margins); } return QDialog::eventFilter(obj, event); }
I also tried only adding myWidget without a QHBoxLayout, but it seems that contentsMargins is not working on QCheckBox.
-
-
@SWest It just occured to me that monitoring the lineEdit's move event would be easier, no need to add left margin, width and spacing any more. (If you can also get the pointer of the lineEdit, and it needs to be the direct child widget of the external widget.)
MyDialog() { ... external->lineEdit()->installEventFilter(this); } protected: bool eventFilter(QObject *watched, QEvent *event) { if(event->type() == QEvent::Move && watched == external->lineEdit()) { QMoveEvent* me = (QMoveEvent*)event; auto margins = hBox->contentsMargins(); margins.setLeft(me->pos().x()); hBox->setContentsMargins(margins); } return QDialog::eventFilter(obj, event); }