Qt:使用二维数组值更新像素图网格布局

2023-12-05

我正在使用 Visual Studio 2010 和 Qt 4.7(都是 Windows)中的 C++ 组合进行游戏。该游戏是战舰的克隆,基于控制台输入。我已经按照我想要的样子创建了 gui,在 Qt 设计器的 Qt 端,我的 gui 由一个 10x10 的网格布局组成,使用标签来保存游戏单元的像素图:

current look of the game

我煞费苦心地命名了每个标签来表示它在二维数组中的位置(即舰队地图 =>F_00 => F[0,0] => F[i],[j])。我可以使用属性编辑器手动选择要显示的像素图,但我想要一些动态的东西。

我使用更新地图板类在玩家开火后重新绘制游戏板,这会继续存储在字符数组上。我想使用通用的 getupdatearray 类型函数来更新每个像素图。当我们遍历数组时,它将更新当前与各个标签关联的像素图,以匹配数组中的同类标签。 (说F[5][6] = 'X'对于 hit,那么当循环到达数组中的该位置时,它将更新 F_56 处的像素图网格以等于hit.png,替换空.png.

我知道如何制作可以实现此目的的循环,但不确定如何使每个标签的像素图更符合运行时功能与现在编译时(静态)功能的关系。我读过 QPainter 和另一个处理图像的 Qt 类,但仍然很难做到。

对于你们中的任何人来说,我如何根据二维数组更新这些像素图?

  1. 循环结构 - 我能弄清楚
  2. 条件语句 - 我能弄清楚
  3. qt 处理标签的特定语法 - 新手,所以不知道 atm。

这是我尝试用 map.h 做的一些伪代码:

#include <QtCore>
#include <QtGui>

// WARNING: PSEUDOCODE, DOES NOT COMPILE
// AT A LOSS ON HOW TO SELECT THE CORRECT LABEL
// MAYBE A CHILD CLASS FOR THAT?

class map {
public:
    char updateboard(char mapname, char b[][10]){
        for(int i=0;i<10;i++){
            for(int j=0;j<10;j++){
                char C = b[i][j]; 
                if (C == 'M'){//miss
                    Qlabel mapname_[i][j](<img src='images/missspace.png'/>);
                    mapname_[i][j].show();
                } 
                else if(C == 'X'){//hit
                    Qlabel mapname_[i][j](<img src='images/hitspace.png'/>);
                    mapname_[i][j].show();
                }
                else if(C == ' '){//undiscovered space
                    Qlabel mapname_[i][j](<img src='image/emptyspace.png'/>);
                    mapname_[i][j].show();
                }
            }
        }
    }
};

然后在我的 mainwindow.cpp 中,我包含 map.h 并说:

// calls class function update board
// takes updated array values and replaces old pixmap with new

map.updateboard(T,b[][10]); // target map update
map.updateboard(F,v[][10]); // fleet map update

提前致谢

UPDATE:

我已经到了可以通过按下按钮来交换像素图的地步,但我想创建一些更动态的东西。我想使用 Qstring,在其中添加要更改的标签名称,方法是使用以下命令附加 x y 值:

TR_position.append(QString::number(xvalue));

当我尝试使用以下方式调用它时:

ui->TR_position->setPixmap(QPixmap(":/images/missspace.png"));

……这显然是行不通的。有没有办法输入大小写,或者使用字符串的内容作为 Qlabel 名称?


您手动输入并命名200 个标签小部件?不要让任何人说你懒惰。 :)

根据您的更新,您现在知道如何使用QLabel::setPixmap()。你什么think您需要从名称中获取 QLabel 指针,该指针是两件事的组合:

  • QWidget::findChild得到一个QWidget* from a QString

  • qobject_cast得到一个QLabel* from a QWidget

如果你沿着这条路走下去,你最终会得到这样的结果:

QWidget* cellWidget = ui->findChild(TR_position);
QLabel* cellLabel = qobject_cast<QLabel*>(cellWidget);
cellLabel->setPixmap(QPixmap(":/images/missspace.png"));

但要小心!这种方法有很多问题。

  • 它很脆:如果碰巧没有任何具有该名称的小部件怎么办(神秘崩溃)?或者更糟糕的是,如果有怎么办?multiple具有该名称和此代码的小部件幸福地前进,对可能是错误的奇怪情况一无所知?

  • 这是糟糕的 OOP:虽然有一些不错的情况使用动态转换(或“向下转换”),但它通常表明设计中存在缺陷。你知道所有的 QLabel 都是 QWidget,但并非所有的 QWidget 都是 QLabels...所以qobject_cast调用可能会返回 NULL。这只是又一个失败点。有时您无法避免这种情况,但实际上您的程序没有理由需要以这种方式构建。

  • 速度非常慢:通过名称搜索小部件本质上是一种简单的递归搜索。如果您为每个网格留出一个单独的小部件框架并且仅搜索该框架,则 Qt 将必须进行 100 次字符串比较才能找到最后一个元素(因此平均情况下为 50 次)。想象一下用循环清除网格...现在您正在谈论 100*50 字符串比较!

