QT学习开发笔记(数据库之实用时钟)

时间:2022-09-15 01:03:17

数据库

数据库是什么?简易言之,就是保存数据的文件。可以存储大量数据,包括插入数据、更
新数据、截取数据等。用专业术语来说,数据库是“按照数据结构来组织、存储和管理数据的
仓库”。是一个长期存储在计算机内的、有组织的、可共享的、统一管理的大量数据的集合。

什么时候需要数据库?在嵌入式里,存储大量数据,或者记录数据,就需要用到数据库。
举个简单的例子,比如手机的闹钟就使用到了数据库,我们设置的闹钟数据将会保存到数据库
里,闹钟程序运行时会从数据库里读取出上次保存的闹钟数据。如果没有数据库,则闹钟程序
关机了数据不保存在物理储存设备里,下次运行闹钟时就没有上次设置的闹钟数据,这显然是
不合理的。所以我们需要用到数据库。

本章认为读者已经基本了解数据库,已经对数据库有一定的认识,如果没有对数据库了解,
请自行学习,毕竟本书是讲 Qt 的,不是讲数据库,数据库知识很多,而我们只是讲解 Qt 怎么
去用数据库,对数据库的简单操作!目的就是在 Qt 里使用数据库!

想要在项目中使用 Qt SQL 模块,需要在项目配置文件里添加如下语句。
QT += core gui sql

Qt SQL 简介

Qt SQL 模块为数据库提供了编程支持,Qt 支持很多种常见的数据库,如 MySQL、Oracle、

MS SQL Server、SQLite 等。Qt SQL 模块里包含了很多个类,可以轻松实现数据库的连接、执
行 SQL 语句,获取数据库里的数据与界面显示等功能,一般数据与界面之间会采用 Model/View

架构,从而很方便的显示数据界面和操作数据库。

在嵌入式里,一般常用的数据库就是 Sqlite3。SQLite 是非常小的,是轻量级的,完全配置
时小于 400KiB,省略可选功能配置时小于 250KiB。SQLite 是一个进程内的库,实现了自给自
足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。它是一个零配置的数据库,这意
味着与其他数据库不一样,您不需要在系统中配置。就像其他数据库,SQLite 引擎不是一个独
立的进程,可以按应用程序需求进行静态或动态连接。SQLite 可以直接访问其存储文件。

本章主要对 Sqlite3 进行实验。需要用其他数据库的请自行学习,在我们正点原子里 Linux

开发板里就是用 sqlite3,文件系统里不提供其他数据库类型。嵌入式一般是用 sqlite3,如需要
其他类型数据库,请自行移植与学习!

应用实例

本章不讲解数据库中的语法,本书认为读者是已经数据库语法有一定了解的了,请知悉!
详细声明请看本章前言!本章前言。
Model(模型),复杂的事情往往可以简单化,Qt 提供了 QSqlDatabase 类用于建立数据库的
连接,往往以指定加载的数据库驱动,然后设置数据库的登录参数,如主机地址,用户名、登
录密码等。这些都是服务器类型的数据库所需要做的操作。恰好单机型(本地数据库类型)的

Sqlite3 数据库不需要设置登录参数就可以方便的打开数据库进行操作了。在 QSqlDatabase 连接
数据库后,用 QSqlTableModel 从数据库里读取出表格模型,然后通过 Qt 的 QTableView 类显示
数据库的内容在我们面前。需要对数据库的数据进行修改可以使用 QSqlQuery,或者直接修改

QSqlTableModel 对象,修改里面的模型数据即可!Qt 对数据库的基本操作流程大概是这样子,
当然 Qt 提供了很多操作数据库的类,我们只讲解基本的与常用的就已经足够了。下面用个图示
来再对上面的操作稍微了解一下。
QT学习开发笔记(数据库之实用时钟)

实用闹钟(非 QTableView 显示)

一般显示数据库表格会使用 QTableView 显示,但是 QTableView 适合专业看数员看且适用
于对界面操作要求不高的开发人员看。如果直接用这种表格展示给一般用户看,估计用户看数
据得头皮发麻。本例就如本章开头所说,结合数据库开发一个闹钟实例,记录新建的闹钟数据,
可以对闹钟进行增、删、改等操作。注意(闹钟不做响铃操作设计。可后期使用本例自行开发,
本例主要讲解不使用 QTableView 如何对数据库表格的操作)。本小节开发的闹钟实例很好理解,
它与手机的闹钟操作基本一模一样,读者理解起来不会很吃力。本例程序篇幅过长,请注意,
我们只需要关注 mainwindow.h 和 mainwindow.cpp 这两个文件即可!其他的.h 和.cpp 文件是笔
者为了界面的好看参考了一些博客而设计的程序。主要实现了数字选择器的功能和闹钟开关按
钮的功能,因为 Qt C++里它本身没有这种好看的控件,所以得自行设计。由于篇幅过长,数字
选择器与闹钟开关的代码不作分析(有兴趣自行分析),我们可以直接将它们当作普通的控件来
用即可!重点是 mainwindow.h 和 mainwindow.cpp 里的数据库操作。笔者写这个例子都要好长
时间,希望读者不要一口吃个胖老虎,急于求成,本例界面看似简单,可能大多数读者可能对
数据库并不是很了解!理解这个例子时,笔者担心是在看天书一样!抓住我们想要理解的重点
即可!不必要每句都去理解!

本例目的:了解不使用 QTableView 的情况下,也能把数据表完好展示在用户面前。

例 17_sqlite_alarm,实用闹钟(难度:很难【为什么定义为很难,笔者认为大多数读者对
数据库没有一定的了解】)。项目路径为 Qt/2/17_sqlite_alarm。

项目文件 17_sqlite_alarm 文件第一行添加的代码部分如下。

17_sqlite_alarm.pro 编程后的代码

QT += core gui sql

2 

3 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 

4 

5 CONFIG += c++11 

6 

7 # The following define makes your compiler emit warnings if you use 

8 # any Qt feature that has been marked deprecated (the exact warnings 

9 # depend on your compiler). Please consult the documentation of the 

10 # deprecated API in order to know how to port your code away from it. 

11 DEFINES += QT_DEPRECATED_WARNINGS 

12 

13 # You can also make your code fail to compile if it uses deprecated APIs. 

14 # In order to do so, uncomment the following line. 

15 # You can also select to disable deprecated APIs only up to a certain 
version of Qt. 

16 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the 
APIs deprecated before Qt 6.0.0 

17 

18 SOURCES += \ 

19 main.cpp \ 

20 mainwindow.cpp \ 

21 numberpicker.cpp \ 

22 switchbutton.cpp 

23 

24 HEADERS += \ 

25 mainwindow.h \ 

26 numberpicker.h \ 

27 switchbutton.h 

28 

29 # Default rules for deployment. 

