python - PyQt:如何拉伸 QGraphicsView 和 QGraphicsScene 小部件的宽度和高度?
问题描述
我正在尝试创建一个延伸到窗口宽度和高度的网格小部件。网格的大小(当前为 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_())
我希望小部件看起来像什么:
解决方案
您的方法比它需要的要复杂得多,并且存在各种问题(其中一些非常重要)。
首先,不需要每次都计算正方形的大小,因为 QGraphicsView 可以通过使用 来做到这一点fitInView()
,默认情况下会忽略纵横比。只需使用适合您需要的任意正方形大小。
然后,您永远不应该在 a 中创建和添加小部件paintEvent
,因为它可能会导致递归。
一旦在小部件上设置了布局,除非绝对必要,否则不应设置另一个布局(无论如何,不应该那样做)。
使用 向 graphicsScene 添加 rect 时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()