我有一个棋盘游戏,编号的图块位于方形网格中。该板使用 GridView 和继承自 QAbstractListModel 的自定义 GameBoard 模型(GameBoardModel 导出到 QML)。标准形式的游戏使用 4x4 的图块网格,因为这是模型的默认构造函数创建的图块数量 (16)。不过,我想制作某种组合框,允许选择棋盘尺寸,然后生成棋盘尺寸并开始游戏。
现在的问题是,我没有看到从 QML 发送数字(或调用函数)的明显方法,该方法将继续生成具有所需参数的模型,将其加载到 QML 中并更新视图。
我尝试创建一个单独的按钮并使用模型的 dimension 属性通过 MouseArea 的 onClicked 将尺寸设置为新值并编写 _gameboard.model.dimension = 5 (其中 _gameboard 是 GameBoard QML 类型的 id,它使用 GameBoardModel),但我仍然不知道如何正确更新我的模型。我尝试创建某种 reloadModel 方法,该方法本质上创建了一个带有新数字的新图块列表,并且在每次更新 dimension 后都会调用该方法,但即使在调用 dataChanged 之后,它也只 显示旧数字元素数 是 16 个而不是 25 个(不包括故意隐藏的元素)。
C++
part of gameboard.h
class GameBoard : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int dimension READ dimension WRITE setDimension NOTIFY dimensionChanged)
Q_PROPERTY(int hiddenElementValue READ boardSize NOTIFY hiddenElementChanged)
public:
static constexpr size_t defaultPuzzleDimension = 4;
GameBoard(QObject* parent = nullptr, const size_t boardDimension = defaultPuzzleDimension);
size_t dimension() const;
void setDimension(size_t newDimension);
size_t boardSize() const;
signals:
void dimensionChanged(const size_t newDimension);
void hiddenElementChanged(int newHiddenElementValue);
private:
std::vector<Tile> m_rawBoard;
size_t m_dimension;
size_t m_boardSize;
void reloadModel();
}
part of gameboard.cpp
size_t GameBoard::dimension() const
{
return m_dimension;
}
void GameBoard::setDimension(size_t newDimension)
{
m_dimension = newDimension;
reloadModel();
emit dimensionChanged(m_dimension);
emit hiddenElementChanged(m_boardSize);
}
size_t GameBoard::boardSize() const
{
return m_boardSize;
}
void GameBoard::reloadModel()
{
m_rawBoard.clear();
m_boardSize = m_dimension * m_dimension;
m_rawBoard.resize(m_boardSize);
std::iota(m_rawBoard.begin(),m_rawBoard.end(),1);
shuffle();
dataChanged(createIndex(0,0),createIndex(m_boardSize,0));
}
QML
main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
id: root
width: 680
height: 440
visible: true
title: qsTr("Hello World")
Item {
id: _firstTile
width: 0.5 * root.width
height: 0.1 * root.height
anchors.horizontalCenter: parent.horizontalCenter
Tile {
radius: 30
anchors.fill: parent
anchors.topMargin: 0.05 * parent.height
anchors.bottomMargin: 0.05 * parent.height
MouseArea {
anchors.fill: parent
onClicked: {
_gameboard.model.dimension = 5;
}
}
}
}
Item {
width: root.width
height: 0.9 * root.height
anchors.top: _firstTile.bottom
GameBoard {
id: _gameboard
anchors.fill: parent
}
}
}
GameBoard.qml
import QtQuick 2.0
import Game 1.0
GridView {
id: root
model: GameBoardModel {
}
cellHeight: height / root.model.dimension
cellWidth: width / root.model.dimension
delegate: Item {
id: _backgroundDelegate
width: root.cellWidth
height: root.cellHeight
visible: display != root.model.hiddenElementValue
Tile {
displayText: display
anchors.fill: _backgroundDelegate
anchors.margins: 3
MouseArea {
anchors.fill: parent
onClicked: {
root.model.move(index);
}
}
}
}
}
Atmo 在评论中提供的答案是使用 beginResetModel 和 endResetModel 信号。