Qt5数据库读写、Xml文档读写、model\View模型视图示例

编程入门 行业动态 更新时间:2024-10-07 16:25:24

Qt5数据库读写、Xml文档读写、model\View模型<a href=https://www.elefans.com/category/jswz/34/1770164.html style=视图示例"/>

Qt5数据库读写、Xml文档读写、model\View模型视图示例

  • 本示例来自qt网站(.15/qtsql-masterdetail-example.html),但对原示例做部份修改,因为原示例存在很多bug,只能说能正常编译通过,但没有按预期的设计要求运行,有些功能不正常,比如:新艺术家插入专辑时不正常,可能插入空行;删除专辑时,没有刷新右边艺术家及专辑信息
  • 示例运行界面:

示例功能:

可以通过File菜单,用编程的方法新增、删除艺术家及专辑(不是通过TableView)
当选择Artist时,Details会显示这个艺术家的名字、专辑数量
当点击专辑时,Details会显示专辑标题及专辑列表

- 容易出错的地方:

经常有人问,向模型插入数据时,会插入空行,或者插入失败,首先要看是不是数据库的问题,比如:

首先QSqlRelationalTableModel类的对象,一般要求对应的数据表要有“主键”,并且不能设置成另一个表的外健;

其次QSqlRelationalTableModel类的对象有些方法有特别的要求,比如下面几个函数:

  • 当向模型的末尾插入一条记录,会用到命令insertRecord(-1, record),在Qt网站的技术文档里有这一句话:Inserts the record at position row. If row is negative, the record will be ppended to the end. Calls insertRows() and setRecord() internally,意思是:在row位置插入记录,如果行是负数,记录将被追加到末尾,在内部调用insertRows()和setRecord();在setRecord()的技术文档里有还有一句话:For edit strategies OnFieldChange and OnRowChange, only one row may be inserted at a time and the model may not contain other cached changes;意思是:对于 OnFieldChange 和OnRowChange编辑策略,一次只能插入一行,并且模型不能缓存未提交的更改,否则会插入失败,所以在我们用这一条命令时,要确保缓存的更改都已经提交数据库。
  • setRecord(rowindex,record)函数也有同样的要求:Qt文档写着:For edit strategies OnFieldChange and OnRowChange, a row may receive a change only if no other row has a cached change. 意思是: 对于OnFieldChange和OnRowChange编辑策略,只有当没有其他行具有缓存的更改时,一行才可能接收到更改
  • bool QSqlTableModel::setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)函数也有同样的要求, 对于编辑策略OnFieldChange,只有当没有其他索引缓存更改时,索引才会收到更改,更改会立即提交;对于OnRowChange,只有当没有其他行具有缓存的更改时,索引才可能接收到更改,更改不会自动提交

再次看看 virtual bool submit() override和 bool submitAll()两个方法的区别

  • 使用submit()方法:当用户停止编辑当前行时,该项委托调用这个槽函数,如果模型的策略设置为OnRowChange或OnFieldChange,则提交当前编辑的行, 对OnManualSubmit策略没有任何作用, 不会自动重新填充模型
  • 使用submitAll()方法:提交所有挂起的更改,并在成功时返回true,出错时返回false,在OnManualSubmit中,一旦成功,该模型将被重新填充,任何呈现它的视图都将丢失它们未提交的缓存,注意:在OnManualSubmit模式下,当submitAll()失败时,不会从缓存中清除已经提交的更改,这允许在不丢失数据的情况下回滚和重新提交事务

最后说说model与它的所有relationModel之间的关系:

  • 一个model可以对应n个的relationModel,当在OnRowChange或OnFieldChange模式下时,relationModel对应的数据表有insertRecord(-1, record)时,插入的操作为立即提交数据库,但不会重新填充model数据模型,一定要执行model->select()重新填充model数据模型,否则,在model中再次插入记录时,会插入空行,或者插入失败

QSqlRelationalTableModel类的对象的三种策略的区别:

