Jellby
Jellby

Reputation: 2694

QToolBar size and alignment with hidden actions

I'm adding a toolbar to a widget, and dynamically hiding actions (they are also used in context menus). I'm encountering some problem with alignment/size. In the image below, Test 1 is "correct", and I want the other two to have only the "C" button, right-aligned (as in Test 3, but without the extra left space).

enter image description here

The code shows my attempt. Test 2 simply uses .setVisible(False) on the action A and B, while Test 3 does the same and adds a couple of empty QLabel on the left (if I add only one), the C does not end up right-aligned. It looks like QToolBar wants a minimum of 3 buttons or something.

Any idea how to fix this?

#!/usr/bin/env python

from PyQt4.QtGui import *
import sys

class MainWindow(QMainWindow):

  def __init__(self):
    super(QMainWindow, self).__init__()

    stylesheet = 'QToolButton{padding: 0; margin: 0} QToolBar{border: 1px solid black}'

    layout = QVBoxLayout()

    a = QAction('A', self)
    b = QAction('B', self)
    c = QAction('C', self)
    toolbar = QToolBar()
    toolbar.addAction(a)
    toolbar.addAction(b)
    toolbar.addAction(c)
    toolbar.setStyleSheet(stylesheet)
    hbox = QHBoxLayout()
    hbox.addWidget(QLabel('Test 1'))
    hbox.addStretch(1)
    hbox.addWidget(toolbar)
    group = QGroupBox()
    group.setLayout(hbox)
    layout.addWidget(group)

    a = QAction('A', self)
    b = QAction('B', self)
    c = QAction('C', self)
    toolbar = QToolBar()
    toolbar.addAction(a)
    toolbar.addAction(b)
    toolbar.addAction(c)
    a.setVisible(False)
    b.setVisible(False)
    toolbar.setStyleSheet(stylesheet)
    hbox = QHBoxLayout()
    hbox.addWidget(QLabel('Test 2'))
    hbox.addStretch(1)
    hbox.addWidget(toolbar)
    group = QGroupBox()
    group.setLayout(hbox)
    layout.addWidget(group)

    a = QAction('A', self)
    b = QAction('B', self)
    c = QAction('C', self)
    toolbar = QToolBar()
    toolbar.addWidget(QLabel(''))
    toolbar.addWidget(QLabel(''))
    toolbar.addAction(a)
    toolbar.addAction(b)
    toolbar.addAction(c)
    a.setVisible(False)
    b.setVisible(False)
    toolbar.setStyleSheet(stylesheet)
    hbox = QHBoxLayout()
    hbox.addWidget(QLabel('Test 3'))
    hbox.addStretch(1)
    hbox.addWidget(toolbar)
    group = QGroupBox()
    group.setLayout(hbox)
    layout.addWidget(group)

    layout.addStretch(1)

    widget = QWidget()
    widget.setLayout(layout)

    self.setCentralWidget(widget)

    self.show()

app = QApplication(sys.argv)
win = MainWindow()
sys.exit(app.exec_())

Upvotes: 1

Views: 1905

Answers (1)

nathancy
nathancy

Reputation: 46670

To dynamically hide actions in a QToolbar, you cannot use setVisible(False) on the action since it will only "hide" the action from view but the button is inherently still there which is why you have the extra white space. Even though the action is hidden, there is still padding from a hidden object which gives you the undesired empty space. Similarly, when you add empty QLabels, this "hidden" widget also leaves white space since the physical area of the widget is still there.

Considering this, a solution is to remove the action from the QToolbar using removeAction(). This way, the actual object will be removed from the layout so there is no white space. Here's an example that shows how to add and remove actions in a QToolbar using handlers. You can check what objects are in the Qtoolbar with .actions() and depending on what action you want to remove, you can simply pass this to removeAction(). I'll leave it up to you to implement error handling when there are no more actions to add or no more actions to remove.

enter image description here

from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys

class MainWindow(QMainWindow):
    def __init__(self):
        super(QMainWindow, self).__init__()

        self.stylesheet = 'QToolButton{padding: 0; margin: 0} QToolBar{border: 1px solid black}'

        self.main_layout = QGridLayout()
        self.layout = QVBoxLayout()

        self.a = QAction('A', self)
        self.b = QAction('B', self)
        self.c = QAction('C', self)

        self.action_table = {1: self.a,
                             2: self.b,
                             3: self.c
        }

        self.test1_toolbar = QToolBar()
        self.test1_toolbar.addAction(self.a)
        self.test1_toolbar.addAction(self.b)
        self.test1_toolbar.addAction(self.c)
        self.test1_toolbar.setStyleSheet(self.stylesheet)
        self.test1_hbox = QHBoxLayout()
        self.test1_hbox.addWidget(QLabel('Test 1'))
        self.test1_hbox.addStretch(1)
        self.test1_hbox.addWidget(self.test1_toolbar)
        self.test1_group = QGroupBox()
        self.test1_group.setLayout(self.test1_hbox)
        self.layout.addWidget(self.test1_group)

        self.test2_toolbar = QToolBar()
        self.test2_toolbar.addAction(self.a)
        self.test2_toolbar.addAction(self.b)
        self.test2_toolbar.addAction(self.c)
        self.test2_toolbar.setStyleSheet(self.stylesheet)
        self.test2_add_button = QPushButton('Add')
        self.test2_add_button.clicked.connect(self.test2_add_action)
        self.test2_remove_button = QPushButton('Remove')
        self.test2_remove_button.clicked.connect(self.test2_remove_action)
        self.test2_hbox = QHBoxLayout()
        self.test2_hbox.addWidget(QLabel('Test 2'))
        self.test2_hbox.addStretch(1)
        self.test2_hbox.addWidget(self.test2_toolbar)
        self.test2_group = QGroupBox()
        self.test2_group.setLayout(self.test2_hbox)

        self.layout.addWidget(self.test2_group)

        self.test3_toolbar = QToolBar()
        self.test3_toolbar.addAction(self.a)
        self.test3_toolbar.addAction(self.b)
        self.test3_toolbar.addAction(self.c)
        self.test3_toolbar.setStyleSheet(self.stylesheet)
        self.test3_hbox = QHBoxLayout()
        self.test3_hbox.addWidget(QLabel('Test 3'))
        self.test3_hbox.addStretch(1)
        self.test3_hbox.addWidget(self.test3_toolbar)
        self.test3_group = QGroupBox()
        self.test3_group.setLayout(self.test3_hbox)
        self.layout.addWidget(self.test3_group)

        self.layout.addStretch(1)

        self.widget = QWidget()

        self.main_layout.addLayout(self.layout,0,0,1,1)
        self.main_layout.addWidget(self.test2_add_button,0,1,1,1)
        self.main_layout.addWidget(self.test2_remove_button,0,2,1,1)
        self.widget.setLayout(self.main_layout)
        self.setCentralWidget(self.widget)
        self.show()

    def test2_add_action(self):
        objects = len(self.test2_toolbar.actions())
        self.test2_toolbar.addAction(self.action_table[objects + 1])

    def test2_remove_action(self):
        objects = len(self.test2_toolbar.actions())
        self.test2_toolbar.removeAction(self.action_table[objects])

app = QApplication(sys.argv)
win = MainWindow()
sys.exit(app.exec_())

Upvotes: 1

Related Questions