QML:如何使用具有运行时确定的构造函数参数的自定义模型?

问题描述 投票:0回答:1

我有一个棋盘游戏,编号的图块位于方形网格中。该板使用 GridView 和继承自 QAbstractListModel 的自定义 GameBoard 模型(GameBoardModel 导出到 QML)。标准形式的游戏使用 4x4 的图块网格,因为这是模型的默认构造函数创建的图块数量 (16)。不过,我想制作某种组合框,允许选择棋盘尺寸,然后生成棋盘尺寸并开始游戏。

现在的问题是,我没有看到从 QML 发送数字(或调用函数)的明显方法,该方法将继续生成具有所需参数的模型,将其加载到 QML 中并更新视图。

我尝试创建一个单独的按钮并使用模型的 dimension 属性通过 MouseAreaonClicked 将尺寸设置为新值并编写 _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);
                }
            }
        }
    }
}
c++ qt qml
1个回答
0
投票

Atmo 在评论中提供的答案是使用 beginResetModelendResetModel 信号。

© www.soinside.com 2019 - 2024. All rights reserved.