常数说明
QSqlTableModel::OnFieldChange0对模型的所有更改都将立即应用于数据库
QSqlTableModel::OnRowChange1当用户选择不同的行时,将应用对行的更改
QSqlTableModel::OnManualSubmit2在调用submitAll()或revertAll()之前,所有更改都将缓存在模型中

示例:

  • 用Qt Creator新建一个Application(Qt)项目,名称:XmlAndDBWriteRead,默认构建系统Define
    Build System选择qmake

  • 主窗体默认从QMainWindow派生

  • 语言Language选择:Chinese(china),其它都默认。

  • 双击“mainwindow.ui”,把主窗体设计如下,其中Album里面是一个QTableView小部件,Details下面包含三个QTextLabel,一个QListWidget小部件

  • 类对象层次结构

  • 右击项目名称,【Add New…】,增加一个资源文件,名称:XMLAndDataBase,直到完成

  • 右键点击资源文件,选择【添加现有文件…】

  • 选择项目目录下的两个图片文件,完成

  • 右击项目名称,【Add New…】一个新增专辑及艺术家的对话框

  • 选择第一个,Dialog with Buttons Bottom,其它都默认为,直到完成

  • 把对话框修改成如下:

  • 底部的三个按钮在这里选择

  • 类对象层次结构

  • 为Dialog对话框头文件包含sql、xml、小部件三个模块

#include <QtWidgets>
#include <QtSql>
#include <QtXml>
  • 为Dialog对话框增加一个能接受四个参数的构造函数,三个参数分别是专辑数据模型、保存albumdetails.xml数据参数、对应albumdetails.xml文件的QFile对象,在头文件声明如下
explicit Dialog(QSqlRelationalTableModel *albums, QDomDocument details,QFile *output, QWidget *parent = nullptr);
  • 在源文件实现
Dialog::Dialog(QSqlRelationalTableModel *albums, QDomDocument details,QFile *output, QWidget *parent) :QDialog(parent),ui(new Ui::Dialog)
{ui->setupUi(this);
}
  • 在Dialog对话框源文件#include的后面定义现个全局变量,保存专辑数量及艺术家数据
int uniqueAlbumId;
int uniqueArtistId;
  • 增加一个database.h的头文件,主要功能是新建默认数据库接连,类型为内存数据库,打开数据库,并新增3个表,为每个表增加几条记录;右击项目名称,【Add New…】,文件和类选择:“C/C++"类,右边选择”C/C++ Header File“的C/C++头文件,名称:database.h,直到完成

下面开始编写代码:

  • 修改项目的pro文件,增加sql、xml模块的支持
QT       += core gui sql xml
  • 最终database.h代码如下
