首页 Qt 学习之路 2 Qt 学习之路 2(57):可视化显示数据库数据

Qt 学习之路 2(57):可视化显示数据库数据

27 3.7K

前面我们用了两个章节介绍了 Qt 提供的两种操作数据库的方法。显然,使用QSqlQuery的方式更灵活,功能更强大,而使用QSqlTableModel则更简单,更方便与 model/view 结合使用(数据库应用很大一部分就是以表格形式显示出来,这正是 model/view 的强项)。本章我们简单介绍使用QSqlTableModel显示数据的方法。当然,我们也可以选择使用QSqlQuery获取数据,然后交给 view 显示,而这需要自己给 model 提供数据。鉴于我们前面已经详细介绍过如何使用自定义 model 以及如何使用QTableWidget,所以我们这里不再详细说明这一方法。

我们还是使用前面一直在用的 student 表,直接来看代码:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    if (connect("demo.db")) {
        QSqlTableModel *model = new QSqlTableModel;
        model->setTable("student");
        model->setSort(1, Qt::AscendingOrder);
        model->setHeaderData(1, Qt::Horizontal, "Name");
        model->setHeaderData(2, Qt::Horizontal, "Age");
        model->select();

        QTableView *view = new QTableView;
        view->setModel(model);
        view->setSelectionMode(QAbstractItemView::SingleSelection);
        view->setSelectionBehavior(QAbstractItemView::SelectRows);
//        view->setColumnHidden(0, true);
        view->resizeColumnsToContents();
        view->setEditTriggers(QAbstractItemView::NoEditTriggers);

        QHeaderView *header = view->horizontalHeader();
        header->setStretchLastSection(true);

        view->show();
    } else {
        return 1;
    }
    return a.exec();
}

这里的connect()函数还是我们前面使用过的,我们主要关注剩下的代码。

正如前一章的代码所示,我们在main()函数中创建了QSqlTableModel对象,使用 student 表。student 表有三列:id,name 和 age,我们选择按照 name 排序,使用setSort()函数达到这一目的。然后我们设置每一列的列头。这里我们只使用了后两列,第一列没有设置,所以依旧显示为列名 id。

在设置好 model 之后,我们又创建了QTableView对象作为视图。注意这里的设置:单行选择,按行选择。resizeColumnsToContents()说明每列宽度适配其内容;setEditTriggers()则禁用编辑功能。最后,我们设置最后一列要充满整个窗口。我们的代码中有一行注释,设置第一列不显示。由于我们使用了QSqlTableModel方式,不能按列查看,所以我们在视图级别上面做文章:将不想显示的列隐藏掉。

接下来运行代码即可看到效果:

数据库显示

如果看到代码中很多“魔术数字”,更好的方法是,使用一个枚举将这些魔术数字隐藏掉,这也是一种推荐的方式:

enum ColumnIndex
{
    Column_ID = 0,
    Column_Name = 1,
    Column_Age = 2
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    if (connect("demo.db")) {
        QSqlTableModel *model = new QSqlTableModel;
        model->setTable("student");
        model->setSort(Column_Name, Qt::AscendingOrder);
        model->setHeaderData(Column_Name, Qt::Horizontal, "Name");
        model->setHeaderData(Column_Age, Qt::Horizontal, "Age");
        model->select();

        QTableView *view = new QTableView;
        view->setModel(model);
        view->setSelectionMode(QAbstractItemView::SingleSelection);
        view->setSelectionBehavior(QAbstractItemView::SelectRows);
        view->setColumnHidden(Column_ID, true);
        view->resizeColumnsToContents();
        view->setEditTriggers(QAbstractItemView::NoEditTriggers);

        QHeaderView *header = view->horizontalHeader();
        header->setStretchLastSection(true);

        view->show();
    } else {
        return 1;
    }
    return a.exec();
}

27 评论

李英举 2013年7月3日 - 13:43

有没有关于样式表的文章?

回复
豆子 2013年7月5日 - 09:26

有计划的,不过是在后面的章节中

回复
小菜鸟_yang 2015年1月23日 - 11:15

想问下,如果数据库插入删除操作后,QTableView 里的内容如何自动更新?

回复
豆子 2015年1月23日 - 14:41

QTableView 的数据是通过 model 的更新自动刷新的,所以在你更新了数据库之后,只需要同步更新 model 就可以了,Qt 会帮你完成剩下的工作

回复
小菜鸟_yang 2015年1月23日 - 16:33

是这样更新吗?
view->setModel(NULL);
view->setModel(model);
比如我按下一个button,向插入数据库里插入了些数据,在button 的on_clicked()里就要加入
view->setModel(NULL);
view->setModel(model);

回复
豆子 2015年1月27日 - 09:15

不需要重新设置 model,直接将数据插入 model 即可,比如 model->insert(...) 之类

回复
修罗 2015年6月23日 - 14:17

用QTableview显示大数据时,比如100万条,会直接崩掉,请教一下如何解决,谢谢。

回复
豆子 2015年6月29日 - 10:36

一次加载100万数据,基本任何界面都会崩溃的。一般会因为内存不足的问题。解决方案是分页或者分批次进行加载,从而减少加载的数据量。

