如何添加自定义部件(带布局)重叠在另一个自定义部件(带布局)上 pyqt

1 人关注

我需要添加两个标签,重叠2个QPushButton。如果用户点击右边的标签,他们就点击右边的按钮,如果他们点击左边的标签,他们就点击左边的。

我希望能有这样的东西。

其目的是为了节省显示数据的空间。

为了做到这一点,我创建了一个继承自QWidget的类,它有一个Boxlayout和两个按钮。

class DoublePushButton(QWidget):
    clicked = Signal(int)
    def __init__(self, **kargs) -> None:
        super().__init__(**kargs)
        self.data_to_display = 0
        self.right_button = QPushButton()
        self.right_button.pressed.connect(self.rightF)
        self.left_button = QPushButton()
        self.left_button.pressed.connect(self.leftF)
        self.button_layout = QHBoxLayout()
        self.button_layout.setContentsMargins(0,0,0,0)
        self.button_layout.setSpacing(0)
        buttons = [self.left_button,self.right_button]
        for i in buttons:
            self.setButtonParam(i)
            self.button_layout.addWidget(i)
        self.setLayout(self.button_layout)
    def setButtonParam(self, button):
        button.setFlat(True)
        button.setMinimumSize(30,120)
        button.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
    def rightF(self):
        self.clicked.emit(1)
    def leftF(self):
        self.clicked.emit(-1)

然后我在VBoxLaout中创建2个标签。

class TitleData(QWidget):
    def __init__(self,title="Title", data="Data", **kwargs):
        super().__init__(**kwargs)
        self.title = title
        self.data = data
        self.title_label = QLabel(self.title)
        self.data_label = QLabel(self.data)
        self.title_label.setAttribute(Qt.WA_NoSystemBackground)
        self.title_label.setAttribute(Qt.WA_TransparentForMouseEvents)
        self.data_label.setAttribute(Qt.WA_NoSystemBackground)
        self.data_label.setAttribute(Qt.WA_TransparentForMouseEvents)
        self.l = QVBoxLayout(self.parent())
        self.l.addWidget(self.title_label)
        self.l.addWidget(self.data_label)
        self.setLayout(self.l)

当我试图像这样把title_data重叠在DoublePushButton上。

class DataDisplay(QWidget):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.sub_widget = DoublePushButton()
        self.sub_widget.clicked.connect(self.update_data_choice)
        self.xxx = TitleData(parent=self.sub_widget)
        self.l = QVBoxLayout()
        self.l.addWidget(self.sub_widget)
        self.l.setContentsMargins(0,0,0,0)
        self.l.setSpacing(0)
        self.setLayout(self.l)
    def update_data_choice(self, value):
        print(value)
if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    window = QMainWindow()
    window.setCentralWidget(DataDisplay())
    window.show()
    sys.exit(app.exec_())

我得到这个错误。 QLayout:试图将QLayout "" 添加到DoublePushButton "",它已经有一个布局。

而标签仍然是隐形的。

当我试图将DoublePushbutton封装在一个QFrame中的时候,在init的DoublePushButton类的代码(代替self.setLayout(self.button_layout))。

self.f = QFrame(self.parent())
self.f.setLayout(self.button_layout)

出现标签,但没有按钮...

那么,你知道有什么方法可以让我的TitleData类与DoublePushButton重叠吗?

谢谢你的时间,并对我的英语感到抱歉。

2 个评论
对不起,但你的整个概念似乎令人难以置信和不必要的曲折。我不太清楚你说的 "上面 "是否是指 纵向 (y轴)或 叠加 (Z轴)。此外,一个布局管理器需要 complete 你不能有两个或更多的布局来管理同一个小组件,你必须控制它所设置的小组件(以及它的孩子的几何形状)。DoublePushButton已经有了它的水平布局,你期望通过设置 另一个 在TitleData中对其进行布局?我建议你 edit 你的问题,并澄清所有这些,可能会有一个预期结果的图像。
@musicamante ,我实际上是指重叠。我按照你的建议编辑了这个帖子,并附上了预期结果的图片。 我明白,我不能为同一个部件有两个布局。我试图做的是让两个布局在同一个地方相互重叠在一起。
python
layout
pyqt
pyside2
edwin
edwin
发布于 2022-01-08
1 个回答
musicamante
musicamante
发布于 2022-01-08
已采纳
0 人赞同

