繁体   English   中英

为什么带有自定义绘画的小部件不可见?

[英]Why is the widget with a custom painting not visible?

因此,我尝试使用自定义窗口小部件构建一个简单的PyQt应用程序。 但是,画家不画任何东西。 如果我注释掉第44-45行( label = QLabel('Map');box.addWidget(label) ),我会看到一个大彩色矩形。 但是,当我尝试在矩形上方添加标签时,该矩形不再显示。

我想我可能使用的画家错误,但是我不确定。

我是PyQt的新手,对我的编码风格或逻辑的任何评论也将不胜感激。

from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPainter, QColor
from PyQt5.QtWidgets import (QMainWindow,
                               QWidget,
                               QFrame,
                               QDesktopWidget,
                               QGridLayout,
                               QLabel,
                               QTextEdit,
                               QSplitter,
                               QVBoxLayout,
                               QApplication)


class Simulator(QMainWindow):
    def __init__(self):
        super().__init__()

        self.stdout = QTextEdit()
        self.stderr = QTextEdit()
        self.exec = QTextEdit()

        self.frame = QFrame()
        self.setCentralWidget(self.frame)
        self.screen = QDesktopWidget().screenGeometry()
        self.setGeometry(self.screen)
        self.grid = QGridLayout()
        self.frame.setLayout(self.grid)
        self.map = SimulatedFieldMap()

        # -- setting splitters
        splitter_r = QSplitter(Qt.Vertical)
        splitter_l = QSplitter(Qt.Vertical)
        splitter_h = QSplitter(Qt.Horizontal)
        splitter_h.addWidget(splitter_l)
        splitter_h.addWidget(splitter_r)
        # --------------

        # -- top left --
        frame = QFrame()
        box = QVBoxLayout()
        frame.setLayout(box)
        splitter_l.addWidget(frame)
        label = QLabel('Map')
        box.addWidget(label)
        box.addWidget(self.map)
        # ------

        # -- bottom left --
        box = QVBoxLayout()
        frame = QFrame()
        frame.setLayout(box)
        box.addWidget(QLabel('Exec'))
        box.addWidget(self.exec)
        splitter_l.addWidget(frame)
        # -------

        # -- top right --
        box = QVBoxLayout()
        frame = QFrame()
        frame.setLayout(box)
        splitter_r.addWidget(frame)
        box.addWidget(QLabel('STDOUT'))
        box.addWidget(self.stdout)
        # -------

        # -- bottom right --
        box = QVBoxLayout()
        frame = QFrame()
        frame.setLayout(box)
        splitter_r.addWidget(frame)
        box.addWidget(QLabel('STDERR'))
        box.addWidget(self.stderr)
        # -------

        self.grid.addWidget(splitter_h, 0, 0)
        splitter_h.setSizes((self.screen.width() * 0.7, self.screen.width() * 0.3))
        splitter_l.setSizes((self.screen.height() * 0.7, self.screen.height() * 0.3))
        splitter_r.setSizes((self.screen.height() * 0.7, self.screen.height() * 0.3))


class SimulatedFieldMap(QWidget):
    def __init__(self):
        super().__init__()

    def paintEvent(self, event):
        qp = QPainter()
        qp.begin(self)
        self.paintMap(qp)
        qp.end()

    def paintMap(self, qp):
        qp.setBrush(QColor(200, 162, 200))  # lilac
        qp.setPen(QColor(200, 162, 200))
        geo = self.geometry()
        qp.drawRect(geo)


if __name__ == '__main__':
    app = QApplication([])
    app.setStyle('Fusion')
    sim = Simulator()
    sim.show()
    status = app.exec_()
    exit(status)

这个没有彩色矩形

我在macOS 10.13.5上使用Python3.7。

绘制窗口小部件时,将使用内部坐标,但是geometry()是相对于父级的坐标,因此您不应使用它,而应使用rect()

from PyQt5 import QtCore, QtGui, QtWidgets


