文档章节

跟我一起学QT10:项视图类

fzyz_sb
 fzyz_sb
发布于 2014/11/21 21:16
字数 2031
阅读 111
收藏 0

0. 源代码下载

1. 使用项视图来选择和查看数据

https://github.com/leichaojian/qt/tree/master/flowchartsymbolpicker

2. 使用项视图类来新增数据

https://github.com/leichaojian/qt/tree/master/CoordinateSetter

3. 使用预定义模型之QStringListModel

https://github.com/leichaojian/qt/tree/master/TeamLeadersDialog

4. 使用预定义模型之QDirModel

https://github.com/leichaojian/qt/tree/master/DirectoryViewer

5. 使用预定义模型之QSortFilterProxyModel

https://github.com/leichaojian/qt/tree/master/ColorNamesDialog

6. 实现自定义模型之显示数据

https://github.com/leichaojian/qt/tree/master/CurrencyModel

7. 实现自定义模型之修改数据

https://github.com/leichaojian/qt/tree/master/CityModel


8. 实现自定义委托

https://github.com/leichaojian/qt/tree/master/TrackEditor


0. 基础知识汇总

1. MVC(model-view-controller:模型-视图-控制器)模型:模型(model)代表数据集,它对需要查看数据的获取以及任何存储的改变负责。每种类型的数据集都有自己的模型,但不管底层的数据集是什么样子,模型提供给视图(view)的API都是相同的。视图代表的是面向用户的那些数据。在同一时间,任何大数据集只有有限的部分是可见的,所以这个有限的部分就是视图所请求的那部分数据。控制器是用户和视图之间的媒介,它把用户的操作转换为浏览或者编辑数据的请求,这部分数据是根据需要由视图传送给模型的数据。

2. QT中的MV模型:QT没有使用控制器,而是使用委托:用于对项的如何显示和如何编辑提供精细控制。

3. QT中MV模型的优势:可以将一个模型注册到多个视图中,则多个视图会自动保持同步。而且如果决定改变底层数据集的存储方式,只需要修改模型,而视图仍将能够继续正常工作。

1. 使用项视图类来选择和查看数据(使用QListWidget)

1. 关键代码

//视图
    listWidget = new QListWidget;
    listWidget->setIconSize(QSize(60, 60));

    //创建一个项视图类来查看数据
    QMapIterator<int, QString> i(symbolMap);
    while (i.hasNext()) {
        i.next();
        //为每一个数据构建一个项视图(MV结构:M为模型数据:i.value(),而V为视图:listWidget)
        QListWidgetItem *item = new QListWidgetItem(i.value(),
                                                    listWidget);
        //设定一个Icon(视图)
        item->setIcon(iconForSymbol(i.value()));
        //将ID保存到QListWidgetItem中去---Qt::UserRole为自定义角色(模型数据)
        item->setData(Qt::UserRole, i.key());
    }

    而当我们选择了当前的图标,并点击OK的时候,会触发done函数,而函数中的id为map数据中的key()值:


void flowchartsymbolpicker::done(int result)
{
    id = -1;
    if (result = QDialog::Accepted) {
        QListWidgetItem *item = listWidget->currentItem();
        if (item) {
            id = item->data(Qt::UserRole).toInt();
        }
    }
    QDialog::done(result);
}


2. 程序效果图

2. 使用项视图类来新增数据(使用QTableWidget)

1. 关键代码

void CoordinateSetter::addRow()
{
    int row = tableWidget->rowCount();

    //在row后面插入一行,此时tableWidget为新增的一行
    tableWidget->insertRow(row);

    //设置第一列
    QTableWidgetItem *item0 = new QTableWidgetItem;
    item0->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
    tableWidget->setItem(row, 0, item0);

    //设置第二列
    QTableWidgetItem *item1 = new QTableWidgetItem;
    item1->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
    tableWidget->setItem(row, 1, item1);

    tableWidget->setCurrentItem(item0);
}

    如何将数据写入到table表中呢:


//创建0行两列
    tableWidget = new QTableWidget(0, 2);
    tableWidget->setHorizontalHeaderLabels(
                QStringList() << tr("X") << tr("Y"));

    //增加一行,然后往新增的行上写入数据
    for (int row = 0; row < coordinates->count(); ++row) {
        QPointF point = coordinates->at(row);
        addRow();
        tableWidget->item(row, 0)->setText(QString::number(point.x()));;
        tableWidget->item(row, 1)->setText(QString::number(point.y()));;
    }


2. 程序效果图


3. 使用预定义模型之QStringListModel

1. 关键代码

//新建一个QStringListModel模型
    model = new QStringListModel(this);
    //初始化模型数据
    model->setStringList(leaders);

    //listView为视图,数据从模型model中获取
    listView = new QListView;
    listView->setModel(model);
    listView->setEditTriggers(QAbstractItemView::AnyKeyPressed
                              | QAbstractItemView::DoubleClicked);



void TeamLeadersDialog::insert()
{
    //模型用于操作实际的数据--如新增一行,删除一行,然后通过视图来显示
    int row = listView->currentIndex().row();
    model->insertRows(row, 1);

    //但是新增一行的内容必须在视图上进行填写
    QModelIndex index = model->index(row);
    listView->setCurrentIndex(index);
    listView->edit(index);
}

void TeamLeadersDialog::del()
{
    model->removeRows(listView->currentIndex().row(), 1);
}


2. 程序效果图


4. 使用预定义模型之QDirModel

1. 关键代码

//新建模型QDirModel,并且设置只读属性,排序按照目录优先,不区分大小写和以名字排序
    model = new QDirModel;
    model->setReadOnly(false);
    model->setSorting(QDir::DirsFirst | QDir::IgnoreCase | QDir::Name);

    //新建视图QTreeView
    treeView = new QTreeView;
    //将视图和模型关联起来
    treeView->setModel(model);
    //设置视图的属性
    treeView->header()->setStretchLastSection(true);
    treeView->header()->setSortIndicator(0, Qt::AscendingOrder);
    treeView->header()->setSortIndicatorShown(true);
    treeView->header()->setSectionsClickable(true);

    QModelIndex index = model->index(QDir::currentPath());
    //设定模型数据可扩展
    treeView->expand(index);
    treeView->scrollTo(index);
    treeView->resizeColumnToContents(0);

void DirectoryViewer::createDirectory()
{
    //找到要创建文件夹的位置
    QModelIndex index = treeView->currentIndex();
    if (!index.isValid())
        return;

    QString dirName = QInputDialog::getText(this,
                              tr("Create Directory"),
                              tr("Directory name"));
    if (!dirName.isEmpty()) {
        //创建文件夹
        if (!model->mkdir(index, dirName).isValid())
            QMessageBox::information(this, tr("Create Directory"),
                    tr("Failed to create the directory"));
    }
}

void DirectoryViewer::remove()
{
    QModelIndex index = treeView->currentIndex();
    if (!index.isValid())
        return;

    bool ok;
    //判断是文件夹还是文件
    if (model->fileInfo(index).isDir()) {
        ok = model->rmdir(index);
    } else {
        ok = model->remove(index);
    }
    if (!ok)
        QMessageBox::information(this, tr("Remove"),
                tr("Failed to remove %1").arg(model->fileName(index)));
}

2. 程序效果图

5. 使用预定义模型之QSortFilterProxyModel

1. 关键代码

//新建模型并以所有的颜色作为模型数据
    sourceModel = new QStringListModel(this);
    sourceModel->setStringList(QColor::colorNames());

    //新建QSortFilterProxyModel模型,以sourceModel作为基础模型
    proxyModel = new QSortFilterProxyModel(this);
    proxyModel->setSourceModel(sourceModel);
    proxyModel->setFilterKeyColumn(0);

    //新建QListView视图
    listView = new QListView;
    listView->setModel(proxyModel);
    listView->setEditTriggers(QAbstractItemView::NoEditTriggers);

    filterLabel = new QLabel(tr("&Filter:"));
    filterLineEdit = new QLineEdit;
    filterLabel->setBuddy(filterLineEdit);

//设置过滤器
void ColorNamesDialog::reapplyFilter()
{
    QRegExp::PatternSyntax syntax =
            QRegExp::PatternSyntax(syntaxComboBox->itemData(
                    syntaxComboBox->currentIndex()).toInt());
    QRegExp regExp(filterLineEdit->text(), Qt::CaseInsensitive, syntax);
    proxyModel->setFilterRegExp(regExp);
}

2. 程序效果图

1. 在每个模型中,每一个数据元素都有一个模型索引和一套属性,称为角色(role),这些角色保存任意值。

2. 对于列表模型,唯一和索引部分相关的就是行号,可以通过QModelIndex::row()得到。对于表模型,与索引部分相关的就是行号和列号,分别可以通过QModelIndex::row()和QModelIndex::column()得到。对于列表模型和表模型,每一个项的父对象都是根,通常由一个无效的QModelIndex表示。

3. 树模型的父对象是根,但是其他每一个项的父对象都是继承树中的其他一些项。这些父对象可以通过QModelIndex::parent()得到。每一个项都有自己的角色数据,都有0个或多个子对象,每一个项都有属于自己的东西。因为项可以拥有其他项作为子对象,这样它就可以用来显示递归的数据结构。


6. 实现自定义模型之显示数据

1. 关键代码

//role为角色,不同的角色执行不同的动作,通过索引index来进行数据的读取
QVariant CurrencyModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid()) {
        return QVariant();
    }

    //返回于数字匹配的对其模式
    if (role == Qt::TextAlignmentRole) {
        return int(Qt::AlignRight | Qt::AlignVCenter);
    } else if (role == Qt::DisplayRole) {   //否则,返回数据
        QString rowCurrency = currencyAt(index.row());
        QString columnCurrency = currencyAt(index.column());

        //0不能被除
        if (currencyMap.value(rowCurrency) == 0.0) {
            return "####";
        }

        double amount = currencyMap.value(columnCurrency)
                / currencyMap.value(rowCurrency);

        return QString("%1").arg(amount, 0, 'f', 4);
    }

    return QVariant();
}

