PyQt:如何拉伸QGraphicsView和QGraphicsScene的宽度和高度?

1 投票
1 回答
2511 浏览
提问于 2025-06-18 04:01

我正在尝试创建一个网格小部件,想让它的宽度和高度都能填满整个窗口。虽然网格的大小(现在是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_())

我希望小部件的样子:

在这里输入图片描述

相关问题:

  • 暂无相关问题
暂无标签

1 个回答

1

你的做法比需要的复杂多了,而且还有一些问题(其中一些问题还挺重要)。

首先,每次都计算方块的大小其实没必要,因为QGraphicsView可以通过使用fitInView()来自动处理这个问题,默认情况下它不会考虑宽高比。你只需要使用一个适合你需求的方块大小就行了。

然后,你绝对不要paintEvent里创建和添加小部件,这样可能会导致递归调用。

一旦在一个小部件上设置了布局,就不应该再设置另一个布局,除非真的非常必要(而且,反正也不应该这样做)。

在使用addRect向图形场景添加矩形时,通常不需要先创建一个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()

撰写回答