【问题标题】:PyQt5 Image and QGridlayoutPyQt5 图像和 QGridlayout
【发布时间】:2019-03-08 01:33:48
【问题描述】:

我有一个小部件,它想显示带有QLabelQCheckBox 的图像。创建了 4 个类,每个类都包含一些要放在最终屏幕上的信息。 Class Grid 对齐和网格图像、文本和复选框。

脚本运行后获取当前屏幕。当前小部件中没有图像。

图片在哪里?

想要的画面

代码

import sys, os
from PyQt5 import QtCore, QtGui, QtWidgets

iconroot = os.path.dirname(__file__)

class ImageWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(ImageWidget, self).__init__(parent)

        self.hlay = QtWidgets.QHBoxLayout(self)
        buckling_ilabel = QtWidgets.QLabel(self)
        pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/fixed-fixed.png"))
        buckling_ilabel.resize(150, 150)
        buckling_ilabel.setPixmap(pixmap.scaled(buckling_ilabel.size(), QtCore.Qt.KeepAspectRatio))
        self.hlay.addWidget(buckling_ilabel)

        buckling_blabel = QtWidgets.QLabel(self)
        pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/pinned-pinned.png"))
        buckling_blabel.resize(150, 150)
        buckling_blabel.setPixmap(pixmap.scaled(buckling_blabel.size(), QtCore.Qt.KeepAspectRatio))
        self.hlay.addWidget(buckling_blabel)

        buckling_clabel = QtWidgets.QLabel(self)
        pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/fixed-free.png"))
        buckling_clabel.resize(150, 150)
        buckling_clabel.setPixmap(pixmap.scaled(buckling_clabel.size(), QtCore.Qt.KeepAspectRatio))
        self.hlay.addWidget(buckling_clabel)

        buckling_dlabel = QtWidgets.QLabel(self)
        pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/fixed-pinned.png"))
        buckling_dlabel.resize(150, 150)
        buckling_dlabel.setPixmap(pixmap.scaled(buckling_dlabel.size(), QtCore.Qt.KeepAspectRatio))
        self.hlay.addWidget(buckling_dlabel)
        self.setLayout(self.hlay)



