分享

Qt模型/视图架构的学习5(Model/View)

 ylsnData 2018-04-09

目录:
1,用QDirModel和QTreeView实现目录浏览
2,QStringListModel的使用
3,自定义模型代理的方法
一:用QDirModel和QTreeView实现目录浏览

1,
QDirModel:视图窗口的数据模型,
2,
QTreeView:显示的视图窗口
二:使用介绍
(1),步骤一:定义模型,对模型的相关设置
QDirModel myModel; //定义一个模型,为数据访问做准备
//对模型实例进行设置
myModel.setReadOnly(false); //设置对视图可以进行修改
myModel.setSorting(QDir::DirsFirst | QDir::IgnoreCase | QDir::Name); //设置排序方式:文件夹优先、忽略大小写、文件名
(2),步骤二:定义一个视图,并且对视图进行相关设置
QTreeView myView; //定义一个视图
myView.setModel(&myModel); //为当前视图设置一个模型
//设置最后一列自动扩展,否则保持原始大小
myView.header()->setStretchLastSection(true); //当QTreeView的宽度大于所有列宽之和时,最后一列的宽度自动扩展以充满最后的边界;
//设置排序的方式
myView.header()->setSortIndicator(0,Qt::AscendingOrder); //设置按文件名排序
myView.header()->setSortIndicatorShown(true); //设置显示列表前的排序的小箭头

myModelIndex=myModel.index(QDir::currentPath()); //得到程序当前的运行路径
myView.expand(myModelIndex); //展开当前的路径
myView.scrollTo(myModelIndex); //视图滚到当前的路径
myView.resizeColumnToContents(0); //是要求把列头适应内容的宽度,也就是不产生..符号
(3):将当前视图显示到界面上
ui->verticalLayout->addWidget(&myView);
最终的效果为:


注意:上述内容是旧版版本的,新版本中使用QFileSystemModel替换了QDirModel类,QFileSystemModel采用单独的线程获取目录文件结构,而QDirModel不使用单独的线程。使用单独的线程不会阻碍注线程,所以推荐使用QFileSystemModel。
二:QStringListModel的使用
本实例可以实现列表串的实时编辑和显示,编辑对应的字符串串后,立即在界面中显示出来。
界面显示

1,在头文件中定义一个字符串的数据模型:
QStringListModel *myStringListModel; //定义一个字符串的模型列表
2,在构造函数中进行变量的创建,完成数据模型和界面组件的关联
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
QStringList myStringList; //定义一个需要操作的字符串
myStringList<><><"上海";>
myStringListModel=new QStringListModel(this); //新建字符串数据模型
myStringListModel->setStringList(myStringList); //设置字符串模型的初始字符串
ui->listViewModel->setModel(myStringListModel); //为视图模型设置数据模型
//设置视图模型的编辑方式双击编辑和选中后单击编辑
ui->listViewModel->setEditTriggers(QAbstractItemView::DoubleClicked|QAbstractItemView::SelectedClicked);
}
上述步骤完成后可以在界面中显示字符串中的数据
3,编辑、添加、删除项的操作
(1)编辑项
QListView::setEditTriggers()函数设置QListView的条目是否可以编辑,以及如何进入编辑状态,函数的参数是QAbstractItemView::EditTrigger枚举类型值的组合。构造函数中设置为:
ui->listViewModel->setEditTriggers(QAbstractItemView::DoubleClicked|QAbstractItemView::SelectedClicked);
表示在双击,或者选择后单击进入 编辑状态。
若要设置为不可编辑,则可设置为:
ui->listViewModel->setEditTriggers(QAbstractItemView::NoEditTriggers);
(2)添加项
添加项是要在列表的最好一行添加一行,界面上的添加项的槽函数为:
//在列表中添加一个数据项
void Widget::on_btnAddItem_clicked()
{
myStringListModel->insertRow(myStringListModel->rowCount()); //在模型数据的尾部插入一个数据项
QModelIndex index=myStringListModel->index(myStringListModel->rowCount()-1,0); //得到当前插入项的模型索引值
myStringListModel->setData(index,"new item",Qt::DisplayRole); //设置插入项的显示数据
ui->listViewModel->setCurrentIndex(index); //设置为当前选中的项目
}
对数据的操作都是针对数据模型的,所以,插入一行使用的是QStringListModel的insertRow(int row)函数,其中row是一个行号,表示在row行之前插入一行。要在列表的最后插入一行,参数row设置为当前列表的行数即可。
(3)插入项
"插入项"按钮的功能是在列表的当前行前面插入一行,槽函数代码为:
//在当前行插入一个数据项
void Widget::on_btnInsertItem_clicked()
{
QModelIndex index=ui->listViewModel->currentIndex(); //得到当前选中的模型索引值,插入的模型在当前行的前面
myStringListModel->insertRow(index.row()); //在模型中插入一行
myStringListModel->setData(index,"insert Item",Qt::DisplayRole); //设置显示的数据
ui->listViewModel->setCurrentIndex(index); //设置插入的项为当前的项
}
QListView::currentIndex()获得当前项的索引index,index.row()则返回这个模型的索引号。
(4)删除当前项
使用QStringListModel的removeRow()删除某一行的代码如下:
//删除当前的项
void Widget::on_btnDeleteItem_clicked()
{
QModelIndex index=ui->listViewModel->currentIndex(); //得到当前选中的项
myStringListModel->removeRow(index.row()); //删除当前选中的行
}
(5)删除列表
删除列表的所有项可以使用QStringListModel的removeRows(int row,int count)函数,它表示从行号row开始删除count行。代码如下:
//清空当前的列表
void Widget::on_btnClearList_clicked()
{
myStringListModel->removeRows(0,myStringListModel->rowCount()); //删除列表中的所有项
}
工程源码(基于Qt5.5):https://pan.baidu.com/s/1maGn3wfJPwRvgLg7aiAUlg
三:自定义模型代理的方法
前言:自定义代理的基本设计要求
自定义代理建议以QStyleItemDelegate作为基类,必须实现如下4个函数:
(1)createEditor()函数创建用于编辑模型数据的widget组件,如一个QSpinBox组件或QComBox组件;
(2)setEditorData()从数据模型中获取数据,并且设置到widget组件进行数据编辑;
(3)setModelData()将widget的数据更新到数据模型中;
(4)updateEditorGeometry()用于给widget组价你设置一个合适的大小。

