在 Qt 中将 QML ItemModelSurfaceDataProxy 与 C++ 模型绑定

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

我正在开展一个项目,需要使用 Qt 可视化 3D 表面。曲面的数据存储在 C++ 模型中的

cv::Mat
中,我正在尝试将此模型绑定到 QML 中的
ItemModelSurfaceDataProxy

这是我的 C++ 模型:

class MyTableModel: public QAbstractTableModel {
    Q_OBJECT

public:
    enum Roles {
        PixelRole = Qt::UserRole + 1
    };

    QHash<int, QByteArray> roleNames() const override;

    MyTableModel(const cv::Mat& data, QObject* parent = nullptr);

    int rowCount(const QModelIndex& parent = QModelIndex()) const override;

    int columnCount(const QModelIndex& parent = QModelIndex()) const override;

    QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;

private:
    cv::Mat m_dataMatrix;
};

Q_PROPERTY
在另一个
Q_OBJECT
中定义如下:

Q_PROPERTY(QAbstractTableModel* myModel READ getMyModel NOTIFY dataChanged)

private:
MyTableModel* getMyModel() { return m_myModel; }
MyTableModel* m_myModel;

这是我的 QML 代码:

Surface3D 
{
    anchors.fill:parent
    Surface3DSeries 
    {
        ItemModelSurfaceDataProxy 
        {
            itemModel: pageModel.myModel;
            rowRole: "x"
            columnRole: "y"
            zPosRole: "PixelValue"
         }
     }
}

当我启动应用程序时,3D 表面是空的,没有数据显示。我怀疑从后端模型获取数据可能存在问题。我不确定我设定的角色是否正确。

我找到了有关如何使用

HeightMapSurfaceDataProxy
或直接在 QML 中内置的
ListModel
设置 Surface3D 的在线资源,但没有解释如何在 C++ 中构建模型并将其与 QML 绑定。

如果需要,我可以上传

MyTableModel
类的方法实现。

这里data方法的实现:

QVariant MyTableModel::data(const QModelIndex& index, int role) const
{
    if (!index.isValid() || role != MyTableModel::Roles::PixelRole)
        return QVariant();

    float value = dataMatrix.at<float>(index.row(), index.column());

    return QVariant(value);
}
c++ qt qml
1个回答
1
投票

此示例使用

QSurfaceDataProxy
Surface3DSeries
提供数据。源自
MatData
QSurfaceDataProxy
的构造函数包含使用随机数据创建
cv::Mat
并将其映射到
QSurfaceDataArray
。这里的关键是对
resetArray()
的调用,它将用提供的数据替换
QSurface3DSeries
QSurfaceDataProxy

我使用的是 Qt 6.5.4,因此

Surface3D
Surface3DSeries
的导入是 QtDataVisualization 而不是 QtGraphs。如果您使用 Qt 6.6 或更高版本,您可以调整导入。

构造函数中有一个小技巧,这是QTBUG-58884QTBUG-65322QTBUG-103965中报告的以下问题的解决方法。上一个错误报告对我正在使用的解决方法进行了评论。

您可以在here找到示例的完整源代码。

MatData::MatData(QObject *parent)
    : QSurfaceDataProxy(parent)
{
    // Create a cv::Mat to be used as surface
    cv::Mat test(20, 20, CV_32F);
    cv::Mat mean = cv::Mat::zeros(1, 1, CV_32F);
    cv::Mat sigma = cv::Mat::ones(1, 1, CV_32F);
    sigma.at<float>(0, 0, 0) = 10;

    cv::RNG rng;
    rng.fill(test, cv::RNG::NORMAL, mean, sigma);

    cv::Mat mat;
    blur(test, mat, cv::Size(5, 5));

    m_dataArray = new QSurfaceDataArray;
    m_dataArray->reserve(mat.rows);

    for (int i = 0; i < mat.rows; i++) {
        QSurfaceDataRow *newProxyRow = new QSurfaceDataRow(mat.cols);
        m_dataArray->append(newProxyRow);

        for (int j = 0; j < mat.cols; j++) {
            QSurfaceDataItem &item = (*newProxyRow)[j];
            item.setPosition(QVector3D(i, mat.at<float>(i, j), j));

            // https://bugreports.qt.io/browse/QTBUG-103965
            auto tmp = (*newProxyRow)[j];
            tmp.setPosition(QVector3D(tmp.z(), tmp.y(), tmp.x()));
            (*newProxyRow)[j] = tmp;
        }
    }

    resetArray(m_dataArray);
}
import QtQuick
import QtDataVisualization
import CustomProxy

Window {
    width: 800
    height: 600
    visible: true
    title: qsTr("Hello World")

    ColorGradient {
        id: surfaceGradient
        ColorGradientStop { position: 0.0; color: "black" }
        ColorGradientStop { position: 0.2; color: "red" }
        ColorGradientStop { position: 0.5; color: "blue" }
        ColorGradientStop { position: 0.8; color: "yellow" }
        ColorGradientStop { position: 1.0; color: "white" }
    }

    Surface3D {
        id: surfaceGraph
        anchors.fill: parent

        Surface3DSeries {
            id: surfaceSeries
            flatShadingEnabled: false
            drawMode: Surface3DSeries.DrawSurface | Surface3DSeries.DrawWireframe
            baseGradient: surfaceGradient
            colorStyle: Theme3D.ColorStyleRangeGradient
            itemLabelFormat: "(@xLabel, @zLabel): @yLabel"

            MatData {}
        }
    }
}

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