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 的网络服务

    我正在寻找使用 Qt 服务器端 实现 Web 服务的代码 如果您有任何信息 我将不胜感激 Regards 您可以使用libqxt http libqxt bitbucket org doc 0 6 qxtweb html实现服务器端Web服
  • 常量类成员、赋值运算符和 QList

    请确认我是否正确并告诉我是否有更好的解决方案 我了解具有常量成员的对象 例如int const width 无法由编译器隐式创建的合成赋值运算符处理 但是 QList 我想 std list 也是如此 需要一个有效的赋值运算符 因此 当我想
  • Qt:删除富文本

    对于明文有QFontMetrics elideText https doc qt io qt 5 qfontmetrics html elidedText https doc qt io qt 5 qfontmetrics html eli
  • 如何使用 ClangCodeModel 插件在 QtCreator 中设置 C++ 标准?

    抱歉 如果这是一个愚蠢的问题 但我已经尝试了几乎所有的方法 现在正在用头撞墙 问题是 带有 Clang 代码模型插件的 QtCreator 4 8 0 beta for Windows 解析我的项目 为 C 98 而实际上它是 C 17 但
  • 如何从 Qt 应用程序通过 ODBC 连接到 MySQL 数据库?

    我有一个新安装的 MySQL 服务器 它监听 localhost 3306 从 Qt 应用程序连接到它的正确方法是什么 原来我需要将MySQL添加到ODBC数据源 我在遵循这个视频教程后做到了这一点 https youtu be K3GZi
  • QChart 对大数据集无响应

    我的这段代码适用于高达 1000 的数据大小 现在我用 65536 个点对其进行了测试 series new QLineSeries QList
  • Qt 创建者 4.8.4。 Windows 7 - 64 位安装

    我在 QT 方面遇到了一些困难 我需要在学校使用它来完成一些 GUI 应用程序 我最近完成了以下步骤 1 mingw get inst 20120426 exefrom 来源锻造 http sourceforge net projects
  • 从 Qt 更改屏幕分辨率?

    我想更改屏幕分辨率 然后使用一个 ActiveX 控件 Flash 播放器 进入全屏 显然 仅适用于 Windows 的解决方案就可以了 有 Qt api 吗 还是我需要深入研究 winapi 如果是这样 我该在哪里查找 关键字 谢谢您的帮
  • 如何在不同的QT线程中创建一个窗口?

    我有一个应用程序 其中每个线程 主线程除外 都需要创建自己的窗口 我尝试创建一个线程然后调用this gt exec in the run功能 然而 在我接到那个电话之前我就收到了一个错误 ASSERT failure in QWidget
  • 在Qt中,如何正确实现委托?

    我遵循模型 视图 控制器范例 我很确定模型和视图是正确的 但我认为我的代表做错了一些事情 一切都 有效 除了第一次单击控件只是 点亮控件 而第二次单击与之交互之外 这是代表通常的实施方式吗 我的实现需要大量的构造和销毁 由scoped pt
  • 如何重写(重新实现)QFileSystemModel 中的成员函数

    我已经为此苦苦挣扎了一段时间 Qt s QFileSystemModel由于图标获取算法非常糟糕 在获取数百个文件时速度非常慢 我想完全禁用图标 它们被提取到QFileSystemModel data方法不是虚拟的 QFileSystemM
  • C++ QT libXL 错误:“启动期间程序退出,代码为 0xc0000135”

    我正在尝试编写一个使用 libXL 的 QT 应用程序 但是当我尝试编译时 我收到一个弹出框 显示 During Startup program exited with code 0xc0000135 我已经准确地找出了哪一行导致了问题 它
  • 如何使用bind将成员函数作为函数指针传递?

    我试图将成员函数作为函数指针传递 这样我就不需要依赖单例或全局函数来处理 Qt 5 中的 Qt 消息 据我所知 我的 std function 是正确的类型 它具有正确的签名 并且绑定应该允许我插入隐式this指针 本质上是将成员函数传递为
  • PyQt:如何通过匿名代理使用网页

    这真让我抓狂 我想在 QWebPage 中显示一个 url 但我想通过匿名代理来实现 Code setting up the proxy proxy QNetworkProxy proxy setHostName 189 75 98 199
  • 如何从键盘为 QTableWidget 创建信号?

    我有一张桌子 可以通过左 右 上 下按钮在里面移动 现在 当我停留在某个单元格并按空格键时 我需要创建一个信号 该信号还应该带来该单元格的坐标 我尝试使用 QTableWidget 的标准信号 但它不起作用 我该如何解决这个问题 创建一个单
  • Qt - QProcess 不工作

    我尝试启动 Internet Explorer 所以我使用下面的代码 QProcess process new QProcess this QString temp C Program Files Internet Explorer iex
  • Qt - 意外的 GDB 退出

    我正在尝试开发一个应用程序 该应用程序创建图像并使用双线性插值填充颜色像素 然后显示它 到目前为止我的代码如下 include
  • 在 Windows 上静默安装 Qt55 Enterprise

    编辑 在 Qt 支持的帮助下 我已经解决了如何自动化 Qt 企业安装程序的这两个部分 下面是脚本调用 我正在尝试在 Windows 8 1 和 Windows 10 上静默安装 Qt 5 5 1 Enterprise 使用 script 开
  • 使用 QTestLib 时抑制 qDebug

    我正在向 Qt 中的项目添加单元测试 并希望使用 QTestLib 我已经设置了测试并且它们运行良好 问题是在项目中我们重写了 qDebug 以输出到我们自己的日志文件 这在运行应用程序时效果很好 问题是当我测试类时 它有时会开始记录 然后
  • PyQt:使用 alpha 通道创建 QPixmap,而不是预乘颜色通道

    我想创建一个 QPixmap 来使用 QPainter 进行绘制 QPixmap 应支持透明度 而不使用预乘颜色通道 目前 我通过创建具有所需尺寸的 QPixmap 并用每个通道 包括 alpha 设置为零的 QColor 填充它来实现此目

随机推荐