QMainWindow (主窗口)
Qt的 QMainWindow 用于创建具有标准组件的桌面应用程序,是构建复杂桌面应用程序用户界面的基础。
特点:
- 标准化结构
 - 提高开发效率
 - 功能清晰。
 
五个常用的部分:
- 菜单栏 Menu Bar
 - 工具条 Tool Bar
 - 停靠部件 Dock Widgets
 - 中心部件 Central Widget
 - 状态栏 Status Bar
 
图示:

模式对话框
模式对话框是指独占所有输入的对话框,在此对话框结束之前,所有的对话框都禁止使用的对话框。
消息对话框
消息对话框属于模式对话框。
QMessageBox::question  // 带问号图标的对话框
QMessageBox::information  // 带蓝色叹号的对话框
QMessageBox::warning  // 带红色叹号的对话框
QMessageBox::critical // 带致命错误图标的对话框
        QFileDialog 对话框
Qt 提供的一些标准的对话框,如文件操作对话框(QFileDialog等)方便用户调用并获取信息。
QFileDialog(
QWidget *parent = nullptr,
const QString &caption = QString(),
const QString &directory = QString(),
const QString &filter = QString()
)
        QDialog 对话框
QDialog 对话框是模式对话框的基类,用它可以自定义模式和非模式对话框。
QDialog 的槽函数有:
// 接受(返回QDialog::Accepted --> 1)
virtual void  accept()
// 返回 自定义的值。
virtual void  done(int r) 
virtual int exec() // 显示为模式对话框
// 拒绝(QDialog::Rejected --> 0)
virtual void reject()
        SQLite 数据库
数据库介绍
数据库从字面意思解释就是存储数据的仓库。
数据库按存储数据的方式可以分为:
- 
关系型数据库
- 以数据表的形式存储,表和表之间建立逻辑关系,如:
 - Oracle、MySQL、SQLite等。
 
 - 
非关系型数据库
- 
以键值对或字典等方式存储,如:
- Redis、MongoDB等。
 
 
 - 
 
数据表 table
- 列:字段(每个字段有统一的数据类型),各个字段的类型可以不同。
 - 行:记录,用于记录数据,每一行称之为一条数据。
 - 数据表:有行列组成。
 
数据表student
| ID | 姓名 | 年龄 | 
|---|---|---|
| 1 | 张三 | 18 | 
| 2 | 李四 | 19 | 
INSERT INTO student VALUES(1, "张三", 18);
INSERT INTO student(name, age, id) VALUES("李四", 19, 2);
SELECT * FROM student;
        数据表科目 subject
| id | 科目 | 
|---|---|
| 1 | 语文 | 
| 2 | 数学 | 
INSERT INTO sub VALUES(1, "语文");
INSERT INTO sub VALUES(2, "数学");
SELECT * FROM sub;
        数据表 score
| id | 学生 ID | 科目ID | 成绩 | 
|---|---|---|---|
| 1 | 1 | 1 | 100 | 
| 2 | 1 | 2 | 88 | 
| 3 | 2 | 1 | 99 | 
| 4 | 2 | 2 | 66 | 
INSERT INTO scr VALUES(1, 1, 1, 100);
INSERT INTO scr VALUES(2, 1, 2, 88);
INSERT INTO scr VALUES(3, 2, 1, 99);
INSERT INTO scr VALUES(4, 2, 2, 66);
SELECT * FROM scr;
        SQLite 数据库简介
SQLite 是一个轻量级的关系型数据库
SQLite = SQL + Lite
SQL(Structured Query Language) 是结构化查询语言。
Lite 是轻量的意思。
SQLite专门为嵌入式设计,仅仅需要几百K内存就可以运行。
SQLite 支持多个操作系统:Windows,Linux,UNIX等。
SQLite 数据库是遵守ACID规则的数据库。
ACID是数据库管理的四个特征
- 
原子性(Atomicity)
- 支持事务操作,要么全部执行,要么都不执行。
 
 - 
一致性(Consistency)
- 在事务开始前和事务结束后,数据库是完整的,没有给破坏过。
 
 - 
隔离性(Isolation)
- 允许多个事务进行并发的对数据库进行读写和修改,隔离性可以防止在并发执行时导致数据的不一致性。
 
 - 
持久性(Durability)
- 在事务完成后,对于数据库的修改会持久的保存在数据库中,并不会被恢复。
 
 
安装 SQLite
sudo apt install sqlite3 libsqlite3-dev -y
        SQLite3 官网 https://www.sqlite.org/
使用 sqlite3 命令来操作数据库
sqlite3 [数据库文件名]
        示例
$ sqlite3 test.db 
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> 
        SQLite3 控制台的基本操作
.version // 查看数据库的版本信息
.help    // 查看所有的SQLite命令
.quit/.exit  //  退出数据库控制台
.print       // 打印一些信息
.tables      // 查看当前数据库中的所有数据表。
.schema [数据表]  // 查看数据表的创建结构。
        SQLite3数据库基础数据类型