2. 程序效果图

7. 实现自定义模型之修改数据

1. 关键代码

QVariant CityModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    //当为对其模式的时候,则对其table表
    if (role == Qt::TextAlignmentRole) {
        return int(Qt::AlignRight | Qt::AlignVCenter);
    } else if (role == Qt::DisplayRole) {
        //为同一个城市,则距离为0
        if (index.row() == index.column())
            return 0;
        //得到不同城市之间的距离
        int offset = offsetOf(index.row(), index.column());
        return distances[offset];
    }
    return QVariant();
}

//用户编辑一项的时候,会触发setData
bool CityModel::setData(const QModelIndex &index,
                        const QVariant &value, int role)
{
    if (index.isValid() && index.row() != index.column()
            && role == Qt::EditRole) {
        int offset = offsetOf(index.row(), index.column());
        distances[offset] = value.toInt();

        //createIndex()函数用于产生一个模型索引。我们需要使用它获得主对角线另外一侧和当前
        //正在被设置的项所对应项的模型索引,参数顺序是行号在列好之前,所以我们得颠倒一下顺序:column,row
        QModelIndex transposedIndex = createIndex(index.column(),
                                                  index.row());
        //修改整个区域(index,index)来刷新界面
        emit dataChanged(index, index);
        emit dataChanged(transposedIndex, transposedIndex);
        return true;
    }
    return false;
}

2. 程序效果图

8. 实现自定义委托

    代码不甚了解,直接保存程序,供后续学习。程序效果图如下:

© 著作权归作者所有

fzyz_sb
粉丝 411
博文 209
码字总数 447144
作品 0
武汉
程序员
私信 提问
使用Preference构造设置界面

以前都是自己写的应用设置界面,但是总觉得有些丑,然后又有很多数据要在SharePreference中存取,相对的麻烦,然后很久之前也在Android Studio中看见过SettingActivity的模板,他的效果和原生...

Stack_overflow
2017/12/05
0
0
一步一步学Linq to sql(三):增删查改

前言   今天主要是来学习一下,通过Linq如何进行数据库的操作,增加、删除、修改。准备工作,先是建立了一个Asp.Net Mvc 3.0的Web项目, 然后建立一个数据库,表 USE [YQBlog]GOCREATE TAB...

aehyok
2013/04/12
0
0
PyQt5系列教程(30): 文本输入栏(QLineEdit)4

这期我们继续介绍一下文本输入栏(QLineEdit),我们已经介绍了其常用属性、信号、函数还有自定义密码输入框,今天是最后一章,文本框自动补全。 若我们想用到QLineEdit自动补全的功能,必须...

学点编程吧
2018/03/02
0
0
一起学Android之ListView

本文以一个小例子,简述Android开发中ListView的相关应用,仅供学习分享使用。 概述 ListView是一个显示可滚动项目列表的视图组(view group),列表项通过适配器(Adapter)将数组或者数据库...

Alan.hsiang
01/20
0
0
从零开始学WPF Prism框架(三) HelloWorld

我觉得这篇文章比较详细的介绍了HelloWorld的这个Sample示例程序,参考地址(http://www.cnblogs.com/hegezhou_hot/archive/2012/12/21/2828162.html) 我在学习过程中的笔记如下: 1.程序入口 ...

andrewniu
2017/11/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

计算机网络

计算机网络体系结构 OSI 其中表示层和会话层用途如下: 表示层 :数据压缩、加密以及数据描述,这使得应用程序不必关心在各台主机中数据内部格式不同的问题。 会话层 :建立及管理会话。 五层...

一只小青蛙
58分钟前
2
0
0.01-Win10安装linux子系统

一、安装Debian子系统 -1、控制面板设置: -1.1、打开“控制面板” —— “程序” —— “启用或关闭Windows功能” —— 勾选 “适用于Linux的Windows子系统” -2、设置: -2.1、打开“设置”...

静以修身2025
昨天
2
0
init 0-6 (启动级别:init 0,1,2,3,4,5,6)

启动级别: init 0,1,2,3,4,5,6 这是个很久的知识点了,只是自己一直都迷迷糊糊的,今天在翻出来好好理解下。。 0: 停机 1:单用户形式,只root进行维护 2:多用户,不能使用net file system...

圣洁之子
昨天
2
0
Android Camera HAL浅析

1、Camera成像原理介绍 Camera工作流程图 Camera的成像原理可以简单概括如下: 景物(SCENE)通过镜头(LENS)生成的光学图像投射到图像传感器(Sensor)表面上,然后转为电信号,经过A/D(模数转...

天王盖地虎626
昨天
2
0
聊聊Elasticsearch的ProcessProbe

序 本文主要研究一下Elasticsearch的ProcessProbe ProcessProbe elasticsearch-7.0.1/server/src/main/java/org/elasticsearch/monitor/process/ProcessProbe.java public class ProcessProb......

go4it
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部