Qt GUI 开发 - 使用 QGraphicsView 显示 2D 网格

发布于 2024-12-18 04:33:51 字数 263 浏览 2 评论 0原文

我是 Qt 开发的新手,所以我一直在尝试研究我需要设计的用户界面的解决方案。我的项目是模拟在线游戏中的玩家在全球地图上移动。为了表示地图,我需要显示一个 2D 网格,网格中的每个空间代表地图的一个区域。然后我需要显示游戏中每个玩家的位置。后端全部正常工作,地图实现为 2D 数组。我只是卡在如何显示网格上。

我所做的研究使我相信 QGraphicsView 是实现此目的的最佳方法,但我似乎找不到与我需要的相关的教程。如果有人对如何实现这一点有任何提示,我们将不胜感激。

谢谢,丹

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

本王不退位尔等都是臣 2024-12-25 04:33:51

二维网格只不过是一组水平线和垂直线。假设您有一张 500x500 的地图,并且想要绘制一个网格,其中两个方向的线之间的距离为 50。下面的示例代码向您展示了如何实现它。

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

您应该检查 QGraphicsViewQGraphicsScene 文档以及相应的 示例。您还可以观看图形视图培训视频或一些图形视图来自 Qt 开发者时代的相关视频

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.

半﹌身腐败 2024-12-25 04:33:51

好吧,如果你有一个恒定的网格大小,甚至是有限数量的网格大小,我喜欢做的就是在 gimp 或任何其他程序中绘制一个网格块,然后将其设置为背景画笔(仅绘制网格的底部和右侧) block) qt 将重复图像并为您提供完整的网格。我认为这对性能也有好处。

这是我在我的一个程序中使用的网格图像,它是 10x10 像素。

grid 10px

然后调用 QGraphicsScene setBackgroundBrush 如下:

    scene->setBackgroundBrush(QBrush(QPixmap(":/grid/grid10.png")));

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")));
伴随着你 2024-12-25 04:33:51

更原生的方式是这样的:

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...

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...

初熏 2024-12-25 04:33:51

假设一个场景设置为图形视图,那么在一行的下方将显示网格。

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

还可以传递其他几个值,例如: Qt::Dense7Pattern

这些是 enum BrushStyle 的成员,只需单击 Qt 创建者中的任何使用的值,它就会带您枚举声明,您可以在其中看到所有其他可能的值。

附:
场景可以这样设置:

ui->graphicsView->setScene(new QGraphicsScene()); 

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()); 
琉璃梦幻 2024-12-25 04:33:51

实际上有 Qt 示例代码演示了在 QGraphicsView/QGraphicsScene 中绘制网格线。在图表场景示例中,可以打开网格线或关闭。此实现使用QGraphicsScene::setBackgroundBrush,如果您尝试一下该示例,您将看到此方法的问题是什么:如果您对场景应用缩放变换,背景画笔可能会变得像素化。

如果您要允许深入缩放场景,更好的方法是继承自 GraphicsScene 并在自定义场景类中重写 drawBackground() 。这样做很容易,因为drawBackground接收一个要在场景坐标中绘制的矩形;您只需要找出矩形中的网格线即可。但请注意,当场景应用比例时,线条的粗细将会放大,因此最好使用零粗细的笔进行绘制。 Qt 中的零粗细笔绘制与比例无关的 1 像素线。

另外,为了不使用这种方法获得绘图工件,我需要将 QGraphicsView 的视口更新模式设置为 QGraphicsView::FullViewportUpdate 因为在放大 Qt 处理时平移时设置 MinimalViewportUpdate背景好像没有改变,也没有在需要的地方重新绘制。

下面的示例代码。 k_line_spacing 是在类或 .cpp 文件中定义的双精度浮点常量。

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);
    }
}

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);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文