#ifndef DATABASE_H
#define DATABASE_H#include <QMessageBox>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>static bool createConnection()
{QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");db.setDatabaseName(":memory:");if (!db.open()) {QMessageBox::critical(nullptr, QObject::tr("Cannot open database"),QObject::tr("Unable to establish a database connection.\n""This example needs SQLite support. Please read ""the Qt SQL driver documentation for information how ""to build it.\n\n""Click Cancel to exit."), QMessageBox::Cancel);return false;}QSqlQuery query;// 歌手id,艺术家名字,专辑数量query.exec("create table artists (id int primary key, ""artist varchar(40), ""albumcount int)");query.exec("insert into artists values(0, '<all>', 0)");query.exec("insert into artists values(1, 'Ane Brun', 2)");query.exec("insert into artists values(2, 'Thomas Dybdahl', 3)");query.exec("insert into artists values(3, 'Kaizers Orchestra', 3)");// 专辑id,专辑标题,艺术家id,发行年份query.exec("create table albums (albumid int primary key, ""title varchar(50), ""artistid int, ""year int)");query.exec("insert into albums values(1, 'Spending Time With Morgan', 1, ""2003)");query.exec("insert into albums values(2, 'A Temporary Dive', 1, 2005)");query.exec("insert into albums values(3, '...The Great October Sound', 2, ""2002)");query.exec("insert into albums values(4, 'Stray Dogs', 2, 2003)");query.exec("insert into albums values(5, ""'One day you`ll dance for me, New York City', 2, 2004)");query.exec("insert into albums values(6, 'Ompa Til Du D\xc3\xb8r', 3, 2001)");query.exec("insert into albums values(7, 'Evig Pint', 3, 2002)");query.exec("insert into albums values(8, 'Maestro', 3, 2005)");return true;
}#endif // DATABASE_H
  • QSqlDatabase::addDatabase(“QSQLITE”)是静态方法,原型: QSqlDatabase
    QSqlDatabase::addDatabase(const QString &type, const QString
    &connectionName = QLatin1String(defaultConnection))
    有两个参数,第一个参数表示“类型”,第二个参数是“连接名”,如果连接名省略,默认是使用“默认连接”defaultConnection,当我们要用数据库表填充数据模型对象时,通过构造函数QSqlRelationalTableModel(this)填充模型对象,实际上QSqlRelationalTableModel(this)省略了第二个参数,它的原型是:
    QSqlRelationalTableModel(QObject *parent = nullptr, QSqlDatabase db =
    QSqlDatabase()) 被省略的第二个默认参数是确定要访问的数据库,通过调用 QSqlDatabase
    database(const QString &connectionName =
    QLatin1String(defaultConnection), bool open = true) 方法来返回默认数据库。

  • 在mainwindow.h头文件中,包含如下sql模块、小部件模块、QFile文件模块

   #include <QtSql>#include <QtWidgets>#include <QFile>#include <QDomDocument>#include "dialog.h"
  • 并增加一个私有QSqlRelationalTableModel变量,用来填充数据库表的数据
 QSqlRelationalTableModel *model;
  • 在mainwindow.h头文件中增加一个构造函数,带四个参数,前面两个QString类型的参数分别对应数据库中artists、albums表,第三个参数对应磁盘中的Xml文档,如下
explicit MainWindow(const QString &artistTable, const QString &albumTable,QFile *albumDetails, QWidget *parent = nullptr);
  • 并在mainwindow.cpp文件中对此构造函数进行实现,增加如下语句,用数据库表albums填充model数据模型,并把artists、albums两个表做一个关联,并执行select查询。
   MainWindow::MainWindow(const QString &artistTable, const QString &albumTable,QFile *albumDetails, QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//使用默认数据库连接,构造model对象model = new QSqlRelationalTableModel(this);// 设置专辑albums数据表给modelmodel->setTable(albumTable);// 2-歌手id,artist-歌手名字/* SELECT al.albumid,al.title,ar.artist,al.yearFROM albumTable alINNER JOIN artistTable arON al.artistid = ar.id;*/// 下面语句相当于上面的sql语句model->setEditStrategy(QSqlTableModel::OnFieldChange);model->setRelation(2, QSqlRelation(artistTable, "id", "artist"));/** 使用指定的筛选和排序条件,用通过setTable()设置的表中的数据填充模型,* 如果成功,则返回true,否则返回false。* 注意:调用select()将恢复任何未提交的更改并删除任何插入的列。*/model->select();
}
  • 修改main.cpp文件,包含如下模块
#include "database.h"
#include <QFile>
#include <QDir>
  • 并在mian函数的QApplication a(argc, argv);语句之后,增加访问数据库的语句,主要功能是新建默认数据库接连,类型为内存数据库,打开数据库,并新增3个表,为每个表增加几条记录
if (!createConnection())return EXIT_FAILURE;
  • 在项目目录下新建一个albumdetails.xml文件,内容如下