回复
zhouchujing 2019年8月6日 - 15:43

100万条数据在一个界面上显示首先是没有意义的,要采用分页显示

回复
哈哈哈哈哈哈 2015年11月20日 - 10:01

请问一下,model/view的实现必须在main中实现吗,如果我自己用可视化创建的控件是否可以使用这个机制,该怎么实现呢?谢谢!

回复
豆子 2015年11月22日 - 11:18

当然不是的,你可以在任何地方实现 model/view,只需在控件的函数中完成,并且记得调用就可以了,比如在构造函数中。

回复
江月何年初照人 2016年4月10日 - 00:32

QHeaderView *header = view->horizontalHeader();
header->setStretchLastSection(true);
以上两行是什么意思?

回复
豆子 2016年4月11日 - 22:10

设置表头的最后一列是拉伸的,也就是会占用所有剩余可用范围。也可以合并成一句:view->horizontalHeader()->setStretchLastSection(true);

回复
kami 2016年5月15日 - 23:28

请问 用qt5写的程序但是tableview中数据库里的中文全是乱码 改怎么解决?

回复
豆子 2016年5月20日 - 15:07

查看编码是不是一致

回复
wty 2016年7月24日 - 21:37

大神,我想问下,数据库是一直打开着吗?要不要关闭的!按钮的最后不加数据库的关闭的画,会不会崩?

回复
豆子 2016年7月24日 - 22:55

打开数据库的操作是一个相对昂贵的操作,因此如果你的程序需要频繁读写数据库,可以考虑在程序运行期间始终打开数据库;否则的话可以在每次使用时打开,然后关闭。数据库打开之后一般需要关闭,不关闭的话可能会由于资源无法释放造成奇怪的问题。

回复
wty 2016年7月24日 - 22:57

代码中我找不到关闭的语句!不知道我又没有看漏

回复
豆子 2016年7月25日 - 09:34

文中的代码都是演示性质的,并没有按照实际应用去实现。在你的真实项目中,不仅需要关闭数据库,还需要对数据库打开等一系列操作做错误检测和日志才可以的。

回复
路易十三 2016年8月19日 - 16:57

我想请教下 QSqlTableModel model;
model.setTable("FT_Verisons");
model.sort(0,Qt::AscendingOrder);
model.setHeaderData(2,Qt::Horizontal,"FT_Company");
model.setHeaderData(3,Qt::Horizontal,"FT_BaseAddr");
model.select();

(ui->tableView)->setModel(&model);
(ui->tableView)->setSelectionMode(QAbstractItemView::SingleSelection);
(ui->tableView)->setSelectionBehavior(QAbstractItemView::SelectRows);
(ui->tableView)->resizeColumnsToContents();
(ui->tableView)->setEditTriggers(QAbstractItemView::NoEditTriggers);

QHeaderView *header = (ui->tableView)->horizontalHeader();
header->setStretchLastSection(true);
为什么 我用不用QSqlTableModel 的指针 就不行呢 &model : (ui->tableView)->setModel(&model);这个为何不行,照理跟指针的概念是一样的,但是测试下来就是不行,用指针就行。

回复
豆子 2016年8月20日 - 07:22

用指针就行是什么意思?使用 new 创建的吗?如果是的话,是因为你这样写 model 是在栈上创建的,超出作用域就被析构了;new 则是在堆上。我猜你这段代码是在构造函数中的,因此,如果是栈上创建的 model,显示时构造函数已经结束,所以是不行的

回复
路易十三 2016年8月21日 - 16:16

的确如此,我用成员变量就可以。谢谢。qt中的类用new后不需要delete吗,qt是不是有什么机制能保证堆上的东西最后是被销毁的?这个例子中,如果不想用new ,是不是只能用成员变量实现呢?

回复
Joe 2017年1月10日 - 14:41

你好,请教一个问题:如果是海量数据进行显示,如:100W条或更多,QsqlQuery和QSqlTableModel哪个性能上会更好一些?

回复
豆子 2017年1月12日 - 09:55

我没有测试,不过我觉得 100W 这个数据量,使用哪种都不会很好。推荐是 QSqlQuery,因为 SQL 完全可控,你可以优化 SQL。不过,一次性显示 100W 数据绝对不是个好主意,除非某些特殊领域,没有人会去关注 100W 数据,你需要分页或者分块查询。

回复
Joe 2017年2月3日 - 16:07

恩,多谢。

回复
yyq 2017年6月12日 - 17:49

您好,请问qml中如何显示从数据库中读取的数据?能简要说下步骤吗

回复
豆子 2017年6月15日 - 13:56

QML 最好只做显示用,数据库还是用 C++ 读取,然后将数据转发给 QML。需要用到 C++ 与 QML 的交互。

回复

回复 zhouchujing 取消回复

关于我

devbean

devbean

豆子,生于山东,定居南京。毕业于山东大学软件工程专业。软件工程师,主要关注于 Qt、Angular 等界面技术。

主题 Salodad 由 PenciDesign 提供 | 静态文件存储由又拍云存储提供 | 苏ICP备13027999号-2