<QML_JanQuickDemo>四、人员管理-TableView的使用

目录

前言 

界面展示

界面结构 

代码结构

操作展示

数据展示

修改数据

删除数据

添加数据

EBaseTableView

Dialog

ETableModel

页面整体代码

DataHandleVM

源码地址

总结


前言 

        本篇介绍一下JanQuick_Demo的人员管理页面,主要是介绍TableView和QAbstractTableModel的使用,通过自定义model,delegate实现表格样式自定义和对表格的增删改查。展示的数据来源于本地文件,对表格进行增删改查时没有去改动本地文件,重启demo将恢复初始状态

        同样的,本篇的demo源码地址放在末尾,有需要的读者可以自取

界面展示

界面结构 

        本次的页面结构比较简单,Rectangle作为整体背景,一个TableView展示数据内容 

代码结构

       Rectangle作为根元素,下属三个子元素 : EBaseTableView 、Dialog 、ETableModel

        

操作展示

        数据展示

 

         修改数据

         删除数据

        添加数据

EBaseTableView

        该控件继承QtQuick.Controls 1中的TableView,对headerDelegate 、itemDelegate、rowDelegate的样式进行了自定义,具体代码如下:

EBaseTableView.qml

import QtQuick 2.13
import QtQuick.Controls 1.4
import QtQuick.Controls 2.12
import Qt.labs.settings 1.0

import EUIpackage 1.0
import EControl 1.0
TableView{
    id:tableview
    frameVisible:false
    anchors.margins: 24
    signal rowHoveredChanged(var hovered,var row)
    property int currSelectedRow: -1
    headerDelegate: Rectangle{
        width: parent.width
        height: 50
        color: "white"
        Rectangle{
            width: 1
            height: 25
            color: EColor.borderColor(EColor.Border_3)
            anchors.left: parent.left
            anchors.verticalCenter: parent.verticalCenter
        }
        Rectangle{
            width: parent.width
            height: 1
            anchors.bottom: parent.bottom
            color: EColor.borderColor(EColor.Border_3)
        }
        Text {
            text: styleData.value
            color: EColor.textColor(EColor.Text_Main)
            font.pixelSize: 16
            width: parent.width
            height: contentHeight
            elide:Text.ElideRight
            anchors.left: parent.left
            anchors.leftMargin: 2
            anchors.verticalCenter: parent.verticalCenter
            font.family: EFont.textHanSansNormal
        }
    }

    rowDelegate:Rectangle{
        id:rowbg
        width: parent.width
        height: 48
        color: "transparent"
        border.width: 0
        property int currSelectedRow: tableview.currSelectedRow
        Rectangle{
            width: parent.width
            height: 1
            color: EColor.borderColor(EColor.Border_3)
            anchors.bottom: parent.bottom

        }
        onCurrSelectedRowChanged: {
            if(currSelectedRow ===styleData.row)
                rowbg.color = EColor.bgColor(EColor.BGColor_2)
            else
                rowbg.color = "transparent"
        }

        Connections{
            target: tableview
            onRowHoveredChanged:{
                if(row ===styleData.row && currSelectedRow !==styleData.row){
                    if(hovered)
                        rowbg.color = EColor.bgColor(EColor.BGColor_2)
                    else
                        rowbg.color = "transparent"
                }
            }
        }
    }

    itemDelegate: Item{
        id:itemdel
        width: parent.width
        height: 48
        clip: true
        property bool hovered: false
        onHoveredChanged: {
            tableview.rowHoveredChanged(hovered,styleData.row)
        }
        MouseArea{
            anchors.fill: parent
            hoverEnabled: true
            onEntered: itemdel.hovered= true
            onExited: itemdel.hovered = false
        }
        Text {
            text: styleData.value
            color: EColor.textColor(EColor.Text_Routine)
            font.pixelSize: 14
            width: parent.width
            height: contentHeight
            elide:Text.ElideRight
            anchors.verticalCenter: parent.verticalCenter
            font.family: EFont.textHanSansNormal
        }

    }
}

Dialog

        

        该弹窗是用于新增项目和修改项目填写信息使用的,由于只使用了一次就没控件化了,代码如下:

Dialog{
        id:inputdialog
        anchors.centerIn: parent
        width: parent.width/2.5
        height: parent.height/4*3
        modal: true
        closePolicy: Popup.NoAutoClose
        property bool isNew: false
        property int currSelectedRow: -1
        background: Rectangle{
            radius: 4
            anchors.fill: parent
            border.width: 1
            border.color: EColor.borderColor(EColor.Border_1)
        }
        contentItem: Item{
            anchors.fill: parent
            Text {
                id: titleText
                text: inputdialog.isNew? "添加新成员" : "修改成员信息"
                anchors.top: parent.top
                anchors.topMargin: 12
                anchors.horizontalCenter: parent.horizontalCenter
                font.family: EFont.textHanSansMedium
                font.pixelSize: 26
                color: EColor.textColor(EColor.Text_Main)
                width: contentWidth
                height: contentHeight
            }
            Column{
                id:inputColumn
                width:  parent.width-40
                anchors.top: titleText.bottom
                anchors.topMargin: 22
                anchors.horizontalCenter: parent.horizontalCenter
                spacing: 22
                CusTipInput{
                    width: parent.width
                    height: 40
                    tiptext: "姓        名"
                    placeholderText:"请输入姓名"
                }
                CusTipInput{
                    width: parent.width
                    height: 40
                    tiptext: "国        家"
                    placeholderText:"请输入国家名"
                }
                CusTipInput{
                    width: parent.width
                    height: 40
                    tiptext: "城        市"
                    placeholderText:"请输入城市名"
                }

                CusTipInput{
                    width: parent.width
                    height: 40
                    tiptext: "出生日期"
                    placeholderText:"请输入出生日期"
                }
                CusTipInput{
                    width: parent.width
                    height: 40
                    tiptext: "联系方式"
                    placeholderText:"请输入联系方式"
                }
            }//end columm
            EBaseBtn{
                width: 100
                height: 40
                anchors.left: parent.left
                anchors.bottom: parent.bottom
                anchors.margins: 20
                cusText:"取消"
                onClicked: {
                    inputdialog.close()
                }
            }
            EMainBtn{
                width: 100
                height: 40
                anchors.right: parent.right
                anchors.bottom: parent.bottom
                anchors.margins: 20
                cusText:"确定"
                onClicked: {
                    var childrenList = inputColumn.children
                    if(childrenList[0].inputText === ""){
                        dialogToast.showToast("姓名不能为空",EToast.StyleEnum.ERROR)
                        return
                    }

                    if(inputdialog.isNew){
                        var dataList = []
                        for(var i = 0;i<childrenList.length;++i){
                            dataList.push(childrenList[i].inputText)
                        }
                        DataHandleVM.insertNewRow(etablemodel,dataList)
                    }
                    else{
                        var dataObj = {}
                        for(i = 0;i<etablemodel.roles.length;++i){
                            let role = etablemodel.roles[i]
                            dataObj[role] = childrenList[i].inputText.toString()
                        }
                        DataHandleVM.setRowData(etablemodel,inputdialog.currSelectedRow,dataObj)
                    }

                    inputdialog.close()
                    inputdialog.currSelectedRow =-1
                }
            }
            EToast{
                id:dialogToast
                anchors.horizontalCenter: parent.horizontalCenter
                anchors.top: parent.top
            }
        }//end Dialog.contenItem
    }//end Dialog

ETableModel

        该model继承 QAbstractTableModel,然后注册到qml使用,这里写成了一个比较通用的model,复用性较高。代码如下

ECusTableModel.h

#ifndef ECUSTABLEMODEL_H
#define ECUSTABLEMODEL_H
#include <QObject>
#include <QAbstractTableModel>

class ECusTableModel : public QAbstractTableModel
{
    Q_OBJECT
    Q_PROPERTY(QStringList roles READ roles WRITE setRoles)
public:
    ECusTableModel(QObject *parent = nullptr);
    ~ECusTableModel() override;

    //继承基类的函数
    QVariant data(const QModelIndex &index, int role) const override;
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    int columnCount(const QModelIndex &parent = QModelIndex()) const override;
    QHash<int, QByteArray> roleNames() const override;
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;

    //根据行和roleNmae获取数据
    QVariant rowData(const int row,const QString roleName);
    //根据行和roleName修改数据
    bool setRowData(const int row,const QString roleName,const QVariant newValue);
    //增加行到末尾
    void insertNewRowData(QVariantList dataList);
    //删除行
    void removeRowData(int row);

    QStringList roles() const;
    void setRoles(const QStringList roles);

    void loadData(QList<QVariantList> data);
signals:
private:
    QList<QVariantList> m_data;
    QStringList m_roles;
};

#endif // ECUSTABLEMODEL_H

 ECusTableModel.cpp

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

ECusTableModel::ECusTableModel(QObject *parent)
{
    Q_UNUSED(parent)
}

ECusTableModel::~ECusTableModel()
{
    qDebug()<<__FUNCTION__;
}

QVariant ECusTableModel::data(const QModelIndex &index, int role) const
{
    if (role == Qt::DisplayRole) {
        return m_data[index.row()].at(index.column());
    }
    else
    {
        int columnIndex = role - Qt::UserRole - 1;
        QModelIndex modelIndex = this->index(index.row(), columnIndex);
        return m_data[modelIndex.row()].at(modelIndex.column());
    }
}

int ECusTableModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return m_data.size();
}

int ECusTableModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    if(m_data.isEmpty())
        return 0;
    return m_data.at(0).size();
}

QHash<int, QByteArray> ECusTableModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    for(int i = 0;i < m_roles.size();i++)
    {
        roles[Qt::UserRole+i+1] = m_roles.at(i).toLocal8Bit();
    }
    return roles;
}

bool ECusTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if(index.isValid() && role > Qt::UserRole){
        int row = index.row();
        int column = index.column();
        m_data[row][column] = value;
        emit dataChanged(index,index);
        return  true;
    }
    return false;
}

QVariant ECusTableModel::rowData(const int row, const QString roleName)
{
    int role = roleNames().key(roleName.toUtf8());
    int column = role-Qt::UserRole-1;
    if(!this->index(row,column).isValid()){
        return false;
    }
    QVariant value = this->data(this->index(row,column),role);
    return value;
}

bool ECusTableModel::setRowData(const int row, const QString roleName, const QVariant newValue)
{
    int role = roleNames().key(roleName.toUtf8());
    int column = role-Qt::UserRole-1;
    if(!this->index(row,column).isValid()){
        return false;
    }
    bool ret = this->setData(this->index(row,column),newValue,role);
    return  ret;
}

void ECusTableModel::insertNewRowData(QVariantList dataList)
{
    beginInsertRows(QModelIndex(),rowCount(),rowCount());
    m_data.push_back(dataList);
    this->insertRow(rowCount());
    endInsertRows();
}

void ECusTableModel::removeRowData(int row)
{
    beginRemoveRows(QModelIndex(),row,row);
    m_data.removeAt(row);
    endRemoveRows();
}

QStringList ECusTableModel::roles() const
{
    return m_roles;
}

void ECusTableModel::setRoles(const QStringList roles)
{
    if(!roles.isEmpty()){
        m_roles = roles;
    }
}

void ECusTableModel::loadData(QList<QVariantList> data)
{
    beginResetModel();
    m_data = data;
    endResetModel();
}

页面整体代码

import QtQuick 2.13
import QtQuick.Controls 1.4
import QtQuick.Controls 2.12
import Qt.labs.settings 1.0

import EUIpackage 1.0
import EControl 1.0

import "./"
import "../demoControl"

Rectangle{
    color: "white"
    radius: 4

    EBaseTableView{
        id:tableview
        anchors.fill: parent
        model:etablemodel
        TableViewColumn {
            role: "name";
            title: "姓名";
            width: (parent.width-50)/5
        }
        TableViewColumn {
            role: "country";
            title: "国家";
            width: (parent.width-50)/5
        }
        TableViewColumn {
            role: "city";
            title: "城市";
            width: (parent.width-50)/5
        }
        TableViewColumn {
            role: "birthday";
            title: "出生日期";
            width: (parent.width-50)/5
        }
        TableViewColumn {
            role: "contact";
            title: "联系方式";
            width: (parent.width-50)/5
        }

        MouseArea{
            anchors.fill: parent
            acceptedButtons: Qt.RightButton
            onClicked: {
                tableview.currSelectedRow = tableview.rowAt(mouseX,mouseY)
                menu.popup(mouseX,mouseY)
            }
        }
        CusMenu{
            id:menu
            Action{
                text: "修改员工信息"
                icon.name: "\uf044"
                onTriggered: {
                    //打开dialog清空输入
                    let childrenList = inputColumn.children
                    let name = DataHandleVM.getRowData(etablemodel,tableview.currSelectedRow,"name")
                    for(var i = 0;i<etablemodel.roles.length;++i){
                        let value = DataHandleVM.getRowData(etablemodel,tableview.currSelectedRow,etablemodel.roles[i])
                        childrenList[i].inputText =value.toString()
                    }
                    inputdialog.currSelectedRow = tableview.currSelectedRow
                    inputdialog.isNew = false
                    inputdialog.open()
                }
            }
            Action{
                text: "删除当前员工"
                icon.name: "\uf056"
                enabled: tableview.currSelectedRow >=0
                onTriggered: {
                    DataHandleVM.removeRow(etablemodel,tableview.currSelectedRow)
                }
            }
            Action{
                text: "添加新员工"
                icon.name: "\uf055"
                onTriggered: {
                    //打开dialog清空输入
                    var childrenList = inputColumn.children
                    for(var i = 0;i<childrenList.length;++i){
                        childrenList[i].inputText =""
                    }
                    inputdialog.isNew = true
                    inputdialog.open()
                }
            }
            onVisibleChanged: {
                if(!visible)
                     tableview.currSelectedRow = -1
            }
        }
    }

    Dialog{
        id:inputdialog
        anchors.centerIn: parent
        width: parent.width/2.5
        height: parent.height/4*3
        modal: true
        closePolicy: Popup.NoAutoClose
        property bool isNew: false
        property int currSelectedRow: -1
        background: Rectangle{
            radius: 4
            anchors.fill: parent
            border.width: 1
            border.color: EColor.borderColor(EColor.Border_1)
        }
        contentItem: Item{
            anchors.fill: parent
            Text {
                id: titleText
                text: inputdialog.isNew? "添加新成员" : "修改成员信息"
                anchors.top: parent.top
                anchors.topMargin: 12
                anchors.horizontalCenter: parent.horizontalCenter
                font.family: EFont.textHanSansMedium
                font.pixelSize: 26
                color: EColor.textColor(EColor.Text_Main)
                width: contentWidth
                height: contentHeight
            }
            Column{
                id:inputColumn
                width:  parent.width-40
                anchors.top: titleText.bottom
                anchors.topMargin: 22
                anchors.horizontalCenter: parent.horizontalCenter
                spacing: 22
                CusTipInput{
                    width: parent.width
                    height: 40
                    tiptext: "姓        名"
                    placeholderText:"请输入姓名"
                }
                CusTipInput{
                    width: parent.width
                    height: 40
                    tiptext: "国        家"
                    placeholderText:"请输入国家名"
                }
                CusTipInput{
                    width: parent.width
                    height: 40
                    tiptext: "城        市"
                    placeholderText:"请输入城市名"
                }

                CusTipInput{
                    width: parent.width
                    height: 40
                    tiptext: "出生日期"
                    placeholderText:"请输入出生日期"
                }
                CusTipInput{
                    width: parent.width
                    height: 40
                    tiptext: "联系方式"
                    placeholderText:"请输入联系方式"
                }
            }//end columm
            EBaseBtn{
                width: 100
                height: 40
                anchors.left: parent.left
                anchors.bottom: parent.bottom
                anchors.margins: 20
                cusText:"取消"
                onClicked: {
                    inputdialog.close()
                }
            }
            EMainBtn{
                width: 100
                height: 40
                anchors.right: parent.right
                anchors.bottom: parent.bottom
                anchors.margins: 20
                cusText:"确定"
                onClicked: {
                    var childrenList = inputColumn.children
                    if(childrenList[0].inputText === ""){
                        dialogToast.showToast("姓名不能为空",EToast.StyleEnum.ERROR)
                        return
                    }

                    if(inputdialog.isNew){
                        var dataList = []
                        for(var i = 0;i<childrenList.length;++i){
                            dataList.push(childrenList[i].inputText)
                        }
                        DataHandleVM.insertNewRow(etablemodel,dataList)
                    }
                    else{
                        var dataObj = {}
                        for(i = 0;i<etablemodel.roles.length;++i){
                            let role = etablemodel.roles[i]
                            dataObj[role] = childrenList[i].inputText.toString()
                        }
                        DataHandleVM.setRowData(etablemodel,inputdialog.currSelectedRow,dataObj)
                    }

                    inputdialog.close()
                    inputdialog.currSelectedRow =-1
                }
            }
            EToast{
                id:dialogToast
                anchors.horizontalCenter: parent.horizontalCenter
                anchors.top: parent.top
            }
        }//end Dialog.contenItem
    }//end Dialog

    ETableModel{
        id:etablemodel
        roles:["name","country","city","birthday","contact"]
        Component.onCompleted: {
            DataHandleVM.loadPeopelModelData(etablemodel)
        }
    }
}