| 存储类 | 说明 | 常见声明的类型 | 
|---|---|---|
| NULL | 空值 | |
| INTEGER | 带符号整数 | INTEGER, INT, BIGINT, TINYINT | 
| REAL | 浮点数 | REAL, FLOAT, DOUBLE | 
| TEXT | 文本字符串 | TEXT, VARCHAR(N), CHAR(N), CLOB | 
| BLOB | 二进制数据 | BLOB(如果没有声明类型,默认也是 BLOB) | 
SQL 语言的语句的两种类型
- DDL(数据定义语言)
 - DML(数据操作语言)
 
SQL 语句的关键字不区分大小写,即(CREATE、create 和CrEaTe都是一样的)
DDL(数据定义语言)-- 用来操作数据表
DDL用于定义和管理数据库的结构,包括创建、修改和删除数据库对象(如表)
创建数据表的SQL语句
-- 格式
CREATE TABLE 表名(字段名1 字段数据类型1,字段名2 字段数据类型2,...);
        示例
CREATE TABLE student(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER); 
CREATE TABLE sub(id INTEGER PRIMARY KEY AUTOINCREMENT, subject VARCHAR(20) NOT NULL UNIQUE);
CREATE TABLE scr(id INTEGER PRIMARY KEY AUTOINCREMENT, stu_id INTEGER, sub_id INTEGER, score INT);
        SQL 中的约束关键字
NOT NULL    // 非空(不允许没有值)
UNIQUE      // 唯一(字段内不允许重复)
PRIMARY KEY // 主键(非空且唯一,通常作为唯一标识使用)
AUTOINCREMENT // 整数值自动递增。
        删除数据表的SQL语句
DROP TABLE 表名
        示例
DROP TABLE student;
DROP TABLE scr;
DROP TABLE sub;
        DML 数据操作语言 -- 用来操作数据记录的
DML包括的命令有
- INSERT - 插入记录
 - UPDATE - 更新(修改)记录的值
 - DELETE - 删除记录
 - SELECT - 查询记录
 
插入数据记录 INSERT
作用:向数据表中插入记录
语法格式
INSERT INTO 数据表名(字段名1, 字段名2,...) VALUES(字段数据1,字段数据2,...);
// 或
INSERT INTO 数据表名 VALUES(字段数据1,字段数据2,...);
        示例
INSERT INTO student(id, name, age) VALUES(1, "zhang3", 18);
INSERT INTO student(name, age) VALUES('li4', 19);
INSERT INTO student VALUES(3, 'wang5', 17);
        查询记录 SELECT
作用:用于查询记录
语法规则
SELECT 字段名1, 字段名2, ... FROM 表名;
SELECT * FROM 表名;
SELECT 字段名1, 字段名2, ...  FROM 表名 WHERE 条件;
        示例
SELECT * FROM student;
SELECT name, age FROM student;
SELECT name FROM student;
SELECT name, age, id FROM student;
// 查询 年龄小于 18 周岁的学生的姓名和年龄
SELECT name,age FROM student WHERE age < 18;
        修改数据记录 UPDATE
作用:修改指定条件的数据记录的某个字段的值
语法规则
UPDATE 表名 SET 字段名1=字段值1, 字段名2=字段值2, ... WHERE 条件;
        示例
// 修改ID 为 1 的用户的 姓名为 张三丰 年龄为 19 周岁
UPDATE student SET name="张三丰",age=19 WHERE id=1;
        SQL 中的比较运算
> 大于 >= 大于等于 < 小于 <= 小于等于 = 等于 != <> 不等于SQL 中的逻辑运算
AND 与运算 OR 或运算 NOT 非运算
删除记录 DELETE
作用:删除指定条件的数据记录。
语法规则
DELETE FROM 表名 WHERE 条件;
        示例
// 删除 ID 为 1 的用户
DELETE FROM student WHERE id=1;
// 删除所有记录但不删除数据表
DELETE FROM student;
        Linux 下SQLite数据的查询工具 sqlitebrowser
# 安装方法
sudo apt install sqlitebrowser
# 运行方法
sqlitebrowser SQLite.db文件
        联合UNION查询
// 查询 所有 成绩中大于 80 的成绩
SELECT * FROM scr WHERE score >80;
// 查询 所有 成绩中大于 80 的语文成绩
SELECT * FROM scr WHERE score >80 and sub_id = 1;
// 将三张表拼接成一张大表
SELECT * FROM scr
 JOIN student
 ON scr.stu_id = student.id
 JOIN sub ON scr.sub_id = sub.id;
// 查询 语文 成绩中大于 80 的学生姓名
SELECT name, subject, score FROM scr
 JOIN student
 ON scr.stu_id = student.id
 JOIN sub ON scr.sub_id = sub.id
 WHERE subject="语文" and score >80;
 