30 qnx: target.path = /tmp/$${TARGET}/bin 

31 else: unix:!android: target.path = /opt/$${TARGET}/bin 

32 !isEmpty(target.path): INSTALLS += target 

33 

34 RESOURCES += \ 

35 res.qrc 

在头文件“mainwindow.h”具体代码如下。

mainwindow.h 编程后的代码

 /****************************************************************** 
 Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. 
 * @projectName 17_sqlite_example 
 * @brief mainwindow.h 
 * @author Deng Zhimao 
* @email 1252699831@qq.com 
 * @net www.openedv.com 
 * @date 2021-05-15 
 *******************************************************************/ 

1 #ifndef MAINWINDOW_H 

2 #define MAINWINDOW_H 

3 

4 #include <QSqlDatabase> 

5 #include <QSqlQuery> 

6 #include <QMainWindow> 

7 #include <QDialog> 

8 #include <QHBoxLayout> 

9 #include <QVBoxLayout> 

10 #include <QPushButton> 

11 #include <QListWidget> 

12 #include <QLabel> 

13 #include <QTime> 

14 #include <QSqlTableModel> 

15 #include "numberpicker.h" 

16 #include "switchbutton.h" 

17 

18 class NumberPicker; 

19 class SwitchButton; 

20 

21 /* ListWiget 项结构体 */ 

22 struct ItemObjectInfo { 

23 /* 闹钟开关 */ 

24 SwitchButton *switchButton; 

25 /* Widget 容器 */ 

26 QWidget *widget; 

27 /* 水平布局 */ 

28 QHBoxLayout *hBoxLayout; 

29 }; 

30 

31 

32 class MainWindow : public QMainWindow 

33 { 

34 Q_OBJECT 

35 

36 public: 

37 MainWindow(QWidget *parent = nullptr); 

38 ~MainWindow(); 

39 

40 private: 

41 

42 /* 数据库连接类 */ 

43 QSqlDatabase sqlDatabase; 

44 

45 /* 数据库操作模型 */ 

46 QSqlTableModel *model; 

47 

48 /* 时针选择器 */ 

49 NumberPicker *hourPicker; 

50 

51 /* 分钟选择器 */ 

52 NumberPicker *minutePicker; 

53 

54 /* 弹出选择时间对话框 */ 

55 QDialog *alarmDialog; 

56 

57 /* 水平布局 */ 

58 QHBoxLayout *hBoxLayout[3]; 

59 

60 /* 垂直布局 */ 

61 QVBoxLayout *vBoxLayout[2]; 

62 

63 /* 显示闹钟列表 */ 

64 QListWidget *listWidget; 

65 

66 /* 主 Widget */ 

67 QWidget *mainWidget; 

68 

69 /* 底部 Wiget */ 

70 QWidget *bottomWidget; 

71 

72 /* 弹出对话框布局窗口选择时间容器 */ 

73 QWidget *timeWidget; 

74 

75 /* 弹出对话框布局窗口按钮容器 */ 

76 QWidget *btWidget; 

77 

78 /* 添加闹钟按钮 */ 

79 QPushButton *addAlarm; 

80 

81 /* 确认按钮 */ 

82 QPushButton *yesButton; 

83 

84 /* 取消按钮 */ 

85 QPushButton *cancelButton; 

86 

87 /* listWiget 项信息存储 */ 

88 QVector<ItemObjectInfo> itemObjectInfo; 

89 

90 private slots: 

91 /* 添加闹钟按钮被点击 */ 

92 void addAlarmClicked(); 

93 

94 /* 列表被点击 */ 

95 void listWidgetItemClicked(QListWidgetItem *); 

96 

97 /* 确认按钮被点击 */ 

98 void yesButtonClicked(); 

99 

100 /* 取消按钮被点击 */ 

101 void cancelButtonClicked(); 

102 

103 /* 开关按钮点击 */ 

104 void switchButtonClicked(bool); 

105 }; 

106 #endif // MAINWINDOW_H 

头文件主要声明布局用的类和数据库,重要关注是 QSqlDatabase 和 QSqlTableModel。这里
声明的是全局变量。

在源文件“mainwindow.cpp”具体代码如下。

mainwindow.cpp 编程后的代码

 /****************************************************************** 
 Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. 
 * @projectName 17_sqlite_example 
 * @brief mainwindow.cpp 
 * @author Deng Zhimao 
 * @email 1252699831@qq.com 
 * @net www.openedv.com 
 * @date 2021-05-15 
 *******************************************************************/ 

1 #include "mainwindow.h" 

2 #include <QDebug> 

3 #include <QSqlError> 

4 

5 MainWindow::MainWindow(QWidget *parent) 

6 : QMainWindow(parent) 

7 { 

8 /* 设置主窗体的显示位置与大小 */ 

9 this->setGeometry(0, 0, 800, 480); 

11 /* 查看本机可用的数据库驱动 */ 

12 QStringList drivers = QSqlDatabase::drivers(); 

13 foreach(QString driver, drivers) { 

14 qDebug()<<driver; 

15 } 

16 

17 /* 以 QSQLITE 驱动方式打开或者创建数据库 */ 

18 sqlDatabase = QSqlDatabase::addDatabase("QSQLITE"); 

19 sqlDatabase.setDatabaseName("alarm.db"); 

20 /* 以 open 的方式打开 alarm.db 数据库,则会创建一个 alarm.db */ 

21 if (!sqlDatabase.open()) 

22 qDebug()<<"连接数据库错误"<<sqlDatabase.lastError()<<endl; 

23 else 

24 qDebug()<<"连接数据库成功"<<endl; 

25 

26 QSqlQuery query(sqlDatabase); 

27 /* 使用指令式创建表 */ 

28 query.exec("create table alarm (id int primary key, time vchar(15), 
flag vchar(5))"); 

29 /* 以指令的方式插入数据 */ 

30 //query.exec("insert into alarm values(0, '06:00', 'false')"); 

31 

32 model = new QSqlTableModel(this, sqlDatabase); 

33 

34 /* 模型设置表的名字,需要与数据库的表的名字相同 */ 

35 model->setTable("alarm"); 

36 

37 /* 如果有修改则同步修改到数据库, 
38 * 注意这个规则需要与 tabview 这样的控件才生效, 
39 * 因为 tabview 可以直接编辑表里的内容 */ 

40 model->setEditStrategy(QSqlTableModel::OnFieldChange); 

41 

42 /* 成功则返回 true,查看数据库里是否有 alarm 这个表格 */ 

43 model->select(); 

44 

45 /* 如果数据表数据为空,则添加两个闹钟 */ 

46 if (model->rowCount() == 0) { 

47 /* 插入一行 */ 

48 model->insertRow(model->rowCount()); 

49 /* 在该行插入数据 */ 

50 model->setData(model->index(0, 0), 1); 

51 model->setData(model->index(0, 1), "06:00"); 

52 model->setData(model->index(0, 2), "false"); 

53 /* 插入数据后记得提交 */ 

54 model->submit(); 

55 

56 /* 再插入一行 */ 

57 model->insertRow(model->rowCount()); 

58 model->setData(model->index(1, 0), 2); 

59 model->setData(model->index(1, 1), "18:00"); 

60 model->setData(model->index(1, 2), "true"); 

61 /* 提交 */ 

62 model->submit(); 

63 } 

64 

65 hourPicker = new NumberPicker(this); 

66 hourPicker->setRange(0, 24); 

67 

68 minutePicker = new NumberPicker(this); 

69 minutePicker->setRange(0, 60); 

70 

71 /* 标签,用于显示时&分 */ 

72 QLabel *label[3]; 

73 label[0] = new QLabel(); 

74 label[1] = new QLabel(); 

75 label[2] = new QLabel(); 

76 

77 QFont font; 

78 font.setBold(true); 

79 font.setPixelSize(10); 

80 QPalette pal; 

81 pal.setBrush(QPalette::WindowText, QColor(0, 0, 0)); 

82 

83 label[0]->setFont(font); 

84 label[1]->setFont(font); 

85 label[2]->setFont(font); 

86 

87 label[0]->setText(" "); 

88 label[1]->setText("时"); 

89 label[2]->setText("分"); 

90 

91 /* 主布局初始化 */ 

92 listWidget = new QListWidget(); 

93 mainWidget = new QWidget(); 

94 bottomWidget = new QWidget(); 

95 alarmDialog = new QDialog(this); 

96 timeWidget = new QWidget(); 

97 btWidget = new QWidget(); 

98 addAlarm = new QPushButton(); 

99 yesButton = new QPushButton(); 

100 cancelButton = new QPushButton(); 

101 vBoxLayout[0] = new QVBoxLayout(); 

102 vBoxLayout[1] = new QVBoxLayout(); 

103 hBoxLayout[0] = new QHBoxLayout(); 

104 hBoxLayout[1] = new QHBoxLayout(); 

105 hBoxLayout[2] = new QHBoxLayout(); 

106 

107 addAlarm->setMaximumSize(84, 84); 

108 addAlarm->setObjectName("addAlarm"); 

109 addAlarm->setMinimumSize(84, 84); 

110 bottomWidget->setMinimumHeight(84); 

111 bottomWidget->setMaximumHeight(84); 

112 yesButton->setText("确认"); 

113 cancelButton->setText("取消"); 

114 yesButton->setMaximumSize(100, 50); 

115 yesButton->setMinimumSize(100, 50); 

116 cancelButton->setMinimumSize(100, 50); 

117 cancelButton->setMaximumSize(100, 50); 

118 btWidget->setMaximumHeight(70); 

119 btWidget->setMinimumHeight(70); 

120 alarmDialog->setMinimumSize(300, 300); 

121 alarmDialog->setMaximumSize(300, 300); 

122 alarmDialog->setModal(true); 

123 yesButton->setObjectName("yesButton"); 

124 cancelButton->setObjectName("cancelButton"); 

125 
126 /* 主布局 */ 

127 vBoxLayout[0]->addWidget(listWidget); 

128 vBoxLayout[0]->addWidget(bottomWidget); 

129 vBoxLayout[0]->setContentsMargins(0, 0, 0, 0); 

130 

131 mainWidget->setLayout(vBoxLayout[0]); 

132 

133 setCentralWidget(mainWidget); 

134 

135 /* 底部按钮布局 */ 

136 hBoxLayout[0]->addWidget(addAlarm); 

137 hBoxLayout[0]->setContentsMargins(0, 0, 0, 0); 

138 bottomWidget->setLayout(hBoxLayout[0]); 

139 

140 /* 对话框布局 */ 

141 vBoxLayout[1]->addWidget(timeWidget); 

142 vBoxLayout[1]->addWidget(btWidget); 

143 vBoxLayout[1]->setContentsMargins(0, 0, 0, 0); 

144 alarmDialog->setLayout(vBoxLayout[1]); 

145 

146 hBoxLayout[1]->addWidget(label[0]); 

147 hBoxLayout[1]->addWidget(hourPicker); 

148 hBoxLayout[1]->addWidget(label[1]); 

149 hBoxLayout[1]->addWidget(minutePicker); 

150 hBoxLayout[1]->addWidget(label[2]); 

151 hBoxLayout[1]->setContentsMargins(0, 0, 0, 0); 

152 timeWidget->setLayout(hBoxLayout[1]); 

153 

154 hBoxLayout[2]->addWidget(yesButton); 

155 hBoxLayout[2]->addWidget(cancelButton); 

156 

157 btWidget->setLayout(hBoxLayout[2]); 

158 

159 /* 打印出闹钟数据库里的信息 */ 

160 for (int i = 0; i < model->rowCount(); i++) { 

161 for (int j = 0; j < 3; j++) { 

162 QModelIndex qindex = model->index(i, j); 

163 switch (j) { 

164 case 0: 

165 qDebug()<<"第"<<model->data(qindex).toInt()<<"行数据"; 

166 break; 

167 case 1: 

168 listWidget->addItem(model->data(qindex).toString()); 

169 qDebug()<<"闹钟时间为:"<<model->data(qindex).toString(); 

170 break; 

171 case 2: 

172 qDebug()<<"闹钟状态为:" 

173 <<model->data(qindex).toString()<<endl; 

174 if (model->data(qindex).toString() != "true") 

175 listWidget->item(i) 

176 ->setTextColor(QColor(22, 22, 22, 60)); 

177 else 

178 listWidget->item(i) 

179 ->setTextColor(QColor(22, 22, 22, 225)); 

180 break; 

181 default: 

182 break; 

183 } 

184 } 

185 } 

186 

187 /* 在列表里添加闹钟开关 */ 

188 for (int i = 0; i < model->rowCount(); i++) { 

189 ItemObjectInfo info; 

190 info.widget = new QWidget(); 

191 info.switchButton = new SwitchButton(); 

192 info.hBoxLayout = new QHBoxLayout(); 

193 info.switchButton->setMaximumSize(55, 30); 

194 info.switchButton->setMinimumSize(55, 30); 

195 info.hBoxLayout->setContentsMargins(0, 0, 0, 0); 

196 info.hBoxLayout->setAlignment(Qt::AlignRight); 

197 info.hBoxLayout->addWidget(info.switchButton); 

198 info.widget->setLayout(info.hBoxLayout); 

199 listWidget->setItemWidget(listWidget->item(i), 

200 info.widget); 

201 itemObjectInfo.append(info); 

202 

203 /* 连接信号槽 */ 

204 connect(info.switchButton, 

205 SIGNAL(toggled(bool)), 

206 this, 

207 SLOT(switchButtonClicked(bool))); 

208 

209 /* 获取数据库里的闹钟开关状态 */ 

210 QModelIndex qindex = model->index(i, 2); 

211 if (model->data(qindex).toBool()) 

212 /* 设置列表里的闹钟开关按钮状态 */ 

213 info.switchButton->setToggle(true); 

214 } 

215 

216 /* 按钮 */ 

217 connect(addAlarm, SIGNAL(clicked()), this, 

218 SLOT(addAlarmClicked())); 

219 

220 connect(yesButton, SIGNAL(clicked()), this, 

221 SLOT(yesButtonClicked())); 

222 

223 connect(cancelButton, SIGNAL(clicked()), this, 

224 SLOT(cancelButtonClicked())); 

225 

226 /* 列表 */ 

227 connect(listWidget, 

228 SIGNAL(itemClicked(QListWidgetItem*)), 

229 this, 

230 SLOT(listWidgetItemClicked(QListWidgetItem*))); 

231 } 