class EffLengthInfo(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(EffLengthInfo, self).__init__(parent)

        ilabel = QtWidgets.QLabel('Ley = 1.0 L\nLec = 1.0 L')
        blabel = QtWidgets.QLabel('Ley = 0.699 L\nLec = 0.699 L')
        clabel = QtWidgets.QLabel('Ley = 2.0 L\nLec = 2.0 L')   
        dlabel = QtWidgets.QLabel('Ley = 0.5 L\nLec = 0.5 L')

        self.ilay = QtWidgets.QHBoxLayout()
        self.ilay.addWidget(ilabel)
        self.ilay.addWidget(blabel)
        self.ilay.addWidget(clabel)
        self.ilay.addWidget(dlabel)


class CheckInfo(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(CheckInfo, self).__init__(parent)

        icheck = QtWidgets.QCheckBox()
        bcheck = QtWidgets.QCheckBox()
        ccheck = QtWidgets.QCheckBox()
        dcheck = QtWidgets.QCheckBox()

        self.checklay = QtWidgets.QHBoxLayout()
        self.checklay.addWidget(icheck, alignment=QtCore.Qt.AlignCenter)
        self.checklay.addWidget(bcheck, alignment=QtCore.Qt.AlignCenter)
        self.checklay.addWidget(ccheck, alignment=QtCore.Qt.AlignCenter)
        self.checklay.addWidget(dcheck, alignment=QtCore.Qt.AlignCenter)



class Grid(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Grid, self).__init__(parent)

        self.imagewidget = ImageWidget()
        self.efflengthinfo = EffLengthInfo()
        self.checkinfo = CheckInfo()

        vlay = QtWidgets.QVBoxLayout(self)
        vlay.addLayout(self.imagewidget.hlay)
        vlay.addLayout(self.efflengthinfo.ilay)
        vlay.addLayout(self.checkinfo.checklay)
        self.setLayout(vlay)



if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    im = Grid()
    im.show()
    sys.exit(app.exec_())

【问题讨论】:

    标签: python python-3.x pyqt pyqt5 qlabel


    【解决方案1】:

    线路:vlay.addLayout (self.imagewidget.hlay)

    错误是:QLayout :: addChildLayout: layout "" already has a parent

    试试看:

    import sys, os
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    iconroot = os.path.dirname(__file__)
    
    class ImageWidget(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(ImageWidget, self).__init__(parent)
    
    #        self.hlay = QtWidgets.QHBoxLayout(self)
            self.hlay = QtWidgets.QHBoxLayout()                       # < --- -self
            buckling_ilabel = QtWidgets.QLabel(self)
            pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/logo.png"))
            buckling_ilabel.resize(150, 150)
            buckling_ilabel.setPixmap(pixmap.scaled(buckling_ilabel.size(), QtCore.Qt.KeepAspectRatio))
            self.hlay.addWidget(buckling_ilabel)
    
            buckling_blabel = QtWidgets.QLabel(self)
            pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/logo.png"))
            buckling_blabel.resize(150, 150)
            buckling_blabel.setPixmap(pixmap.scaled(buckling_blabel.size(), QtCore.Qt.KeepAspectRatio))
            self.hlay.addWidget(buckling_blabel)
    
            buckling_clabel = QtWidgets.QLabel(self)
            pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/logo.png"))
            buckling_clabel.resize(150, 150)
            buckling_clabel.setPixmap(pixmap.scaled(buckling_clabel.size(), QtCore.Qt.KeepAspectRatio))
            self.hlay.addWidget(buckling_clabel)
    
            buckling_dlabel = QtWidgets.QLabel(self)
            pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/logo.png"))
            buckling_dlabel.resize(150, 150)
            buckling_dlabel.setPixmap(pixmap.scaled(buckling_dlabel.size(), QtCore.Qt.KeepAspectRatio))
            self.hlay.addWidget(buckling_dlabel)
    
    #        self.setLayout(self.hlay)                                  # < ---
    
    
    
    
    class EffLengthInfo(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(EffLengthInfo, self).__init__(parent)
    
            ilabel = QtWidgets.QLabel('Ley = 1.0 L\nLec = 1.0 L')
            blabel = QtWidgets.QLabel('Ley = 0.699 L\nLec = 0.699 L')
            clabel = QtWidgets.QLabel('Ley = 2.0 L\nLec = 2.0 L')   
            dlabel = QtWidgets.QLabel('Ley = 0.5 L\nLec = 0.5 L')
    
            self.ilay = QtWidgets.QHBoxLayout()
            self.ilay.addWidget(ilabel)
            self.ilay.addWidget(blabel)
            self.ilay.addWidget(clabel)
            self.ilay.addWidget(dlabel)
    
    
    class CheckInfo(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(CheckInfo, self).__init__(parent)
    
            icheck = QtWidgets.QCheckBox()
            bcheck = QtWidgets.QCheckBox()
            ccheck = QtWidgets.QCheckBox()
            dcheck = QtWidgets.QCheckBox()
    
            self.checklay = QtWidgets.QHBoxLayout()
            self.checklay.addWidget(icheck, alignment=QtCore.Qt.AlignCenter)
            self.checklay.addWidget(bcheck, alignment=QtCore.Qt.AlignCenter)
            self.checklay.addWidget(ccheck, alignment=QtCore.Qt.AlignCenter)
            self.checklay.addWidget(dcheck, alignment=QtCore.Qt.AlignCenter)
    
    
    
    class Grid(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(Grid, self).__init__(parent)
    
            self.imagewidget   = ImageWidget()
            self.efflengthinfo = EffLengthInfo()
            self.checkinfo     = CheckInfo()
    
            vlay = QtWidgets.QVBoxLayout(self) 
    
            vlay.addLayout(self.imagewidget.hlay)                            # < ---
            # Error: QLayout::addChildLayout: layout "" already has a parent # < ---
    
            vlay.addLayout(self.efflengthinfo.ilay)
            vlay.addLayout(self.checkinfo.checklay)
            self.setLayout(vlay)
    
    
    
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
        im = Grid()
        im.show()
        sys.exit(app.exec_())
    

    【讨论】:

    • 感谢您的回复和帮助。我还没有测试更正的代码,当我不在电脑附近时,我会稍后回复,看来你的代码可以与类一起使用。
    【解决方案2】:

    The @S.Nick's solution 有效,但它不是正确的,除了它没有解释问题,它只指示您应该提供的错误消息。

    你的第一个错误是你没有一致的设计,例如,即使一个小部件是一个视觉元素,它不仅意味着它是唯一的,它还有相关的数据,所以我问自己: 你为什么要创建ImageWidget 类,同样的事情?对于EffLengthInfoCheckInfo?好吧,似乎只是为了创建一个布局,是否有必要创建一个小部件来创建一个布局?不,因为小部件是不必要的资源,即浪费内存。因此,我指出S.Nick's solution是不正确的,因为他是在邀请其他人重叠设计错误。

    如果您的目标只是创建布局,那么最好使用函数:

    import sys, os
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    iconroot = os.path.dirname(__file__)
    
    def create_image_layout():
            hlay = QtWidgets.QHBoxLayout()
            for icon_name in ("images/fixed-fixed.png", 
                              "images/pinned-pinned.png",
                              "images/fixed-free.png",
                              "images/fixed-pinned.png"):
    
                label = QtWidgets.QLabel()
                pixmap = QtGui.QPixmap(os.path.join(iconroot, icon_name))
                label.resize(150, 150)
                label.setPixmap(pixmap.scaled(label.size(), QtCore.Qt.KeepAspectRatio))
                hlay.addWidget(label)
            return hlay
    
    def create_EffLengthInfo_layout():
        hlay = QtWidgets.QHBoxLayout()
        for text in ('Ley = 1.0 L\nLec = 1.0 L',
                     'Ley = 0.699 L\nLec = 0.699 L',
                     'Ley = 2.0 L\nLec = 2.0 L',
                     'Ley = 0.5 L\nLec = 0.5 L'):
            label = QtWidgets.QLabel(text)
            hlay.addWidget(label)
        return hlay
    
    def create_checkInfo_layout():
        hlay = QtWidgets.QHBoxLayout()
        for _ in range(3):
            checkbox = QtWidgets.QCheckBox()
            hlay.addWidget(checkbox, alignment=QtCore.Qt.AlignCenter)
        return hlay
    
    class Grid(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(Grid, self).__init__(parent)
    
            image_lay = create_image_layout()
            efflengthinfo_lay = create_EffLengthInfo_layout()
            checkinfo_lay = create_checkInfo_layout()
    
            vlay = QtWidgets.QVBoxLayout(self)
            vlay.addLayout(image_lay)
            vlay.addLayout(efflengthinfo_lay)
            vlay.addLayout(checkinfo_lay)
    
    
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
        im = Grid()
        im.show()
        sys.exit(app.exec_())
    

    为什么在 EffLengthInfo 和 CheckInfo “有效”的情况下显示?

    我指出它在引号中起作用,因为它起作用但它不是解决方案,直截了当,布局是在布局中建立的,它是小部件的一部分,之后它不能放在另一个中小部件,如果我们检查ImageWidget,我们会看到您已经为小部件建立了两次布局:

    class ImageWidget(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(ImageWidget, self).__init__(parent)
    
            self.hlay = QtWidgets.QHBoxLayout(self) # 1.
            ...
            self.setLayout(self.hlay) # 2.
    
    1. 当您在构建布局时设置小部件时,它会在该小部件中设置。

    2. 当小部件使用setLayout()方法设置布局时

    因此,您应该在vlay.addLayout(self.imagewidget.hlay) 行中抛出以下错误:

    QLayout::addChildLayout: layout "" 已经有一个父级

    另一种解决方案是设置小部件而不是布局:

    class ImageWidget(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(ImageWidget, self).__init__(parent)
            self.hlay = QtWidgets.QHBoxLayout(self)
            ...
            # self.setLayout(self.hlay) # comment this line
    
    class EffLengthInfo(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(EffLengthInfo, self).__init__(parent)
            ...
            self.ilay = QtWidgets.QHBoxLayout(self) # <-- add self
    
    class CheckInfo(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(CheckInfo, self).__init__(parent)
            ...
            self.checklay = QtWidgets.QHBoxLayout(self)  # <-- add self
    
    class Grid(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(Grid, self).__init__(parent)
            self.imagewidget = ImageWidget()
            self.efflengthinfo = EffLengthInfo()
            self.checkinfo = CheckInfo()
    
            vlay = QtWidgets.QVBoxLayout(self)
            vlay.addWidget(self.imagewidget)  # <-- change addLayout() to addWidget()
            vlay.addWidget(self.efflengthinfo) # <-- change addLayout() to addWidget()
            vlay.addWidget(self.checkinfo) # <-- change addLayout() to addWidget()
            ...
    

    您可能会想到的另一种观点,这取决于您要赋予小部件的用途,即您希望信息单元是图像、文本和复选框,因此如果创建小部件是正确的:

    import sys, os
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    iconroot = os.path.dirname(__file__)
    
    
    class FooWidget(QtWidgets.QWidget):
        def __init__(self, path_icon, text, checked=False, parent=None):
            super(FooWidget, self).__init__(parent)
            lay = QtWidgets.QVBoxLayout(self)
    
            pixmap = QtGui.QPixmap(os.path.join(iconroot, path_icon))
            pixmap_label = QtWidgets.QLabel()
            pixmap_label.resize(150, 150)
            pixmap_label.setPixmap(pixmap.scaled(pixmap_label.size(), QtCore.Qt.KeepAspectRatio))
    
            text_label = QtWidgets.QLabel(text)
            checkbox = QtWidgets.QCheckBox(checked=checked)
    
            lay.addWidget(pixmap_label)
            lay.addWidget(text_label)
            lay.addWidget(checkbox)
    
    
    class Grid(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(Grid, self).__init__(parent)
    
            lay = QtWidgets.QHBoxLayout(self)
    
            icons = ["images/fixed-fixed.png", 
                     "images/pinned-pinned.png",
                     "images/fixed-free.png",
                     "images/fixed-pinned.png"]
    
            texts = ["Ley = 1.0 L\nLec = 1.0 L",
                     "Ley = 0.699 L\nLec = 0.699 L",
                     "Ley = 2.0 L\nLec = 2.0 L",
                     "Ley = 0.5 L\nLec = 0.5 L"]
    
            for path_icon, text in zip(icons, texts):
                w = FooWidget(os.path.join(iconroot, path_icon), text)
                lay.addWidget(w)
    
    
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
        im = Grid()
        im.show()
        sys.exit(app.exec_())
    

    【讨论】:

    • 非常感谢。你在类和函数方面的方式很棒。我记住了, addLayout 和 addWidget 之间有什么区别,但您的解释有助于理解。我还没有调试代码,我不在电脑附近。我稍后会回来。
    • @ZarKha 布局不是可视元素,它是一个允许建立位置和大小的类,而小部件是可视元素。布局处理项目,这些项目可以是小部件或其他布局,也就是说,它们最终用于建立某种几何图形。
    • @ZarKha [继续] 有一个小部件只是为了创建在另一个小部件中建立的布局是没有意义的,因为小部件永远不会显示它,因此它永远不会有用编程它意味着花费内存和时间。如果你有 Qt Designer,你会看到这些元素是用线条表示的,但是当它们被执行时,它们不会显示出来,线条是一种表示,以便您的组织易于理解
    • 谢谢。现在我已经运行了代码,它没有任何符号。我的理解布局和小部件正在扩展。非常棒的反馈。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-12
    • 2022-11-01
    • 2021-12-21
    • 1970-01-01
    • 1970-01-01
    • 2022-01-21
    • 1970-01-01
    相关资源
    最近更新 更多