Почему виджет с заказной картиной не виден? - PullRequest
0 голосов
/ 29 октября 2018

Поэтому я пытаюсь создать простое приложение 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)

There is no colored rectangle on this

Я использую Python3.7 в macOS 10.13.5.

Ответы [ 2 ]

0 голосов
/ 29 октября 2018

Причина

Когда вы добавляете QLabel к макету, его политика размера устанавливается по умолчанию на QSizePolicy.Policy(Preferred) и занимает все пространство, не оставляя места для вашего виджета SimulatedFieldMap. По сути, ваш пользовательский виджет есть, но его высота равна 0, поэтому он не виден.

Soultion

Одним из решений было бы ограничение высоты метки путем установки ее на фиксированное значение, например 14. Для этого после label = QLabel('Map') добавьте label.setFixedHeight(14).

Результат

Вот результат этого решения:

Window with a label, violet rectangle and input widgets.

Примечание: В демонстрационных целях я вручную переместил левый вертикальный сплиттер вниз.

0 голосов
/ 29 октября 2018

Когда виджет нарисован, используются внутренние координаты, но 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)    
# ------

enter image description here

Обновление: Проблема вызвана вертикальной размерной политикой QLabel, которая расширяет 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)
# ------

enter image description here

...