DataHandleVM

        DataHadleVm是整个demo中处理业务逻辑的一个类,比如读取本地数据、加载数据、修改表格等。目的是为了使业务逻辑有统一的操作入口。在本次的人员管理的表格中,DataHandleVm中相关的业务处理函数如下,具体函数实现可以下载源码了解

源码地址

JanQuick_Demo

总结

本次分享就到这了,对你有帮助的话点个赞吧。

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
可以使用以下 Java 正则表达式进行匹配: ```java import java.util.regex.Matcher; import java.util.regex.Pattern; String html = "<div class=\"qml-stem\"><p style=\"\"><span style=\"font-family: 宋体;\">读一读,猜一猜。</span></p><p style=\"\"><span style=\"font-family: 宋体;\">什么鸟跑得快,不爱树林爱沙漠?(<span style=\"font-family: 'Times New Roman'\" qml-space-size=\"2\"> </span>)</span></p><div class=\" qml-og\"><table class=\"qml-og\" style=\"width:100%\"><tr><td>A. <span class=\"qml-op\"><span style=\"font-family: 宋体;\">山椒鸟</span></span></td><td>B. <span class=\"qml-op\"><span style=\"font-family: 宋体;\">鸵鸟</span></span></td><td colspan=\"1\">C. <span class=\"qml-op\"><span style=\"font-family: 宋体;\">犀鸟</span></span></td></tr></table></div></div>"; Pattern pattern = Pattern.compile("<td>A\\.\\s*<span.*?>(.*?)</span></td>"); Matcher matcher = pattern.matcher(html); if (matcher.find()) { String optionA = matcher.group(1); System.out.println(optionA); // 输出:山椒鸟 } else { System.out.println("没有选项A"); } ``` 该正则表达式的含义是匹配 `<td>` 标签中以大写字母 A 开头,以 `</td>` 结尾的内容(即选项 A)。使用 `\\s*` 匹配零个或多个空格。使用 `.*?` 匹配任意字符(包括换行符),直到后面的 `</span>` 结束标签。使用 `()` 捕获选项 A 的内容。使用 `Matcher.find()` 函数可以在字符串中搜索第一个匹配项。如果找到了匹配项,则使用 `matcher.group(1)` 获取第一个匹配的子串,即选项 A 的内容。如果没有找到匹配项,则说明没有选项 A。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值