基于QSpinBox的自定义代理类
1,创建一个类继承于QStyleItemDelegate;
2,分别实现上面提到的四个函数(该函数在父类中是虚函数,函数的原型是固定不变的)
(1)createEditor()函数的实现
createEditor()函数用于创建需要的编辑组件,该类中需要实现一个QSpinBox的编辑组件,实现代码如下:
//创建代理类的编辑器
QWidget *MySpinBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QSpinBox *editor=new QSpinBox(parent);// 创建QSpinBox作为编辑器
editor->setFrame(false); //设置无边框
//简单设置了下选项的内容,最大值和最小值
editor->setMinimum(0);
editor->setMaximum(10000);
return editor; //将这个编辑器返回
}
这段代码创建了一个QSpinBox类型的编辑器editor,parent指向了视图组件;然后对创建的editor组件做一些设置,将editor做为函数的返回值。
(2)setEditorData()函数的实现
setEditorData()函数用于从数据模型获取数值,设置为编辑器的显示值。当双击一项静茹编辑状态时,就会自动调用此函数,其实现代码如下:
//得到模型的数据并且设置到编辑器中
void MySpinBoxDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const
{
int value=index.model()->data(index,Qt::EditRole).toInt(); //得到模型的数据
QSpinBox *spinBox=static_cast(editor); //将编辑器转换成spinBox的指针
spinBox->setValue(value); //将模型中的数据设置到编辑器中
}
函数传递来的参数editor指向了代理组件,index是关联的数据单元模型索引。
通过强制类型转换将editor转换为QSpinBox类型组件spinBox,然后将获取的数值设置为spinBox的值。
(3)setModelData()函数的实现
setModelData()函数用于将代理编辑器上的值更新个数据模型,当用户在界面上完成编辑时会自动调用此函数,将界面的数据更新到数据模型。实现代码:
//得到界面编辑器的数据,并且设置到模型数据中
void MySpinBoxDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
{
QSpinBox *spinBox=static_cast(editor); //将编辑器转换成spinBox的指针
spinBox->interpretText();
int value=spinBox->value(); //得到编辑器中数值
model->setData(index,value,Qt::EditRole); //将编辑器的值设置到模型数据中
}
程序先获取代理组件编辑器里的数值,然后利用传递来的数据模型model和模型索引参数index将编辑器的最新值更新到数据模型中。
(4)updateEditorGeometry()函数的实现
updateEditorGeometry()函数用于为代理设置一个合适的大小,函数参数传递的参数option的rect变量定义了单元格适合显示代理组件的带下,直接设置为此值即可,代码如下:
//设置模型编辑器设置一个合适的大小
void MySpinBoxDelegate::updateEditorGeometry(QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index) const
{
editor->setGeometry(option.rect); //设置模型编辑器的大小
}

自定义代理组件的使用
在需要使用的头文件中定义个代理组件,在视图中设置代理组件即可。例:
MySpinBoxDelegate intSpinBoxDelegate; //定义整型代理组件
ui->listViewModel->setItemDelegate(&intSpinBoxDelegate); //使用定义的代理组件

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多