所有这些事情都是可以避免的。正如可以使用循环按名称设置控件上的图像一样,也可以使用循环首先创建小部件。您基本上会在设计工具中将游戏板区域留空,然后使用代码动态创建控件...使用代码将它们附加到布局...并将指向它们的指针保存在 2D 数组中。 (此时您不会通过标签名称访问它们,您会像为板建立索引一样对它们进行索引。)

您可以创建自己的从 QLabel 派生的类(例如GameCell类),其中包含您的董事会单元的信息以及与其相关的方法。那么您就不需要与代表您的板的数组并行的标签小部件数组。您只需拥有一组对象来处理实现的两个方面。


UPDATE:既然您在评论中询问了具体细节,这里有一个 GameCell 类:

class GameCell : public QLabel
{
    Q_OBJECT    

public:
    enum State { Undiscovered, Hit, Miss };

    GameCell (QWidget *parent = 0) : QLabel (parent),
        currentState (Undiscovered)
    {
        syncBitmap();
    }

    State getState() const { return currentState; }

    void setState(State newState) {
        if (currentState != newState) {
            currentState = newState;
            syncBitmap();
        }
    }

private:
    void syncBitmap() { // you'd use setPixmap instead of setText
        switch (currentState) {
        case Undiscovered: setText("U"); break;
        case Hit: setText("H"); break;
        case Miss: setText("M"); break;
        }
    }

    State currentState;
};

这通过表现得像 QWidget 以及维护一部分内部状态来完成双重任务。然后 GameMap 小部件可以使用这些 GameCell 的 QGridLayout:

class GameMap : public QWidget {
    Q_OBJECT

public:
    static const int Rows = 10;
    static const int Columns = 10;

    GameMap (QWidget* parent = 0) :
        QWidget (parent)
    {
        layout = new QGridLayout (this);
        for (int column = 0; column < Columns; column++) {
            for (int row = 0; row < Rows; row++) {
                GameCell* cell = new GameCell (this);
                cells[column][row] = cell;
                layout->addWidget(cell, row, column);
            }
        }
    }

private:
    GameCell* cells[Columns][Rows];
    QGridLayout* layout;
};

如果您愿意,您可以在设计器中的布局中留下想要用 GameMap 小部件填充的空间。或者您可以继续以编程方式完成整个事情。为了简单起见,我将两个板并排放置,并在对话框的表面上有一个垂直分隔符:

class Game : public QDialog
{
    Q_OBJECT

public:
    Game (QWidget *parent = 0)
        : QDialog(parent)
    {
        targetMap = new GameMap (this);
        fleetMap = new GameMap (this);

        verticalSeparator = new QFrame (this);
        verticalSeparator->setFrameShape(QFrame::VLine);
        verticalSeparator->setFrameShadow(QFrame::Sunken);

        layout = new QHBoxLayout (this);
        layout->addWidget(targetMap);
        layout->addWidget(verticalSeparator);
        layout->addWidget(fleetMap);
        setLayout(layout);

        setWindowTitle(tr("Battleship"));
    }

private:
    GameMap* targetMap;
    QFrame* verticalSeparator;
    GameMap* fleetMap;
    QHBoxLayout* layout;
};

我不会在这里编写整个游戏或让它看起来很花哨。这只是要点,展示了如何以编程方式获取 200 个标签:

simple battleship

使用我的代码,从 (x,y) 坐标获取 GameCell 不需要平均 50 次字符串比较。由于二维数组的形式化和可预测性,索引cells[x][y]仅需要一次乘法运算和一次加法运算。没有任何贬低,你可以简单地写:

cells[x][y].setState(GameCell::Miss);

ADDENDUM:为每个网格单元创建一个 QWidget 并不一定是首先要采取的方法。有些人可能认为这是“重量级”。如果你的游戏是在一个大的虚拟瓷砖空间上玩的,那么它可能会太慢。您可能会发现了解一下很有用QGraphicsGridLayout,从长远来看,这可能是更合适的方法:

http://doc.qt.io/qt-5/qtwidgets-graphicsview-basicgraphicslayouts-example.html

然而,使用 QWidgets 对于 10x10 网格来说不会有太大问题,所以如果您想坚持使用 QWidgets 那么您可以。如果您打算这样做,那么至少您不应该手动放置它们!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt:使用二维数组值更新像素图网格布局 的相关文章

  • 如何在 QT 安装程序框架中区分每用户安装与系统范围安装?

    我正在使用一些名为 pgModeler 的应用程序 它的当前版本提供了一个基于 QT 安装程序框架的安装程序 Windows 上该安装程序的问题是它安装每个用户的开始菜单条目 https github com pgmodeler pgmod
  • SWI-Prolog 与 C++ 接口的问题

    我试图让 SWI Prolog 与 C 很好地配合 现在束手无策 现在 在我开始准确解释我的问题是什么之前 我想首先说明我的项目是关于什么的以及我选择了哪些工具来开发解决方案 我的教授分配给我的任务是开发一个 GUI 程序 作为 SWI p
  • 在哪里可以找到 QT 5.3.0 命令提示符

    用于学习Qt的书 C gui programming with qt 4 2nd 版 我需要Qt的命令提示符 我已经安装了Qt 5 3 0 creator 5 3 0开源 但不知道它的命令提示符在哪里 有人可以帮助我吗 我认为您正在寻找的是
  • 如何在 QT 中绘制点?

    我正在用 QT 用 C 编写一个应用程序 其中有 n 个点并计算它的凸包 然而 一旦计算出来 我不知道如何绘制点并绘制船体的边界 制作菜单按钮等很简单 但我不确定我是否知道执行此操作的工具 你怎么做到这一点 图形视图 addEllipse
  • QML:无法读取未定义的属性“xxx”

    ApplicationWindow id root property string rootName rootName visible true width 800 height 400 title qsTr WatchFace Maker
  • 用 C++/Qt 编写的程序中的 RTF / doc / docx 文本提取

    我正在写一些程序Qt https en wikipedia org wiki Qt 28software 29 C 我需要从中读取文本微软Word https en wikipedia org wiki Microsoft Word RTF
  • 第一次信号发射后自动断开

    我正在从文件加载网页 然后替换其中的一些 html self template web page QtWebKit QWebPage self template web page mainFrame load QtCore QUrl tem
  • 如何让小部件在上下文菜单出现时接收鼠标释放事件

    在Ubuntu20 04上 当上下文菜单出现时 我无法让小部件接收鼠标释放事件 而Windows可以接收 我的pyqt版本是5 15 2 我考虑过手动发送鼠标释放事件 但我不知道当上下文菜单出现时哪些系统会收到鼠标释放事件 这样做可能会导致
  • 清除pyqt中布局中的所有小部件

    有没有办法清除 删除 布局中的所有小部件 self plot layout QtGui QGridLayout self plot layout setGeometry QtCore QRect 200 200 200 200 self r
  • Retina 显示屏中具有 QOpenGLWIdget 的 Qt MainWindow 显示错误大小

    我有一个 Qt 应用程序MainWindow 我嵌入一个QOpenGLWidget在里面 一切正常 直到我开始使用 Apple Retina 显示屏并在高 DPI 模式下运行我的应用程序 我的QOpenGLWidget只是它应该具有的大小的
  • QMainWindow 上的 Qt 布局

    我设计了一个QMainWindow with QtCreator s设计师 它由默认的中央小部件 aQWidget 其中包含一个QVBoxLayout以及其中的所有其他小部件 现在我想要的一切就是QVBoxLayout自动占据整个中央小部件
  • 如何在Qt 5中的paintEvent上使用mouseMoveEvent?

    我是 Qt 和 c 的新手 所以我遇到了一些困难 我正在尝试创建一个小部件 它可以获取 mouseMoveEvent 位置并在鼠标位置的像素图上绘制椭圆 下面你可以看到代码 include myimage h include
  • Qt中Q_PROPERTY的意义是什么?

    我无法理解 Q PROPERTY 的用法 Q PROPERTY 如何帮助程序具有防御性 它是干什么用的 我看过这个论坛 但确实无法应用 我已经理解了这个例子 但不明白它的用法 这是一个例子 我能从中得到什么 我知道阅读将赋予只读特权 wri
  • Qt中用于线程间通信的类设计

    问题陈述 用相机跟踪物体并相应地移动相机的方位角和仰角 Process 相机获取物体的图像 处理相机的每一帧以查找物体 应该被跟踪 并将每帧中生成的信息传递给机械设备 万向节 以平移和倾斜方式移动摄像机 Design 主 Gui 在一个线程
  • 针对初学者的 QT 商业许可证与非商业许可证 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 QT 许可似乎非常反学习 因为据我所知 用它开发的任何东西都只能是商业的当且仅当 its entire开发是在使用商业许可证的情况下完成的
  • 如何将自定义 Qt 类型与 QML 信号一起使用?

    我在 Qt 5 2 qml 应用程序中创建了一个自定义类型 class Setting public QObject Q OBJECT Q PROPERTY QString key READ key WRITE setKey Q PROPE
  • 连接到 QNetworkReply::error 信号

    我正在使用 Qt5 的新连接语法 QNetworkReply 有一个名为error http qt project org doc qt 5 0 qtnetwork qnetworkreply html error 2还有一个函数叫做err
  • 如何在Android中使用QML - QWebView

    我想在 Android 中部署一个 YouTube 应用程序 但它只能在我的电脑上运行 在安卓上不起作用 它不加载任何视频 问题仅出在 QWebView 上 我使用了与此类似的代码 http doc qt io archives qt 5
  • QFileSystemModel setRootPath

    我正在尝试创建一个 Qt 应用程序来显示文件夹 Mac OS 中的 Users 文件夹 的内容 这是代码 QFileSystemModel dirModel new QFileSystemModel dirModel gt setRootP
  • Q风格所有权

    在 Qt 应用程序中使用样式时 我遇到了一个有趣的问题QStyle所有权 QStyle继承自QObject 通常接受QObject parent作为构造函数参数来管理其子级的生命周期 但QStyle的构造函数没有此构造函数参数 第一个问题

随机推荐