【问题标题】:PyQt: How to stretch the width and height of a QGraphicsView and QGraphicsScene widget?PyQt:如何拉伸 QGraphicsView 和 QGraphicsScene 小部件的宽度和高度?
【发布时间】:2020-05-18 19:20:26
【问题描述】:

我正在尝试创建一个延伸到窗口宽度和高度的网格小部件。网格的大小(当前为 14x49)可能会发生变化,但我希望小部件的整体大小保持不变。

代码:

import sys

from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QLayout, 
QGridLayout, QSizePolicy, QGraphicsScene, QGraphicsView
from PyQt5.QtCore import QCoreApplication, QSize, Qt, QRectF, QPointF, QSizeF
from PyQt5.QtGui import QColor, QPen, QBrush, qRgb

class Map(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.initUI()

    def initUI(self):
        self.setMinimumSize(500, 500) # min-size of the widget
        self.columns = 14 # num of columns in grid
        self.rows = 49 # num of rows in grid

    def resizeEvent(self, event):
        # compute the square size based on the aspect ratio, assuming that the
        reference = self.width() * self.rows / self.columns
        if reference > self.height():
            # the window is larger than the aspect ratio
            # use the height as a reference (minus 1 pixel)
            self.squareSize = (self.height() - 1) / self.rows
        else:
            # the opposite
            self.squareSize = (self.width() - 1) / self.columns

    def paintEvent(self, event):
        grid = QGridLayout()
        self.sceneWithPen(grid)
        self.setLayout(grid)

    # creates the grid of squares
    def sceneWithPen(self, grid):
        scene = QGraphicsScene()
        w = QGraphicsView()
        w.setScene(scene)
        side = self.squareSize
        brush = QBrush(QColor(qRgb(255, 255, 255))) # background color of square
        pen = QPen(Qt.black) # border color of square
        for i in range(self.rows):
            for j in range(self.columns):
                r = QRectF(QPointF(
                    i*side, j*side), QSizeF(side, side)) # each square 
                scene.addRect(r, pen, brush)
        grid.addWidget(w)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    view = Map()
    view.show()
    sys.exit(app.exec_())

我希望小部件看起来像什么:

【问题讨论】:

    标签: python pyqt5


    【解决方案1】:

    您的方法比它需要的复杂得多,并且存在各种问题(其中一些非常重要)。

    首先,不需要每次都计算正方形的大小,因为 QGraphicsView 可以通过使用fitInView() 来做到这一点,默认情况下会忽略纵横比。只需使用适合您需要的任意正方形大小即可。

    然后,您应该从不paintEvent 中创建和添加小部件,因为它可能会导致递归。

    一旦在一个小部件上设置了布局,就不应设置另一个布局,除非绝对必要(而且,无论如何,不​​应该那样做)。

    当使用addRect 向 graphicsScene 添加矩形时,通常不需要先创建 QRectF,因为您可以使用接受坐标和大小的便捷函数(无论如何,Qt 都会在 C++ 端自动创建 QRectF ,这可能会稍微快一些)。

    另一方面,由于您要创建多个相同大小的矩形,您可以只创建一个 QRectF,然后使用translated() 设置坐标。

    当它们是现有变量或常量时,通常建议使用 QPointF 和 QSizeF 创建 QRectF,否则您可以使用基本的 QRectF(x, y, width, height) 构造函数。

    class Map(QWidget):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.initUI()
    
        def initUI(self):
            self.setMinimumSize(500, 500) # min-size of the widget
            self.columns = 14 # num of columns in grid
            self.rows = 49 # num of rows in grid
    
            grid = QGridLayout(self)
            self.view = QGraphicsView()
            grid.addWidget(self.view)
            self.view.setRenderHints(QPainter.Antialiasing)
    
            self.scene = QGraphicsScene()
            self.view.setScene(self.scene)
    
            brush = QBrush(QColor(qRgb(255, 255, 255))) # background color of square
            pen = QPen(Qt.black) # border color of square
            side = 10
            rect = QRectF(0, 0, side, side)
            for i in range(self.rows):
                for j in range(self.columns):
                    self.scene.addRect(rect.translated(i * side, j * side), pen, brush)
    
            # this is required to ensure that fitInView works on first shown too
            self.resizeScene()
    
        def resizeScene(self):
            self.view.fitInView(self.scene.sceneRect())
    
        def resizeEvent(self, event):
            # call fitInView each time the widget is resized
            self.resizeScene()
    
        def showEvent(self, event):
            # call fitInView each time the widget is shown
            self.resizeScene()
    

    【讨论】:

    • 所以这段代码创建了一个白色背景的网格。假设我想从另一个类更改每个矩形的颜色,我需要包括什么来做到这一点?
    • 使用从scene.addRect() 返回的每个 QGraphicsRectItem 创建您自己的数据结构(基于列表列表的基本数组),然后使用 setBrush()(例如,self.array[row][column].setBrush(color))基于你的数据矩阵。
    • 假设我想从另一个类更改 self.rows。我有一个 set 函数,其他类可以调用它来更改行。当我运行程序时, self.rows 在 set 函数中发生了变化,但图形没有变化。我认为这是因为“绘图”代码在 initUI 中,但我不知道放在哪里。
    • 那么你必须将场景创建移动到另一种方法(并在重建之前使用clear())。
    猜你喜欢
    • 2014-01-22
    • 2015-07-11
    • 2015-09-03
    • 1970-01-01
    • 2023-04-03
    • 2017-02-16
    • 2015-03-23
    • 1970-01-01
    • 2015-06-07
    相关资源
    最近更新 更多