QPushButton vertical alignment in QToolBar
-
I'm adding QActions, QLabels, QSpinBoxes and a QPushButton to a QToolBar in a QMainWindow. Minimal styling is involved (only some padding on the QLabels via CSS).
I've spent the last 30 minutes trying to make the QPushButton vertically aligned with the other widgets, without success. I've tried CSS margins, padding,
setContentMargins
andsetAlignment
, nothing works.Any ideas?
Thanks.
# This is part of QMainWindow # Command buttons toolbar = self.addToolBar('Main') toolbar.setIconSize(QSize(25, 25)) toolbar.setMovable(False) toolbar.setContextMenuPolicy(Qt.PreventContextMenu) toolbar.addAction(self.act_reload) toolbar.addAction(self.act_reset_zoom) toolbar.addAction(self.act_toggle_grid) toolbar.addSeparator() # Depth spin boxes lbl_spin_min = QLabel('Min depth') lbl_spin_min.setStyleSheet('QLabel {padding: 0 10}') toolbar.addWidget(lbl_spin_min) self.spin_min = DepthSpinBox() toolbar.addWidget(self.spin_min) lbl_spin_max = QLabel('Max depth') lbl_spin_max.setStyleSheet('QLabel {padding: 0 10}') toolbar.addWidget(lbl_spin_max) self.spin_max = DepthSpinBox() # Minimal changes to QSpinBox, see below toolbar.addWidget(self.spin_max) self.spin_min.valueChanged.connect(self.spin_value_changed) self.spin_max.valueChanged.connect(self.spin_value_changed) self.btn_reset_spin = QPushButton('Reset') toolbar.addWidget(self.btn_reset_spin) self.btn_reset_spin.clicked.connect(self.depth_spin_reset) # Somewhere else... class DepthSpinBox(QSpinBox): def __init__(self): super().__init__() self.setSingleStep(5) self.setAlignment(Qt.AlignRight) self.setFixedWidth(60)
-
Hi,
Why not build a widget to contain all of these and then add that widget to the toolbar ?
-
@Strangelove
Yes, that is exactly what @SGaist means :) It would give you a nice, self-contained widget with all your sub-widgets nicely laid out. For use here, or elsewhere.You do not have to sub-class
QWidget
for this --- you could just use a plainQWidget
. However, it is probably a good idea to do so as it makes it neater, explicable and even more self-contained. -
@JonB Thank you. While waiting for an answer I tried subclassing QWidget and indeed it solves the alignment issue. It has good sides and bad sides, though, and I'm wondering what's the best practice here.
Good
- It is indeed a self-contained widget which could be used elsewhere (although it's very specific to this application...)
class ToolbarFilterWidget(QWidget): def __init__(self): super().__init__() layout = QHBoxLayout() lbl_spin_min = QLabel('Min depth', self) lbl_spin_min.setStyleSheet('QLabel {padding: 0 10}') layout.addWidget(lbl_spin_min) self.spin_min = DepthSpinBox(self) layout.addWidget(self.spin_min) lbl_spin_max = QLabel('Max depth', self) lbl_spin_max.setStyleSheet('QLabel {padding: 0 10}') layout.addWidget(lbl_spin_max) self.spin_max = DepthSpinBox(self) layout.addWidget(self.spin_max) self.category_checkbox = {} for cat in config.categories: self.category_checkbox[cat] = QCheckBox(cat.capitalize()) layout.addWidget(self.category_checkbox[cat]) self.checkbox_include_done = QCheckBox('Include Done') layout.addWidget(self.checkbox_include_done) self.btn_reset_filters = QPushButton('Reset Filters') layout.addWidget(self.btn_reset_filters) self.setLayout(layout)
- My Reset button is finally where it should be :)
Not so good
- Seems like a lot of work just to have a button stay vertically centered.
- Because the widget is now a class independent of my QMainWindow, all the controls inside the widget have to be accessed through an additional variable which makes the code a mouthful (and IMHO rather ugly), since I have to prefix everything with
filter_widget
:
def reset_filters(self): min_loc_depth, max_loc_depth = self.map.extents self.filter_widget.spin_min.setMinimum(min_loc_depth) self.filter_widget.spin_min.setMaximum(max_loc_depth) self.filter_widget.spin_max.setMinimum(min_loc_depth) self.filter_widget.spin_max.setMaximum(max_loc_depth) self.filter_widget.spin_min.setValue(min_loc_depth) self.filter_widget.spin_max.setValue(max_loc_depth) for checkbox in self.filter_widget.category_checkbox.values(): checkbox.blockSignals(True) checkbox.setChecked(True) checkbox.blockSignals(False) self.filter_widget.checkbox_include_done.setChecked(True) self.set_filter()
BTW, how would you go about doing this without subclassing QWidget?
Thanks a lot.
-
It's up to you to add appropriate getter and setter to not have to worry about the internals of your custom widget.
In your case, you could have done as I suggested and just create that "container widget". The rest of your code would have not changed.
-
I believe I figured out the "container widget" approach, which is just to instantiate each widget with a second argument pointing to an empty parent widget, then adding the parent widget to the toolbar.
FWIW, I've attached screenshots of the results. It seems that — at least on my machine (macOS Catalina) — a subclass of QWidget still centers the button better than the container widget does. No idea why.
@JoeCFD said in QPushButton vertical alignment in QToolBar:
Try QToolButton which is made for QToolBar
Thank you, I already have several QToolButtons in the toolbar but I really needed this one to stand out.