Search code examples
pythonpysidemayapyside2

Add widgets inside pushButton?


Hi I’m still relatively new to PySide2 and setting up some UIs inside maya . Is it possible to have a QPushButton which has other widgets as children ?

For instance I want to make a pair of QPushButtona side by side that turn each other toggled on and off when either is clicked , each should have a spinBox inside them . The spinBox is disabled if it’s parent button is ‘off’

I was going to make a simple button class which can toggle it’s counterpart off , so that bit is straightforward , but I can’t see a way to put the spinBox inside it too, maybe something I’ve missed ? Can I add a layout to my button then add widgets inside ?

Thanks for any help

Ben


Solution

  • Wondering to see if it was possible, and it looks like yes, you can use a button and nest another widget in it. I thought you would have to jump through a lot more hoops to get it working properly, but it's not too bad.

    You can make the buttons checkable, then use a QButtonGroup to make the buttons behave like a QRadioButton. Though unlike a QGroupBox you need to handle the enabled state of the spin box yourself. So here's a working example:

    from PySide2 import QtCore
    from PySide2 import QtGui
    from PySide2 import QtWidgets
    
    
    class ButtonContainer(QtWidgets.QPushButton):
    
        def __init__(self, parent=None):
            super(ButtonContainer, self).__init__(parent)
    
            self.setMinimumHeight(50)  # Set minimum otherwise it will collapse the container
            self.setCheckable(True)
    
            self.setStyleSheet("""
                QPushButton {
                    background-color: rgb(50, 50, 50);
                    border: none;
                }
    
                QPushButton:checked {
                    background-color: green;
                }
            """)
    
    
    class Win(QtWidgets.QWidget):
    
        def __init__(self, parent=None):
            super(Win, self).__init__(parent)
            self.resize(300, 0)
    
            # 1st groupbox and spinbox.
            self.container_layout1 = QtWidgets.QVBoxLayout()
    
            self.container1 = ButtonContainer()
            self.container1.setChecked(True)
            self.container1.setLayout(self.container_layout1)
            self.container1.clicked.connect(self.on_container_clicked)
    
            self.spinbox1 = QtWidgets.QSpinBox(parent=self.container1)  # Set the container as its parent so that we can use `findChildren` in the event later.
            self.container_layout1.addWidget(self.spinbox1)
    
            # 2nd groupbox and spinbox.
            self.container_layout2 = QtWidgets.QVBoxLayout()
    
            self.container2 = ButtonContainer()
            self.container2.setLayout(self.container_layout2)
            self.container2.clicked.connect(self.on_container_clicked)
    
            self.spinbox2 = QtWidgets.QSpinBox(parent=self.container2)  # Set the container as its parent so that we can use `findChildren` in the event later.
            self.container_layout2.addWidget(self.spinbox2)
    
            # Group buttons together so they behave as radio buttons.
            self.button_group = QtWidgets.QButtonGroup()
            self.button_group.addButton(self.container1)
            self.button_group.addButton(self.container2)
    
            self.main_layout = QtWidgets.QHBoxLayout()
            self.main_layout.addWidget(self.container1)
            self.main_layout.addWidget(self.container2)
            self.setLayout(self.main_layout)
    
            # Trigger event to set initial enabled states.
            self.on_container_clicked()
    
        def on_container_clicked(self):
            for container in [self.container1, self.container2]:  # Loop through all of our custom containers.
                for child in container.findChildren(QtWidgets.QWidget):  # Get all of the container's children.
                    child.setEnabled(container.isChecked())  # Set its enabled state based if the container is checked.
    
    
    win = Win()
    win.show()
    

    You technically don't really need to subclass the QPushButton though it makes it easier to recycle the code.

    Example