class Simulator(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        self.stdout = QtWidgets.QTextEdit()
        self.stderr = QtWidgets.QTextEdit()
        self.exec = QtWidgets.QTextEdit()

        self.frame = QtWidgets.QFrame()
        self.setCentralWidget(self.frame)

        self.grid = QtWidgets.QGridLayout(self.frame)
        self.map = SimulatedFieldMap()

        # -- setting splitters
        splitter_r = QtWidgets.QSplitter(QtCore.Qt.Vertical)
        splitter_l = QtWidgets.QSplitter(QtCore.Qt.Vertical)
        splitter_h = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
        splitter_h.addWidget(splitter_l)
        splitter_h.addWidget(splitter_r)
        # --------------

        # -- top left --
        frame = QtWidgets.QFrame()
        box = QtWidgets.QVBoxLayout(frame)
        splitter_l.addWidget(frame)
        label = QtWidgets.QLabel('Map')
        box.addWidget(label)
        box.addWidget(self.map)
        # ------

        # -- bottom left --
        frame = QtWidgets.QFrame()
        box = QtWidgets.QVBoxLayout(frame)
        box.addWidget(QtWidgets.QLabel('Exec'))
        box.addWidget(self.exec)
        splitter_l.addWidget(frame)
        # -------

        # -- top right --
        frame = QtWidgets.QFrame()
        box = QtWidgets.QVBoxLayout(frame)
        splitter_r.addWidget(frame)
        box.addWidget(QtWidgets.QLabel('STDOUT'))
        box.addWidget(self.stdout)
        # -------

        # -- bottom right --
        frame = QtWidgets.QFrame()
        box = QtWidgets.QVBoxLayout(frame)
        splitter_r.addWidget(frame)
        box.addWidget(QtWidgets.QLabel('STDERR'))
        box.addWidget(self.stderr)
        # -------

        screen = QtWidgets.QDesktopWidget().screenGeometry()

        self.grid.addWidget(splitter_h, 0, 0)
        splitter_h.setSizes((screen.width() * 0.7, screen.width() * 0.3))
        splitter_l.setSizes((screen.height() * 0.7, screen.height() * 0.3))
        splitter_r.setSizes((screen.height() * 0.7, screen.height() * 0.3))


class SimulatedFieldMap(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

    def paintEvent(self, event):
        qp = QtGui.QPainter(self)
        self.paintMap(qp)

    def paintMap(self, qp):
        qp.setBrush(QtGui.QColor(200, 162, 200))  # lilac
        qp.setPen(QtGui.QColor(200, 162, 200))
        qp.drawRect(self.rect())


if __name__ == '__main__':
    import sys

    app = QtWidgets.QApplication(sys.argv)
    app.setStyle('Fusion')
    sim = Simulator()
    sim.showMaximized()
    sys.exit(app.exec_())

更新:如果希望将其放置在某个位置,则不应将其放置在布局中,但标签必须是地图的子项,并使用move()相对于地图的左上角确定位置。

# -- top left --
frame = QtWidgets.QFrame()
box = QtWidgets.QVBoxLayout(frame)
box.addWidget(self.map)
splitter_l.addWidget(frame)
label = QtWidgets.QLabel('Map', self.map)
label.move(0, 100)    
# ------

在此处输入图片说明

更新:问题是由QLabel的垂直sizePolicy引起的,它是QSizePolicy::Preferred使其扩展,一个简单的解决方案是将其更改为QSizePolicy::Maximum ,因此根据字体计算正确的高度。

# -- top left --
frame = QtWidgets.QFrame()
box = QtWidgets.QVBoxLayout(frame)
splitter_l.addWidget(frame)
label = QtWidgets.QLabel('Map')
sp = label.sizePolicy()
sp.setVerticalPolicy(QtWidgets.QSizePolicy.Maximum)
label.setSizePolicy(sp)
box.addWidget(label)
box.addWidget(self.map)
# ------

在此处输入图片说明

原因

QLabel添加到布局时,默认情况下将其大小策略设置为QSizePolicy.Policy(Preferred) ,它将占用整个空间,而小部件SimulatedFieldMap则不留空间。 基本上,您的自定义窗口小部件在那里,但是其高度为0,因此不可见。

Soultion

一种解决方案是通过将标签设置为固定值(例如14来限制标签​​的高度。 为此,在label = QLabel('Map')添加label.setFixedHeight(14)

结果

这是此解决方案的结果:

带有标签,紫罗兰色矩形和输入小部件的窗口。

注意:出于演示目的,我手动向下移动了左侧垂直拆分器。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM