数据组织和数据展示是ui编程避不开的两个方面,QT中对数据组织(Model)和展示(View)都有完善的类支持。
Model/View框架的核心思想是模型(数据)与视图(显示)相分离,模型对外提供标准接口存取数据,不关心数据如何显示,视图自定义数据的显示方式,不关心数据如何组织存储,即数据存储和渲染隔离开。
Model/View框架中数据与显示的分离,可以允许使用不同界面显示同一数据,也能够在不改变数据的情况下添加新的显示界面。为了处理用户输入,引入了委托(delegate)。引入委托的好处是可以自定义数据项的渲染和编辑。
目录
1.Model / View结构介绍
模型必须为每一个数据提供独一无二的索引,视图通过索引访问模型中的数据。
模型与数据源进行交互,为框架中其它组件提供接口。交互的本质在于数据源的类型以及模型的实现方式。视图从模型获取模型索引,通过将模型索引反向传给模型,视图又可以从数据源获取数据。在标准视图中,委托渲染数据项;在需要编辑数据时,委托使用直接模型索引直接与模型进行交互。
Model/View架构分为三部分:模型、视图和委托。每一个组件都由一个抽象类定义,抽象类提供了基本的公共接口以及一些默认实现。
模型、视图和委托使用信号槽进行交互:
(1)底层维护的数据发生改变时,模型发出信号通知视图
(2)当用户与视图进行交互时,视图发出信号提供了有关用户与界面进行交互的信息
(3) 当用户编辑数据项时,委托发出信号用于告知模型和视图编辑器的状态。
2.数据模型
3.视图
4.代理
5.使用举例
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QFileSystemModel>
#include "qintdelegate.h"
// Data直接到View
// Data => View
// Data通过通道Model到View
// Data => Model => View
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
QFileSystemModel *m_fileModel;
QIntDelegate intDelegate;
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_treeView_clicked(const QModelIndex &index);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
qintdelegate.h
#ifndef QINTDELEGATE_H
#define QINTDELEGATE_H
#include <QObject>
#include <QStyledItemDelegate>
// 自定义代理
class QIntDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit QIntDelegate(QObject *parent = nullptr);
//创建用于编辑数据的widget组件,如QSpinBox,QComboBox ...
virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index);
//从数据模型获取数据,供widget组件进行编辑
virtual void setEditorData(QWidget *editor, const QModelIndex &index);
//将widget上的数据更新到模型
virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index);
//用于给widget组件设置一个合适的大小
virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index);
signals:
};
#endif // QINTDELEGATE_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDir>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_fileModel = new QFileSystemModel(this);
m_fileModel->setRootPath(QDir::currentPath());
ui->treeView->setModel(m_fileModel);
ui->listView->setModel(m_fileModel);
ui->tableView->setModel(m_fileModel);
ui->tableView->verticalHeader()->setVisible(false);
//信号和槽实现联动
connect(ui->treeView, SIGNAL(clicked(QModelIndex)),
ui->listView, SLOT(setRootIndex(QModelIndex)));
connect(ui->treeView, SIGNAL(clicked(QModelIndex)),
ui->tableView, SLOT(setRootIndex(QModelIndex)));
ui->tableView->setItemDelegateForColumn(0, &intDelegate);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_treeView_clicked(const QModelIndex &index)
{
ui->label->setText(m_fileModel->fileName(index));
ui->label_4->setText(m_fileModel->filePath(index));
ui->label_3->setText(m_fileModel->type(index));
unsigned sz = m_fileModel->size(index)/1024;
if (sz < 1024) {
ui->label_2->setText(QString::asprintf("%d KB", sz));
}
else {
ui->label_2->setText(QString::asprintf("%d MB", sz/1024));
}
ui->checkBox->setChecked(m_fileModel->isDir(index));
}
qintdelegate.cpp
#include "qintdelegate.h"
#include <QSpinBox>
QIntDelegate::QIntDelegate(QObject *parent)
: QStyledItemDelegate{parent}
{
}
QWidget *QIntDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) {
QSpinBox* editor = new QSpinBox(parent);
editor->setMinimum(0);
editor->setMaximum(1000);
editor->setFrame(false);
return editor;
}
void QIntDelegate::setEditorData(QWidget *editor, const QModelIndex &index) {
int value = index.model()->data(index, Qt::EditRole).toInt();
qDebug() << "value:: " << value;
QSpinBox *spinBox = static_cast<QSpinBox *>(editor);
spinBox->setValue(value);
}
void QIntDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) {
QSpinBox *spinBox = static_cast<QSpinBox *>(editor);
spinBox->interpretText();
int value = spinBox->value();
model->setData(index, value, Qt::EditRole);
}
void QIntDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) {
editor->setGeometry(option.rect);
}
运行效果: