Using C++ Models in QML

博主参考YouTube上Qt官方视频,重新敲了代码并打包上传到百度云盘。教程主要实现了简单待办事项,可删除勾选记录,用C++继承QAbstractListModel实现model供QML调用,还分享了相关源码文件及参考链接。

参考youtube上qt官方的视频:https://www.youtube.com/watch?v=9BcAYDlpuT8
youtube视频下方本来有github地址的,进去后代码为空,就照着视频教程把代码重新敲了一遍。
视频我下载下来了,1080p的,自己敲的代码也打包了,百度云盘:
链接:https://pan.baidu.com/s/1BGfC0WLY7u0ZLab0TYtwLQ
提取码:ji42
如果失效了,麻烦留言。
(我csdn没资源积分了,麻烦分多或者会员的大佬,下载我上传的资源,赏我点积分,非常感谢!)
https://download.youkuaiyun.com/download/hp_cpp/11197399
(plus,本来想设置成1积分的,结果发现没法设置资源积分,csdn居然还在偷偷涨资源积分,看来要转github这样的平台了(⊙o⊙)…)

本教程主要功能
1.实现了一个简单的待办事项
2.删除勾选的一行记录,也可以删除多行已经勾选的记录
是用C++继承QAbstractListModel实现了model,然后给qml调用。
运行效果:
在这里插入图片描述
源码之前了无秘密:
ToDoList.qml

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3

import ToDo 1.0
ColumnLayout
{
    Frame {
        ListView {
            implicitWidth: 250
            implicitHeight: 250
            clip: true

            /*
            model: ListModel {
                ListElement {
                    done: true
                    description: "Wash the car"
                }
                ListElement {
                    done: true
                    description: "fix the sink"
                }
            }
            */
            model: ToDoModel {
                list:  toDoList
            }

            delegate: RowLayout {
                width: parent.width
                CheckBox {
                    checked: model.done
                    onClicked: model.done = checked
                }
                TextField {
                    text: model.description
                    onEditingFinished: model.description = text
                    Layout.fillWidth:  true
                }
            }
        }
    }

    RowLayout {
        Button {
            text: qsTr("Add new item")
            onClicked: toDoList.appendItem()
            Layout.fillWidth: true
        }
        Button {
            text: qsTr("Remove completed")
            onClicked: toDoList.removeCompleteItems()
            Layout.fillWidth: true
        }
    }
}

main.qml文件:

import QtQuick 2.9
import QtQuick.Window 2.2

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    ToDoList {
        anchors.centerIn: parent
    }
}

todolist.h文件:

#ifndef TODOLIST_H
#define TODOLIST_H

#include <QObject>
#include <QVector>

struct ToDoItem
{
    bool done;
    QString description;
};

class ToDoList : public QObject
{
    Q_OBJECT
public:
    explicit ToDoList(QObject *parent = nullptr);

    QVector<ToDoItem> items() const;

    bool setItemAt(int index, const ToDoItem &item);


signals:
    void preItemAppended();
    void postItemAppended();

    void preItemRemoved(int index);
    void postItemRemoved();

public slots:
    void appendItem();
    void removeCompleteItems();

private:
    QVector<ToDoItem> mItems;
};

#endif // TODOLIST_H

todolist.cpp文件:

#include "todolist.h"

ToDoList::ToDoList(QObject *parent) : QObject(parent)
{
    mItems.append({true, QStringLiteral("Wash the car")});
    mItems.append({true, QStringLiteral("Fix the car")});
}

QVector<ToDoItem> ToDoList::items() const
{
    return mItems;
}

bool ToDoList::setItemAt(int index, const ToDoItem &item)
{
    if (index < 0 || index >= mItems.size())
        return false;

    const ToDoItem &oldItem = mItems.at(index);
    if (item.done == oldItem.done && item.description == oldItem.description)
        return false;

    mItems[index] = item;
    return true;
}

void ToDoList::appendItem()
{
    emit preItemAppended();

    ToDoItem item;
    item.done = false;
    mItems.append(item);

    emit postItemAppended();
}

void ToDoList::removeCompleteItems()
{
    for (int i = 0; i < mItems.size(); ) {
        if (mItems.at(i).done) {
            emit preItemRemoved(i);

            mItems.removeAt(i);

            emit postItemRemoved();
        } else {
            ++i;
        }
    }
}

todomodel.h文件:

#ifndef TODOMODEL_H
#define TODOMODEL_H

#include <QAbstractListModel>

class ToDoList;

class ToDoModel : public QAbstractListModel
{
    Q_OBJECT
    Q_PROPERTY(ToDoList *list READ list WRITE setList)

public:
    explicit ToDoModel(QObject *parent = nullptr);

    enum {
        DoneRole = Qt::UserRole,
        DescriptionRole
    };

    // Basic functionality:
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;

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

    // Editable:
    bool setData(const QModelIndex &index, const QVariant &value,
                 int role = Qt::EditRole) override;

    Qt::ItemFlags flags(const QModelIndex& index) const override;

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


    ToDoList *list() const;
    void setList(ToDoList *list);

private:
    ToDoList *mList;
};

#endif // TODOMODEL_H

todomodel.cpp文件:

#include "todomodel.h"
#include "todolist.h"

ToDoModel::ToDoModel(QObject *parent)
    : QAbstractListModel(parent)
    , mList(nullptr)
{
}

int ToDoModel::rowCount(const QModelIndex &parent) const
{
    // For list models only the root node (an invalid parent) should return the list's size. For all
    // other (valid) parents, rowCount() should return 0 so that it does not become a tree model.
    if (parent.isValid() || !mList)
        return 0;

    // FIXME: Implement me!
    return mList->items().size();
}

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

    // FIXME: Implement me!
    const ToDoItem item = mList->items().at(index.row());
    switch (role) {
    case DoneRole:
        return QVariant(item.done);
    case DescriptionRole:
        return QVariant(item.description);
    }
    return QVariant();
}

