There actually is Qt sample code that demonstrates painting grid lines in a QGraphicsView/QGraphicsScene. In Diagram Scene Example, gridlines can be turned on or off. This implementation uses QGraphicsScene::setBackgroundBrush
and if you play around with the example you will see what the problem with this approach is: if you apply a scale transformation to the scene the background brush can become pixelated.
If you are going to allow zooming deeply into the scene, a better approach is to inherit from GraphicsScene
and override drawBackground()
in your custom scene class. It is very easy to do it this way because drawBackground
receives a rectangle to draw in scene coordinates; you just need to figure out which grid lines are in the rectangle. Note, however, that the thickness of the lines will be magnified when the scene has a scale applied so a good idea is to draw with a pen of zero thickness. Zero thickness pens in Qt draw 1 pixel lines independent of scale.
Also in order to not get drawing artifacts with this approach I needed to set the QGraphicsView's viewport update mode to QGraphicsView::FullViewportUpdate
because with MinimalViewportUpdate
set when panning while zoomed in Qt treated the background as though it was not changing and did not repaint it where it needed to.
Example code below. k_line_spacing
is a double precision floating point constant defined in the class or in the .cpp file.
void my_scene::drawBackground(QPainter* painter, const QRectF& rect) {
painter->fillRect(rect, Qt::white);
painter->setRenderHint(QPainter::Antialiasing, true);
QPen pen(Qt::lightGray);
pen.setWidth(0);
painter->setPen(pen);
qreal x1, y1, x2, y2;
r.getCoords(&x1, &y1, &x2, &y2);
int left_gridline_index = static_cast<int>(std::ceil(x1 / line_spacing));
int right_gridline_index = static_cast<int>(std::floor(x2 / line_spacing));
for (auto i = left_gridline_index; i <= right_gridline_index; ++i) {
auto x = i * k_line_spacing;
painter->drawLine(x, y1, x, y2);
}
int top_gridline_index = static_cast<int>(std::ceil(y1 / line_spacing));
int bottom_gridline_index = static_cast<int>(std::floor(y2 / line_spacing));
for (auto i = top_gridline_index; i <= bottom_gridline_index; ++i) {
auto y = i * k_line_spacing;
painter->drawLine(x1, y, x2, y);
}
}