232 

233 MainWindow::~MainWindow() 

234 { 

235 /* 关闭数据库 */ 

236 sqlDatabase.close(); 

237 } 

238 

239 void MainWindow::addAlarmClicked() 

240 { 

241 /* 选择时间对话框里显示当前系统时间 */ 

242 hourPicker->setValue(QTime::currentTime().hour()); 

243 minutePicker->setValue(QTime::currentTime().minute()); 

244 

245 /* 取消按钮显示文本为"取消" */ 

246 cancelButton->setText("取消"); 

247 

248 /* 如果是点击添加闹钟的按钮,则设置闹钟列表的索引 index 为-1 */ 

249 listWidget->setCurrentRow(-1); 

250 

251 /* 显示对话框 */ 

252 alarmDialog->show(); 

253 } 

254 

255 void MainWindow::listWidgetItemClicked(QListWidgetItem *item) 

256 { 

257 /* 从被点击项里获取闹钟数据 */ 

258 QStringList list = 

259 
listWidget->item(listWidget->row(item))->text().split(":"); 

260 

261 /* 选择时间对话框里显示被选择项的时间 */ 

262 hourPicker->setValue(list.at(0).toInt()); 

263 minutePicker->setValue(list.at(1).toInt()); 

264 

265 /* 取消按钮显示文本为"删除" */ 

266 cancelButton->setText("删除"); 

267 

268 /* 显示闹钟选择对话框 */ 

269 alarmDialog->show(); 

270 

271 /* 作用使其失去选择 */ 

272 listWidget->clearSelection(); 

273 } 

274 

275 void MainWindow::yesButtonClicked() 

276 { 

277 /* 获取数值选择值的数据,转为字符串 */ 

278 QString hour; 

279 QString minute; 

280 

281 if (hourPicker->readValue() < 10) 

282 hour = "0" + QString::number(hourPicker->readValue()) + ":"; 

283 else 

284 hour = QString::number(hourPicker->readValue()) + ":"; 

285 

286 if (minutePicker->readValue() < 10) 

287 minute = "0" + QString::number(minutePicker->readValue()); 

288 else 

289 minute = QString::number(minutePicker->readValue()); 

290 

291 /* 如果不是选中闹钟列表的数据 */ 

292 if (listWidget->currentRow() == -1) { 

293 /* 插入一行数据,闹钟时间为选择的闹钟时间 */ 

294 int row = model->rowCount(); 

295 

296 /* 插入数据到数据库 */ 

297 model->insertRow(row); 

298 model->setData(model->index(row, 0), row + 1); 

299 model->setData(model->index(row, 1), hour + minute); 

300 model->setData(model->index(row, 2), "true"); 

301 model->submit(); 

302 

303 /* 添加闹钟到列表 */ 

304 listWidget->addItem(hour + minute); 

305 

306 /* 添加到容器 */ 

307 ItemObjectInfo info; 

308 info.widget = new QWidget(); 

309 info.switchButton = new SwitchButton(); 

310 info.hBoxLayout = new QHBoxLayout(); 

311 info.switchButton->setMaximumSize(55, 30); 

312 info.switchButton->setMinimumSize(55, 30); 

313 info.hBoxLayout->setContentsMargins(0, 0, 0, 0); 

314 info.hBoxLayout->setAlignment(Qt::AlignRight); 

315 info.hBoxLayout->addWidget(info.switchButton); 

316 info.widget->setLayout(info.hBoxLayout); 

317 info.switchButton->setToggle(true); 

318 

319 /* 连接信号槽 */ 

320 connect(info.switchButton, SIGNAL(toggled(bool)), this, 

321 SLOT(switchButtonClicked(bool))); 

322 

323 listWidget->setItemWidget( 

324 listWidget->item(listWidget->count() - 1), 

325 info.widget); 

326 itemObjectInfo.append(info); 

327 } else { 

328 /* 修改数据(更新闹钟数据) */ 

329 int row = listWidget->currentRow(); 

330 model->setData(model->index(row, 0), row + 1); 

331 model->setData(model->index(row, 1), hour + minute); 

332 model->setData(model->index(row, 2), "true"); 

333 model->submit(); 

334 

335 /* 设置当前项的闹钟文本 */ 

336 listWidget->currentItem()->setText(hour + minute); 

337 } 

338 

339 /* 再确保提交 */ 

340 if (model->isDirty()) 

341 model->submitAll(); 

342 

343 /* 关闭对话框 */ 

344 alarmDialog->close(); 

345 } 

346 

347 void MainWindow::cancelButtonClicked() 

348 { 

349 if (cancelButton->text() == "删除") { 

350 /* 删除数据库整一行数据 */ 

351 model->removeRow(listWidget->currentRow()); 

352 model->submit(); 

353 /* 执行上面语句 */ 

354 model->select(); 

355 itemObjectInfo.remove(listWidget->currentRow()); 

356 listWidget->takeItem(listWidget->currentRow()); 

357 } 

358 

359 /* 再确保提交 */ 

360 if (model->isDirty()) 

361 model->submitAll(); 

362 

363 /* 关闭对话框 */ 

364 alarmDialog->close(); 

365 } 

366 

367 

368 /* 当点击闹钟开关时,将闹钟开关状态同步更新到数据库里 */ 

369 void MainWindow::switchButtonClicked(bool checked) 

370 { 

371 listWidget->clearSelection(); 

372 

373 SwitchButton *button = (SwitchButton *)sender(); 

374 for (int i = 0; i < itemObjectInfo.count(); i++) { 

375 if (button == itemObjectInfo.at(i).switchButton) { 

376 if (checked) { 

377 model->setData(model->index(i, 2), "true"); 

378 listWidget->item(i) 

379 ->setTextColor(QColor(22, 22, 22, 225)); 

380 } else { 

381 model->setData(model->index(i, 2), "false"); 

382 listWidget->item(i) 

383 ->setTextColor(QColor(22, 22, 22, 60)); 

384 } 

385 

386 model->submit(); 

387 break; 

388 } 

389 } 

390 } 

第 5~231 行,数据库的连接、建立模型和界面布局等。界面布局这些不再详细说,这些在
前面章节已经讲过很多次。在这部分代码里,我们发现没有用到 QTableView 来展示我们的闹
钟数据,原因很简单,因为我们的界面需要适合大众眼光,而不是展示一个表格,应该展示一
个闹钟列表,进而笔者设计使用了 QListWidget 这个控件。恰好与手机里的闹钟的列表相似。
12~15 行,查看本地主机可用的数据库驱动。一般 Qt 安装时都会自带 Sqlite3 驱动。注意
了,如果本地主机没有可用的数据库,则实验不可操作!不可生搬硬套到其他开发板子测试。
所以查看本地主机的数据库操作是调试时候必须的!
18~24 行,添加一个数据库,以 QSQLITE 驱动方式打开或者连接名字为 alarm.db 的数据库
文件。数据库存储的形式为一个 alarm.db 文件。
26~28 行,在数据库里创建一个名字为 alarm 的表格。如果已经创建,也会覆盖这个表格
名字,但是不会覆盖表格内容。必须先创建表格,才可以对表格的数据进行操作(增删查减等)。
32~43 行,新建模型 model,使用通过 setTable()设置的表中的数据填充模型,使用指定的
过滤器和排序条件,如果成功返回 true;否则返回 false。注意:调用 select()将恢复任何未提交的
更改,并删除任何插入的列。

46~63 行,笔者在这里判断,如果是刚运行该程序,发现数据库表中没有数据,则默认设
置两行闹钟数据,数据 ID 为 1,闹钟时间为 06:00,状态为关;另一条是数据 ID 为 2,闹钟时
间为 18:00,状态为开。到这里我们就已经学会在数据库里插入数据,记得插入数据后需要手动
执行 submit()函数,表示提交。不提交是不会记录保存到数据库里的。
328~336 行,直接设置数据库里的行数据,即可覆盖该行数据的内容。
347~363 行,model 对象直接移除某一行的数据就完成删除数据库里某行内容。注意可以
移除一行或者一列,闹钟数据是以每行记录保存,所以这里是移除一行。移除之后记得提交。
其他的内容都是一些逻辑与界面设计的内容,重点讲解的是 Qt 对数据库操作的步骤。其他
内容请根据源码的注释理解即可。或者运行程序去理解本例逻辑。
main.cpp 内容如下,主要是加载 qss 样式文件。

1 #include "mainwindow.h" 

2 

3 #include <QApplication> 

4 #include <QFile> 

5 

6 int main(int argc, char *argv[]) 

7 { 

8 QApplication a(argc, argv); 

9 /* 指定文件 */ 

10 QFile file(":/style.qss"); 

11 

12 /* 判断文件是否存在 */ 

13 if (file.exists() ) { 

14 /* 以只读的方式打开 */ 

15 file.open(QFile::ReadOnly); 

16 /* 以字符串的方式保存读出的结果 */ 

17 QString styleSheet = QLatin1String(file.readAll()); 

18 /* 设置全局样式 */ 

19 qApp->setStyleSheet(styleSheet); 

20 /* 关闭文件 */ 

21 file.close(); 

22 } 

23 

24 MainWindow w; 

25 w.show(); 

26 return a.exec(); 

27 } 

style.qss 样式文件如下。素材已经在源码处提供。注意下面的 style.qss 不能有注释!

1 QListWidget { 

2 font-size: 30px; 

3 outline:none; 

4 } 

5 

6 QListWidget::item:active { 

7 background: transparent; 

8 } 

9 

10 QListWidget::item { 

11 height:80; 

12 } 

13 

14 QListWidget::item:selected:hover { 

15 background:#22222222; 

16 } 

17 

18 QListWidget::item:selected { 

19 background:transparent; 

20 color:#ee222222; 

21 } 

22 

23 QPushButton#addAlarm { 

24 border-image:url(:/icons/addalarm1.png); 

25 background:transparent; 

26 outline: none; 

27 } 

28 

29 QPushButton#addAlarm:hover { 

30 border-image:url(:/icons/addalarm2.png); 

31 } 

32 

33 QPushButton#yesButton { 

34 border: 1px solid #22222222; 

35 border-radius: 25px; 

36 background:#22222222; 

37 outline:none; 

38 } 

39 

40 QPushButton#yesButton:pressed { 

41 background:#44222222; 

42 color:white; 

43 } 

44 

45 QPushButton#cancelButton { 

46 border: 1px solid #22222222; 

47 border-radius: 25px; 

48 background:#22222222; 

49 outline:none; 

50 } 

51 

52 QPushButton#cancelButton:pressed { 

53 background:#44222222; 

54 color:white; 

55 } 

56 

57 QScrollBar:vertical { 

58 width:30px; 

59 background:rgba(255, 255, 255, 100%) 

60 } 

61 

62 QScrollBar::handle:vertical { 

63 width:30px; 

64 background:rgba(200, 200, 200, 20%); 

65 border-radius:15px; 

66 } 

67 

68 QScrollBar::add-line:vertical { 

69 width:0px; height:0px; 

70 } 

71 QScrollBar::sub-line:vertical { 

72 width:0px; 

73 height:0px; 

74 } 

75 QScrollBar::handle:vertical:hover { 

76 width:30px; 

77 background:rgba(200, 200, 200, 80%); 

78 border-radius:15px; 

79 } 

80 QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical { 

81 background:rgba(255, 255, 255, 100%) 

82 } 

其中数字选择器与闹钟开关按钮的代码,代码笔者参考了一些博客优化后写成的代码。有
兴趣可以细读代码,不作为本章注释讲解的代码。
数字选择器的作用是选择闹钟的时间,效果如下,通过上下滑动可以选择数字作为时钟的
时针和分针数据。通过点击对话框确认后存储到数据库里。

QT学习开发笔记(数据库之实用时钟)
数字选择器的头文件“numberpicker.h”代码如下。

 /****************************************************************** 
 Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. 
 * @projectName NumberPicker 
 * @brief numberpicker.h 
 * @author Deng Zhimao 
 * @email 1252699831@qq.com 
 * @net www.openedv.com 
 * @date 2021-05-14 
 *******************************************************************/ 

1 #ifndef NUMBERPICKER_H 

2 #define NUMBERPICKER_H 

3 

4 #include <QMainWindow> 

5 #include <QPropertyAnimation> 

6 

7 class NumberPicker : public QWidget 

