gpt4 book ai didi

c++ - 使用 QAbstractItemModel 将 2D C++ 游戏板暴露给 QML

转载 作者:搜寻专家 更新时间:2023-10-31 00:29:45 25 4
gpt4 key购买 nike

我正在用 C++ 中的游戏板模型编写一个简单的贪吃蛇游戏,其中包含一个二维状态 vector ( std::vector<std::vector<board::state>> )。现在我想将这个棋盘暴露给 QML,这样它基本上就是某种可以访问模型状态的网格/棋盘。我已经阅读了很多关于这个主题的文章,但仍然无法理解足够的机制来解决我的问题。将文档、教程和博客条目应用到我的问题是我在这里的障碍。

我子类化了QAbstractItemModel对于我的游戏板模型并实现了必要的功能。现在我想进入 QML 并在那里使用/显示我的模型的内容。

这是我的代码:

board.h

#pragma once

#include <vector>

#include <QAbstractItemModel>

class board : public QAbstractItemModel
{
Q_OBJECT

public:
enum class state
{
empty,
snake,
fruit
};

board(int x, int y);

state get_state(int x, int y) const;
void set_state(int x, int y, state state);

QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex& index) const;
int rowCount(const QModelIndex& parent = QModelIndex()) const;
int columnCount(const QModelIndex& parent = QModelIndex()) const;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;

private:
std::vector<std::vector<state>> m_board;
};

Q_DECLARE_METATYPE(board::state)

board.cpp

#include "board.h"

board::board(int x, int y) :
m_board(x, std::vector<board::state>(y, board::state::empty))
{
}

//----------------------------------------------------------------------------------------------------------------------

board::state board::get_state(int x, int y) const
{
if((size_t) x >= m_board.size() || x < 0)
return board::state::empty;

if((size_t) y >= m_board.at(0).size() || y < 0)
return board::state::empty;

return m_board.at(x).at(y);
}

//----------------------------------------------------------------------------------------------------------------------

void board::set_state(int x, int y, state state)
{
if(get_state(x, y) == state)
return;

m_board.at(x).at(y) = state;
}

//----------------------------------------------------------------------------------------------------------------------

QModelIndex board::index(int row, int column, const QModelIndex&) const
{
if((size_t) row >= m_board.size() || row < 0)
return QModelIndex();

if((size_t) column >= m_board.at(0).size() || column < 0)
return QModelIndex();

return createIndex(row, column);
}

//----------------------------------------------------------------------------------------------------------------------

QModelIndex board::parent(const QModelIndex& index) const
{
if((size_t) index.row() >= m_board.size() || index.row() < 0)
return QModelIndex();

if((size_t) index.column() >= m_board.at(0).size() || index.column() < 0)
return QModelIndex();

return createIndex(index.row(), index.column());
}

//----------------------------------------------------------------------------------------------------------------------

int board::rowCount(const QModelIndex&) const
{
return m_board.size();
}

//----------------------------------------------------------------------------------------------------------------------

int board::columnCount(const QModelIndex&) const
{
return m_board.at(0).size();
}

//----------------------------------------------------------------------------------------------------------------------

QVariant board::data(const QModelIndex& index, int role) const
{
if(!index.isValid())
return QVariant();

if(role != Qt::DisplayRole)
return QVariant();

if((size_t) index.row() >= m_board.size() || index.row() < 0)
return QVariant();

if((size_t) index.column() >= m_board.at(0).size() || index.column() < 0)
return QVariant();

return qVariantFromValue(get_state(index.row(), index.column()));
}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QQuickView>

#include <board.h>

int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);



board game_board(10, 10);
game_board.set_state(4, 9, board::state::snake);
game_board.set_state(3, 10, board::state::fruit);

QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
QQmlContext *ctxt = view.rootContext();
ctxt->setContextProperty("myGameBoard", &game_board);

QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

return app.exec();
}

ma​​in.qml

import QtQuick 2.6
import QtQuick.Window 2.2

Window {
visible: true

MouseArea {
anchors.fill: parent
onClicked: {
Qt.quit();
}
}

Text {
text: qsTr("Hello World")
anchors.centerIn: parent
}

GridView {
model: myGameBoard
delegate: Rectangle {
width: 30
height: 30
color: blue
}
}
}

我确定有很多东西是我遗漏的或者是明显错误的。我也知道将 C++ 模型暴露给 QML 是经常被问及的问题,但我仍然无法做到。

陈述几个更具体的问题:

  • 如何在 QML 中显示模型中的数据?我已经看到这是通过角色名称完成的,但我的行的列没有角色名称
  • 我的模型是否正确实现?
  • 我需要使用什么 QML 组件来拥有棋盘,如果我需要自定义组件,它需要具备哪些属性才能从模型中读取数据?

感谢您的关注!

最佳答案

  1. QtQuick 是使用 QML 的主要 UI 框架,基本上只处理列表模型,因此使用角色来模拟表格,例如使用 TableView

  2. parent() 方法是错误的,因为它基本上再次返回相同的索引。这不会对您的情况造成任何问题,因为您有一张 table 而不是一棵树。

建议:如果你只需要一个表模型,派生自QAbstractTableModel 并让它处理index()parent()

  1. 没有可以处理表格模型的标准 QtQuick 元素,因此您必须构建自己的模型或使用列表模型,只需将“列表项”排列在网格中即可。

如果是自定义项,您可以构建一个适用于您的模型的项,甚至可以直接处理数据,而无需模型。

如果您使用该模型并希望从 QML 实例化该模型,那么您需要一个“指向您的模型类的指针”或“指向 QAbstractItemModel 的指针”的属性。

如果您不想使用模型或不需要从 QML 实例化它,那么您根本不需要任何特定属性。

无论哪种情况,您的自定义项都可以使用以下方法之一:

  1. 它可以自己绘制所有东西,即瓷砖的网格和瓷砖本身
  2. 只需提供网格并使用委托(delegate)来绘制不同类型的图 block ,即像 ListView 允许为列表元素、页眉、页脚等设置委托(delegate)

关于c++ - 使用 QAbstractItemModel 将 2D C++ 游戏板暴露给 QML,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39707951/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com