Search code examples
pythonoopinheritancepyqtpyqt4

PyQt4 Adding a custom widget derived from another custom widget to layout


I'm trying to build a widget structure which will have a base widget which is derived from QtGui.QWidget, then I'll put the base features I want in every widget I create. Once the base widget is done, i'll create other types of widgets derived from the base widget.

here is an example

class TurquoiseWidget(QtGui.QWidget):
    def __init__(self, title="Widget", enable_title=False, font_size=9):
        super(TurquoiseWidget, self).__init__()
        self.setFixedSize(self.minimumSize())
        self.widget_area = QtGui.QFrame()
        self.widget_area.setFrameShape(QtGui.QFrame.Box)
        self.widget_area.setFrameShadow(QtGui.QFrame.Sunken)

        title_lbl = QtGui.QLabel(title)
        font = title_lbl.font()
        font = QtGui.QFont()
        # font.setFamily("Quicksand")
        font.setPointSize(font_size)
        title_lbl.setFont(font)
        title_lyt = QtGui.QHBoxLayout()
        title_lyt.setAlignment(QtCore.Qt.AlignCenter)
        title_lyt.addWidget(title_lbl)


        main_lyt = QtGui.QVBoxLayout()
        main_lyt.setAlignment(QtCore.Qt.AlignTop)
        if enable_title:
            main_lyt.addLayout(title_lyt)
        main_lyt.addWidget(self.widget_area)
        self.setLayout(main_lyt)



class ArmControlWidget(TurquoiseWidget):
    def __init__(self):
        super(ArmControlWidget, self).__init__()
        self.arm_button = QtGui.QPushButton("Arm")
        self.disarm_button = QtGui.QPushButton("Disarm")
        self.arm_button.clicked.connect(lambda: self.Arm(True))
        self.disarm_button.clicked.connect(lambda: self.Arm(False))
        self.srv = rospy.ServiceProxy("/mavros/cmd/arming", CommandBool)

        lyt = QtGui.QHBoxLayout()
        lyt.setAlignment(QtCore.Qt.AlignRight)
        lyt.addWidget(self.disarm_button)
        lyt.addWidget(self.arm_button)
        self.widget_area.setLayout(lyt)

    def Arm(self, arm):
        srv_msg = CommandBoolRequest()
        srv_msg.value = arm
        print self.srv(srv_msg)




class StatusToolbar(TurquoiseWidget):
    """docstring for StatusToolbar."""
    def __init__(self):
        super(StatusToolbar, self).__init__()
        self.lyt = QtGui.QGridLayout()
        self.a = ArmControlWidget()
        self.lyt.addWidget(self.a)
        # self.lyt.addWidget(ArmControlWidget())
        self.widget_area.setLayout(self.lyt)

In this case the TurquoiseWidget is the base widget (every base widget has a frame and a title label in it.), ArmControlWidget is a widget performs spesific task and the StatusToolbar is the toolbar object, which has a set of widgets inside of it that derives from TurquoiseWidget or base widget.

So when I just do some_widget = ArmControlWidget() some_widget.show() it works perfectly. But when I create this widget inside of toolbar widget and display it in there, nothing shows.

Sorry if I'm not clear. Thanks in advance!


Solution

  • What is the minimum size of a widget that has no children? You can be very small and when you set it as a fixed size the widget will have a small size even if you have other widgets or layouts. So the solution is to remove the line self.setFixedSize(self.minimumSize()) and add to the end of the constructor of the StatusToolbar self.setFixedSize(self.sizeHint()).

    class TurquoiseWidget(QtGui.QWidget):
        def __init__(self, title="Widget", enable_title=False, font_size=9):
            super(TurquoiseWidget, self).__init__()
            # self.setFixedSize(self.minimumSize()) delete this line
            self.widget_area = QtGui.QFrame()
            # ...
    
    # ...
    
    class StatusToolbar(TurquoiseWidget):
        """docstring for StatusToolbar."""
        def __init__(self):
            super(StatusToolbar, self).__init__()
            self.lyt = QtGui.QGridLayout()
            self.a = ArmControlWidget()
            self.lyt.addWidget(self.a)
            self.widget_area.setLayout(self.lyt)
            self.setFixedSize(self.sizeHint()) # add this line