主要问题是,一个小部件只能有 one 布局管理器,而且如果已经存在一个布局,就不可能再设置另一个布局。它还应该 not 是一个子部件的责任,在父部件上设置布局。

另一个重要的方面是,盒式布局不允许重叠的小部件,所以唯一的解决办法是使用网格布局,并根据重叠的小部件应该如何放置来指定跨度。

考虑到上述情况,有两种可能性:在包含按钮的部件上使用网格布局,并在其上面添加标签,或者用另一种方式。在下面的例子中,我采用了后者。请注意,在这种情况下,带有标签的小组件会 not 是孩子,而是父母。

class TitleData(QWidget):
    def __init__(self,title="Title", data="Data", buttons=None, **kwargs):
        super().__init__(**kwargs)
        self.title = title
        self.data = data
        self.title_label = QLabel(self.title)
        self.data_label = QLabel(self.data)
        for label in self.title_label, self.data_label:
            label.setAttribute(Qt.WA_NoSystemBackground)
            label.setAttribute(Qt.WA_TransparentForMouseEvents)
            label.setAlignment(Qt.AlignHCenter)
        self.l = QGridLayout(self)
        self.l.addWidget(self.title_label, 0, 0, alignment=Qt.AlignTop)
        self.l.addWidget(self.data_label, 1, 0)
        self.l.setRowStretch(1, 1)
        if buttons:
            self.l.addWidget(buttons, 0, 0, 2, 1)
            buttons.lower()
class DataDisplay(QWidget):
    def __init__(self, **kwargs):
        # ...
        self.xxx = TitleData(buttons=self.sub_widget)
        self.l = QVBoxLayout()
        self.l.addWidget(self.xxx)
        # ...

请注意,按钮小部件是lowered以确保它被放在标签后面。

请考虑这种方法从用户体验的角度来看并不是很好,至少在目前的实现中是这样的:按钮可以保持一个焦点矩形,即使它们是平的,这可能会使标签难以阅读(想象一下有垂直线的字母,或者可以变成不同的字母with竖线,如 "o "变成 "d "或 "b")。为此创建两个类也是不必要的,因为你可以用一个简单的类来做同样的事情,而且你最终可以使用样式表来提高可读性。

class TitleDataButton(QWidget):
    clicked = pyqtSignal(int)
    def __init__(self, title='Title', data='Data', buttons=True, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.title = title
        self.data = data
        self.title_label = QLabel(self.title)
        self.data_label = QLabel(self.data)
        for label in self.title_label, self.data_label:
            label.setAttribute(Qt.WA_NoSystemBackground)
            label.setAttribute(Qt.WA_TransparentForMouseEvents)
            label.setAlignment(Qt.AlignHCenter)
        layout = QGridLayout(self)
        layout.addWidget(self.title_label, 0, 0, 1, 2, alignment=Qt.AlignTop)
        layout.addWidget(self.data_label, 1, 0, 1, 2)
        layout.setRowStretch(1, 1)
        if buttons:
            self.right_button = QPushButton()
            self.right_button.pressed.connect(self.rightF)
            self.left_button = QPushButton()
            self.left_button.pressed.connect(self.leftF)
            for c, button in enumerate((self.left_button, self.right_button)):
                layout.addWidget(button, 0, c, 2, 1)
                button.setMinimumSize(30,120)
                button.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
                button.lower()
                button.setFocusPolicy(Qt.NoFocus)
                button.setStyleSheet('''
                    QPushButton {
                        border: 1px solid transparent;
                        border-radius: 2px;
                    QPushButton:hover {
                        border-color: darkGray;
                        background: lightGray;
                    QPushButton:pressed {
                        background: darkGray;
    def rightF(self):
        self.clicked.emit(1)