<archive><album id="1" ><track number="01" >Humming one of your songs</track><track number="02" >Are they saying goodbye</track><track number="03" >On off</track><track number="04" >I shot my heart</track><track number="05" >Drowning in Those Eyes</track><track number="06" >So you did it again</track><track number="07" >One more time</track><track number="08" >Headphone silence</track><track number="09" >What I want</track><track number="10" >Sleeping by the Fyris River</track><track number="11" >Wooden Body</track><track number="12" >Humming one of your songs (encore)</track></album><album id="2" ><track number="01" >To let myself go</track><track number="02" >Rubber and Soul</track><track number="03" >Balloon ranger</track><track number="04" >My lover will go</track><track number="05" >Temporary dive</track><track number="06" >Laid in earth</track><track number="07" >This voice</track><track number="08" >Where friend rhymes with end</track><track number="09" >Song No.6 feat Ron Sexsmith</track><track number="10" >The Fight Song</track></album><album id="3" ><track number="01" >From Grace</track><track number="02" >All's not last</track><track number="03" >That Great October Sound</track><track number="04" >Life Here Is Gold</track><track number="05" >Tomorrow Stays The Same</track><track number="06" >Postulate</track><track number="07" >Adelaide</track><track number="08" >John Wayne</track><track number="09" >Love's Lost</track><track number="10" >Dreamweaver</track><track number="11" >Outro</track></album><album id="4" ><track number="01" >Rain down on me</track><track number="02" >Cecilia</track><track number="03" >Make a mess of yourself</track><track number="04" >Pale green eyes</track><track number="05" >Either way I'm gone</track><track number="06" >Honey</track><track number="07" >Rise in shame</track><track number="08" >Stray dogs</track><track number="09" >The willow</track><track number="10" >Stay home</track><track number="11" >Outro</track></album><album id="5" ></album><album id="6" ><track number="01" >Kontroll på kontinentet</track><track number="02" >Ompa til du dør</track><track number="03" >Bøn fra helvete</track><track number="04" >170</track><track number="05" >Rullett</track><track number="06" >Dr. Mowinckel</track><track number="07" >Fra sjåfør til passasjer</track><track number="08" >Resistansen</track><track number="09" >Dekk bord</track><track number="10" >Bak et halleluja</track><track number="11" >Bris</track><track number="12" >Mr. Kaizer, hans Constanze og meg</track></album><album id="7" ><track number="01" >Di grind</track><track number="02" >Hevnervals</track><track number="03" >Evig pint</track><track number="04" >De involverte</track><track number="05" >Djevelens orkester</track><track number="06" >Container</track><track number="07" >Naade</track><track number="08" >Min kvite russer</track><track number="09" >Veterans klage</track><track number="10" >Til depotet</track><track number="11" >Salt og pepper</track><track number="12" >Drøm Hardt (Requiem Part I)</track></album><album id="8" ><track number="01" >KGB</track><track number="02" >Maestro</track><track number="03" >Knekker deg til sist</track><track number="04" >Senor Flamingos Adieu</track><track number="05" >Blitzregn baby</track><track number="06" >Dieter Meyers Inst.</track><track number="07" >Christiania</track><track number="08" >Delikatessen</track><track number="09" >Jævel av en tango</track><track number="10" >Papa har lov</track><track number="11" >Auksjon (i Dieter Meyers hall)</track><track number="12" >På ditt skift</track></album>
</archive>
  • 在实例化mainwindow对象语句前(MainWindow w),先创建QFile对象
QFile albumDetails(QDir::currentPath() + "/../XmlAndDBWriteRead/albumdetails.xml");
  • 并修改MainWindow w语句,如下
MainWindow w("artists", "albums", &albumDetails);
  • 最终main.cpp文件如下
#include "mainwindow.h"#include <QApplication>
#include <QLocale>
#include <QTranslator>int main(int argc, char *argv[])
{QApplication a(argc, argv);if (!createConnection())return EXIT_FAILURE;QTranslator translator;const QStringList uiLanguages = QLocale::system

更多推荐

Qt5数据库读写、Xml文档读写、model\View模型视图示例

本文发布于:2024-02-26 04:25:37,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1701346.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:视图   示例   模型   文档   数据库

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!