Qt GUI Development - Displaying a 2D grid using QGraphicsView
Asked Answered
R

5

12

I'm new to Qt development so I've being trying to research a solution to a user interface I need to design. My project is to simulate players in an online game moving around a global map. To represent the map I need to display a 2D grid, with each space in the grid representing a region of a map. I then need to display the location of each player in the game. The back-end is all fully working, with the map implemented as a 2D array. I'm just stuck on how to display the grid.

The research I have done has led me to believe a QGraphicsView is the best way to do this, but I can't seem to find a tutorial relevant to what I need. If anyone has any tips on how to implement this it would be much appreciated.

Thanks, Dan

Rounders answered 26/11, 2011 at 15:45 Comment(1)
I personally learned a lot about Qt graphics from examples that are shipped with SDK. 40000 chips is nice example of implementing custom graphics view and graphics item for displaying huge scenes. Reading source code is not that easy, but I didn't find any decent tutorial on that subject. Btw, some of the examples are fully documented and it helps a lot in the beginning.Fate
A
11

A 2D Grid is nothing more than a set of horizontal and vertical lines. Suppose you have a 500x500 map and you want to draw a grid where the distance between the lines in both directions is 50. The sample code that follows shows you how you can achieve it.

// create a scene and add it your view
QGraphicsScene* scene = new QGraphicsScene;
ui->view->setScene(scene);

// Add the vertical lines first, paint them red
for (int x=0; x<=500; x+=50)
    scene->addLine(x,0,x,500, QPen(Qt::red));

// Now add the horizontal lines, paint them green
for (int y=0; y<=500; y+=50)
    scene->addLine(0,y,500,y, QPen(Qt::green));

// Fit the view in the scene's bounding rect
ui->view->fitInView(scene->itemsVBoundingRect());

You should check the QGraphicsView and the QGraphicsScene documentation as well as the corresponding examples. Also you can watch the graphics view training videos or some graphics view related videos from the Qt developer days.

Anatol answered 26/11, 2011 at 18:18 Comment(0)
S
4

Well if you have a constant grid size or even a limited number of grid sizes what i like to do is to draw a grid block in gimp or any other program and then set that as the background brush (draw only bottom and right side of the block) qt will repeat the image and will give you a full grid. I think this is good for performance too.

This is the grid image i used in one of my programs it's 10x10 pixels.

grid 10px

Then call QGraphicsScene setBackgroundBrush as the follwing:

    scene->setBackgroundBrush(QBrush(QPixmap(":/grid/grid10.png")));
Slabber answered 21/6, 2013 at 13:5 Comment(0)
D
4

The more native way is this:

scene = self.getScene()                    # Your scene.

brush = QBrush()
brush.setColor(QColor('#999'))
brush.setStyle(Qt.CrossPattern)            # Grid pattern.
scene.setBackgroundBrush(brush)

borderColor = Qt.black
fillColor = QColor('#DDD')
rect = QRectF(0.0, 0.0, 1280, 720)         # Screen res or whatever.

scene.addRect(rect,borderColor,fillColor)  # Rectangle for color.
scene.addRect(rect,borderColor,brush)      # Rectangle for grid.

Sorry by PyQt...

Dichloride answered 19/5, 2017 at 23:35 Comment(2)
I think this answer could have some value to those looking for a solution in C++, because the conversion is probably easy enough. But in general please only post answers that match the language specified in the question. Thank you!Spadework
@FabioTurati I have to disagree. Qt is widely used in C++ and Python, so asking for people to post code in the original example shuts of access to a significant part of the expertise. I use only Python, although I have used C++ in the past, so I am happy for answers to Qt questions in any language, and I think most would agree.Contempt
A
3

Suppose a scene is set to the graphicsview then simply below one line will show the grid.

ui->graphicsView->scene()->setBackgroundBrush(Qt::CrossPattern);

There several other values can be passed for ex: Qt::Dense7Pattern

These are members of enum BrushStyle, just click on any used value in Qt creator and it will take you to the enum declaration where you can see all other possible values.

PS: A scene can be set like this:

ui->graphicsView->setScene(new QGraphicsScene()); 
Alitta answered 13/12, 2019 at 9:36 Comment(0)
V
0

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);
    }
}
Vasilek answered 7/5, 2023 at 21:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.