// 查询 数学 成绩中大于 80 的学生姓名
SELECT name, subject, score FROM scr
 JOIN student
 ON scr.stu_id = student.id
 JOIN sub ON scr.sub_id = sub.id
 WHERE subject="数学" and score >80; 
        笛卡尔积图示

SQLite3 的C语言接口
详见:/usr/include/sqlite3.h 文件
相关函数
sqlite3_open()
sqlite3_exec();
sqlite3_close()
sqlite3_step() 
sqlite3_prepare()
        示例
#include <stdio.h>
#include <sqlite3.h>
static int callback(void *NotUsed, int argc, char **argv, char **azColName){
  int i;
  for(i=0; i<argc; i++){
    printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
  }
  printf("\n");
  return 0;
}
int main(int argc, char **argv){
  sqlite3 *db;
  char *zErrMsg = 0;
  int rc;
  if( argc!=3 ){
    fprintf(stderr, "Usage: %s DATABASE SQL-STATEMENT\n", argv[0]);
    return(1);
  }
  rc = sqlite3_open(argv[1], &db);
  if( rc ){
    fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    return(1);
  }
  rc = sqlite3_exec(db, argv[2], callback, 0, &zErrMsg);
  if( rc!=SQLITE_OK ){
    fprintf(stderr, "SQL error: %s\n", zErrMsg);
    sqlite3_free(zErrMsg);
  }
  sqlite3_close(db);
  return 0;
}
        编译
gcc 01_sqlite_demo.cpp -lsqlite3
        运行
./a.out test.db "SELECT * FROM student;"
或
./a.out test.db "SELECT * FROM sub;"
        SQLite 的Qt接口
Qt 提供了两个类 QSqlDatabase 和 QSqlQuery 用于数据库操作,
他们的作用如下:
- QSqlDatabase 用于连接数据库。
 - QSqlQuery 用于查询操作
 
使用步骤:
- 在 .pro 项目文件中加入:
QT += sql来让数据库模块参加编译 - 使用
QSqlDatabase连接数据库,并检测连接是否正常。 - 使用 
QSqlQuery调用SQL语句进行查询等DML操作并得到结果。 
示例
sqlitewidget.h
#ifndef SQLITEWIDGET_H
#define SQLITEWIDGET_H
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QTextEdit>
#include <QWidget>
class SQLiteWidget : public QWidget
{
    Q_OBJECT
public:
    SQLiteWidget(QWidget *parent = nullptr);
    ~SQLiteWidget();
protected:
    void initSqlite(void);
    void initUI(void);
    void onSqlExecBtn(void);
private:
    QTextEdit * textEdit; // 用于输入SQL 语句
    QSqlDatabase db;   // 用于记录数据库连接
};
#endif // SQLITEWIDGET_H
        sqlitewidget.cpp
#include <QVBoxLayout>
#include <QPushButton>
#include <QDebug>
#include "sqlitewidget.h"
SQLiteWidget::SQLiteWidget(QWidget *parent)
    : QWidget(parent)
{
    initSqlite();
    initUI();
}
SQLiteWidget::~SQLiteWidget()
{
}
void SQLiteWidget::initSqlite(void)
{
    // 添加SQLITE 数据库引擎,并生成数据库对象db
    db = QSqlDatabase::addDatabase("QSQLITE");
    // 连接 test.db 数据库。
    db.setDatabaseName("../test.db");
    // 打开数据库,并判断是否成功连接
    if (db.open()) {
        qDebug() << "数据库连接成功!";
    } else {
        qDebug() << "数据库连接失败!";
    }
}
void SQLiteWidget::initUI(void)
{
    textEdit = new QTextEdit;
    textEdit->setPlaceholderText("请输入SQL语句");
    QPushButton * btn = new QPushButton("运行SQL");
    QVBoxLayout * vlayout = new QVBoxLayout(this);
    vlayout->addWidget(textEdit);
    vlayout->addWidget(btn);
    connect(btn, &QPushButton::pressed,
            this, &SQLiteWidget::onSqlExecBtn);
}
void SQLiteWidget::onSqlExecBtn(void)
{
    // 获取用户输入的信息的纯文本。
    QString sql = textEdit->toPlainText();
    qDebug() << sql;
    // 创建查询对象
    QSqlQuery query;
    // 执行SQL 语句
    if (!query.exec(sql)) {
        qDebug() << "SQL 语句执行失败!";
        return;
    }
    // qDebug() << "查询到" << query.size() << "条记录!";
    // 遍历每一条数据记录
    while(query.next()) {
        // 根据 列名称返回该条记录对应的列,并转为整数。
        int id = query.value("id").toInt();
        QString name = query.value("name").toString();
        // 根据 列号(列索引)返回该条记录对应的列,并转为整数。
        int age = query.value(2).toInt();
        qDebug() << "id:" << id << "name:" << name
                    << "age:" << age;
    }
}