8 { 

9 Q_OBJECT 

10 

11 Q_PROPERTY(int deviation READ readDeviation WRITE setDeviation ) 

12 public: 

13 NumberPicker(QWidget *parent = nullptr); 

14 ~NumberPicker(); 

15 

16 /* 设置最大值与最小值的范围 */ 

17 void setRange(int min, int max); 

18 

19 /* 读取当前值 */ 

20 int readValue(); 

21 

22 protected: 

23 void mousePressEvent(QMouseEvent *); 

24 

25 void mouseMoveEvent(QMouseEvent *); 

26 

27 void mouseReleaseEvent(QMouseEvent *); 

28 

29 void wheelEvent(QWheelEvent *); 

30 

31 void paintEvent(QPaintEvent *); 

32 

33 public: 

34 /* 描绘数字 */ 

35 void paintNum(QPainter &painter, int num, int deviation); 

36 

37 /* 使选中的数字回到屏幕中间 */ 

38 void homing(); 

39 

40 /* 鼠标移动偏移量,默认为 0 */ 

41 int readDeviation(); 

42 

43 /* 设置偏移量 */ 

44 void setDeviation(int n); 

45 

46 /* 设置字体大小 */ 

47 void setNumSize(int); 

48 

49 /* 设置间隔大小 */ 

50 void setInterval(int); 

51 

52 /* 设置分格数量,一般设置为 3、5、7... */ 

53 void setDevide(int); 

54 

55 /* 设置数字颜色,设置 rgb 的数值 */ 

56 void setNumberColor(QRgb rgb); 

57 

58 /* 设置当前值 */ 

59 void setValue(int value); 

60 

61 signals: 

62 

63 void currentValueChanged(int value); 

64 

65 void deviationChange(int deviation); 

66 

67 private: 

68 /* 最小值 */ 

69 int minRange; 

70 

71 /* 最大值 */ 

72 int maxRange; 

73 

74 /* 当前选中的值 */ 

75 int currentValue; 

76 

77 /* 鼠标是否按下 */ 

78 bool isDragging; 

79 

80 /* 偏移量,记录鼠标按下后移动的垂直距离 */ 

81 int deviation; 

82 

83 /* 鼠标按下的垂直位置 */ 

84 int mouseSrcPos; 

85 

86 /* 数字大小 */ 

87 int numSize; 

88 

89 /* 动画 */ 

90 QPropertyAnimation *homingAni; 

91 

92 /* 间隔大小 */ 

93 int interval; 

94 

95 /* 分格数量 */ 

96 int devide; 

97 

98 /* 数字颜色 */ 

99 QColor numberColor; 

100 }; 

101 #endif // NUMBERPICKER_H 

数字选择器的源文件“numberpicker.cpp”代码如下。

 /****************************************************************** 
 Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. 
 * @projectName NumberPicker 
 * @brief numberpicker.cpp 
 * @author Deng Zhimao 
 * @email 1252699831@qq.com 
 * * @net www.openedv.com 
 * @date 2021-05-14 
 *******************************************************************/ 

1 #include <QMouseEvent> 

2 #include <QDebug> 

3 #include "numberpicker.h" 

4 #include <QPainter> 

5 

6 NumberPicker::NumberPicker(QWidget *parent) : 

7 /* 最小值默认为 0 */ 

8 minRange(0), 

9 

10 /* 最大值默认 60 */ 

11 maxRange(60), 

12 

13 /* 当前值默认 0 */ 

14 currentValue(0), 

15 

16 /* 按下标志位为假 */ 

17 isDragging(false), 

18 

19 /* 默认偏移量为 0 */ 

20 deviation(0), 

21 

22 /* 数值越大 */ 

23 numSize(15), 

24 

25 /* 间隔为 1 */ 

26 interval(1), 

27 

28 /* 默认分成 3 格 */ 

29 devide(3), 

30 

31 /* 默认颜色黑色 */ 

32 numberColor(0, 0, 0) 

33 { 

34 setParent(parent); 

35 setMinimumSize(50, 150); 

36 homingAni = new QPropertyAnimation(this, "deviation"); 

37 homingAni->setDuration(300); 

38 homingAni->setEasingCurve(QEasingCurve::OutQuad); 

39 } 

40 

41 NumberPicker::~NumberPicker() 

42 { 

43 

44 } 

45 

46 void NumberPicker::setRange(int min, int max) 

47 { 

48 minRange = min; 

49 maxRange = max; 

50 if (currentValue < min) { 

51 currentValue = min; 

52 } 

53 if (currentValue > max) { 

54 currentValue = max; 

55 } 
56 repaint(); 

57 } 

58 

59 int NumberPicker::readValue() 

60 { 

61 return currentValue; 

62 } 

63 

64 void NumberPicker::mousePressEvent(QMouseEvent *e) 

65 { 

66 homingAni->stop(); 

67 isDragging = true; 

68 mouseSrcPos = e->pos().y(); 

69 QWidget::mousePressEvent(e); 

70 } 

71 

72 void NumberPicker::mouseMoveEvent(QMouseEvent *e) 

73 { 

74 if (isDragging){ 

75 deviation = e->pos().y() - mouseSrcPos; 

76 

77 /* 若移动速度过快,则进行限制 */ 

78 if (deviation > (height() - 1) / devide) { 

79 deviation = (height() - 1) / devide; 

80 } else if (deviation < -(height() - 1) / devide) { 

81 deviation = -( height() - 1) / devide; 

82 } 

83 

84 emit deviationChange(deviation / ((height() - 1) / devide)); 

85 repaint(); 

86 } 

87 } 

88 

89 void NumberPicker::mouseReleaseEvent(QMouseEvent *) 

90 { 

91 if (isDragging) { 

92 isDragging = false; 

93 homing(); 

94 } 

95 } 

96 

97 void NumberPicker::wheelEvent(QWheelEvent *e) 

98 { 

99 if (e->delta() > 0) { 

100 deviation = (this->height() - 1) / devide; 

101 } else { 

102 deviation = -(this->height() - 1) / devide; 

103 } 

104 

105 homing(); 

106 repaint(); 

107 } 

108 

109 void NumberPicker::paintEvent(QPaintEvent *) 

