PyQt:如何拉伸 QGraphicsView 和 QGraphicsScene 小部件的宽度和高度? [英] PyQt: How to stretch the width and height of a QGraphicsView and QGraphicsScene widget?

查看:181
本文介绍了PyQt:如何拉伸 QGraphicsView 和 QGraphicsScene 小部件的宽度和高度?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to create a grid widget that stretches to the width and height of the window. The size of the grid (currently 14x49) is subject to change but I want the overall size of the widget to stay the same.

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_())


我希望小部件的外观:

推荐答案

你的方法比它需要的要复杂得多,并且有很多问题(其中一些非常重要).

Your approach is much more complex than it needs, and there are various issues about it (some of them quite important).

首先,不需要每次都计算正方形的大小,因为 QGraphicsView 可以通过使用 fitInView(),默认忽略纵横比.只需使用适合您需求的任意正方形大小即可.

First of all, there's no need to compute the size of the squares each time, since QGraphicsView can do that by using fitInView(), which by default ignores the aspect ratio. Just use an arbitrary square size that fits your needs.

然后,您应该切勿paintEvent 中创建和添加小部件,因为这可能会导致递归.

Then, you should NEVER create and add widgets in a paintEvent, as it might cause recursion.

在小部件上设置布局后,除非绝对必要,否则不应再设置其他布局(无论如何,不​​应那样做).

Once a layout is set on a widget, you should not set another one, unless absolutely necessary (and, anyway, it shouldn't be done like that).

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

When adding a rect to a graphicsScene using addRect, there's usually no need to create a QRectF first, as you can just use the convenience function that accepts coordinate and size (Qt will automatically create the QRectF anyway on the C++ side, which might be slightly faster).

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

On the other hand, since you're creating multiple rectangles of the same size, you could just create a single QRectF and then use translated() to set the coordinates.

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

Creating a QRectF with QPointF and QSizeF is usually suggested when those are existing variables or constants, otherwise you can just use the basic QRectF(x, y, width, height) constructor.

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()

这篇关于PyQt:如何拉伸 QGraphicsView 和 QGraphicsScene 小部件的宽度和高度?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