app手机上app退款能退多少天的款吗

帐号:密码:下次自动登录{url:/nForum/slist.json?uid=guest&root=list-section}{url:/nForum/nlist.json?uid=guest&root=list-section}
贴数:1&分页:不可有非分之想发信人: liubodao (不可有非分之想), 信区: XWindow&&&&&&&& 标&&题: Re: 请教QT做MYSQL数据库接口问题!!
发信站: BBS 水木清华站 (Tue Oct&&8 08:08:15 2002), 站内信件 && 转贴一篇网页,不知道对您有没有用:-) && Home | All Classes | Main Classes | Annotated | Grouped Classes | Functions && Qt的SQL模块
本模块是 Qt 企业版的一部分。
SQL 模块结构
SQL 驱动插件(Driver Plugins)
连接至数据库
连接至一个数据库
连接至多个数据库
通过 QSqlQuery执行Sql 命令
事物 Transactions
基本数据处理
浏览数据集
使用 QSqlCursor
获得记录集
对记录集进行排序与过滤
操纵记录集
数据感知组件
数据感知表
创建一个数据感知窗体
在一个数据窗体中显示记录
定制的编辑组件
为 QTables定制的编辑组件
QSqlCursor查询子集
Qt的 SQL 类可以帮助你在Qt的应用程序中实现无缝的数据库集成。
本节假设你已了解基本的SQL知识。你应了解简单的 SELECT, INSERT, UPDATE 与 DELE
TE 等命令。尽管 QSqlCursor 类已提供了一个接口用于浏览与编辑数据而不无需你进行
相应的SQL编程,但我们还是推荐你应有这方面的功底。有关这方面基础知识的书籍是&& An Introduction to Database Systems (7th ed.) by C. J. Date, ISBN
本文所描述的样例是从完全人工编写代码的角度出发的,你还可以参考 Qt Designer 的
用户手册中 "创建数据库应用程序" 这一节,它提供了更高层次的实现方法来演示组件
、滑动与获取外键这类的操作。
本文档分成以下六节:
SQL 模块结构 描述各个类如何互相配合。
连接至数据库 描述如何用 QSqlDatabase 类设置一个数据库连接。
执行 SQL 命令 描述如何执行标准的数据操作命令,诸如 SELECT, INSERT, UPDATE an
d DELETE。 (当然任何有效的 SQL 指令均可被送往数据库)。焦点在于用 QSqlQuery进
行交互操纵。
使用光标 描述如何使用 QSqlCursor 类来实现更为强大的 API 函数而不象在 QSqlQue
ry中执行SQL语句。
数据感知组件 描述如何把数据库与用户接口链接起来。在这一节中我们介绍 QDataTab
le, QSqlForm, QSqlPropertyMap 与 QSqlEditorFactory 类,演示如何使用定制的数据
感知组件。 Qt Designer 提供了一个方便的可视化途径来实现同样的事情。可参考 Qt &&Designer 的手册, 相关的数据还有QDataBrowser 与 QDataView 。
继承 QSqlCursor. 本节给出了继承 QSqlCursor的样例。继承类可为字段提供缺省值与
计算字段等功能(比如以一个自动数值为主键的索引列),以及显示计算字段等等的内容
。比如显示一个名称而不是一个代码。
SQL 模块结构
SQL 类分成以下三个层次:
用户接口层 这些类提供了数据感知组件,这些组件不仅连接数据库还可为用户所浏览。
(以 QSqlCursor 作为数据源)。终端用户通过这些组件来浏览与编辑数据。 Qt Design
er 集成了这些类并可用来创建数据感知窗体。这些组件也可在程序中与你的C++代码直
接交互。这些类包括 QSqlEditorFactory, QSqlForm, QSqlPropertyMap, QDataTable, &&QDataBrowser 与 QDataView.
SQL API 层 这些类存取数据库。 QSqlDatabase 用来连接数据库。数据交互的实现要么
通过 QSqlQuery 类以SQL语句来实现,要么用 QSqlCursor 类,它封装了 SQL 命令集。
除了 QSqlDatabase, QSqlCursor 与 QSqlQuery这些类外, QSqlError, QSqlField, Q
SqlIndex 与 QSqlRecord也支持该层。
驱动层 本层由三个类组成: QSqlResult, QSqlDriver 与 QSqlDriverFactoryInterfa
ce。 该层在底层提供了连接桥梁。由于该层具有很强的数据库相关性,因此它们的 文
档 是独立的,在通常的数据库应用程序中也很少被关注。如果您对这方面的信息有兴趣
请点击 这儿 。
SQL 驱动插件
Qt的 SQL 模块可以在运行期动态地装载新的驱动程序,这是通过 Qt 组件模型实现的。 && SQL 驱动程序的文档 描述了如何为一个特定的数据库建立相应的插件。
一旦该插件被建立,Qt 可以自动地装载它,之后就可为 QSqlDatabase 所用(详细信息
请看 QSqlDatabase::drivers() ).
连接数据库
如果要使用 QSqlQuery 或 QSqlCursor 类,则少要连接并打开一个数据库连接。
如果应用程序只需要一个数据库连接, QSqlDatabase 可以创建一个为所有SQL操作所利
用的缺省连接,如果创建了多个连接,每个连接也可以容易地设置。
QSqlDatabase 需要 qsqldatabase.h 这个头文件。
连接至单个数据库
创建一个数据库连接需要三个操作:激活驱动程序、设置连接信息、打开连接。 &&&& #include &qapplication.h& &&&& #include &qsqldatabase.h& &&&& #include "../login.h" &&&& int main( int argc, char *argv[] ) &&&& { &&&&&&&& QApplication app( argc, argv ); &&&&&&&& QSqlDatabase *defaultDB = QSqlDatabase::addDatabase( DB_SALES_DRIVER &&); &&&&&&&& if ( defaultDB ) { &&&&&&&&&&&& defaultDB-&setDatabaseName( DB_SALES_DBNAME ); &&&&&&&&&&&& defaultDB-&setUserName( DB_SALES_USER ); &&&&&&&&&&&& defaultDB-&setPassword( DB_SALES_PASSWD ); &&&&&&&&&&&& defaultDB-&setHostName( DB_SALES_HOST ); &&&&&&&&&&&& if ( defaultDB-&open() ) { &&&&&&&&&&&&&&&& // Database we can now issue SQL comman
ds. &&&&&&&&&&&& } &&&&&&&& } &&&&&&&& return 0; &&&& }
From sql/overview/connect1/main.cpp
在以上代码中我们先通过 QSqlDatabase::addDatabase()激活了一个数据库驱动程序,
传入了驱动程序名。现在可利用的驱动程序为: QODBC3 (开放式数据库连接), QOCI8&& (Oracle), QTDS7 (Sybase Adaptive Server 与 Microsoft SQL Server), QPSQL7 (Po
stgreSQL 6 and 7) 与 QMYSQL3 (MySQL). 请注意部分驱动程序并未包括在Qt的免费版
本中,有关信息可查看 README 文件。
连接创建后就成为应用程序的缺省数据库连接并可为 Qt的 SQL 类所使用。
其次我们调用了 setDatabaseName(), setUserName(), setPassword() and setHostNa
me() 来初使化连接信息。
最后我们调用了 open() 来打开数据库以存取数据,如果该步失败将返回 FALSE,用户
可通过 QSqlDatabase::lastError()来查明错误信息。
连接至多个数据库
连接至多个数据库需要在使用 QSqlDatabase::addDatabase() 传入两个参数,其中第二
个参数用来指明一个唯一的连接。 &&&& #include &qapplication.h& &&&& #include &qsqldatabase.h& &&&& #include "../login.h" &&&& bool createConnections(); &&&& int main( int argc, char *argv[] ) &&&& { &&&&&&&& QApplication app( argc, argv ); &&&&&&&& if ( createConnections() ) { &&&&&&&&&&&& // Databases get pointers to them: &&&&&&&&&&&& QSqlDatabase *oracledb = QSqlDatabase::database( "ORACLE" ); &&&&&&&&&&&& // Now we can now issue SQL commands to the oracle connection &&&&&&&&&&&& // or to the default connection &&&&&&&& } &&&&&&&& return 0; &&&& } &&&& bool createConnections() &&&& { &&&&&&&& // create the default database connection &&&&&&&& QSqlDatabase *defaultDB = QSqlDatabase::addDatabase( DB_SALES_DRIVER &&); &&&&&&&& if ( ! defaultDB ) { &&&&&&&&&&&& qWarning( "Failed to connect to driver" ); &&&&&&&&&&&& return FALSE; &&&&&&&& } &&&&&&&& defaultDB-&setDatabaseName( DB_SALES_DBNAME ); &&&&&&&& defaultDB-&setUserName( DB_SALES_USER ); &&&&&&&& defaultDB-&setPassword( DB_SALES_PASSWD ); &&&&&&&& defaultDB-&setHostName( DB_SALES_HOST ); &&&&&&&& if ( ! defaultDB-&open() ) { &&&&&&&&&&&& qWarning( "Failed to open sales database: " + &&&&&&&&&&&&&&&&&&&&&& defaultDB-&lastError().driverText() ); &&&&&&&&&&&& qWarning( defaultDB-&lastError().databaseText() ); &&&&&&&&&&&& return FALSE; &&&&&&&& } &&&&&&&& // create a named connection to oracle &&&&&&&& QSqlDatabase *oracle = QSqlDatabase::addDatabase( DB_ORDERS_DRIVER,&& "ORACLE" ); &&&&&&&& if ( ! oracle ) { &&&&&&&&&&&& qWarning( "Failed to connect to oracle driver" ); &&&&&&&&&&&& return FALSE; &&&&&&&& } &&&&&&&& oracle-&setDatabaseName( DB_ORDERS_DBNAME ); &&&&&&&& oracle-&setUserName( DB_ORDERS_USER ); &&&&&&&& oracle-&setPassword( DB_ORDERS_PASSWD ); &&&&&&&& oracle-&setHostName( DB_ORDERS_HOST ); &&&&&&&& if ( ! oracle-&open() ) { &&&&&&&&&&&& qWarning( "Failed to open orders database: " + &&&&&&&&&&&&&&&&&&&&&& oracle-&lastError().driverText() ); &&&&&&&&&&&& qWarning( oracle-&lastError().databaseText() ); &&&&&&&&&&&& return FALSE; &&&&&&&& } &&&&&&&& return TRUE; &&&& }
From sql/overview/create_connections/main.cpp
在这个样例中我们打开了两个连接并加入了错误处理。静态函数 QSqlDatabase::datab
ase() 可以在任何地方调用以获得一个数据库连接的指针。如果我们在调用此函数时未
使用参数则返回缺省连接,如果有参数则返回指定的连接,如上例中的 "ORACLE"。
请注意以上的代码上 ODBC 连接没有命名,因此被作为缺省连接。 QSqlDatabase 维护
着通过 addDatabase() 这个静态函数返回的的连接指针。如果有移去一个连接,先调用 &&QSqlDatabase::close()来关闭连接,然后通过静态函数 QSqlDatabase::removeDatab
ase()来移除连接。
使用 QSqlQuery来执行 SQL 命令
QSqlQuery 类提供了一个接口来执行 SQL 命令。它也提供相应的函数来浏览数据集,获
得指定的记录或列的数据。
QSqlCursor 类在下一节中讲述。它为我们提供了更高层的接口来实现SQL命令。QSqlCu
rsor 特别适用于在屏幕上显示的可见组件。 不熟悉 SQL 的程序员可略过这一节,直接
去阅读&&"使用 QSqlCursor"来了解QSqlCursor类。
如果下面的数据库引擎支持事物处理,则函数 QSqlDriver::hasFeature( QSqlDriver:
:Transactions ) 将返回 TRUE。你可以通过调用 QSqlDatabase::transaction() 来初
始化一个事物。之后执行你想在该事物中处理的工作。完了再执行 QSqlDatabase::com
mit() 来提交事物或 QSqlDatabase::rollback()取消事物。
基本浏览 &&&& #include &qapplication.h& &&&& #include &qsqldatabase.h& &&&& #include &qsqlquery.h& &&&& #include "../login.h" &&&& bool createConnections(); &&&& int main( int argc, char *argv[] ) &&&& { &&&&&&&& QApplication app( argc, argv ); &&&&&&&& if ( createConnections() ) { &&&&&&&&&&&& QSqlDatabase *oracledb = QSqlDatabase::database( "ORACLE" ); &&&&&&&&&&&& // Copy data from the oracle database to the ODBC (default) &&&&&&&&&&&& // database &&&&&&&&&&&& QSqlQ &&&&&&&&&&&& QSqlQuery query( "SELECT id, name FROM", oracledb ); &&&&&&&&&&&& if ( query.isActive() ) { &&&&&&&&&&&&&&&& while ( query.next() ) { &&&&&&&&&&&&&&&&&&&& target.exec( "INSERT INTO people ( id, name ) VALUES ( " &&+ &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& query.value(0).toString() + &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", '" + query.value(1).toString() +&&"' );
" ); &&&&&&&&&&&&&&&& } &&&&&&&&&&&& } &&&&&&&& } &&&&&&&& return 0; &&&& }
From sql/overview/basicbrowsing/main.cpp
在以上样例中我们加入了一个头文件:qsqlquery.h. 我们使用缺省数据库创建了一个Q
uery: target, 其初始值是空的。我们使用 "ORACLE" 数据库创建了第二个Query以存
取数据。数据连接的设置在 createConnections() 中完成。
在创建了一个 SELECT 语句后,函数 isActive() 被用来检测该命令是否被成功执行。
之后的 next() 被用来遍历整个数据集。 value() 函数返回字段中的值,其数据类型为 &&QVariants。插入操作通过先前就已创建的&&QSqlQuery target来完成。 &&&&&&&&&&&& int count = 0; &&&&&&&&&&&& if ( query.isActive() ) { &&&&&&&&&&&&&&&& while ( query.next() ) { &&&&&&&&&&&&&&&&&&&& target.exec( "INSERT INTO people ( id, name ) VALUES ( " &&+ &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& query.value(0).toString() + &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ", '" + query.value(1).toString() +&&"' );
" ); &&&&&&&&&&&&&&&&&&&& if ( target.isActive() ) &&&&&&&&&&&&&&&&&&&&&&&& count += target.numRowsAffected(); &&&&&&&&&&&&&&&& } &&&&&&&&&&&& }
From sql/overview/basicbrowsing2/main.cpp
以上的代码来统计有多少记录被成功地插入数据库。如果操作失败则 isActive() 将返
回 FALSE ,此时numRowsAffected() 将返回 -1顾。
基本的数据操作 &&&& int main( int argc, char *argv[] ) &&&& { &&&&&&&& QApplication app( argc, argv ); &&&&&&&& int rows = 0; &&&&&&&& if ( createConnections() ) { &&&&&&&&&&&& QSqlQuery query( "INSERT INTO staff ( id, forename, surname, sal
ary ) " &&&&&&&&&&&&&&&&&&&&&&&&&&"VALUES ( 1155, 'Ginger', 'Davis', 50000 );" ); &&&&&&&&&&&& if ( query.isActive() ) rows += query.numRowsAffected() ; &&&&&&&&&&&& query.exec( "UPDATE staff SET salary=60000 WHERE id=1155;" ); &&&&&&&&&&&& if ( query.isActive() ) rows += query.numRowsAffected() ; &&&&&&&&&&&& query.exec( "DELETE FROM staff WHERE id=1155;" ); &&&&&&&&&&&& if ( query.isActive() ) rows += query.numRowsAffected() ; &&&&&&&& } &&&&&&&& return ( rows == 3 ) ? 0 : 1; &&&& }
From sql/overview/basicdatamanip/main.cpp
这个样例演示了直接的 SQL DML (数据操作语言) 命令。既然我们没有在 QSqlQuery 的
构建函数中指明数据库则缺省数据库将被使用。 QSqlQuery 也可以用来执行 SQL DDL&& (数据定义语言) 命令,诸如 CREATE TABLE 与 CREATE INDEX。
浏览数据集
一旦SELECT 语句被成功执行,我们就可以存取与之对应的结果集。我们先前已使用了一
个浏览函数:next()。它可以顺序扫描整个记录集。 QSqlQuery 同时也提供了 first(
), last(), next() 与 prev()。执行其中的任意一个函数后我们都可以通过 isValid(
)来检验是否成功执行。
我们也可以通过seek()来定位至任意一条记录。第一条记录号为零。最后一条记录号为
记录的总数减一。请注意并不时所有的数据都为 SELECT 查询提供记录总数这样的信息
,此时size()将返回 -1。 &&&&&&&& if ( createConnections() ) { &&&&&&&&&&&& QSqlQuery query( "SELECT id, name FROM people ORDER BY" ); &&&&&&&&&&&&&& if ( ! query.isActive() ) return 1; // Query failed &&&&&&&&&&&& &&&&&&&&&&&& i = query.size();&&&&&&&&&&&&&& // In this example we have 9 rec
i == 9. &&&&&&&&&&&& query.first();&&&&&&&&&&&&&&&&&&// Moves to the first record. &&&&&&&&&&&& i = query.at();&&&&&&&&&&&&&&&& // i == 0 &&&&&&&&&&&& query.last();&&&&&&&&&&&&&&&&&& // Moves to the last record. &&&&&&&&&&&& i = query.at();&&&&&&&&&&&&&&&& // i == 8 &&&&&&&&&&&& query.seek( query.size() / 2 ); // Moves to the middle record. &&&&&&&&&&&& i = query.at();&&&&&&&&&&&&&&&& // i == 4 &&&&&&&& }
From sql/overview/navigating/main.cpp
以上样例显示了一些浏览函数据用法。
不是所有的驱动程序都支持 size(), 我们可以通过以下的示例来获知驱动程序是否支
持这一特征。 &&&& QSqlDatabase* defaultDB = QSqlDatabase::database(); &&&& if ( defaultDB-&driver()-&hasFeature( QSqlDriver::QuerySize ) ) { &&&&&&&& // QSqlQuery::size() supported &&&& } &&&& else { &&&&&&&& // QSqlQuery::size() cannot be relied upon &&&& }
当我们定位了一定记录录后我们往往希望取出这条记录的内容。 &&&&&&&& if ( createConnections() ) { &&&&&&&&&&&& QSqlQuery query( "SELECT id, surname FROM" ); &&&&&&&&&&&& if ( query.isActive() ) { &&&&&&&&&&&&&&&& while ( query.next() ) { &&&&&&&&&&&&&&&&&&&& qDebug( query.value(0).toString() + ": " + &&&&&&&&&&&&&&&&&&&&&&&&&&&& query.value(1).toString() ); &&&&&&&&&&&&&&&& } &&&&&&&&&&&& } &&&&&&&& }
From sql/overview/retrieve1/main.cpp
请注意如果你只是希望扫描整个记录集你只需不断地进行 next()操作。
提示:函数 lastQuery() 返回最后一次的的Sql语句,有时你可能想检查一下最后那次
操作是否是你所想象中的操作。
使用 QSqlCursor
QSqlCursor 类提供了一个更高层次的接口来浏览与编辑记录,它不需要你写 SQL语句。 && QSqlCursor 几乎可以做 QSqlQuery 所能做的所有事情。有两点例外:由于其代表的是
数据库中的一张表或视图。缺省情况下 当你浏览记录时QSqlCursor 总是取出记录中的
所有字段。如果你只关心其中的一部分字段你需要进行一些配置,或者使用 QSqlRecor
d::setGenerated()来屏幕掉一些字段。当然你也可以使用 QSqlQuery 来完成这个功能
。 如果表或者视图有其唯一索引你可以通过 QSqlCursor 来编辑记录。否则就只能通过 &&QSqlQuery 来编辑了。 (请注意不是所有的数据库支持视图编辑)
QSqlCursor 一次只操作一条记录。无论是执行 insert, update 还是 delete,QSqlCu
rsor都只是影响一条记录。当浏览记录集时无论何时都只有一条记录处于应用状态。也
就是说 QSqlCursor 只维护了一条记录的可编辑缓冲区。该编辑缓冲区单独放置,因此
当你浏览记录时该缓冲并不会受其影响。
当我们使用 QSqlCursor 前我们必须先创建与打开一个数据库连接。数据库连接在上面
的 连接数据库 一节中已经被讲述。在样例中我们假设已经通过 createConnections() &&创建了连接如同在 QSqlDatabase 样例 描述的那样。
在随后的 数据感知组件 一节中我们将展示如何连接组件至数据库,当我们了解了指针
(cursors)和数据感知组件( data-aware widgets)后我们就可以讨论 subclassing &&QSqlCursor.
QSqlCursor 类需要 qsqlcursor.h 这个头文件。
获取记录 &&&& #include &qapplication.h& &&&& #include &qsqldatabase.h& &&&& #include &qsqlcursor.h& &&&& #include "../login.h" &&&& bool createConnections(); &&&& int main( int argc, char *argv[] ) &&&& { &&&&&&&& QApplication app( argc, argv ); &&&&&&&& if ( createConnections() ) { &&&&&&&&&&&& QSqlCursor cur( "staff" ); // Specify the table/view name &&&&&&&&&&&& cur.select(); // We'll retrieve every record &&&&&&&&&&&& while ( cur.next() ) { &&&&&&&&&&&&&&&& qDebug( cur.value( "id" ).toString() + ": " + &&&&&&&&&&&&&&&&&&&&&&&& cur.value( "surname" ).toString() + " " + &&&&&&&&&&&&&&&&&&&&&&&& cur.value( "salary" ).toString() ); &&&&&&&&&&&& } &&&&&&&& } &&&&&&&& return 0; &&&& }
From sql/overview/retrieve2/main.cpp
我们指定表或视图的名字来创建 QSqlCursor 对象,如果我们使用的不是缺省的数据库
我们需要在 QSqlCursor 的构造函数中指明。
cur.select() 将自动执行以下的Sql语句: &&&& SELECT staff.id, staff.forename, staff.surname, staff.salary, staff.stat
usid FROM staff
然后我们通过 cur.next()来遍历整个记录集。获取字段的方法与 QSqlQuery类似,不过
它指明的是字段名而不是列索引。
对记录进行排序和过滤
如果我们需要取记录子集,我们可以在 select() 函数中指定过滤条件,随后取到的结
果集就都是满足条件的记录 (过滤条件在 SQL 语言中由 WHERE 负责). &&&& cur.select( "id & 100" );
这个select() 函数的调用将执行以下的命令: &&&& SELECT staff.id, staff.forename, staff.surname, staff.salary, staff.stat
usid &&&& FROM staff WHERE staff.id & 100
之后得到的结果集中,id 号都将大于 100.
与过滤类似我们也可以对指定记录集进行排序。这个功能需要通过 QSqlIndex 来实现,
它可以包括排序的字段。 &&&& QSqlCursor cur( "staff" ); &&&& QSqlIndex nameIndex = cur.index( "surname" ); &&&& cur.select( nameIndex );
以上语句使用"surname"字段创建了一个 QSqlIndex 对象object,当我们该对象与 sel
ect() 函数集合起来以后,得到的记录集就是按 staff.surname进行排序的,在索引对
象中的每个字段通过 ORDER BY 组织起来,SQL 语名如下所示: &&&& SELECT staff.id, staff.forename, staff.surname, staff.salary, staff.stat
usid &&&& FROM staff ORDER BY staff.surname ASC
把过滤与排序结合起来的方法也是简单易懂的。 &&&& cur.select( "surname LIKE 'A%'", nameIndex );
过滤字符串引起 WHERE 操作,QSqlIndex 对象引起 ORDER BY 的操作,最后的命令如下
: &&&& SELECT staff.id, staff.forename, staff.surname, staff.salary, staff.stat
usid &&&& FROM staff WHERE staff.surname LIKE 'A%' ORDER BY staff.surname ASC
如果需要对不止一个字段进行排序,则索引对象创建时可包含多个字段。顺序还是倒序
也可以通过 QSqlIndex::setDescending()来指定,缺省是顺序排序。 &&&&&&&&&&&& QSqlCursor cur( "staff" ); &&&&&&&&&&&& QStringList fields = QStringList() && "surname" && "forename"; &&&&&&&&&&&& QSqlIndex order = cur.index( fields ); &&&&&&&&&&&& cur.select( order ); &&&&&&&&&&&& while ( cur.next() ) {
From sql/overview/order1/main.cpp
以上代码中我们通过一个字符串队列来存放不止一个字段,排序中它们都将被用到。然
后我们基于这些字段创建了 QSqlIndex 对象,最后的 select() 操作将执行以下语句: &&&&&& SELECT staff.id, staff.forename, staff.surname, staff.salary, staff.stat
usid &&&& FROM staff ORDER BY staff.surname ASC, staff.forename ASC
你可以在多重排序中加入过滤条件。 &&&&&&&&&&&& QSqlCursor cur( "staff" ); &&&&&&&&&&&& QStringList fields = QStringList() && "id" && "forename"; &&&&&&&&&&&& QSqlIndex order = cur.index( fields ); &&&&&&&&&&&& QSqlIndex filter = cur.index( "surname" ); &&&&&&&&&&&& cur.setValue( "surname", "Bloggs" ); &&&&&&&&&&&& cur.select( filter, order ); &&&&&&&&&&&& while ( cur.next() ) {
From sql/overview/order2/main.cpp
这将执行以下的Sql语句: &&&& SELECT staff.id, staff.forename, staff.surname, staff.salary, staff.stat
usid &&&& FROM staff WHERE staff.surname='Bloggs' ORDER BY staff.id ASC, staff.for
QSqlIndex 对象"order"包含了两个字段:"id" 与 "forename",它们被用来对记录集排
序。 QSqlIndex 对象"filter"包含了一个字段: "surname"。当索引对象被作为过滤条
件传给 select() 函数的时候,该对象中的字段名将被用来进行条件限制的列名,即 f
ieldname=value 。其中的value即是对应字段的限定值。我们可以用 setValue() 来确
定每一个过滤字段的限定值。
取出数据 &&&&&&&&&&&& QSqlCursor cur( "creditors" ); &&&&&&&&&&&& QStringList orderFields = QStringList() && "surname" && "forenam
e"; &&&&&&&&&&&& QSqlIndex order = cur.index( orderFields ); &&&&&&&&&&&& QStringList filterFields = QStringList() && "surname" && "city"; &&&&&&&&&&&&&& QSqlIndex filter = cur.index( filterFields ); &&&&&&&&&&&& cur.setValue( "surname", "Chirac" ); &&&&&&&&&&&& cur.setValue( "city", "Paris" ); &&&&&&&&&&&& cur.select( filter, order ); &&&&&&&&&&&& while ( cur.next() ) { &&&&&&&&&&&&&&&& int id = cur.value( "id" ).toInt(); &&&&&&&&&&&&&&&& QString name = cur.value( "forename" ).toString() + " " + &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&cur.value( "surname" ).toString(); &&&&&&&&&&&&&&&& qDebug( QString::number( id ) + ": " + name ); &&&&&&&&&&&& }
From sql/overview/extract/main.cpp
在以上的样例中,我们为creditors表创建了一个指针(cursor),我们创建了两个 QSq
lIndex 对象,第一个 "order"创建于"orderFields" 字串列,第二个"filter"创建于"
filterFields"字串列,我们为过滤字段"surname" 与 "city"分别设定了条件值。 现在
我们调用select(),产生的Sql语句如下: &&&& SELECT creditors.city, creditors.surname, creditors.forename, creditors.
id &&&& FROM creditors &&&& WHERE creditors.surname = 'Chirac' AND creditors.city = 'Paris' &&&& ORDER BY creditors.surname ASC, creditors.forename ASC
过滤字段用于 WHERE 语句,排序字段用于 ORDER BY 语句。
现在我们遍历整个符合条件的记录集 (如果有的话),我们得到字段 id、forename 与&& surname 的值并把它们传入我们需要处理的函数中去,在这个样例中该函数是 qDebug(
当一张表或视图有唯一索引的情况下,使用 QSqlCursor 可对表或视图的记录进行插入
、更新与删除操作。否则只能用 QSqlQuery 来进行操作 (注意不是所有数据库都支持可
每一个游标(cursor)有一个内部的编辑缓冲区用于编辑操作 (insert, update and d
elete)。 编辑过程对于每种操作都是类似是:获取指向相关缓冲区的指针,调用 setV
alue() 来更新缓冲,调用 insert() 或 update() 或 del() 来执行所需要的操作。举
例来说,当通过游标(cursor)来插入记录时,你通过 primeInsert() 来获得一个指向
编辑缓冲区的指针,调用 setValue() 来刷新缓冲区中每个字段的值,然后调用 QSQlC
ursor::insert() 把缓冲区的数据插入数据库。类似的,当刷新(或删除)一条记录的
时候,缓冲区中的数据将刷新(或删除)至数据库。你调用任何一个 游标浏览 的函数
都不会影响缓冲区中的内容。请注意如果你调用setValue() 传入的是一个单引号括起来
的字符串,单引号将被忽略,因为单引号在 SQL中有着特殊的意义。
primeInsert(), primeUpdate() 与 primeDelete() 这样的方法都返回一个指向内部可
编辑缓冲区的指针,每一种方法在返回前都会在可编辑缓冲区上执行一些不同的隐藏操
作,缺省情况下,QSqlCursor::primeInsert() 清空缓冲区上所有字段的值。 (请见 Q
SqlRecord::clearValues())。QSqlCursor::primeUpdate() 与 QSqlCursor::primeDel
ete() 在缓冲区中初始化当前游标处的各个字段值,这三个函数都是虚函数,因些你可
以重新定义它们的行为。 (比如重载 primeInsert() 以便对自动数值型的字段作出处理
)。用户界面的数据感知组件会发出信号,比如 primeInsert(),这样就可以进行连接,
这些操作都会传递一个指针至合适的缓冲,因些子数据操作(subclassing)可能并不需
要。相应信息请见 subclassing QSqlCursor 。参考 Qt Designer 的用户手册可了解与 &&primeInsert() 有关的信号。
当你调用了 insert(), update() 或 del() 之后,游标将无法定位至一条有效的记录并
且实际上是不可用的。如果你还想继续浏览记录的话你必须调用 select() 以便从数据
库读取更改后的记录。
插入记录 &&&&&&&&&&&& QSqlCursor cur( "prices" ); &&&&&&&&&&&& QStringList names = QStringList() && &&&&&&&&&&&&&&&& "Screwdriver" && "Hammer" && "Wrench" && "Saw"; &&&&&&&&&&&& int id = 20; &&&&&&&&&&&& for ( QStringList::Iterator name = names.begin(); &&&&&&&&&&&&&&&&&& name != names.end(); ++name ) { &&&&&&&&&&&&&&&& QSqlRecord *buffer = cur.primeInsert(); &&&&&&&&&&&&&&&& buffer-&setValue( "id", id ); &&&&&&&&&&&&&&&& buffer-&setValue( "name", *name ); &&&&&&&&&&&&&&&& buffer-&setValue( "price", 100.0 + (double)id ); &&&&&&&&&&&&&&&& count += cur.insert(); &&&&&&&&&&&&&&&& id++; &&&&&&&&&&&& }
From sql/overview/insert/main.cpp
在以上的样例中我们为"prices"表创建了一个游标,然后我们创建了一个产品名列表并
进入了一个循环。在循环中我们调用了游标的 primeInsert() 方法。该方法返回了一个
指向 QSqlRecord 缓冲区的指针,该缓冲区的所有字段均置为空值。(请注意 QSqlCurs
or::primeInsert() 是虚拟函数,可以在继承类中定制,请见 QSqlCursor)。然后我们
调用 setValue() 来设置每一个字段,最后调用 insert() 来实际插入记录。 insert(
) 返回值告诉我们有多少记录被实际插入。
我们通过primeInsert()调用来获得指向 QSqlRecord 对象的指针。QSqlRecord 对象存
贮一条记录的数据以及相关的中间数据。在实际的应用程序中大多数与 QSqlRecord 有
关的操作只是简单进行 value() 与 setValue() 的调用。就象上面以及下面的样例一样
更新记录 &&&&&&&&&&&& QSqlCursor cur( "prices" ); &&&&&&&&&&&& cur.select( "id=202" ); &&&&&&&&&&&& if ( cur.next() ) { &&&&&&&&&&&&&&&& QSqlRecord *buffer = cur.primeUpdate(); &&&&&&&&&&&&&&&& double price = buffer-&value( "price" ).toDouble(); &&&&&&&&&&&&&&&& double newprice = price * 1.05; &&&&&&&&&&&&&&&& buffer-&setValue( "price", newprice ); &&&&&&&&&&&&&&&& cur.update(); &&&&&&&&&&&& }
From sql/overview/update/main.cpp
以上代码我们先在价格表上创建了一个游标。调用select()把需更新的记录选出来,通
过next()进行定位。再调用 primeUpdate() 来获得一个指向 QSqlRecord 的指针,该缓
冲区中的内容将被当前记录的数据所填充。我们获得当前字段的价格值再计算出一个新
的价格。最后调用 update() 来更新记录,update() 返回实际被更新的记录数。
如果有许多同样的更新需要执行,比如说更新一批价格,通过 QSqlQuery 来执行一条S
QL语句的效率可能更高一些。 &&&& QSqlQuery query( "UPDATE prices SET price = price * 1.05"&&);
删除记录 &&&&&&&&&&&& QSqlCursor cur( "prices" ); &&&&&&&&&&&& cur.select( "id=999" ); &&&&&&&&&&&& if ( cur.next() ) { &&&&&&&&&&&&&&&& cur.primeDelete(); &&&&&&&&&&&&&&&& cur.del();
From sql/overview/del/main.cpp
需要删除记录时,选择相应的记录然后定位,调用 primeDelete() 使缓冲区保存当前记
录的值,然后调用 QSqlCursor::del() 来进行删除操作。
与更新操作一样,如果有多条类似的记录需要删除,使用一条Sql语句的效率可能更高一
些。 &&&& QSqlQuery query( "DELETE FROM prices WHERE id &= 2450 AND id &= 2500" ); && 数据感知组件
数据感知组件通过简便而强有力的方法把数据与用户界面结合起来。使用 Qt Designer &&来创建与维护数据感知组件是一件方便的事情。本节为那些致力于完全用编程语言实现
下述样例的开发人员们做出一个导引。请注意在Qt Designer的手册中"创建数据库应用
程序" 这一节所讲述的应用以及附带的样例。
数据感知表 &&&& #include &qapplication.h& &&&& #include &qsqldatabase.h& &&&& #include &qsqlcursor.h& &&&& #include &qdatatable.h& &&&& #include "../login.h" &&&& bool createConnections(); &&&& int main( int argc, char *argv[] ) &&&& { &&&&&&&& QApplication app( argc, argv ); &&&&&&&& if ( createConnections() ) { &&&&&&&&&&&& QSqlCursor staffCursor( "staff" ); &&&&&&&&&&&& QDataTable *staffTable = new QDataTable( &staffCursor, TRUE ); &&&&&&&&&&&& app.setMainWidget( staffTable ); &&&&&&&&&&&& staffTable-&refresh(); &&&&&&&&&&&& staffTable-&show(); &&&&&&&&&&&& return app.exec(); &&&&&&&& } &&&&&&&& return 0; &&&& }
From sql/overview/table1/main.cpp
数据感知表(Data-Aware tables)需要 qdatatable.h 与 qsqlcursor.h 这两个头文件
。我们创建应用程序对象,然后调用 createConnections() 并创建游标。之后使用游标
的指针创建 QDataTable对象,设置autoPopulate 标志为 TRUE。再把 QDataTable 设为
主控件,调用 refresh() 来获限数据,调用 show() 使用其为用户可见。
autoPopulate 标志告诉 QDataTable 是否根据当前游标创建列。该标志并不影响数据的
的读入。数据的读入是由 refresh() 完成的。 &&&&&&&&&&&& QSqlCursor staffCursor( "staff" ); &&&&&&&&&&&& QDataTable *staffTable = new QDataTable( &staffCursor ); &&&&&&&&&&&& app.setMainWidget( staffTable ); &&&&&&&&&&&& staffTable-&addColumn( "forename", "Forename" ); &&&&&&&&&&&& staffTable-&addColumn( "surname",&&"Surname" ); &&&&&&&&&&&& staffTable-&addColumn( "salary",&& "Annual Salary" ); &&&&&&&&&&&& QStringList order = QStringList() && "surname" && "forename"; &&&&&&&&&&&& staffTable-&setSort( order ); &&&&&&&&&&&& staffTable-&refresh(); &&&&&&&&&&&& staffTable-&show();
From sql/overview/table2/main.cpp
在以上代码中我们创建了一个空的 QDataTable ,然后人工指定将显示的列,每一列我
们都可以指定显示的标题。
我们可以在表中对记录进行排序,或者也可以让设置游标让其完成排序工作。
当所有设置工作完成后就可以调用 refresh() 以便从数据库中获得数据,然后调用 sh
ow() 使其可见。
QDataTables 只接收可见的记录集 (依赖于驱动程序),这样做使得即使是一张大表也可
以被迅速地显示同时消耗较少的内存。
数据感知窗体
创建一个数据感知窗体要比使用数据感知组件要麻烦很多, 这是因为我们必须单独处理
每一个数据列,以下所示的代码绝大部分都可以由 Qt Designer 所产生,相关资料可参
考 Qt Designer 的用户手册。
显示记录 &&&& #include &qapplication.h& &&&& #include &qdialog.h& &&&& #include &qlabel.h& &&&& #include &qlayout.h& &&&& #include &qlineedit.h& &&&& #include &qsqldatabase.h& &&&& #include &qsqlcursor.h& &&&& #include &qsqlform.h& &&&& #include "../login.h" &&&& bool createConnections(); &&&& class FormDialog : public QDialog &&&& { &&&&&&&& public: &&&&&&&&&&&& FormDialog(); &&&& }; &&&& FormDialog::FormDialog() &&&& { &&&&&&&& QLabel *forenameLabel&& = new QLabel( "Forename:", this ); &&&&&&&& QLabel *forenameDisplay = new QLabel( this ); &&&&&&&& QLabel *surnameLabel&&&&= new QLabel( "Surname:", this ); &&&&&&&& QLabel *surnameDisplay&&= new QLabel( this ); &&&&&&&& QLabel *salaryLabel&&&& = new QLabel( "Salary:", this ); &&&&&&&& QLineEdit *salaryEdit&& = new QLineEdit( this ); &&&&&&&& QGridLayout *grid = new QGridLayout( this ); &&&&&&&& grid-&addWidget( forenameLabel,&&&& 0, 0 ); &&&&&&&& grid-&addWidget( forenameDisplay,&& 0, 1 ); &&&&&&&& grid-&addWidget( surnameLabel,&&&&&&1, 0 ); &&&&&&&& grid-&addWidget( surnameDisplay,&&&&1, 1 ); &&&&&&&& grid-&addWidget( salaryLabel,&&&&&& 2, 0 ); &&&&&&&& grid-&addWidget( salaryEdit,&&&&&&&&2, 1 ); &&&&&&&& grid-&activate(); &&&&&&&& QSqlCursor staffCursor( "staff" ); &&&&&&&& staffCursor.select(); &&&&&&&& staffCursor.next(); &&&&&&&& QSqlForm sqlForm( this ); &&&&&&&& sqlForm.setRecord( staffCursor.primeUpdate() ); &&&&&&&& sqlForm.insert( forenameDisplay, "forename" ); &&&&&&&& sqlForm.insert( surnameDisplay, "surname" ); &&&&&&&& sqlForm.insert( salaryEdit, "salary" ); &&&&&&&& sqlForm.readFields(); &&&& } &&&& int main( int argc, char *argv[] ) &&&& { &&&&&&&& QApplication app( argc, argv ); &&&&&&&& if ( ! createConnections() ) return 1; &&&&&&&& FormDialog *formDialog = new FormDialog(); &&&&&&&& formDialog-&show(); &&&&&&&& app.setMainWidget( formDialog ); &&&&&&&& return app.exec(); &&&& }
From sql/overview/form1/main.cpp
我们需要引用各组件所需要的头文件,我们还加入 qsqldatabase.h 与 qsqlcursor.h&& ,同时还有 qsqlform.h.
本窗体是以对话框形式出现的,窗体类FormDialog继承于 QDialog 。我们使用了一个&& QLineEdit 来显示薪水同时也允许用户对其进行修改。所有的组件显示在一个 grid.中
我们为 staff 表创建了一个游标。让它从数据库取出所有的记录并定位至第一条记录。 && 现在我们创建了一个 QSqlForm 对象并把 QSqlForm 的记录缓冲区与游标的更新缓冲区
对应起来。对于每个我们希望其数据感知的组件都把与相应的字段名结合进 QSqlForm, &&最后我们调用 readFields() 把游标缓冲区中的数据刷新至关联组件。
在数据窗口中显示记录
QDataView 是一个可以拥有只读 QSqlForm的组件。 与 QSqlForm 类似它也提供了一个
刷新跟踪(slot refresh) ( QSqlRecord * ) ,因此它可以比较容易地与 QDataTable&& 连接在一起用来显示数据。 &&&& connect( myDataTable, SIGNAL( currentChanged( QSqlRecord* ) ), &&&&&&&&&&&&&&myDataView, SLOT( refresh( QSqlRecord* ) ) );
这个样列与上述的比较相似,所以我们讨论不同部分。 &&&& class FormDialog : public QDialog &&&& { &&&&&&&& Q_OBJECT &&&&&&&& public: &&&&&&&&&&&& FormDialog(); &&&&&&&&&&&& ~FormDialog(); &&&&&&&& public slots: &&&&&&&&&&&& void save(); &&&&&&&& private: &&&&&&&&&&&& QSqlCursor staffC &&&&&&&&&&&& QSqlForm *sqlF &&&&&&&&&&&& QSqlIndex idI &&&& };
From sql/overview/form2/main.h
保存跟踪(save slot)将被用于一个按纽以便让用户进行数据刷新的确认。 &&&&&&&& staffCursor.setTrimmed( "forename", TRUE ); &&&&&&&& staffCursor.setTrimmed( "surname",&&TRUE );
我们在文本字段上调用 setTrimmed()以便获取到数据的时候自动消除右导空格。
我们可以根据需要设置一些属性,比如对齐方式与有效性检查。相对应的函数为 QLine
Edit::setAlignment 与 QLineEdit::setValidator. &&&&&&&& QLineEdit&& *forenameEdit&&= new QLineEdit( this ); &&&&&&&& QPushButton *saveButton&&&&= new QPushButton( "&Save", this ); &&&&&&&& connect( saveButton, SIGNAL(clicked()), this, SLOT(save()) );
FormDialog 的构建函数类似于先前的样例。我们更改 forename 与 surname 组件的类
型至 QLineEdits 以便使其内容可编辑。然后又加入 QPushButton 以便用户点击确认。 &&&&&&&&&& grid-&addWidget( saveButton,&&&&3, 0 );
我们扩展了 grid 以容纳保存按纽。 &&&&&&&& idIndex = staffCursor.index( "id" ); &&&&&&&& staffCursor.select( idIndex ); &&&&&&&& staffCursor.first();
我们创建了一个 QSqlIndex 对象然后使用索引执行一个 select() 操作。然后定位至第
一条记录。 &&&&&&&& sqlForm = new QSqlForm( this ); &&&&&&&& sqlForm-&setRecord( staffCursor.primeUpdate() );
我们创建了一个新的 QSqlForm 对象并把它的缓冲区与游标的更新缓冲区关联起来。 &&&&&&&& sqlForm-&insert( forenameEdit, "forename" ); &&&&&&&& sqlForm-&insert( surnameEdit, "surname" ); &&&&&&&& sqlForm-&insert( salaryEdit, "salary" ); &&&&&&&& sqlForm-&readFields();
现在我们把缓冲区的各个字段与 QLineEdit 组件关联起来。 (在先前的样例中我们把它
与游标的各个字段相关联) 。函数 readFields() 使得各组件获得数据。 &&&& FormDialog::~FormDialog() &&&& { &&&& }
在析构函数中我们无需关注各组件或 QSqlForm 的处理,由于它们都是窗体的子类,因
此将被Qt在适当的时候清除。 &&&& void FormDialog::save() &&&& { &&&&&&&& sqlForm-&writeFields(); &&&&&&&& staffCursor.update(); &&&&&&&& staffCursor.select( idIndex ); &&&&&&&& staffCursor.first(); &&&& }
最后我们加入了保存这一个功能,当用户点击保存按纽时该函数将被执行。最后我们调
用writeFields()使得数据回写入 QSqlRecord 缓冲区。然后我们利用游标的 update() &&函数来更新数据。此后游标不再可用,因此使用 QSqlIndex 再次调用select()来获得
数据并定位至第一条记录。
QDataBrowser 与 QDataView 这两个组件提供了以上这些功能的许多函数。 QDataBrow
ser 提供了一个数据标识来指明是否允许编辑与记录浏览。QDataView 提供了一个数据
的只读形式。相关资料可查看类文档或 Qt Designer 的手册。
Link to sql/overview/form2/main.cpp
自定义编辑组件
QSqlForm 使用了 QSqlPropertyMap 来控制数据在组件与数据库字段间的传输。自定义
组件(Custom widgets)同样可以使用特征表(property map),其中包含了如何转递
数据的信息。
本样例基于前述的 form2 样例。因此这里只讲述不同部分,完整源码可参考: sql/ov
erview/custom1/main.h 与 sql/overview/custom1/main.cpp &&&& class CustomEdit : public QLineEdit &&&& { &&&&&&&& Q_OBJECT &&&&&&&& Q_PROPERTY( QString upperLine READ upperLine WRITE setUpperLine ) &&&&&&&& public: &&&&&&&&&&&& CustomEdit( QWidget *parent=0, const char *name=0 ); &&&&&&&&&&&& QString upperLine() &&&&&&&&&&&& void setUpperLine( const QString &line ); &&&&&&&& public slots: &&&&&&&&&&&& void changed( const QString &line ); &&&&&&&& private: &&&&&&&&&&&& QString upperLineT &&&& };
我们从 QLineEdit 这儿继承了一个类,加入了特征:upperLineText,以便其中存放字
符串的大写。加入一个跟踪(slot): changed. &&&&&&&&&&&& QSqlPropertyMap *propM
由于我们将使用特征表(property map)因此我们把特征表的指针与 FormDialog 的私
有数据关联起来。 &&&& CustomEdit::CustomEdit( QWidget *parent, const char *name ) : &&&&&&&& QLineEdit( parent, name ) &&&& { &&&&&&&& connect( this, SIGNAL(textChanged(const QString &)), &&&&&&&&&&&&&&&&&&this, SLOT(changed(const QString &)) ); &&&& }
在 CustomEdit 的构造函数中,我们执行了 QLineEdit 的构造函数,然后在 textChan
ged 信号与 changed slot.之间建立了连接。 &&&& void CustomEdit::changed( const QString &line ) &&&& { &&&&&&&& setUpperLine( line ); &&&& }
changed() slot 调用 setUpperLine() 这个函数。 &&&& void CustomEdit::setUpperLine( const QString &line ) &&&& { &&&&&&&& upperLineText = line.upper(); &&&&&&&& setText( upperLineText ); &&&& }
setUpperLine() 函数将对文本进行处理以获得一份大写后的拷贝并把它设置成组件的数
我们的 CustomEdit 类确保输入的数据始终是大写并提供了一个特征(property)以便
在特征表( property map)中使用,使得 CustomEdit 的实例可与数据库字段相连。 &&&&&&&& CustomEdit&&*forenameEdit&& = new CustomEdit( this ); &&&&&&&& CustomEdit&&*surnameEdit&&&&= new CustomEdit( this );
我们使用先前用过的 FormDialog ,只是这一次我们把原先使用的 QLineEdit 组件替换
成自己的 CustomEdit 组件。
在grid 中的分布以及游标的设置与先前相同。 &&&&&&&& propMap = new QSqlPropertyM &&&&&&&& propMap-&insert( forenameEdit-&className(), "upperLine" );
我们在堆(heap)中建立一个新的特征表(property map) ,注册 CustomEdit 类并把 &&upperLine 特征关联进特征表( property map)。 &&&&&&&& sqlForm = new QSqlForm( this ); &&&&&&&& sqlForm-&setRecord( staffCursor-&primeUpdate() ); &&&&&&&& sqlForm-&installPropertyMap( propMap );
最后的变化是把特征表(property map)装入 QSqlForm ,这样可把特征表(property &&map)的内存加载入 QSqlForm,由于QSqlForm属于FormDialog,因此 Qt 将在适当的时
候删除它们。
这个样例与前述样例其本相同,例外的是 forename 与 surname 字段由于使用了自定义
的 CustomEdit 组件因此它们都将被大写。
为QTable自定义组件
我们必须重载 QSqlEditorFactory 以便使用自定义编辑组件。在下面的样例中我们将以 &&QComboBox 为基类创建自定义组件并定重载 QSqlEditorFactory 以便在 QTable 使用
自定义组件。 &&&& class StatusPicker : public QComboBox &&&& { &&&&&&&& Q_OBJECT &&&&&&&& Q_PROPERTY( int statusid READ statusId WRITE setStatusId ) &&&&&&&& public: &&&&&&&&&&&& StatusPicker( QWidget *parent=0, const char *name=0 ); &&&&&&&&&&&& int statusId() &&&&&&&&&&&& void setStatusId( int id ); &&&&&&&& private: &&&&&&&&&&&& QMap& int, int & index2 &&&& };
From sql/overview/table3/main.h
我们创建了一个特征:statusid,定义了它的读取与写入的方法,由于 statusid并不与 &&combobox的索引对应因此我们创建了一个 QMap 以映射 combobox 的索引与statusid的
关系。 &&&& class CustomSqlEditorFactory : public QSqlEditorFactory &&&& { &&&&&&&& Q_OBJECT &&&&&&&& public: &&&&&&&&&&&& QWidget *createEditor( QWidget *parent, const QSqlField *field )
我们同样需要继承 QSqlEditorFactory ,声明一个 createEditor() 函数,该函数是我
们唯一需要重载的。 &&&& StatusPicker::StatusPicker( QWidget *parent, const char *name ) &&&&&&&& : QComboBox( parent, name ) &&&& { &&&&&&&& QSqlCursor cur( "status" ); &&&&&&&& cur.select( cur.index( "name" ) ); &&&&&&&& int i = 0; &&&&&&&& while ( cur.next() ) { &&&&&&&&&&&& insertItem( cur.value( "name" ).toString(), i ); &&&&&&&&&&&& index2id[i] = cur.value( "id" ).toInt(); &&&&&&&&&&&& i++; &&&&&&&& }
From sql/overview/table3/main.cpp
在 StatusPicker的构造函数中我们创建了一个游标,遍历整个记录集把每一个 name 插
入 combobox,同时通过&&QMap 型的变量index2id把 combobox 的索引与id列的值关联
起来。 &&&& int StatusPicker::statusId() const &&&& { &&&&&&&& return index2id[ currentItem() ]; &&&& }
statusid 的读取函数只是简单地利用 combobox的索引从index2id 中取值。 &&&& void StatusPicker::setStatusId( int statusid ) &&&& { &&&&&&&& QMap&int,int&::I &&&&&&&& for ( it = index2id.begin(); it != index2id.end(); ++it ) { &&&&&&&&&&&& if ( it.data() == statusid ) { &&&&&&&&&&&&&&&& setCurrentItem( it.key() ); &&&&&&&&&&&&&&&& &&&&&&&&&&&& } &&&&&&&& } &&&& }
statusId() 函数实现 statusid 的定入方法。我们创建了一个 iterator 遍历整个 QM
ap,取出其中的数据如果有与statusid相等的就把 combobox 的索引设成statusid对应
的索引,然后离开循环。
当用户在QDataTable中编辑 status 字段时,就有一个 combobox 出现以便用户选值。
为了不编辑的时候在表中显示 status 的名称我们需要继承 QDataTable 并重载 paint
Field() 函数。 &&&& class CustomTable : public QDataTable &&&& { &&&&&&&& Q_OBJECT &&&& public: &&&&&&&& CustomTable( &&&&&&&&&&&&&&&& QSqlCursor *cursor, bool autoPopulate = FALSE, &&&&&&&&&&&&&&&& QWidget * parent = 0, const char * name = 0 ) : &&&&&&&&&&&& QDataTable( cursor, autoPopulate, parent, name ) {} &&&&&&&& void paintField( &&&&&&&&&&&&&&&& QPainter * p, const QSqlField* field, const QRect & cr, bool &&); &&&& };
From sql/overview/table4/main.h
我们只需简单地调用QDataTable 的原始构造函数而不需做任何改动。同时还声明了 pa
intField 函数。 &&&& void CustomTable::paintField( QPainter * p, const QSqlField* field, &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& const QRect & cr, bool b) &&&& { &&&&&&&& if ( !field ) &&&&&&&&&&&& &&&&&&&& if ( field-&name() == "statusid" ) { &&&&&&&&&&&& QSqlQuery query( "SELECT name FROM status WHERE id=" + &&&&&&&&&&&&&&&&&&&&&&&&&&field-&value().toString() ); &&&&&&&&&&&& QS &&&&&&&&&&&& if ( query.next() ) { &&&&&&&&&&&&&&&& text = query.value( 0 ).toString(); &&&&&&&&&&&& } &&&&&&&&&&&& p-&drawText( 2,2, cr.width()-4, cr.height()-4, fieldAlignment( f
ield ), text ); &&&&&&&& } &&&&&&&& else { &&&&&&&&&&&& QDataTable::paintField( p, field, cr, b) ; &&&&&&&& }
From sql/overview/table4/main.cpp
paintField 函数的代码基于 QDataTable中的源码。我们需要做三个改动,首先加入一
个if语句:field-&name() == "statusid" ,此情况下使用 QSqlQuery获得数据。 其次
为其他字段调用基类函数。最后的变化是在主函数 staffTable 由 QDataTable 改为自
定义的 CustomTable。
Subclassing QSqlCursor &&&& #include &qapplication.h& &&&& #include &qsqldatabase.h& &&&& #include &qsqlcursor.h& &&&& #include &qdatatable.h& &&&& #include "../login.h" &&&& bool createConnections(); &&&& int main( int argc, char *argv[] ) &&&& { &&&&&&&& QApplication app( argc, argv ); &&&&&&&& if ( createConnections() ) { &&&&&&&&&&&& QSqlCursor invoiceItemCursor( "invoiceitem" ); &&&&&&&&&&&& QDataTable *invoiceItemTable = new QDataTable( &invoiceItemCurso
r ); &&&&&&&&&&&& app.setMainWidget( invoiceItemTable ); &&&&&&&&&&&& invoiceItemTable-&addColumn( "pricesid", "PriceID" ); &&&&&&&&&&&& invoiceItemTable-&addColumn( "quantity", "Quantity" ); &&&&&&&&&&&& invoiceItemTable-&addColumn( "paiddate", "Paid" ); &&&&&&&&&&&& invoiceItemTable-&refresh(); &&&&&&&&&&&& invoiceItemTable-&show(); &&&&&&&&&&&& return app.exec(); &&&&&&&& } &&&&&&&& return 1; &&&& }
From sql/overview/subclass1/main.cpp
这个样例与前述的 table1 样例很相似。我们创建了一个游标,在 QDataTable中加入字
段与对应的标题。调用refresh() 获取数据再执行show() 来显示组件。
不幸的是这个样例并不完整,在设置时我们需要输入每一个字段,这是一个单调的工作
。如果在显示价格代码的时候显示产品名牌可能会更合适一些。既然我们知道产品的价
格与数量我们还可以显示产品的花费。最后如果能填入缺省值将更加实用(或者是一些主
键) 。 &&&& class InvoiceItemCursor : public QSqlCursor &&&& { &&&&&&&& public: &&&&&&&&&&&& InvoiceItemCursor(); &&&& };
From sql/overview/subclass2/main.h
我们创建了一个单独的头文件并继承了 QSqlCursor. &&&& InvoiceItemCursor::InvoiceItemCursor() : &&&&&&&& QSqlCursor( "invoiceitem" ) &&&& { &&&&&&&& // NOOP &&&& }
From sql/overview/subclass2/main.cpp
在继承类的构造函数中我们仅仅调用了 QSqlCursor 的构造函数。 &&&&&&&&&&&& InvoiceItemCursor invoiceItemC
当我们需要在 invoiceitem 表上使用的游标时我们可以创建 InvoiceItemCursor 而还
是常用的 QSqlCursor。
我们仍需要显示产品的名称而不是价格代码。 &&&&&&&& protected: &&&&&&&&&&&& QVariant calculateField( const QString & name );
From sql/overview/subclass3/main.h
在头文件中的改动很小:我们简单地加入 calculateField() 以便重载。 &&&& InvoiceItemCursor::InvoiceItemCursor() : &&&&&&&& QSqlCursor( "invoiceitem" ) &&&& { &&&&&&&& QSqlFieldInfo productName( "productname", QVariant::String ); &&&&&&&& append( productName ); &&&&&&&& setCalculated( productName.name(), TRUE ); &&&& } &&&& QVariant InvoiceItemCursor::calculateField( const QString & name ) &&&& { &&&&&&&& if ( name == "productname" ) { &&&&&&&&&&&& QSqlQuery query( "SELECT name FROM prices WHERE id=" + &&&&&&&&&&&&&&&&&&&&&&&&&&field( "pricesid" )-&value().toString() + ";" ); &&&&&&&&&&&& if ( query.next() ) &&&&&&&&&&&&&&&& return query.value( 0 ); &&&&&&&& } &&&&&&&& return QVariant( QString::null ); &&&& }
From sql/overview/subclass3/main.cpp
我们已更改了 InvoiceItemCursor 的构造函数,我们创建了一个 QSqlField 的对象 p
roductname,然后把它加入 InvoiceItemCursor的字段集。我们在productname上调用s
etCalculated()使其成为一个计算字段。在 setCalculated() 中第一个参数是字段名,
第二个参数是一个布尔参数,当其为 TRUE 时意味着 calculateField() 必须被调用以
获得字段的值。 &&&&&&&&&&&& invoiceItemTable-&addColumn( "productname", "Product" );
我们调用 addColumn() 来加入一个字段并指定显示名称。
我们必须定义自己的 calculateField() 函数。在我们的样例数据库中,invoiceitem&& 表内价格代码(pricesid)是价格表的一个外键,我们使用pricesid在价格表中执行Sq
l语句以获得产品名称。
现在我们可以扩展样例,包括进一个计算字段并执行真正的计算工作。
头文件 sql/overview/subclass4/main.h 与前述样例一样。但构造函数与 calculateF
ield() 函数需要一些简单扩展。 &&&& InvoiceItemCursor::InvoiceItemCursor() : &&&&&&&& QSqlCursor( "invoiceitem" ) &&&& { &&&&&&&& QSqlFieldInfo productName( "productname", QVariant::String ); &&&&&&&& append( productName ); &&&&&&&& setCalculated( productName.name(), TRUE ); &&&&&&&& QSqlFieldInfo productPrice( "price", QVariant::Double ); &&&&&&&& append( productPrice ); &&&&&&&& setCalculated( productPrice.name(), TRUE ); &&&&&&&& QSqlFieldInfo productCost( "cost", QVariant::Double ); &&&&&&&& append( productCost ); &&&&&&&& setCalculated( productCost.name(), TRUE ); &&&& }
From sql/overview/subclass4/main.cpp
我们创建了两个额外的字段:价格 price 与花费 cost。把它们加入游标中字段集,此
两个都被注册成为计算字段。 &&&& QVariant InvoiceItemCursor::calculateField( const QString & name ) &&&& { &&&&&&&& if ( name == "productname" ) { &&&&&&&&&&&& QSqlQuery query( "SELECT name FROM prices WHERE id=" + &&&&&&&&&&&&&&&&&&&&&&&&&&field( "pricesid" )-&value().toString() + ";" ); &&&&&&&&&&&& if ( query.next() ) &&&&&&&&&&&&&&&& return query.value( 0 ); &&&&&&&& } &&&&&&&& else if ( name == "price" ) { &&&&&&&&&&&& QSqlQuery query( "SELECT price FROM prices WHERE id=" + &&&&&&&&&&&&&&&&&&&&&&&&&&field( "pricesid" )-&value().toString() + ";" ); &&&&&&&&&&&& if ( query.next() ) &&&&&&&&&&&&&&&& return query.value( 0 ); &&&&&&&& } &&&&&&&& else if ( name == "cost" ) { &&&&&&&&&&&& QSqlQuery query( "SELECT price FROM prices WHERE id=" + &&&&&&&&&&&&&&&&&&&&&&&&&&field( "pricesid" )-&value().toString() + ";" ); &&&&&&&&&&&& if ( query.next() ) &&&&&&&&&&&&&&&& return QVariant( query.value( 0 ).toDouble() * &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&value( "quantity").toDouble() ); &&&&&&&& } &&&&&&&& return QVariant( QString::null ); &&&& }
From sql/overview/subclass4/main.cpp
calculateField() 函数的内容进行了一些增加,因为我们必须计算三个字段。product
name 与 price 字段是通过价格代码 pricesid被选出来的。cost 字段是计算出来的:
价格与数量的乘积。请注意 cost 字段是以 QVariant类型返回的,这是 calculateFie
ld() 函数所要求的。
我们使用了三个独立的查询而不是一个,这使得应用程序更为真实就好象它们是从三个
不同的表或视图中取得的一样。
最后一个特征是当用户插入一条新记录时我们为它加入缺省值。 &&&&&&&&&&&& QSqlRecord *primeInsert();
From sql/overview/subclass5/main.h
我们申明了自已的 primeInsert() 函数以便重载。
构造函数与 calculateField() 函数没有变化。 &&&& QSqlRecord *InvoiceItemCursor::primeInsert() &&&& { &&&&&&&& QSqlRecord *buffer = editBuffer(); &&&&&&&& QSqlQuery query( "SELECT NEXTVAL( 'invoiceitem_seq' );" ); &&&&&&&& if ( query.next() ) &&&&&&&&&&&& buffer-&setValue( "id", query.value( 0 ) ); &&&&&&&& buffer-&setValue( "paiddate", QDate::currentDate() ); &&&&&&&& buffer-&setValue( "quantity", 1 ); &&&&&&&& &&&& }
From sql/overview/subclass5/main.cpp
我们取得了一个指向可编辑缓冲区的指针以便游标用来插入与更新。字段 id 是一个用
invoiceitem_seq产生的唯一整形,字段 paiddate 则缺省为今天的日期。数量缺省为&& 1。最后我们返回一个指向该缓冲区的指针。余下的代码与前述样例没有区别。
所使用的样例表可以用以下标准 SQL语句产生,你可能需要改变数据库名称以便与你所
使用的匹配。
create table people (id integer primary key, name char(40))
create table staff (id integer primary key, forename char(40), &&&&&&&&&&&&&&&&&&&& surname char(40), salary float, statusid integer)
create table status (id integer primary key, name char(30))
create table creditors (id integer primary key, forename char(40), &&&&&&&&&&&&&&&&&&&&&&&& surname char(40), city char(30))
create table prices (id integer primary key, name char(40), price float)
create table invoiceitem (id integer primary key, &&&&&&&&&&&&&&&&&&&&&&&&&& pricesid integer, quantity integer, &&&&&&&&&&&&&&&&&&&&&&&&&& paiddate date)
在以上的calculateField()样例中使用了一个顺序(sequence),请注意并不是所有的
数据库都支持它。
create sequence invoiceitem_seq
----------------------------------------------------------------------------
Copyright ? 2001 Trolltech Trademarks&&翻译:郑巍&&&& Qt version 3.0.0-beta5 && 【 在 coltli (每天想你一点) 的大作中提到: 】
: 连接上一个数据库以后,怎么样显示其中的表名??
: 用mysql中查询:show tables行么?
: 还是用mysql提供的c API?
: 请大侠指定,万分感谢!!
&&&& -- && ※ 来源:·BBS 水木清华站 ·[FROM: 202.115.22.194]
文章数:1&分页:}

我要回帖

更多关于 app退款能退多少天的 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信