Search code examples
pythonpyqtqgraphicsviewqgraphicsscene

Drawing a grid in PyQt6


I am trying to draw a grid in a QGraphicsScene. More specifically, I want a 256 x 256 grid of 32x32 pixel cells, where the cells are separated by 1-pixel thick borders on all sides (including at the boundaries of the entire grid). So the width and height of the entire scene should be (256*32 + 257) = 8449 pixels. I have tried doing this by drawing the lines using QGraphicsLineItem. I then opened a screenshot and measured my cells and noticed that their widths/heights were between 40 and 41 pixels (some were not even square). I assume the problem must be related to the different coordinate systems (item, scene, and view coordinates) involved here. I didn't really understand the documentation regarding this.

Most notably, the documentation says that, in view coordinates, the top-left corner is (0, 0), while the bottom-right corner is (view.width, view.height). How can this possibly be? These coordinates are 0-indexed, so this would result in dimensions of (view.width + 1) x (view.height + 1).

Here is my attempt

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

Solution

  • Setting the flag

    os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "0"
    

    disables the high-DPI scaling, allowing you to place items on the scene in terms of physical pixels.