QT (四)模型/视图 QFileSystemModel,QStringListModel,QStandardItemModel

  • 思考:QTableWidget 在某种程度上可以等价为QStandardItemModel,同理,其他的功能也有类似的等价,但是以当前的QTableWidget QStandardItemModel为例的话,两者都是用于实现建立表格的相关组件,只不过QStandardItemModel使用更为灵活,可以自定义自己的模型

QFileSystemModel,list,view,tree view应用于文件模型








  • 知识点:下列案例是QFileSystemModel文件模型的应用
cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QFileSystemModel>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_treeView_clicked(const QModelIndex &index);

private:
    Ui::MainWindow *ui;
    QFileSystemModel *model;
};
#endif // MAINWINDOW_H
cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QDebug"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //创建模型
    model = new QFileSystemModel;

    //设置文件系统模型的根目录
    //在这指定的目录下安装了一个文件系统监视器,这个目录下的文件信息的改变都会显示在这个模型里面
    model->setRootPath(QDir::currentPath());

    //关联模型和"视图"
    ui->treeView->setModel(model);
    ui->listView->setModel(model);
    ui->tableView->setModel(model);

    //list,tree,table是三种view,实现的功能是一样的,只是对当前文件系统的显示方式不一样
    //使用信号槽,通知其他视图的即使变化,实现3种view同步变化
    connect(ui->treeView,SIGNAL(clicked(QModelIndex)),ui->listView, SLOT(setRootIndex(QModelIndex)));
    connect(ui->treeView,SIGNAL(clicked(QModelIndex)),ui->tableView, SLOT(setRootIndex(QModelIndex)));

}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_treeView_clicked(const QModelIndex &index)
{
    ui->labelFileName->setText(model->fileName(index));
    float size = model->size(index) /1024; //?k

    qDebug() << "size " << size;

    if(size >1024){
        ui->labelFileSize->setText(QString::asprintf("%.1f MB", size/1024.0)) ;
    }else
    {
        ui->labelFileSize->setText(QString::asprintf("%f kB", size)) ;
    }


    ui->labelNodeType->setText(model->type(index));
    ui->checkBox->setChecked(model->isDir(index));
    ui->labelFilePath->setText(model->filePath(index));



}

二 QStringListModel

  • 知识点:总结来说,模型的使用,包括以下几个步骤:

  • 在.h文件中,定义模型指针 QStringListModel *model;;

  • 在cpp文件的构造函数中,构建模型model= new QStringListModel;

  • 构造数据/导入数据, QStringList addrList = {"北京","上海","广州","深圳","贵州","杭州","深圳"}; model->setStringList(addrList);

  • 模型和组件的关联 ui->listView->setModel(model);

  • 数据添加完毕后,让鼠标选中新添加的数据新型显示
bash 复制代码
    ui->listView->setCurrentIndex(index);
cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QStringListModel>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_pushButtonEndAdd_clicked();

    void on_pushButtonInsert_clicked();

    void on_pushButtonDelete_clicked();

    void on_pushButtonClear_clicked();

    void on_pushButtonInit_4_clicked();

    void on_pushButtonInit_3_clicked();

    void on_pushButtonInit_2_clicked();

private:
    Ui::MainWindow *ui;
    QStringListModel *model;
};
#endif // MAINWINDOW_H
cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //创建模型
    model= new QStringListModel;

    //构造数据/导入数据
    QStringList addrList = {"北京","上海","广州","深圳","贵州","杭州","深圳"};
    model->setStringList(addrList);

    //关联
    ui->listView->setModel(model);
    ui->tableView->setModel(model);

}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_pushButtonEndAdd_clicked()
{
    //在尾部插入一行
    model->insertRow(model->rowCount());

    QModelIndex index = model->index(model->rowCount()-1,0); //获取最后一行第0列数据

    //设置插入行的数据
    model->setData(index,"新的城市");

    //数据添加完毕后,让鼠标选中新添加的数据新型显示
    ui->listView->setCurrentIndex(index);

}

void MainWindow::on_pushButtonInsert_clicked()
{
    QModelIndex index = ui->listView->currentIndex();
    model->insertRow(index.row());
    model->setData(index,"插入新的城市");
    ui->listView->setCurrentIndex(index);

}

void MainWindow::on_pushButtonDelete_clicked()
{
    QModelIndex index = ui->listView->currentIndex();
    model->removeRow(index.row());
}

void MainWindow::on_pushButtonClear_clicked()
{
   model->removeRows(0,model->rowCount());
}

void MainWindow::on_pushButtonInit_4_clicked()
{
    QStringList list = model->stringList();

    ui->plainTextEdit->clear();
    for(int i = 0; i < list.count(); i++){
        ui->plainTextEdit->appendPlainText(list[i]);
    }
}

void MainWindow::on_pushButtonInit_3_clicked()
{
    ui->plainTextEdit->clear();
}

void MainWindow::on_pushButtonInit_2_clicked()
{

    //构造数据/导入数据
    QStringList addrList = {"北京","上海","广州","深圳","贵州","杭州","深圳"};
    model->setStringList(addrList);

}

三 QStandardItemModel

  • 问题:这种表格和table view之间的差别和联系是什么:是一种存储数据的模型,虽然展现的格式是表格,但是有自己的数据取出和存储方式,table view是一个组件工具
  • 知识点:之前的自定义槽函数的命名模式是on_actionBold_triggered,on_信号_槽函数,这样做的前提是,信号是QT组件发出的信号,槽函数可以任意自定义,但是如果信号不是Qt组件发出的信号,而是自定义或者调用的类发出的信号,则最好不要这样命名,on_信号 即可,会导致找不到信号,虽然不会影响程序的正常运行。比如当前案例调用了一个类selectionModel = new QItemSelectionModel(model);,这个类发出信号,点击类名QItemSelectionModel查看相应的信号名,最终实现 根据单元格是否是粗体,要更新粗体图标的状态 的功能。 该案例就是用一个类发出信号,而非组件
cpp 复制代码
   // 添加信号槽   void currentChanged(const QModelIndex &current, const QModelIndex &previous);
    connect(selectionModel, SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
            this,SLOT(on_currentChanged(const QModelIndex &, const QModelIndex &)));

最终实现 根据单元格是否是粗体,要更新粗体图标的状态 的功能

cpp 复制代码
 //
void MainWindow::on_currentChanged(const QModelIndex &current, const QModelIndex &previous)
{
    if(current.isValid()){
        auto item = model->itemFromIndex(current);
        //根据当前选中单元格的字体是不是粗体来判断图标的变化,如果是粗体,图标状态是选中状态
        //反之,不选中
        ui->actionBold->setChecked(item->font().bold());

        //在状态栏的标签中,显示所选中单元格是第几行第几列
        labelinfo->setText(QString::asprintf("当前单元格:%d行,%d列",
                           current.row()+1,current.column()+1) +
                           "  单元格内容  " + item->text());
    }
}
cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QStandardItemModel>
#include <QItemSelectionModel>
#include <QLabel>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_actionOpen_triggered();

    void on_actionAdd_triggered();

    void on_actionInsert_triggered();

    void on_actionDelete_triggered();

    void on_actionSee_triggered();

    void on_actionSave_triggered();

    void on_actionRight_triggered();

    void on_actionLeft_triggered();

    void on_actionMiddle_triggered();


    void on_actionBold_triggered(bool checked);

    void on_currentChanged(const QModelIndex &current, const QModelIndex &previous);
private:
    Ui::MainWindow *ui;
    QStandardItemModel *model;
    QItemSelectionModel *selectionModel;
    int collumCount; //列数

    void initModel(QStringList content);

    QLabel *labelinfo;
};
#endif // MAINWINDOW_H
cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QTextStream>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    collumCount = 6;

    model = new QStandardItemModel(2,collumCount, this);
    selectionModel = new QItemSelectionModel(model);

    ui->tableView->setModel(model);
    ui->tableView->setSelectionModel(selectionModel);  //对表数据选择模式,比如选中ctrl+鼠标可以多选

    //配置table view的相关属性
    //QAbstractItemView::ExtendedSelection:当前模式能实现以下的功能
    //单击某选项,以前的选择会被取消
    //同时按下ctrl,以前的选项和现在的选项都会保留
    //同时按下shift,第一次选中的为左上角,当前选择为右下角的数据都会被选中
    ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);

    //选择单元格
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);

    // 添加信号槽   void currentChanged(const QModelIndex &current, const QModelIndex &previous);
    connect(selectionModel, SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
            this,SLOT(on_currentChanged(const QModelIndex &, const QModelIndex &)));

    //手动添加标签到状态栏
    labelinfo = new QLabel(this);
    statusBar()->addWidget(labelinfo);

}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_actionOpen_triggered()
{
      QString filiname = QFileDialog::getOpenFileName(this,"打开一个文件",QCoreApplication::applicationDirPath(), "文本数据文件(*txt);;所有文件(*.*)");

      if(filiname.isEmpty()){
          return;
      }

      QFile qfile(filiname);
      //指定文件的打开方式,如果打不开,结束
      if(!qfile.open(QIODevice::ReadOnly | QIODevice::Text)){
          return;
      }

      QTextStream stream(&qfile);
      QStringList fileContent;
      while(!stream.atEnd()){
          QString line = stream.readLine();
          fileContent.append(line);

          //把读到的内容放到右侧的文本编辑器
          ui->plainTextEdit->appendPlainText(line);
      }
      qfile.close();


      //将数据放置到数据模型里面去
      initModel(fileContent);

}

void MainWindow::initModel(QStringList content)
{
   //需要根据数据文本格式来进行切割
   QString headline = content[0];
   //QRegExp \s 自动匹配1个任意空白字符
   //\s+ 自动匹配1个或者多个任意空白字符
   // \\ 转移为'\'
   QStringList headlist  = headline.split(QRegExp("\\s+"),
                   QString::SkipEmptyParts); //跳过空格

   model->setHorizontalHeaderLabels(headlist);

   //读取数据
   int rows = content.count();
   for(int i =1 ;i < rows; i++){
       QString line = content[i];
       QStringList filedList = line.split(QRegExp("\\s+"), QString::SkipEmptyParts);

       for(int j =0; j < collumCount-1; j++){
           QStandardItem *item = new QStandardItem(filedList[j]);
           model->setItem(i-1,j,item);
       }

       //取最后一列数据,将是打✔,否则维持原状
       QStandardItem *item = new QStandardItem(headlist[collumCount-1]);
       item->setCheckable(true);  // 设置为可勾选
       if(filedList[collumCount-1] == "否"){
           item->setCheckState(Qt::Unchecked);
       }else{
           item->setCheckState(Qt::Checked);
       }
       model->setItem(i-1,collumCount-1,item);
   }
}

void MainWindow::on_actionAdd_triggered()
{
    QStringList initValue = {"无名","男","市场部","销售","50000","婚否"};

    //将数据放入list中
    QList <QStandardItem*> itemList;
    for(int j =0; j < collumCount; j++){
        QStandardItem *item = new QStandardItem(initValue[j]);
        itemList.push_back(item);
    }
    itemList[collumCount-1]->setCheckable(true);  // 设置为可勾选,最后一列数据是可选框的状态
    model->insertRow(model->rowCount(), itemList); //默认在最后一行添加数据

    //设置最后一行是被选中的状态
    selectionModel->clearSelection();
    QModelIndex index = model->index(model->rowCount() -1,0);
    selectionModel->setCurrentIndex(index,QItemSelectionModel::Rows);
}

void MainWindow::on_actionInsert_triggered()
{
    QStringList initValue = {"无名","男","市场部","销售","50000","婚否"};


    QList <QStandardItem*> itemList;
    for(int j =0; j < collumCount; j++){
        QStandardItem *item = new QStandardItem(initValue[j]);
        itemList.push_back(item);
    }
    itemList[collumCount-1]->setCheckable(true);  // 设置为可勾选,最后一列数据是可选框的状态

    QModelIndex index = selectionModel->currentIndex();
    model->insertRow(index.row(), itemList);

    //设置最后一行是被选中的状态
    selectionModel->clearSelection();
    selectionModel->setCurrentIndex(index,QItemSelectionModel::Rows);
}

void MainWindow::on_actionDelete_triggered()
{
    QModelIndex index = selectionModel->currentIndex();


    if(index.row() == model->rowCount()-1){
        model->removeRow(index.row());
    }else
    {
        model->removeRow(index.row());
        selectionModel->setCurrentIndex(index,QItemSelectionModel::Select);
    }
}

void MainWindow::on_actionSee_triggered()
{
    //把左侧数据模型里面的数据,更新到右侧窗口
    ui->plainTextEdit->clear();

    //获取表头
    QString str;
    for(int i =0; i<model->columnCount(); i++)
    {
        QStandardItem *item = model->horizontalHeaderItem(i);
        str +=  item->text() + "\t";
    }
    ui->plainTextEdit->appendPlainText(str); //会自动换行

    //获取每一行数据
    for(int i =1; i<model->rowCount(); i++)
    {
        str = " ";
        for(int j =0; j<model->columnCount()-1; j++)
        {
            QStandardItem *item = model->item(i,j);
            str +=  item->text() + "\t";
        }
        if(model->item(i,model->columnCount()-1)->checkState() == Qt::Checked){
            str += "是";
        }else{
            str += "否";
        }
        ui->plainTextEdit->appendPlainText(str);
    }

}

void MainWindow::on_actionSave_triggered()
{
    //选择保存文件的储存路径
    QString filename = QFileDialog::getSaveFileName(this,"保存文件",QCoreApplication::applicationDirPath());
    if(filename.isEmpty()){
        return;
    }

    QFile qfile(filename);
    //指定文件的打开方式,如果打不开,结束,QIODevice::Truncate把文件截断为0,避免文件已经存在或者已经有数据了
    if(!qfile.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)){
        qDebug() << "打不开";
        return;
    }

    QTextStream stream(&qfile);

    //读表头
    QString str;
    for(int i =0; i<model->columnCount(); i++)
    {
        QStandardItem *item = model->horizontalHeaderItem(i);
        str +=  item->text() + "\t";
    }
    stream << str << "\n"; //写表头

    //获取每一行数据
    for(int i =1; i<model->rowCount(); i++)
    {
        str = " ";
        for(int j =0; j<model->columnCount()-1; j++)
        {
            QStandardItem *item = model->item(i,j);
            str +=  item->text() + "\t";
        }
        if(model->item(i,model->columnCount()-1)->checkState() == Qt::Checked){
            str += "是";
        }else{
            str += "否";
        }

        stream << str << "\n"; //写数据

    }

    qfile.close();

}

void MainWindow::on_actionRight_triggered()
{
    //对选择的单元格进行格式设置
    //先判断是否有选中单元格
    if(!selectionModel->hasSelection()){
        return;
    }

    QModelIndexList indexlist = selectionModel->selectedIndexes();
    for(int i = 0; i < indexlist.count();i++){
        auto item = model->itemFromIndex(indexlist[i]);
        item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
    }
}

void MainWindow::on_actionLeft_triggered()
{
    if(!selectionModel->hasSelection()){
        return;
    }

    QModelIndexList indexlist = selectionModel->selectedIndexes();
    for(int i = 0; i < indexlist.count();i++){
        auto item = model->itemFromIndex(indexlist[i]);
        item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
    }
}

void MainWindow::on_actionMiddle_triggered()
{
    if(!selectionModel->hasSelection()){
        return;
    }

    QModelIndexList indexlist = selectionModel->selectedIndexes();
    for(int i = 0; i < indexlist.count();i++){
        auto item = model->itemFromIndex(indexlist[i]);
        item->setTextAlignment(Qt::AlignCenter | Qt::AlignVCenter);
    }
}


void MainWindow::on_actionBold_triggered(bool checked)
{
    if(!selectionModel->hasSelection()){
        return;
    }

    QModelIndexList indexlist = selectionModel->selectedIndexes();
    for(int i = 0; i < indexlist.count();i++){
        auto item = model->itemFromIndex(indexlist[i]);
        QFont font = item->font();
        font.setBold(checked);
        item->setFont(font);
    }


}

 //根据单元格是否是粗体,要更新粗体图标的状态
void MainWindow::on_currentChanged(const QModelIndex &current, const QModelIndex &previous)
{
    if(current.isValid()){
        auto item = model->itemFromIndex(current);
        //根据当前选中单元格的字体是不是粗体来判断图标的变化,如果是粗体,图标状态是选中状态
        //反之,不选中
        ui->actionBold->setChecked(item->font().bold());

        //在状态栏的标签中,显示所选中单元格是第几行第几列
        labelinfo->setText(QString::asprintf("当前单元格:%d行,%d列",
                           current.row()+1,current.column()+1) +
                           "  单元格内容  " + item->text());
    }
}

四 自定义代理

  • 上述三案例,没有设置表的可编辑模式,但是默认是可以编辑的,并且没有限制。但是如果不对输入数据进行限制,用户可能会输入不符合要求的数据,比如在性别后面输入数据。上一个案例可以编辑是因为使用了默认代理,所谓代理就是用于展示数据的一个媒介。因此优化上述案例,就可以通过自定义代理来实现
  • 代理的两个作用,显示数据和编辑数据

4.1 自定义薪资代理

4.1.1 新建类文件
4.1.2 编辑类文件
  • 在新建的类.h文件中,添加头文件#include <QStyledItemDelegate>,添加Q_OBJECT
  • 让当前类继承于QStyledItemDelegate 类,class QIntSlaryDelegate: public QStyledItemDelegate
  • 构造函数修改为有参构造 QIntSlaryDelegate(QObject *parent = 0);
  • 点击QStyledItemDelegate,转到类定义,将以下四个函数直接复制到新建类里面,createEditor作用是创建组件,setEditorData:将模型的数据给代理,setModelData:将代理里面的数据给到模型,updateEditorGeometry:设置显示格式
  • 设置组件的时候,根据数据需求来选择组件,比如当前的显示的数据是整型数据,要获取能够上下拨动的按钮的功能,对应的组件就是QSpinBox
cpp 复制代码
#ifndef QINTSLARYDELEGATE_H
#define QINTSLARYDELEGATE_H
#include <QStyledItemDelegate>

class QIntSlaryDelegate: public QStyledItemDelegate
{
    Q_OBJECT
public:
    QIntSlaryDelegate(QObject *parent = 0);

    // editing
    QWidget *createEditor(QWidget *parent,
                          const QStyleOptionViewItem &option,
                          const QModelIndex &index) const override;

    void setEditorData(QWidget *editor, const QModelIndex &index) const override;
    void setModelData(QWidget *editor,
                      QAbstractItemModel *model,
                      const QModelIndex &index) const override;

    void updateEditorGeometry(QWidget *editor,
                              const QStyleOptionViewItem &option,
                              const QModelIndex &index) const override;
};

#endif // QINTSLARYDELEGATE_H
cpp 复制代码
#include "qintslarydelegate.h"
#include <QSpinBox>
#include <QDebug>

QIntSlaryDelegate::QIntSlaryDelegate(QObject *parent):QStyledItemDelegate(parent)
{
}

//创建代理组件的时候,调用这个虚函数
QWidget *QIntSlaryDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(option);
    Q_UNUSED(index);

    //QSpinBox只能输入证整数,右侧有上下两个可调箭头的框
    QSpinBox *eidtor =  new QSpinBox(parent);
    eidtor->setMinimum(2000);
    eidtor->setMaximum(100000);
    eidtor->setSingleStep(100);
    return eidtor;
}

//将模型的数据给代理
void QIntSlaryDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    //从数据模型获取数据
    int value = index.model()->data(index).toInt();

    QSpinBox *spinbox = static_cast<QSpinBox*>(editor); //获取代理组件,并转换成相应的组件类型

    spinbox->setValue(value);
}

//将代理里面的数(可能已经修改)据,给到模型
void QIntSlaryDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    QSpinBox *spinbox = static_cast<QSpinBox*>(editor);
    spinbox->interpretText(); //解释数据, 输入的都是文本,这要要的是整数
    int value  = spinbox->value();
    model->setData(index,value);
}

void QIntSlaryDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(index);
    editor->setGeometry(option.rect); //设置代理的大小就是原本的模型数据的小大
}
4.1.3 编辑mainwindow对应文件
  • mainwindow.h文件中,包含新建类的头文件#include "qintslarydelegate.h"
  • 在private下,定义 QIntSlaryDelegate intSalaryDelegate;
  • mainwindow.cpp文件中,构造函数里面指定代理, ui->tableView->setItemDelegateForColumn(4,&intSalaryDelegate);
cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QStandardItemModel>
#include <QItemSelectionModel>
#include <QLabel>
#include "qintslarydelegate.h"
#include "qfloatdelegate.h"
#include "qcomboxdelegate.h"
#include "qdatedelegate.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_actionOpen_triggered();

    void on_actionAdd_triggered();

    void on_actionInsert_triggered();

    void on_actionDelete_triggered();

    void on_actionSee_triggered();

    void on_actionSave_triggered();

    void on_actionRight_triggered();

    void on_actionLeft_triggered();

    void on_actionMiddle_triggered();


    void on_actionBold_triggered(bool checked);

    void on_currentChanged(const QModelIndex &current, const QModelIndex &previous);
private:
    Ui::MainWindow *ui;
    QStandardItemModel *model;
    QItemSelectionModel *selectionModel;
    int collumCount; //列数

    void initModel(QStringList content);

    QLabel *labelinfo;

    QIntSlaryDelegate intSalaryDelegate;
    QFloatDelegate floatDelegate;
    QComboxDelegate jobDelagete;
    QComboxDelegate genderDelegate;
    QDateDelegate dataDelegate;
};
#endif // MAINWINDOW_H
cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    。。。。。  。。。。。  。。。。。
    
    //指定代理
    ui->tableView->setItemDelegateForColumn(4,&intSalaryDelegate);

    ui->tableView->setItemDelegateForColumn(5,&floatDelegate);


    jobDelagete.setItemList(QStringList{"软件工程师","硬件工程师","经理","助理"});
    ui->tableView->setItemDelegateForColumn(3,&jobDelagete);

    genderDelegate.setItemList(QStringList{"男","女"});
    ui->tableView->setItemDelegateForColumn(1,&genderDelegate);

    ui->tableView->setItemDelegateForColumn(2,&dataDelegate);
}

4.2 自定义绩效系数代理

  • 和4.1的区别就只在于组件类型不同,用的组件是QDoubleSpinBox
cpp 复制代码
类文件的.cpp文件
#include "qfloatdelegate.h"
#include <QDoubleSpinBox>


QFloatDelegate::QFloatDelegate(QObject *parent):QStyledItemDelegate(parent)
{ }

QFloatDelegate::QFloatDelegate(){

}
QWidget *QFloatDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(option);
    Q_UNUSED(index);

    QDoubleSpinBox *editor = new QDoubleSpinBox(parent);
    editor->setFrame(false);
    editor->setMinimum(0);
    editor->setMaximum(5);
    editor->setSingleStep(0.1);
    return editor;
}

void QFloatDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    float value = index.model()->data(index).toFloat();
    QDoubleSpinBox *spinbox = static_cast<QDoubleSpinBox*>(editor);
    spinbox->setValue(value);
}

void QFloatDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    QDoubleSpinBox *spinbox = static_cast<QDoubleSpinBox*>(editor);
    spinbox->interpretText();
    float value = spinbox->value();
    QString str = QString::asprintf("%.1f", value);
    model->setData(index,str);
}

void QFloatDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(index);
    editor->setGeometry(option.rect); //设置代理的大小就是原本的模型数据的小大
}

4.3 自定义多选框岗位和性别代理,一个代理对应两个变量

  • 知识点:当前案例和上述有所不同,一个代理对应了两个变量,createEditor函数中的定义有所不同,使用的是addItems而不是addItem,添加的是QStringList
cpp 复制代码
QWidget *QComboxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QComboBox *editor = new  QComboBox(parent);
    editor->addItems(itemList);
    return editor;
}

并设计了一个类的对外的接口,以便在调用的时候来完成itemList的值的设置,因此在mianwindow.cpp构造函数中指定代理前,需要调用该接口来指定QStringList里面的值

cpp 复制代码
    jobDelagete.setItemList(QStringList{"软件工程师","硬件工程师","经理","助理"});
    ui->tableView->setItemDelegateForColumn(3,&jobDelagete);

    genderDelegate.setItemList(QStringList{"男","女"});
    ui->tableView->setItemDelegateForColumn(1,&genderDelegate);
cpp 复制代码
#ifndef QCOMBOXDELEGATE_H
#define QCOMBOXDELEGATE_H
#include <QStyledItemDelegate>


class QComboxDelegate: public QStyledItemDelegate
{
    Q_OBJECT
public:
    QComboxDelegate(QObject *parent = 0);

    // editing
    QWidget *createEditor(QWidget *parent,
                          const QStyleOptionViewItem &option,
                          const QModelIndex &index) const override;

    void setEditorData(QWidget *editor, const QModelIndex &index) const override;
    void setModelData(QWidget *editor,
                      QAbstractItemModel *model,
                      const QModelIndex &index) const override;

    void updateEditorGeometry(QWidget *editor,
                              const QStyleOptionViewItem &option,
                              const QModelIndex &index) const override;

    void setItemList(const QStringList &list);
private:
    QStringList itemList;

};

#endif // QCOMBOXDELEGATE_H
cpp 复制代码
#include "qcomboxdelegate.h"
#include <QComboBox>


QComboxDelegate::QComboxDelegate(QObject *parent):QStyledItemDelegate(parent)
{}

QWidget *QComboxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QComboBox *editor = new  QComboBox(parent);
    editor->addItems(itemList);
    return editor;
}

//从数据模型取数据,给代理组件
void QComboxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    QString value = index.model()->data(index).toString();
    QComboBox *comboBox = static_cast<QComboBox*>(editor);
    comboBox->setCurrentText(value);
}

void QComboxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    QComboBox *comboBox = static_cast<QComboBox*>(editor);
    QString str = comboBox->currentText();
    model->setData(index,str);
}

void QComboxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(index);
    editor->setGeometry(option.rect); //设置代理的大小就是原本的模型数据的小大
}

void QComboxDelegate::setItemList(const QStringList &list)
{
    itemList = list;
}
相关推荐
用户805533698033 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner3 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz8 天前
QML Hello World 入门示例
qt
xcyxiner11 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner12 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner12 天前
DicomViewer (添加模型类)3
qt
xcyxiner13 天前
DicomViewer (目录调整) 2
qt
xcyxiner13 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能15 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G15 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt