qml 实现一个listview

主要通过qml实现listvie功能,主要包括右键菜单,滚动条,拖动改变内容等,c++ 与 qml之间的变量和函数的调用。

main.cpp

#include <QQuickItem>
#include <QQmlContext>
#include "testlistmodel.h"
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    qmlRegisterType<TestListModel>("TestListModel", 1, 0, "TestListModel");
    engine.load(QUrl(QStringLiteral("qrc:/ui1.qml")));
    QObject* root = engine.rootObjects().first();
    QString retVal;
    QVariant message = "Hello from c++";
    QVariant returnedValue;
    QQmlProperty(root,"testmsg").write("hello,world");
    qDebug()<<"Cpp get qml property height222"<<root->property("msg");
    bool ret =QMetaObject::invokeMethod(root,"setSignalB",
                              Q_RETURN_ARG(QVariant,returnedValue),
                              Q_ARG(QVariant,message),
                              Q_ARG(QVariant,8));
    qDebug()<<"returnedValue"<<returnedValue<<root<<ret;
    return app.exec();
}

listview 的model 代码

TestListModel.h

#ifndef TESTLISTMODEL_H
#define TESTLISTMODEL_H

#include <QAbstractListModel>
typedef struct Student
{
    int     id;
    QString name;
    QString sex;
}pStudent;

class TestListModel : public QAbstractListModel
{
    Q_OBJECT
public:
    explicit TestListModel(QObject *parent = nullptr);
    int rowCount(const QModelIndex &parent) const;

    QVariant data(const QModelIndex &index, int role) const;
    virtual QHash<int, QByteArray> roleNames() const;
    Qt::ItemFlags flags(const QModelIndex &index) const override;
    Q_INVOKABLE void modifyItemText(int row1,int row2);
    Q_INVOKABLE void add();

    enum MyType{
        ID=Qt::UserRole+1,
        Name,
        Sex
    };
private:
     QVector<Student>  m_studentList;

signals:
     void    layoutChanged();
};

#endif // TESTLISTMODEL_H

TestListModel.cpp

#include "testlistmodel.h"
#include <QDebug>

TestListModel::TestListModel(QObject *parent)
    : QAbstractListModel{parent}
{
    for(int i=0;i<20;i++)
    {
        Student oneData;
        oneData.id = i;
        oneData.name  = QString("张三%1").arg(i);
        if(i%2==0)
        {
            oneData.sex = "female" ;
        }
        else
        {
            oneData.sex = "male" ;
        }
        //qDebug()<<"TestListModel"<<m_studentList.size();
        m_studentList.append(oneData);
    }   

}

int TestListModel::rowCount(const QModelIndex &parent) const
{
    //qDebug()<<"rowCount"<<m_studentList.size();
    return m_studentList.size();
}
QVariant TestListModel::data(const QModelIndex &index, int role) const
{
   // qDebug()<<"TestListModel::data11111111111"<<index.isValid();

    QVariant var;
    if ( !index.isValid() )
    {
        return QVariant();
    }
    int nRow    = index.row();
    int nColumn = index.column();
    if(Qt::UserRole+1 == role)
    {
        var = QVariant::fromValue(m_studentList.at(nRow).id);
    }
    else if(Qt::UserRole+2 == role)
    {
        var = QVariant::fromValue(m_studentList.at(nRow).name);
        // qDebug()<<"m_listData.at(nRow).name"<<m_listData.at(nRow).name;
    }
    else if(Qt::UserRole+3 == role)
    {
        var = QVariant::fromValue(m_studentList.at(nRow).sex);
        // qDebug()<<"m_listData.at(nRow).name"<<m_listData.at(nRow).name;
    }
    return var;
}

QHash<int, QByteArray> TestListModel::roleNames() const
{
    QHash<int, QByteArray> d;
    d[MyType::ID]="id";
    d[MyType::Name]="name";
    d[MyType::Sex]="sex";
    qDebug()<<"d .size"<<d.size();
    return d;
}
Qt::ItemFlags TestListModel::flags(const QModelIndex &index) const
{
    Q_UNUSED(index)
    // if(index.column() ==1)
    // {
    //     qDebug()<<"UserInfoModel::flags  1111";
    //     return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
    // }
    qDebug()<<"TestListModel::flags";
    return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}

void TestListModel::modifyItemText(int row1, int row2)
{
    m_studentList.swapItemsAt(row1,row2);
    beginResetModel();
    endResetModel();
}

void TestListModel::add()
{
    Student student;
    student.id   = 123;
    student.name = "love";
    student.sex  = "man";
    m_studentList.push_back(student);
    beginResetModel();
    endResetModel();
    emit layoutChanged();

}

ui.qml

import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Layouts 1.2
import TestListModel 1.0


import QtQuick 2.12

import QtQuick 2.2
import QtQml.Models 2.2
//import QtQuick.Controls 2.12
//QtQuick.Controls 2.12  和QtQuick.Controls.Styles 1.4不匹配
import QtQuick.Controls.Styles 1.4
import QtQuick.Controls 1.4
import QtQuick.Controls 2.12
import QtLocation 5.15
//import "CustomMenuItem.qml"
// import QtQuick.Controls 2.15