110 { 

111 QPainter painter(this); 

112 painter.setRenderHint(QPainter::Antialiasing, true); 

113 int Height = height() - 1; 

114 
115 if (deviation >= Height / devide && currentValue > minRange ) { 

116 mouseSrcPos += Height / devide; 

117 deviation -= Height / devide; 

118 currentValue -= interval; 

119 /* 负数处理 */ 

120 if (currentValue < 0) 

121 currentValue = maxRange + currentValue; 

122 } 

123 

124 if (deviation <= -Height / devide && currentValue < maxRange ) { 

125 mouseSrcPos -= Height / devide; 

126 deviation += Height / devide; 

127 currentValue += interval; 

128 } 

129 

130 if (qAbs(int(currentValue)) >= int(maxRange)) 

131 currentValue = minRange; 

132 

133 paintNum(painter, qAbs(int(currentValue + maxRange) % maxRange), 

134 deviation); 

135 

136 paintNum(painter, 

137 qAbs((currentValue - interval + maxRange) % maxRange), 

138 deviation - Height / devide); 

139 

140 paintNum(painter, 

141 qAbs((currentValue + interval + maxRange) % maxRange), 

142 deviation + Height / devide); 

143 

144 for (int i = 2; i <= devide / 2; ++i) { 

145 if (qAbs(currentValue - interval * i) >= minRange) { 

146 paintNum(painter, 

147 qAbs((currentValue - interval * i + maxRange) 

148 % maxRange), 

149 deviation - Height / devide * i); 

150 } 

151 

152 if (qAbs(currentValue + interval * i) <= maxRange) { 

153 paintNum(painter, 

154 qAbs((currentValue + interval * i + maxRange) 

155 % maxRange), 

156 deviation + Height / devide * i); 

157 } 

158 } 

159 } 

160 

161 void NumberPicker::paintNum(QPainter &painter, int num, int deviation) 

162 { 

163 int Width = width() - 1; 

164 int Height = height() - 1; 

165 

166 /* 偏移量越大,数字越小 */ 

167 //int size = (Height - qAbs(deviation)) / numSize; 

168 int size = (Height - qAbs(deviation)) * numSize / 80; 

169 int transparency = 255 - 255 * qAbs(deviation) / Height; 

170 int height = Height / devide; 

171 int y = Height / 2 + deviation - height / 2; 

172 

173 QFont font; 

174 font.setPixelSize(size); 

175 painter.setFont(font); 

176 painter.setPen(QColor(numberColor.red(), 

177 numberColor.green(), 

178 numberColor.blue(), 

179 transparency)); 

180 

181 if ( y >= 0 && y + height < Height) { 

182 //painter.drawRect(0, y, Width, height); 

183 if (num < 10) 

184 painter.drawText(QRectF(0, y, Width, height), 

185 Qt::AlignCenter, 

186 "0" + QString::number(num, 'f', 0)); 

187 else 

188 painter.drawText(QRectF(0, y, Width, height), 

189 Qt::AlignCenter, 

190 QString::number(num, 'f', 0)); 

191 } 

192 } 

193 

194 void NumberPicker::homing() 

195 { 

196 if (deviation > height() / 10) { 

197 homingAni->setStartValue((height() - 1 ) / 8 - deviation); 

198 homingAni->setEndValue(0); 

199 currentValue -= interval; 

200 } else if (deviation > -height() / 10) { 

201 homingAni->setStartValue(deviation); 

202 homingAni->setEndValue(0); 

203 } else if (deviation < -height() / 10) { 

204 homingAni->setStartValue(-(height() - 1) / 8 - deviation); 

205 homingAni->setEndValue(0); 

206 currentValue += interval; 

207 } 

208 

209 emit currentValueChanged(currentValue); 

210 homingAni->start(); 

211 } 

212 

213 int NumberPicker::readDeviation() 

214 { 

215 return deviation; 

216 } 

217 

218 void NumberPicker::setDeviation(int n) 

219 { 

220 deviation = n; 

221 repaint(); 

222 } 

223 

224 void NumberPicker::setNumSize(int size) 

225 { 

226 numSize = size; 

227 repaint(); 

228 } 

229 

230 void NumberPicker::setInterval(int n) 

231 { 

232 interval = n; 

233 repaint(); 

234 } 

235 

236 void NumberPicker::setDevide(int n) 

237 { 

238 devide = n; 

239 repaint(); 

240 } 

241 

242 void NumberPicker::setNumberColor(QRgb rgb) 

243 { 

244 numberColor.setRgb(rgb); 

245 repaint(); 

246 } 

247 

248 void NumberPicker::setValue(int value) 

249 { 

250 if (value < minRange || value > maxRange) { 

251 qDebug()<<"数值设置必须在"<<minRange 

252 <<"和"<<maxRange<<"之间"<<endl; 

253 return; 

254 } 

255 currentValue = value; 

256 repaint(); 

257 } 

开关按钮的效果如下。运行时有动画效果,类似 IOS 手册里的开关按钮一样。
QT学习开发笔记(数据库之实用时钟)

开关按钮的头文件“switchbutton.h”代码如下。

 /****************************************************************** 
 Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. 
 * @projectName 17_sqlite_example 
 * @brief switchbutton.h 
 * @author Deng Zhimao 
 * @email 1252699831@qq.com 
 * @net www.openedv.com 
 * @date 2021-05-14 
 *******************************************************************/ 

1 #ifndef SWITCHBUTTON_H 

2 #define SWITCHBUTTON_H 

3 

4 #include <QWidget> 

5 #include <QTimer> 

6 

7 class SwitchButton : public QWidget 

8 { 
9 Q_OBJECT 

10 

11 public: 

12 explicit SwitchButton(QWidget *parent = nullptr); 

13 

14 /* 返回开关状态 - 打开:true 关闭:false */ 

15 bool isToggled() const; 

16 

17 /* 设置开关状态 */ 

18 void setToggle(bool checked); 

19 

20 /* 设置背景颜色 */ 

21 void setBackgroundColor(QColor color); 

22 

23 /* 设置选中颜色 */ 

24 void setCheckedColor(QColor color); 

25 

26 /* 设置不可用颜色 */ 

27 void setDisbaledColor(QColor color); 

28 

29 protected: 

30 /* 绘制开关 */ 

31 void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; 

32 

33 /* 鼠标按下事件 */ 

34 void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; 

35 

36 /* 鼠标释放事件 - 切换开关状态、发射 toggled()信号 */ 

37 void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; 

38 

39 /* 大小改变事件 */ 

40 void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE; 

41 

42 /* 缺省大小 */ 

43 QSize sizeHint() const Q_DECL_OVERRIDE; 

44 QSize minimumSizeHint() const Q_DECL_OVERRIDE; 

45 

46 signals: 

47 /* 状态改变时,发射信号 */ 

48 void toggled(bool checked); 

49 

50 private slots: 

51 /* 状态切换时,用于产生滑动效果 */ 

52 void onTimeout(); 

53 

54 private: 

55 /* 是否选中 */ 

56 bool m_bChecked; 

57 

58 /* 背景颜色 */ 

59 QColor m_background; 

60 

61 /* 选中颜色 */ 

62 QColor m_checkedColor; 

63 

64 /* 不可用颜色 */ 

65 QColor m_disabledColor; 

66 

67 /* 拇指颜色 */ 

68 QColor m_thumbColor; 

69 

70 /* 圆角 */ 

71 qreal m_radius; 

72 

73 /* x 点坐标 */ 

74 qreal m_nX; 

75 

76 /* y 点坐标 */ 

77 qreal m_nY; 

78 

79 /* 高度 */ 

80 qint16 m_nHeight; 

81 

82 /* 外边距 */ 

83 qint16 m_nMargin; 

84 

85 /* 定时器 */ 

86 QTimer m_timer; 

87 }; 