bool ToDoModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!mList)
        return false;

    ToDoItem item = mList->items().at(index.row());
    switch (role) {
    case DoneRole:
        item.done = value.toBool();
        break;
    case DescriptionRole:
        item.description = value.toString();
        break;
    }

    if (mList->setItemAt(index.row(), item)) {
        // FIXME: Implement me!
        emit dataChanged(index, index, QVector<int>() << role);
        return true;
    }
    return false;
}

Qt::ItemFlags ToDoModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return Qt::NoItemFlags;

    return Qt::ItemIsEditable; // FIXME: Implement me!
}

QHash<int, QByteArray> ToDoModel::roleNames() const
{
    QHash<int, QByteArray> names;
    names[DoneRole] = "done";
    names[DescriptionRole] = "description";
    return names;
}

ToDoList *ToDoModel::list() const
{
    return mList;
}

void ToDoModel::setList(ToDoList *list)
{
    beginResetModel();

    if (mList)
        mList->disconnect(this);

    mList = list;

    if (mList) {
        connect(mList, &ToDoList::preItemAppended, this, [=](){
            const int index = mList->items().size();
            beginInsertRows(QModelIndex(), index, index);
        });
        connect(mList, &ToDoList::postItemAppended, this, [=](){
            endInsertRows();
        });

        connect(mList, &ToDoList::preItemRemoved, this, [=](int index){
            beginRemoveRows(QModelIndex(), index, index);
        });
        connect(mList, &ToDoList::postItemRemoved, this, [=](){
            endRemoveRows();
        });
    }

    endResetModel();
}

main.cpp文件:

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

#include "todomodel.h"
#include "todolist.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    qmlRegisterType<ToDoModel>("ToDo", 1, 0, "ToDoModel");
    qmlRegisterUncreatableType<ToDoList>("ToDo", 1, 0, "toDoList", QStringLiteral("ToDoLsit should not be created in QML"));
    ToDoList toDoList;

    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty(QStringLiteral("toDoList"), &toDoList);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));


    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

其中class ToDoModel : public QAbstractListModel
利用qt creator进行添加比较方便:
在这里插入图片描述
在这里插入图片描述
视频中是勾选的第三个,其余的可以根据需要勾选。
在这里插入图片描述
利用代码补齐,选中mList后,用Alt+Enter可以自动添以下两个函数:
ToDoList *list() const;
void setList(ToDoList *list);
然后发现其他人也看过这个视频,参考:
https://blog.youkuaiyun.com/qq_32768743/article/details/80863753
官方文档:https://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html
纯QML写的:https://blog.youkuaiyun.com/suerimn/article/details/86141903

Qt Quick enables you to build UIs around the behavior of components and how they connect with one another. You create components using Qt Quick and QML types that are available in the Design mode. You can specify values for the properties of a component to change its appearance and behavior. All QML types have a set of predefined properties, some of which control things that are visible to users, while others are used behind the scene. While it is useful to learn the basics of Qt Quick, you can also rely on Qt Design Studio to write the code for you when you drag-and-drop the ready-made components to the working area and change them to your liking by modifying their properties in the Design mode. You can always check up details in the extensive Qt Quick documentation by pressing F1. Creating Qt Quick Projects You can use wizards to create Qt Quick projects. Editing QML Files in Design Mode You can use the Form Editor or the Text Editor in the Design mode to develop Qt Quick applications. Creating Components In addition to your imported artwork, you can use the Design mode to customize ready-made components or design any custom form and shape directly as QML types. You can import visual assets in various formats, such as PNG, JPG, and SVG for use in the components. Managing Item Hierarchy You can manage the items in the current QML file and their relationships in the Navigator. Specifying Item Properties You can specify values for the properties of a component to change its appearance and behavior. All QML types have a set of predefined properties. Some properties, such as position, size, and visibility, are common to all QML types, whereas others are specific to the QML type. You can specify properties for your components in the Properties pane. Creating Animations You can use a timeline and keyframe based editor in the Timeline view to animate the properties of UI components. Animating properties enables their values to move through intermediate values at specified keyframes instead of immediately changing to the target value. Adding Connections You can create connections between the UI components and the application to enable them to communicate with each other. For example, how does the appearance of a button change on a mouse click and which action does the application need to perform in response to it. You can also create connections between UI components by binding their properties together. This way, when the value of a property changes in a parent component, it can be automatically changed in all the child components, for example. Adding States Qt Quick allows you to declare various UI states that describe how component properties change from a base state. Therefore, states can be a useful way of organizing your UI logic. You can associate transitions with items to define how their properties will animate when they change due to a state change. Related Topics Editing PathView Properties You can use a graphical spline editor to specify PathView paths. A path view lays out data provided by data models on a Path. Browsing ISO 7000 Icons You can add ISO 7000 icons from a library delivered with Qt Creator to UIs and change their color. Qt Quick UI Forms Some of the wizards create Qt Quick projects that contain UI forms (.ui.qml files). The forms use a purely declarative subset of the QML language and you can edit them in the Design mode. Using QML Modules with Plugins QML modules may use plugins to expose components defined in C++ to QML applications. Qt Creator cannot load the plugins to determine the details of the contained components, and therefore, the modules must provide extra type information for code completion and the semantic checks to work correctly. Converting UI Projects to Applications Qt Quick UI projects (.qmlproject) are useful for creating user interfaces. To use them for application development, you have to convert them to Qt Quick Application projects that contain .pro, .cpp, and .qrc files. Designing User Interfaces ◦ Creating Qt Quick Projects
最新发布
09-11
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值