//import QtQuick.Controls 2.5


Window {
    id:window
    //anchors.centerIn: parent
    width: 650;
    height: 457
    visible: true
    flags: Qt.FramelessWindowHint | Qt.Dialog
    property string testmsg: "GongJianBo1992"
    Rectangle{
        id:rect1;
        anchors.fill: parent;
        border.width: 1;
        color: "transparent";
        border.color: "red";
        clip:true//这一属性设置表示如果他的子类超出了范围,那么就剪切掉,不让他显示和起作用
    }
    //无边框移动
    MouseArea {
        id: dragRegion
        anchors.fill: parent
        property point clickPos: "0,0"
        onPressed: {
            clickPos = Qt.point(mouse.x,mouse.y)
        }
        onReleased: {
            clickPos = Qt.point(0,0)
        }
        onPositionChanged: {
            //鼠标偏移量
            var delta = Qt.point(mouse.x-clickPos.x, mouse.y-clickPos.y)
            //如果mainwindow继承自QWidget,用setPos
            window.setX(window.x+delta.x)
            window.setY(window.y+delta.y)
        }
    } 
    Menu {
        id: contextMenu
        background: Rectangle {// @disable-check M16
            anchors.fill:parent
            implicitWidth: 200
            implicitHeight: 30
            color: "lightblue"
        }
        Action{
            id:no1
            text:"123"
            onTriggered:
            {
                console.log("选项一被点击")
                tableView.selectAllItem()
            }
            // @disable-check M16
        }
        Menu{
            background: Rectangle {// @disable-check M16
                anchors.fill:parent
                implicitWidth: 200
                implicitHeight: 30
                color: "lightblue"
            }
            title:"love"
            Action{
                id:no4
                text:"789"
                onTriggered:
                {
                    console.log("选项六被点击")
                    tableView.selectAllItem()
                }
            }
        }
        Action {
            id:no2
            text:"234"
            onTriggered:
            {
                console.log("选项二被点击")
                tableView.disselectAllItem()
            }
        }
        MenuSeparator {
            contentItem: Rectangle {// @disable-check M16
                implicitWidth: 200
                implicitHeight: 1
                color: "#21be2b"
            }
        }
        Action {
            id:no3
            text:"345"
            onTriggered: console.log("选项三被点击")
        }
        delegate: MenuItem {// @disable-check M16
            id: menuItem
            height: 40// @disable-check M16
             contentItem: Text{// @disable-check M16
              text:menuItem.text
              color: menuItem.highlighted? "gary": "blue"
            }
            background: Rectangle{// @disable-check M16
                implicitWidth: 200
                implicitHeight: 30
                color: menuItem.highlighted? "purple":"lightblue"
            }
            arrow: Image {// @disable-check M16
                id: arrowImage
                x: parent.width - width
                y: parent.height/2 -height/2
                visible: menuItem.subMenu
                source: "qrc:/Right arrow.png"
            }
        }

    }
     TestListModel{
        id: myMode
        onLayoutChanged:{
           console.log("LayoutChanged")
        }
     }
     // Page{
     //    x:listwidget.x
     //    y:listwidget.y
     //    width:  listwidget.width
     //    height: listwidget.height
     //    background: Rectangle{
     //        anchors.fill: parent
     //        color: "white"
     //        border.width: 1
     //        border.color: "black"
     //    }
     // }
     Rectangle{
         width:  window.width-60+2
         height: 300+2
         border.color: "lightgreen"
         border.width: 1
         color: "transparent"
         x:30
         y:40
     ListView {
         id: listwidget
         width:  parent.width-2//window.width-60
         height: parent.height-2//   300
         x:1
         y:1
         interactive: false // @disable-check M16
         model: myMode
         clip: true  //不写的话,滚动的时候,listview会有拖拽的感觉
         //orientation: ListView.Vertical //垂直列表        
         ScrollBar.vertical: ScrollBar {
             id: scrollBar
             hoverEnabled: true
             active: hovered || pressed
             policy: ScrollBar.AlwaysOn
             orientation: Qt.Vertical
             size: 0.8
             anchors.top: parent.top
             anchors.right: parent.right
             anchors.bottom: parent.bottom
             contentItem: Rectangle  {
                 implicitWidth: 6  //没指定的时候的宽度
                 implicitHeight: 100 //没有指定高度的时候
                 radius: width / 2
                 color: scrollBar.pressed ? "#81e889" : "#c2f4c6"

             }
         }
        Rectangle{
             id : dargRect
             width: 100
             height: 30
             visible: false
             color: "lightgray";
             Text {
                 anchors.verticalCenter: parent.verticalCenter
                 anchors.horizontalCenter: parent.horizontalCenter
                 id: dargRectText
                 // text: "123"
                 horizontalAlignment: Text.AlignHCenter
                 verticalAlignment: Text.AlignVCenter
             }
         }
         delegate: Item{
             id:itemDrag1
             width: window.width-60
             height: 30
             property int dragItemIndex: 0
             property bool isHover: false
             Rectangle {
                 width: window.width-60
                 height: 30
                 //radius: 5;
                 // border.width: 1
                 // border.color: "white"
                 color:isHover === true? "lightgreen":listwidget.currentIndex === index ? "lightblue" : "gray"
                 Text {
                     id:itemDrag2
                     anchors.verticalCenter: parent.verticalCenter
                     anchors.left: parent.left
                     // text: "123"
                     horizontalAlignment: Text.AlignHCenter
                     verticalAlignment: Text.AlignVCenter
                     text: id+":"+name+":"+sex
                 }                
                 MouseArea {
                     id: mouseArea
                     anchors.fill: parent
                     acceptedButtons: Qt.LeftButton | Qt.RightButton
                     hoverEnabled: true
                     onWheel: {// @disable-check M16
                         // 当滚轮被滚动时调用
                         // 事件参数wheel提供了滚动的方向和距离
                         if (wheel.angleDelta.y > 0) {
                             //console.log("向上滚动")
                             scrollBar.decrease();
                         }
                         else {
                             //console.log("向下滚动")
                             scrollBar.increase();
                         }
                     }
                     onEntered:
                     {
                         isHover = true
                         //console.log("onEntered" +isHover)
                     }
                     onExited:
                     {
                         isHover = false
                         //console.log("onExited" +isHover)
                     }
                     onClicked:
                     {
                         if (mouse.button === Qt.RightButton)//菜单
                         {
                             console.log("menu RightButton")
                             contextMenu.popup()
                         }
                         else
                         {
                             //var other_index = listwidget.indexAt(mouseArea.mouseX , mouseArea.mouseY );

                             listwidget.currentIndex = index // 点击时设置当前索引为该项的索引值
                             dragItemIndex = index;
                             console.log("onClicked"+index)
                         }
                     }
                     onPressAndHold:  {
                         if(mouse.button === Qt.LeftButton)
                         {
                             console.log("onPressAndHold"+index)
                             listwidget.currentIndex = index
                             dargRect.x = mouseX +itemDrag1.x
                             dargRect.y = mouseY+itemDrag1.y
                             dragItemIndex = index;
                             dargRectText.text = itemDrag2.text
                             dargRect.visible = true
                         }
                     }
                     onReleased:{
                        if(dargRect.visible === true)
                        {
                            dargRect.visible = false
                            var other_index = listwidget.indexAt(mouseX +itemDrag1.x , mouseY+itemDrag1.y );
                            console.log("onReleased"+other_index)
                            if(dragItemIndex!==other_index)
                            {
                            var afterItem   = listwidget.itemAtIndex(other_index );
                            // listwidget.myModel.get(other_index).text
                            myModel.modifyItemText(dragItemIndex,other_index)
                            //console.log("onReleased"+myModel)
                            }

                        }
                     }
                     onPositionChanged:{
                         //console.log("onPositionChanged111" + mouse.button)
                         if(mouse.button === Qt.LeftButton)
                         {
                             //console.log("onPositionChanged222")
                             var other_index = listwidget.indexAt(mouseX +itemDrag1.x , mouseY+itemDrag1.y );
                             listwidget.currentIndex  = other_index;
                             dargRect.x = mouseX +itemDrag1.x
                             dargRect.y = mouseY+itemDrag1.y
                         }
                     }                     
                 }
             }
         }
     }
 }
    Button {
        id: button1
        x: parent.width-80
        y: parent.height-36
        width:70
        height:30
        //text: qsTr("Button")
        background:Rectangle // @disable-check M16
        {
            //anchors.fill: parent
            border.color: "royalblue"
            border.width: 1
            color: button1.down ? "red" :(button1.hovered?"blue":"lightsteelblue")
        }
        Text {
            text: "1213";
            // anchors.fill: parent
            anchors.centerIn: parent;
            color: button1.hovered?"yellow":"red";
            font.pixelSize: 13;
            //font.weight: Font.DemiBold
        }       
        Connections {
            target: button1
            function onClicked()
            {
                window.close();
            }
        }
    }
    function myQmlFunction( msg,index) {
            console.log("Got message:", msg)
            return "some return value"
        }
    function setSignalB(name, value){

           console.log("setPoint"+" "+testmsg);
           console.log("qml function processB",name,value);
           myMode.add();
           return value
       }

}

运行结果

相关推荐
一个处女座的程序猿O(∩_∩)O2 小时前
小型 Vue 项目,该不该用 Pinia 、Vuex呢?
前端·javascript·vue.js
hackeroink5 小时前
【2024版】最新推荐好用的XSS漏洞扫描利用工具_xss扫描工具
前端·xss
迷雾漫步者6 小时前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-7 小时前
验证码机制
前端·后端
燃先生._.8 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖9 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235249 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_7482402510 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar10 小时前
纯前端实现更新检测
开发语言·前端·javascript