88 #endif // SWITCHBUTTON_H 

开关按钮的源文件“switchbutton.cpp”代码如下。

 /****************************************************************** 
 Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. 
* @projectName 17_sqlite_example 
 * @brief switchbutton.cpp 
 * @author Deng Zhimao 
 * @email 1252699831@qq.com 
 * @net www.openedv.com 
 * @date 2021-05-14 
 *******************************************************************/ 

1 #include "switchbutton.h" 

2 

3 #include <QPainter> 

4 #include <QMouseEvent> 

5 

6 SwitchButton::SwitchButton(QWidget *parent) 

7 : QWidget(parent), 

8 m_bChecked(false), 

9 m_background(Qt::gray), 

10 m_checkedColor(34, 131, 246), 

11 m_disabledColor(190, 190, 190), 

12 m_thumbColor(Qt::gray), 

13 m_radius(12.5), 

14 m_nHeight(16), 

15 m_nMargin(3) 

16 { 

17 /* 鼠标滑过光标形状 - 手型 */ 

18 setCursor(Qt::PointingHandCursor); 

19 

20 /* 连接信号槽 */ 

21 connect(&m_timer, SIGNAL(timeout()), 

22 this, SLOT(onTimeout())); 

23 } 

24 

25 /* 绘制开关 */ 

26 void SwitchButton::paintEvent(QPaintEvent *event) 

27 { 

28 Q_UNUSED(event) 

29 

30 QPainter painter(this); 

31 painter.setPen(Qt::NoPen); 

32 painter.setRenderHint(QPainter::Antialiasing); 

33 

34 QPainterPath path; 

35 QColor background; 

36 QColor thumbColor; 

37 qreal dOpacity; 

38 /* 可用状态 */ 

39 if (isEnabled()) { 

40 /* 打开状态 */ 

41 if (m_bChecked) { 

42 background = m_checkedColor; 

43 thumbColor = m_checkedColor; 

44 dOpacity = 0.600; 

45 /* 关闭状态 */ 

46 } else { 

47 background = m_background; 

48 thumbColor = m_thumbColor; 

49 dOpacity = 0.800; 

50 } 

51 /* 不可用状态 */ 

52 } else { 

53 background = m_background; 

54 dOpacity = 0.260; 

55 thumbColor = m_disabledColor; 

56 } 

57 /* 绘制大椭圆 */ 

58 painter.setBrush(background); 

59 painter.setOpacity(dOpacity); 

60 path.addRoundedRect(QRectF(m_nMargin, 

61 m_nMargin, width() - 2 * m_nMargin, 

62 height() - 2 * m_nMargin), 

63 m_radius, m_radius); 

64 painter.drawPath(path.simplified()); 

65 

66 /* 绘制小椭圆 */ 

67 painter.setBrush(thumbColor); 

68 painter.setOpacity(1.0); 

69 painter.drawEllipse(QRectF(m_nX - (m_nHeight / 2), 

70 m_nY - (m_nHeight / 2), 

71 height(), 

72 height())); 

73 } 

74 

75 /* 鼠标按下事件 */ 

76 void SwitchButton::mousePressEvent(QMouseEvent *event) 

77 { 

78 if (isEnabled()) { 

79 if (event->buttons() & Qt::LeftButton) { 

80 event->accept(); 

81 } else { 

82 event->ignore(); 

83 } 

84 } 

85 } 

86 

87 /* 鼠标释放事件 - 切换开关状态、发射 toggled()信号 */ 

88 void SwitchButton::mouseReleaseEvent(QMouseEvent *event) 

89 { 

90 if (isEnabled()) { 

91 if ((event->type() == QMouseEvent::MouseButtonRelease) 

92 && (event->button() == Qt::LeftButton)) { 

93 event->accept(); 

94 m_bChecked = !m_bChecked; 

95 emit toggled(m_bChecked); 

96 m_timer.start(10); 

97 } else { 

98 event->ignore(); 

99 } 

100 } 

101 } 

102 

103 /* 大小改变事件 */ 

104 void SwitchButton::resizeEvent(QResizeEvent *event) 

105 { 

106 m_nX = m_nHeight / 2; 

107 m_nY = m_nHeight / 2; 

108 QWidget::resizeEvent(event); 

109 } 

110 

111 /* 默认大小 */ 

112 QSize SwitchButton::sizeHint() const 

113 { 

114 return minimumSizeHint(); 

115 } 

116 

117 /* 最小大小 */ 

118 QSize SwitchButton::minimumSizeHint() const 

119 { 

120 return QSize(2 * (m_nHeight + m_nMargin), 

121 m_nHeight + 2 * m_nMargin); 

122 } 

123 

124 /* 切换状态 - 滑动 */

125 void SwitchButton::onTimeout() 

126 { 

127 if (m_bChecked) { 

128 m_nX += 1; 

129 if (m_nX >= width() - m_nHeight - m_nHeight / 2 ) { 

130 m_timer.stop(); 

131 m_nX -= 1; 

132 } 

133 } else { 

134 m_nX -= 1; 

135 if (m_nX <= m_nHeight / 2) { 

136 m_timer.stop(); 

137 m_nX += 1; 

138 } 

139 } 

140 update(); 

141 } 

142 

143 /* 返回开关状态 - 打开:true 关闭:false */ 

144 bool SwitchButton::isToggled() const 

145 { 

146 return m_bChecked; 

147 } 

148 

149 /* 设置开关状态 */ 

150 void SwitchButton::setToggle(bool checked) 

151 { 

152 m_bChecked = checked; 

153 m_timer.start(10); 

154 } 

155 

156 /* 设置背景颜色 */ 

157 void SwitchButton::setBackgroundColor(QColor color) 

158 { 

159 m_background = color; 

160 } 

161 

162 /* 设置选中颜色 */ 

163 void SwitchButton::setCheckedColor(QColor color) 

164 { 

165 m_checkedColor = color; 

166 } 

167 

168 /* 设置不可用颜色 */ 
169 void SwitchButton::setDisbaledColor(QColor color) 

170 { 

171 m_disabledColor = color; 

172 }

程序运行效果

点击程序正下方的“+”按钮则开始添加闹钟数据,根据当前系统的时间或者滑动选择闹
钟的时间,点击确认即新增一条闹钟数据。
QT学习开发笔记(数据库之实用时钟)
修改或者删除数据,点击要修改闹钟的数据项目,弹出的对话框,可以重新设置闹钟或者
删除闹钟。并保存记录到数据库里,下次运行打开时会从数据库里读取保存的闹钟数据。
QT学习开发笔记(数据库之实用时钟)