PyQt6中QGraphicsScene绘制256×256网格的尺寸异常问题求助
QGraphicsScene网格绘制异常与坐标系疑问
问题描述
- 需求:绘制256×256的网格,每个单元格32×32像素,所有单元格(含整个网格边界)均有1像素厚边框,计算场景宽高应为
256×32+257=8449像素 - 异常:使用QGraphicsLineItem绘制后,截图测量单元格宽高在40-41像素之间,部分并非正方形,推测与item、scene、view三种坐标系有关
- 疑问:Qt文档称视图坐标系左上角为(0, 0),右下角为(view.width, view.height),按0索引逻辑会导致尺寸为
(view.width + 1)×(view.height + 1),这似乎不合理
尝试代码
from PyQt6.QtWidgets import QApplication, QGraphicsScene, QGraphicsView, QGraphicsLineItem, QMainWindow, QVBoxLayout, QFrame from PyQt6.QtGui import QColor, QPen app = QApplication([]) scene = QGraphicsScene(0, 0, 8448,8448) scene.setBackgroundBrush(QColor(0, 255, 0)) for i in range(0, 8449, 33): pen = QPen(QColor(0, 0, 255)) pen.setWidth(0) horizontal_line = QGraphicsLineItem(0, 0, 8448, 0) horizontal_line.setPen(pen) horizontal_line.setPos(0, i) scene.addItem(horizontal_line) horizontal_line.setOpacity(0.5) vertical_line = QGraphicsLineItem(0, 0, 0, 8448) vertical_line.setPen(pen) vertical_line.setPos(i, 0) vertical_line.setOpacity(0.5) scene.addItem(vertical_line) window = QMainWindow() window.show() container = QFrame(parent=window) vlayout = QVBoxLayout() view = QGraphicsView(scene, parent=container) vlayout.addWidget(view) container.setLayout(vlayout) window.setCentralWidget(container) view.show() app.exec()
问题解决
1. 网格尺寸异常的修复
核心问题在于视图默认的缩放/适配逻辑会自动拉伸场景,加上场景尺寸和线条绘制的小误差,导致单元格变形:
- 修正场景尺寸:256个32px单元格加257条1px边框,总长度应为
256*32 + 257 = 8449像素,创建场景时要对应设置为QGraphicsScene(0, 0, 8449, 8449)(之前的8448少了1px) - 强制1:1视图映射:禁用视图的自动缩放锚点,确保场景和视图像素一一对应:
view.setTransformationAnchor(QGraphicsView.ViewportAnchor.NoAnchor) view.setResizeAnchor(QGraphicsView.ViewportAnchor.NoAnchor) view.setSceneRect(scene.sceneRect()) - 简化线条绘制:直接在场景坐标系中定义线条位置,无需额外调用
setPos,避免坐标偏移
修改后的完整代码:
from PyQt6.QtWidgets import QApplication, QGraphicsScene, QGraphicsView, QGraphicsLineItem, QMainWindow, QVBoxLayout, QFrame from PyQt6.QtGui import QColor, QPen from PyQt6.QtCore import Qt app = QApplication([]) # 修正场景尺寸为8449x8449 scene = QGraphicsScene(0, 0, 8449, 8449) scene.setBackgroundBrush(QColor(0, 255, 0)) pen = QPen(QColor(0, 0, 255)) pen.setWidth(0) # 0表示1px固定宽度,不受变换影响 # 绘制257条水平线(间隔33px:32px单元格+1px边框) for y in range(0, 8449, 33): line = QGraphicsLineItem(0, y, 8449, y) line.setPen(pen) line.setOpacity(0.5) scene.addItem(line) # 绘制257条垂直线 for x in range(0, 8449, 33): line = QGraphicsLineItem(x, 0, x, 8449) line.setPen(pen) line.setOpacity(0.5) scene.addItem(line) window = QMainWindow() container = QFrame(parent=window) vlayout = QVBoxLayout(container) view = QGraphicsView(scene, parent=container) # 强制1:1映射,禁用自动缩放 view.setTransformationAnchor(QGraphicsView.ViewportAnchor.NoAnchor) view.setResizeAnchor(QGraphicsView.ViewportAnchor.NoAnchor) view.setSceneRect(scene.sceneRect()) # 可选:关闭滚动条,避免视图超出场景范围 view.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) view.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) vlayout.addWidget(view) window.setCentralWidget(container) window.show() app.exec()
2. 视图坐标系疑问解答
Qt的视图坐标系是连续浮点坐标系,并非离散的像素索引:
- (0, 0)对应视图左上角像素的左上角,(view.width(), view.height())对应右下角像素的右下角
- 单个像素占据的坐标区间是
[n, n+1](n为整数),比如宽100px的视图,x坐标范围0到100,刚好覆盖100个像素 - 文档描述是图形系统的标准定义,和离散像素索引逻辑不冲突,两者是连续坐标与离散采样的关系
内容的提问来源于stack exchange,提问作者Ethan Alwaise
相关产品推荐
相关产品推荐

