VS+QT+SQLite实现简单的计算器

VS+QT+SQLite实现简单的计算器

  • 0. 计算器功能说明
    • 0.1 计算器界面
    • 0.2 历史记录模块
    • 0.3 总体说明
  • 1. 安装VS
    • 1.1 下载VS_Community
    • 1.2 安装VS
  • 2. 安装Qt
    • 2.1 下载Qt
    • 2.2 安装Qt
  • 3. 为VS配置Qt VS Tools
    • 3.1 下载安装Qt VS Tools
    • 3.2 配置环境变量
    • 3.3 特殊问题解决
  • 4. 安装SQLite
    • 4.1 下载SQLite
    • 4.2 安装SQLite
    • 4.3 测试SQLite
  • 5. 创建和配置VS+QT的工程
    • 5.1 创建VS工程
    • 5.2 重定向目标工具集
    • 5.3 添加main函数
    • 5.3 配置QT模块
  • 6. 搭建程序框架
    • 6.1 建立计算器的QT类
    • 6.2 在Main中实例化计算器类
    • 6.3 新建UI界面
    • 6.4 编译UI界面
    • 6.5 更换窗体的名称和标题
    • 6.6 建立计算器UI对象
  • 7. 设计UI界面
    • 7.1 Qt设计师面板介绍
    • 7.2 添加一个水平布局
    • 7.3 添加Text Browser和水平布局
    • 7.4 添加垂直布局和按钮
    • 7.5 添加菜单栏
    • 7.6 保存并运行
  • 8. 添加成员变量和函数框架
    • 8.1 添加成员变量
    • 8.2 添加成员函数框架
  • 9. 设置与数据库的连接
    • 9.1 添加数据库头文件
    • 9.2 配置与数据库的连接
  • 10. 实现槽函数功能
    • 10.1 数字按钮组槽函数
    • 10.2 操作符按钮组槽函数
    • 10.3 结果计算与存储函数
    • 10.4 单个键与菜单栏槽函数
    • 10.5 完成效果展示
  • 11. 代码总结
    • 11.1 文档版代码(纯代码)
    • 11.2 整个工程(百度网盘)
  • 12. 多多点赞关注,常交流!

0. 计算器功能说明

0.1 计算器界面

计算器界面及其模块介绍如下:

VS+QT+SQLite实现简单的计算器_第1张图片

0.2 历史记录模块

点开设置按钮,有三个选项,功能如下:
VS+QT+SQLite实现简单的计算器_第2张图片

我们点击查看历史,可以看到效果:

VS+QT+SQLite实现简单的计算器_第3张图片

0.3 总体说明

计算器整体功能简单,就是基本的四则运算,加上存储历史记录的功能,可以用来学习QT和SQLite。

我们会使用三个软件,分别为VS+QT(提供界面UI)+SQLite(提供数据库)。

不会QT和SQLite没关系。这里不涉及很深入的知识,手把手教学,包教包会。

下面就从配置开发环境开始。

1. 安装VS

1.1 下载VS_Community

这里有VS的下载链接,自行取用:VS_Community下载

1.2 安装VS

双击VS_Community.exe,傻瓜式安装(我们只需要C++开发环境),不再详述。

2. 安装Qt

2.1 下载Qt

这里有Qt的离线安装包网址,自行取用:Qt离线安装包下载
VS+QT+SQLite实现简单的计算器_第4张图片

2.2 安装Qt

双击打开qt-opensource-windows-x86-5.12-8.exe,出现欢迎界面,点 next:
VS+QT+SQLite实现简单的计算器_第5张图片
登录Qt账户:
VS+QT+SQLite实现简单的计算器_第6张图片
直接下一步,然后选择文件夹,这个自由选择,只要知道自己装在哪就好了。

选择安装的组件,如下:
VS+QT+SQLite实现简单的计算器_第7张图片
一直下一步,直至安装完成。

3. 为VS配置Qt VS Tools

3.1 下载安装Qt VS Tools

打开VS,找到标题栏的 扩展,点击子选项 管理扩展:
在这里插入图片描述
在管理扩展中安装Qt VS Tools:
VS+QT+SQLite实现简单的计算器_第8张图片
下载安装完成后,关闭VS的所有窗口,会自动应用更改,你只需要最后点击 “modify” 按钮确认即可。

注意: 再次打开VS有可能会出现下图错误,这时两种尝试方法:

  1. 打开VS_Community升级VS至最新版本。
  2. 卸载Qt VS Tools,重新安装,我是采用的第二种方案,解决了。
    VS+QT+SQLite实现简单的计算器_第9张图片

3.2 配置环境变量

之后配置环境变量,WIN+Q组合键打开搜索,键入 “编辑系统环境变量” ,选中打开:

VS+QT+SQLite实现简单的计算器_第10张图片
VS+QT+SQLite实现简单的计算器_第11张图片
在这里插入图片描述

3.3 特殊问题解决

打开VS,找到依次点击:扩展 -> Qt VS Tools -> Qt Options,VS会自动为你选中QT的msvc,如果不报错,配置完成。

注意:如果出现报错,信息显示如:The following error occured:These Qt version are inaccessible,那么需要以下操作:

VS+QT+SQLite实现简单的计算器_第12张图片
VS+QT+SQLite实现简单的计算器_第13张图片

重新打开 Qt Options,进行下面操作:
VS+QT+SQLite实现简单的计算器_第14张图片
删除原先的Qt Version,只保留我们新添加的,然后将其设为默认:
VS+QT+SQLite实现简单的计算器_第15张图片
不报错,就配置完成了。

4. 安装SQLite

4.1 下载SQLite

这里提供SQLite的组件下载地址,大家自行取用:SQLite下载
VS+QT+SQLite实现简单的计算器_第16张图片

4.2 安装SQLite

将两个压缩包放到合适的位置,分别解压即可。
VS+QT+SQLite实现简单的计算器_第17张图片
配置环境变量,仍旧是在Path里面,添加SQLite的路径:
VS+QT+SQLite实现简单的计算器_第18张图片

4.3 测试SQLite

按下 WIN+Q 组合键打开搜索,输出 “cmd” ,然后回车,打开命令行,输入sqlite3,回车:
VS+QT+SQLite实现简单的计算器_第19张图片

5. 创建和配置VS+QT的工程

5.1 创建VS工程

打开VS,点击创建新项目,找到 Qt Empty Application 项目,点击之后进入下一步:
VS+QT+SQLite实现简单的计算器_第20张图片

配置项目名称和位置大家自选就好了,如下:

VS+QT+SQLite实现简单的计算器_第21张图片
配置QT工程,一路默认就好了:
VS+QT+SQLite实现简单的计算器_第22张图片
VS+QT+SQLite实现简单的计算器_第23张图片

5.2 重定向目标工具集

现在编译程序会产生如下的报错,因为我们用的MSVC2017,版本落后,需要升级:
在这里插入图片描述
我们需要按照提示,重定向目标工具集,首先右击解决方案,找到重定向目标解决方案,单击即可:
VS+QT+SQLite实现简单的计算器_第24张图片
出现重定向项目窗口,确定即可:
VS+QT+SQLite实现简单的计算器_第25张图片
再次生成解决方案即可成功。

5.3 添加main函数

在Source Files里面添加main.cpp:
VS+QT+SQLite实现简单的计算器_第26张图片

输入以下代码:

//引入Qt窗口应用程序
#include 

int main(int argc, char* argv[]) {
	// 打开Qt应用环境
	QApplication a(argc, argv);
	// 结束Qt应用环境
	return a.exec();
}

这里只有Qt的基本应用环境的开启和关闭,没有生成任何界面。

5.3 配置QT模块

我们需要为项目添加QT的模块,否则连接会出错,如下:
在这里插入图片描述
首先右键单击项目,找到 属性,单击,进入属性配置界面:
VS+QT+SQLite实现简单的计算器_第27张图片

然后在属性配置界面进行如下操作,进入模块选择界面:

VS+QT+SQLite实现简单的计算器_第28张图片
选择 Core GUI SQL Widget 四个模块,点击Finish即可:
VS+QT+SQLite实现简单的计算器_第29张图片

VS+QT+SQLite实现简单的计算器_第30张图片
点击确定,再次编译运行,通过。

6. 搭建程序框架

6.1 建立计算器的QT类

右键单击项目,光标移到添加,点击Add Qt Class,如图:
VS+QT+SQLite实现简单的计算器_第31张图片
添加一个名为CalculatorMine的类,如下:
VS+QT+SQLite实现简单的计算器_第32张图片
配置类的属性:
VS+QT+SQLite实现简单的计算器_第33张图片

为构造函数添加默认参数 Q_NULLPTR,否则编译会报错:

VS+QT+SQLite实现简单的计算器_第34张图片
VS+QT+SQLite实现简单的计算器_第35张图片

6.2 在Main中实例化计算器类

我们已经有了计算器类,那么就可以在main函数中添加它的对象。在main中添加以下代码:

	// 创建一个计算器对象
	CalculatorMine calculatorMine;
	// 运行计算器对象的界面
	calculatorMine.show();

添加之后的main函数如下:

VS+QT+SQLite实现简单的计算器_第36张图片

运行程序,得到基本的窗口,效果如下:

VS+QT+SQLite实现简单的计算器_第37张图片

6.3 新建UI界面

在资源文件夹中添加UI界面,首先右击 Resource Files,光标移到 添加,单击 新建项,如下:

VS+QT+SQLite实现简单的计算器_第38张图片

然后根据提示进行配置:

VS+QT+SQLite实现简单的计算器_第39张图片
Qt设计师界面会自动打开,或者你双击Resource Files下的CalculatorMine.ui也可以打开,如下:
VS+QT+SQLite实现简单的计算器_第40张图片

6.4 编译UI界面

这个时候,你还查询不到ui界面的头文件,需要将ui文件编译之后得到,如下操作:

VS+QT+SQLite实现简单的计算器_第41张图片
编译完成之后,在外部依赖项中有可能可以找到 ui_CalculatorMine.h 文件,找不到没事,不影响。

6.5 更换窗体的名称和标题

QT默认的窗口名称和标题为mianWindow,我们可以改为自己想要的:

VS+QT+SQLite实现简单的计算器_第42张图片
重新编译CalculatorMine.ui文件。一般来说,UI界面的更改在VS中重新编译.ui文件即可生效,如果不行,重启VS即可。

6.6 建立计算器UI对象

有了UI类,我们就可以实例化计算器的UI了,在CalculatorMine.h中添加的代码如下:
VS+QT+SQLite实现简单的计算器_第43张图片

下一步我们需要初始化对象,并展示其UI。更改CalculatorMine.cpp文件:

VS+QT+SQLite实现简单的计算器_第44张图片

我们运行程序,可以看到效果:

VS+QT+SQLite实现简单的计算器_第45张图片

7. 设计UI界面

7.1 Qt设计师面板介绍

面板功能介绍如下:

VS+QT+SQLite实现简单的计算器_第46张图片

7.2 添加一个水平布局

鼠标左键点击Vertical Layout不放,将其拖放到UI界面效果栏中,如下:

VS+QT+SQLite实现简单的计算器_第47张图片

调整UI界面和水平布局,使其大小合适(调整方式就是拖动边缘),效果如下:

VS+QT+SQLite实现简单的计算器_第48张图片

7.3 添加Text Browser和水平布局

先添加一个Text Browser进入上一个水平布局中,可以看到其占据了所有的界面:

VS+QT+SQLite实现简单的计算器_第49张图片

我们应该调整其大小,令其占据空间合适,这时候就要用到属性编辑器,操作如下:

VS+QT+SQLite实现简单的计算器_第50张图片

以同样的方式编辑其显示字体的大小,把里面显示的字体调大一点,看着舒服:

VS+QT+SQLite实现简单的计算器_第51张图片

拖一个水平布局进去,效果如下:

VS+QT+SQLite实现简单的计算器_第52张图片

7.4 添加垂直布局和按钮

在第二个水平布局中拖入5个垂直布局,可以采用如下方式:

VS+QT+SQLite实现简单的计算器_第53张图片

在每个垂直布局中分别拖入4个按钮(Push Button),效果如下:

VS+QT+SQLite实现简单的计算器_第54张图片

然后我们修改按钮大小和按钮字体大小,ctrl+点击 逐个选中所有按钮,用属性编辑器:

VS+QT+SQLite实现简单的计算器_第55张图片

双击按钮可以编辑按钮的显示文字,编辑成如下的效果:

VS+QT+SQLite实现简单的计算器_第56张图片

VS编辑控件都需要其名称,为了方便使用,这里给所有的按钮都对应一个名字,双击其对象即可编辑,效果如下:

VS+QT+SQLite实现简单的计算器_第57张图片

7.5 添加菜单栏

添加菜单,双击 “在这里输入” ,然后输入 “设置” ,回车即可,如下:

VS+QT+SQLite实现简单的计算器_第58张图片
点击设置,双击 “在这里输入” ,然后输入 “查看历史” ,回车即可,如下:
在这里插入图片描述

重复添加 “关闭历史” ,“清除历史”。最终效果如下:

VS+QT+SQLite实现简单的计算器_第59张图片
**注意:**如果不能输入汉字,可以从其他地方复制过来。

下一步仍旧是修改对象名称,便于使用,修改后的结果如下:

VS+QT+SQLite实现简单的计算器_第60张图片

7.6 保存并运行

首先,使用Ctrl+S保存对界面的修改,整个界面就算设计完成了。

然后返回VS,编译CalculatorMine.ui。

最后编译运行项目,效果如下:

VS+QT+SQLite实现简单的计算器_第61张图片

8. 添加成员变量和函数框架

8.1 添加成员变量

这里首先为计算器类添加我们用到的成员变量,在CalculatorMine.h的类中添加如下代码:

private:
	// 添加一个计算器UI的实例,UI界面的命名空间为Ui
	Ui::CalculatorMineWindow* ui;

	// 定义数字按钮组(numButtonGroup)和操作符按钮组(operatorButtonGroup)。按钮组内的按钮都是相似的,可以共用一个槽函数
	QButtonGroup* numButtonGroup;
	QButtonGroup* operatorButtonGroup;

	// 定义存储操作符(operatorChar)和操作数(storedNum)以及运算结果(resultNum)的变量
	QChar operatorChar;
	double storedNum;
	double resultNum;

	// 定义标志位,isOperatorClicked标记是否已经点击了操作符,isStoredNum标记是否有一个已经存储了一个数字
	bool isOperatorClicked;
	bool isStoredNum;

	// 定义输入数字限制,输入数字的数量不能超过numLimit
	const int numLimit = 16;

注释应该比较清楚,添加进去的效果如下:

VS+QT+SQLite实现简单的计算器_第62张图片
在这里,我们用到了QButtonGroup这个类,所以需要将其头文件包括一下,输入以下代码:

#include 

在文件中的效果如下:

VS+QT+SQLite实现简单的计算器_第63张图片

之后我们需要在CalculatorMine.cpp中为成员变量作初始化,在CalculatorMine类的构造函数中添加以下代码:

	// 初始化存储变量和标志位变量
	isOperatorClicked = false;
	isStoredNum = false;
	storedNum = 0;
	resultNum = 0;

	// 初始化按钮组
	numButtonGroup = new QButtonGroup;
	operatorButtonGroup = new QButtonGroup;

	// 为数字按钮组添加按钮: 0 1 2 3 4 5 6 7 8 9
	numButtonGroup->addButton(ui->pushButton1, 1);
	numButtonGroup->addButton(ui->pushButton2, 2);
	numButtonGroup->addButton(ui->pushButton3, 3);
	numButtonGroup->addButton(ui->pushButton4, 4);
	numButtonGroup->addButton(ui->pushButton5, 5);
	numButtonGroup->addButton(ui->pushButton6, 6);
	numButtonGroup->addButton(ui->pushButton7, 7);
	numButtonGroup->addButton(ui->pushButton8, 8);
	numButtonGroup->addButton(ui->pushButton9, 9);
	numButtonGroup->addButton(ui->pushButton0, 0);

	// 为操作符按钮组添加按钮:+ - * / =
	operatorButtonGroup->addButton(ui->pushButtonAdd, 1);
	operatorButtonGroup->addButton(ui->pushButtonSub, 2);
	operatorButtonGroup->addButton(ui->pushButtonMul, 3);
	operatorButtonGroup->addButton(ui->pushButtonDiv, 4);
	operatorButtonGroup->addButton(ui->pushButtonEqual, 5);

注释是比较清楚的,其在VS中的效果如下:

在这里插入图片描述

8.2 添加成员函数框架

我们已经有了各种控件和所有需要的成员变量,下一步就是定义槽函数,执行按钮功能。

在CalculatorMine.h文件的CalculatorMine的类中添加以下代码:

// 定义一系列槽函数(与控件的信号连接),当点击计算器的某个键时,执行。
private slots:
	// 当数字按钮组中的某个键被点击时调用,用来更新textBrowser等。
	void NumButtonClicked(QAbstractButton*);
	// 当操作符按钮组中的某个键被点击时调用,用来更新textBrower和执行运算等。
	void OperatorButtonClicked(QAbstractButton*);

	// 当C按钮被点击时调用,用来清空textBrowser和各种变量。
	void PushButtonCClicked();
	// 当Del按钮被点击时调用,用来删除一个输入数字。
	void PushButtonDelClicked();
	// 当%按钮被点击时调用,用来将操作数除100。
	void PushButonPercentClicked();
	// 当+/-按钮被点击时调用,用来将操作数取负。
	void PushButtonReverseClicked();
	// 当=按钮被点击时调用,用来计算和显示结果。
	void PushButtonEqualClicked();
	// 当Point按钮被点击时调用,用来增加小数点。
	void PushButtonPointClicked();

	// 当查看历史被点击时调用,用来和数据库通信,获得历史记录并显示。
	void SearchHistory();
	// 用来清空历史显示
	void CloseHistory();
	// 用来清空数据库和显示。
	void ClearHistory();

private:
	// 用来执行运算(在操作符被点击时调用),并与数据库通信,存储数据
	void CalculateResult();

这里的注释也是比较清楚的,看一下在VS中的效果:

VS+QT+SQLite实现简单的计算器_第64张图片
函数声明之后再CalculatorMine.cpp中实现,在文件末尾添加以下代码:

void CalculatorMine::NumButtonClicked(QAbstractButton* numButton) {

}

void CalculatorMine::OperatorButtonClicked(QAbstractButton* operatorButton) {

}

void CalculatorMine::CalculateResult() {
	
}

void CalculatorMine::PushButtonCClicked() {

}

void CalculatorMine::PushButtonDelClicked() {

}

void CalculatorMine::PushButonPercentClicked() {

}

void CalculatorMine::PushButtonReverseClicked() {

}

void CalculatorMine::PushButtonEqualClicked() {

}

void CalculatorMine::PushButtonPointClicked() {

}

void CalculatorMine::SearchHistory() {

}

void CalculatorMine::CloseHistory() {

}

void CalculatorMine::ClearHistory() {

}

这不需要多说,就是一个函数实现的框架,在VS中的效果如下:

VS+QT+SQLite实现简单的计算器_第65张图片

最后,我们需要连接按钮信号和我们定义的槽函数,在Calculator类的构造函数中添加以下代码:

	// 连接按钮组和按钮组的槽函数
	numButtonGroup->connect(numButtonGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(NumButtonClicked(QAbstractButton*)));
	operatorButtonGroup->connect(operatorButtonGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(OperatorButtonClicked(QAbstractButton*)));
	
	// 连接普通按钮和他们对应的槽函数
	connect(ui->pushButtonC, SIGNAL(clicked()), this, SLOT(PushButtonCClicked()));
	connect(ui->pushButtonDel, SIGNAL(clicked()), this, SLOT(PushButtonDelClicked()));
	connect(ui->pushButtonPercent, SIGNAL(clicked()), this, SLOT(PushButonPercentClicked()));
	connect(ui->pushButtonReverse, SIGNAL(clicked()), this, SLOT(PushButtonReverseClicked()));
	connect(ui->pushButtonEqual, SIGNAL(clicked()), this, SLOT(PushButtonEqualClicked()));
	connect(ui->pushButtonPoint, SIGNAL(clicked()), this, SLOT(PushButtonPointClicked()));
	

	// 连接菜单项和他们对应的槽函数
	connect(ui->actionSearchHistory, SIGNAL(triggered()), this, SLOT(SearchHistory()));
	connect(ui->actionCloseHistory, SIGNAL(triggered()), this, SLOT(CloseHistory()));
	connect(ui->actionClearHistory, SIGNAL(triggered()), this, SLOT(ClearHistory()));

就是一个函数connect,用来连接信号和槽,VS中效果如下:

VS+QT+SQLite实现简单的计算器_第66张图片

9. 设置与数据库的连接

9.1 添加数据库头文件

这里用到了数据库的操作,因此要引入数据库的库。在CalculatorMine.h中添加以下代码:

#include 

在VS中的效果如下:

VS+QT+SQLite实现简单的计算器_第67张图片

9.2 配置与数据库的连接

下面开始操作数据库了,在CalculatorMine的构造函数中(连接菜单项代码之前)添加以下代码:

	// 设置与数据库的连接。 数据库的类型为“QSQLITE”,即SQLite; 连接的名称为“sqliteMine”(随意设置);
	// 连接数据库的主机地址为:127.0.0.1,即回环地址(自己);要操作的数据库名称为 “HistoryData.db”(随意设置);
	// 连接的用户为root用户,使用默认密码123456
	QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "sqliteMine");
	db.setHostName("127,0,0,1");
	db.setDatabaseName("HistoryData.db");
	db.setUserName("root");
	db.setPassword("123456");
	if (!db.open()) {
		ui->textBrowser->setText("can't open database");
	}

注释挺清楚的,代码在VS中的效果如下:

VS+QT+SQLite实现简单的计算器_第68张图片

10. 实现槽函数功能

所有的准备工作均已完成,下面我们就要实现按钮的功能了。

10.1 数字按钮组槽函数

我们点击一个数字按钮时,调用NumGroupClicked函数,因此在改函数中添加代码:

	// 用textShow接收显示器上的显示文本,用来执行判断等
	QString textShow = ui->textBrowser->toPlainText();
	// 如果上一个点击的是操作符按钮,那么就代表要输入第二个操作数了,此时清空显示,操作符标志置否。
	if (isOperatorClicked) {
		textShow.clear();
		isOperatorClicked = false;
	}
	// 如果输入的数字数量过多,那么就不能输入了,直接返回
	if (textShow.length() >= numLimit) {
		return;
	}
	// 为textShow追加按钮上的文本(0/1/2/3/4/5/6/7/8/9)
	textShow.append(numButton->text());
	// 将textShow的文本显示到计算器显示器上
	ui->textBrowser->setText(textShow);

代码注释比较清楚,在VS中显示其效果:

VS+QT+SQLite实现简单的计算器_第69张图片
我们运行程序,在计算器的按钮面板上点击数字按钮,发现会出现相应的数字:

VS+QT+SQLite实现简单的计算器_第70张图片

10.2 操作符按钮组槽函数

在OperatorButtonClicked函数中添加以下代码:

	// 如果上一个点击的也是操作符,那么替换掉,将操作符存储在operatorChar中。
	if (isOperatorClicked) {
		operatorChar = operatorButton->text().at(0);
	}
	else {
		// 如果已经存储的有数字,那么证明输入了两个数字,可以运算了,进行运算。
		if (isStoredNum) {
			CalculateResult();
		}
		else {
			// 如果没存数字,证明是第一次点击操作符,那么把显示屏上的数字存起来,这是第一个操作数
			QString textShow = ui->textBrowser->toPlainText();
			storedNum = textShow.toDouble();
			isStoredNum = true;
		}
		// 操作符标志位设置为真,存储操作符
		isOperatorClicked = true;
		operatorChar = operatorButton->text().at(0);
	}

注释挺清楚的,就不多解释了。

10.3 结果计算与存储函数

CalculateResult不是槽函数,是点击操作符需要调用的函数,添加如下代码:

	// 用textShow记录显示器界面的数字。
	QString textShow = ui->textBrowser->toPlainText();
	// 第一个操作数是存储的操作数,第二个操作时为显示屏上显示的数字。
	double previousNum = storedNum;
	double presentNum = textShow.toDouble();
	// 根据操作符(+/-/*/÷)的不同,对两个操作数执行不同的运算,存储到resultNum中。
	if (operatorChar == '+') {
		resultNum = previousNum + presentNum;
	}
	else if (operatorChar == '-') {
		resultNum = previousNum - presentNum;
	}
	else if (operatorChar == '*') {
		resultNum = previousNum * presentNum;
	}
	else if (operatorChar == '/') {
		resultNum = previousNum / presentNum;
	}
	// 计算的结果可以作为下一次计算的第一个操作数,便于连续运算。
	storedNum = resultNum;
	// 将数字转为QString类型的字符串,限制其串长度,赋值给texxtShow,显示在显示屏上。
	textShow = QString::number(resultNum, 'g', numLimit);
	ui->textBrowser->setText(textShow);
	
	// 使用连接 "sqliteMine" 连入数据库,这样就可以访问我们创建的数据库HistoryData了
	QSqlDatabase db = QSqlDatabase::database("sqliteMine");
	// 使用db初始化一个数据库操作的对象,用来对数据库进行管理
	QSqlQuery query(db);
	// 定义一个字符串,字符串内容是SQLite的命令,用于创建表。
	// CREATE TABLE IF NOT EXISTS :标准的SQL命令,意味着如果后面这个表名 history 不存在的话,那么创建一个新表。
	// history是表的名字,previousNum是第一个列的列名,double是第一列的数据类型。很清楚,一共四列。
	QString createTableString = "CREATE TABLE IF NOT EXISTS history(previousNum double, operator varchar, presentNum double, resultNum double)";
	// 执行创建表的命令,如果创建不成功,在显示器中进行提示。
	bool success = query.exec(createTableString);
	if (!success) {
		ui->textBrowser->setText("can't create table");
	}
	// 再次定义一个SQLite命令的字符串,用于插入一行数据。
	// INSERT INTO :标准的SQL命令,向后面的表 history 中插入数据。
	// (previousNum, operator, presentNum, resultNum) : 插入数据列的列名,可以用不一样的顺序,但是列名一定是表中的列。
	// VALUES('%1', '%2', '%3', '%4') : VALUES里面就是插入数据的值,这里的‘%1’等是占位符,真正的值是arg()里面的数据。
	QString insertDataString = QString("INSERT INTO history(previousNum, operator, presentNum, resultNum) VALUES('%1', '%2', '%3', '%4')").arg(previousNum).arg(operatorChar).arg(presentNum).arg(resultNum);
	// 执行插入命令,如果插入不成功,那么在显示器中进行提示。
	success = query.exec(insertDataString);
	if (!success) {
		ui->textBrowser->setText("can't insert data");
	}

注释清楚,不多解释。

10.4 单个键与菜单栏槽函数

剩下的槽函数更加简单,所以直接放代码了(都有注释):

void CalculatorMine::PushButtonCClicked() {
	// 清除显示器和俩标志位即可
	ui->textBrowser->clear();
	isOperatorClicked = false;
	isStoredNum = false;
}

void CalculatorMine::PushButtonDelClicked() {
	// 删除显示器上的最后一个数字后再显示
	QString textShow = ui->textBrowser->toPlainText();
	if (textShow.length() == 0) {
		return;
	}
	textShow.chop(1);
	ui->textBrowser->setText(textShow);
}

void CalculatorMine::PushButonPercentClicked() {
	// 把显示器上的数字除以100之后再显示
	QString textShow = ui->textBrowser->toPlainText();
	double percentResult = 0.01 * textShow.toDouble();
	textShow = QString::number(percentResult, 'g', numLimit);
	ui->textBrowser->setText(textShow);
}

void CalculatorMine::PushButtonReverseClicked() {
	// 把显示器上的数字取负之后再显示
	QString textShow = ui->textBrowser->toPlainText();
	double reverseResult = -1 * textShow.toDouble();
	textShow = QString::number(reverseResult, 'g', numLimit);
	ui->textBrowser->setText(textShow);
}

void CalculatorMine::PushButtonEqualClicked() {
	// 如果符合运算标准,执行运算操作,操作数标志位置假
	QString textShow = ui->textBrowser->toPlainText();
	if (!isStoredNum || textShow.length() == 0 || isOperatorClicked) {
		return;
	}
	CalculateResult();
	isStoredNum = false;
}

void CalculatorMine::PushButtonPointClicked() {
	// 如果显示器上已经有了小数点,直接返回
	QString textShow = ui->textBrowser->toPlainText();
	if (textShow.length() >= (numLimit - 1) || textShow.contains('.', Qt::CaseSensitive)) {
		return;
	}
	// 如果显示器没有数字,那么那么就是0-1之间的小数,先加入一个0
	if (textShow.length() == 0) {
		textShow = "0";
	}
	// 给显示器的末尾添加一个小数点
	textShow.append('.');
	ui->textBrowser->setText(textShow);
}

void CalculatorMine::SearchHistory() {
	// 我们获取的数据共有四个列,分别记录了第一个操作数、操作符、第二个操作数、计算结果。
	// 这里我们设置最多取200条运算记录,定义4个数组存储
	double previousNum[200];
	QString operatorChar[200];
	double presentNum[200];
	double resultNum[200];
	
	// 连接数据库,初始化数据库操作对象
	QSqlDatabase db = QSqlDatabase::database("sqliteMine");
	QSqlQuery query(db);
	// 定义一个SQL语句的字符串,用于获取数据库中所有的记录
	// SELECT * FROM: 标准的SQL命令,用于从后面的表 history 中查询所有的数据
	QString selectDataString = "SELECT * FROM history";
	// 执行查询语句,如果不成功,在显示屏上进行提示
	bool success = query.exec(selectDataString);
	if (!success) {
		ui->textBrowser->setText("can't get history data");
	}

	// 将获取的查询结果放入我们事先准备好的数组中。
	int index = 0;
	while (query.next()) {
		previousNum[index] = query.value(0).toDouble();
		operatorChar[index] = query.value(1).toString();
		presentNum[index] = query.value(2).toDouble();
		resultNum[index] = query.value(3).toDouble();
		index++;
	}
	// 将历史记录一条一条的插入到我们的显示器中,格式为 IDx:操作数1 操作符 操作数2 = 运算结果。
	ui->textBrowser->clear();
	for (int i = 0; i < index; i++) {
		QString historyString = QString("ID%1:  %2 %3 %4 = %5").arg(i + 1).arg(previousNum[i]).arg(operatorChar[i]).arg(presentNum[i]).arg(resultNum[i]);
		ui->textBrowser->append(historyString);
	}
}

void CalculatorMine::CloseHistory() {
	// 直接清空显示器就好了
	ui->textBrowser->clear();
}

void CalculatorMine::ClearHistory() {
	// 连接数据库,建立数据库操作对象
	QSqlDatabase db = QSqlDatabase::database("sqliteMine");
	QSqlQuery query(db);
	// 定义一个SQL语句的字符串,用来删除表。
	// DROP TABLE : 标准SQL语句,用于删除后面的表 history 。
	QString dropTableString = "DROP TABLE history";
	// 执行删除表的语句,如果未成功,在显示器上提醒。
	bool success = query.exec(dropTableString);
	if (!success) {
		ui->textBrowser->setText("can't clear history data");
	}
	else {
		ui->textBrowser->clear();
	}
}

不解释啦,注释好好看,肯定都看得懂,功能都是类似的。

10.5 完成效果展示

VS+QT+SQLite实现简单的计算器_第71张图片

11. 代码总结

11.1 文档版代码(纯代码)

main.cpp

#include 
#include "CalculatorMine.h"

int main(int argc, char* argv[]) {
	// 打开Qt应用环境
	QApplication a(argc, argv);
	// 创建一个计算器对象
	CalculatorMine calculatorMine;
	// 运行计算器对象的界面
	calculatorMine.show();
	// 结束Qt应用环境
	return a.exec();
}

CalculatorMine.h

#pragma once

#include 
#include 
#include 
#include "ui_CalculatorMine.h"

class CalculatorMine : public QMainWindow
{
	Q_OBJECT

public:
	CalculatorMine(QWidget *parent = Q_NULLPTR);
	~CalculatorMine();

// 定义一系列槽函数(与控件的信号连接),当点击计算器的某个键时,执行。
private slots:
	// 当数字按钮组中的某个键被点击时调用,用来更新textBrowser等。
	void NumButtonClicked(QAbstractButton*);
	// 当操作符按钮组中的某个键被点击时调用,用来更新textBrower和执行运算等。
	void OperatorButtonClicked(QAbstractButton*);

	// 当C按钮被点击时调用,用来清空textBrowser和各种变量。
	void PushButtonCClicked();
	// 当Del按钮被点击时调用,用来删除一个输入数字。
	void PushButtonDelClicked();
	// 当%按钮被点击时调用,用来将操作数除100。
	void PushButonPercentClicked();
	// 当+/-按钮被点击时调用,用来将操作数取负。
	void PushButtonReverseClicked();
	// 当=按钮被点击时调用,用来计算和显示结果。
	void PushButtonEqualClicked();
	// 当Point按钮被点击时调用,用来增加小数点。
	void PushButtonPointClicked();

	// 当查看历史被点击时调用,用来和数据库通信,获得历史记录并显示。
	void SearchHistory();
	// 用来清空历史显示
	void CloseHistory();
	// 用来清空数据库和显示。
	void ClearHistory();

private:
	// 用来执行运算(在操作符被点击时调用),并与数据库通信,存储数据
	void CalculateResult();

private:
	// 添加一个计算器UI的实例,UI界面的命名空间为Ui
	Ui::CalculatorMineWindow* ui;

	// 定义数字按钮组(numButtonGroup)和操作符按钮组(operatorButtonGroup)。按钮组内的按钮都是相似的,可以共用一个槽函数
	QButtonGroup* numButtonGroup;
	QButtonGroup* operatorButtonGroup;

	// 定义存储操作符(operatorChar)和操作数(storedNum)以及运算结果(resultNum)的变量
	QChar operatorChar;
	double storedNum;
	double resultNum;

	// 定义标志位,isOperatorClicked标记是否已经点击了操作符,isStoredNum标记是否有一个已经存储了一个数字
	bool isOperatorClicked;
	bool isStoredNum;

	// 定义输入数字限制,输入数字的数量不能超过numLimit
	const int numLimit = 16;
};

CalculatorMine.cpp

#include "CalculatorMine.h"

CalculatorMine::CalculatorMine(QWidget *parent)
	: QMainWindow(parent),
	ui(new Ui::CalculatorMineWindow)
{
	// 启动我们的ui界面
	ui->setupUi(this);

	// 初始化存储变量和标志位变量
	isOperatorClicked = false;
	isStoredNum = false;
	storedNum = 0;
	resultNum = 0;

	// 初始化按钮组
	numButtonGroup = new QButtonGroup;
	operatorButtonGroup = new QButtonGroup;

	// 为数字按钮组添加按钮: 0 1 2 3 4 5 6 7 8 9
	numButtonGroup->addButton(ui->pushButton1, 1);
	numButtonGroup->addButton(ui->pushButton2, 2);
	numButtonGroup->addButton(ui->pushButton3, 3);
	numButtonGroup->addButton(ui->pushButton4, 4);
	numButtonGroup->addButton(ui->pushButton5, 5);
	numButtonGroup->addButton(ui->pushButton6, 6);
	numButtonGroup->addButton(ui->pushButton7, 7);
	numButtonGroup->addButton(ui->pushButton8, 8);
	numButtonGroup->addButton(ui->pushButton9, 9);
	numButtonGroup->addButton(ui->pushButton0, 0);

	// 为操作符按钮组添加按钮:+ - * / =
	operatorButtonGroup->addButton(ui->pushButtonAdd, 1);
	operatorButtonGroup->addButton(ui->pushButtonSub, 2);
	operatorButtonGroup->addButton(ui->pushButtonMul, 3);
	operatorButtonGroup->addButton(ui->pushButtonDiv, 4);
	operatorButtonGroup->addButton(ui->pushButtonEqual, 5);

	// 连接按钮组和按钮组的槽函数
	numButtonGroup->connect(numButtonGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(NumButtonClicked(QAbstractButton*)));
	operatorButtonGroup->connect(operatorButtonGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(OperatorButtonClicked(QAbstractButton*)));
	
	// 连接普通按钮和他们对应的槽函数
	connect(ui->pushButtonC, SIGNAL(clicked()), this, SLOT(PushButtonCClicked()));
	connect(ui->pushButtonDel, SIGNAL(clicked()), this, SLOT(PushButtonDelClicked()));
	connect(ui->pushButtonPercent, SIGNAL(clicked()), this, SLOT(PushButonPercentClicked()));
	connect(ui->pushButtonReverse, SIGNAL(clicked()), this, SLOT(PushButtonReverseClicked()));
	connect(ui->pushButtonEqual, SIGNAL(clicked()), this, SLOT(PushButtonEqualClicked()));
	connect(ui->pushButtonPoint, SIGNAL(clicked()), this, SLOT(PushButtonPointClicked()));
	
	// 设置与数据库的连接。 数据库的类型为“QSQLITE”,即SQLite; 连接的名称为“sqliteMine”(随意设置);
	// 连接数据库的主机地址为:127.0.0.1,即回环地址(自己);要操作的数据库名称为 “HistoryData.db”(随意设置);
	// 连接的用户为root用户,使用默认密码123456
	QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "sqliteMine");
	db.setHostName("127,0,0,1");
	db.setDatabaseName("HistoryData.db");
	db.setUserName("root");
	db.setPassword("123456");
	if (!db.open()) {
		ui->textBrowser->setText("can't open database");
	}

	// 连接菜单项和他们对应的槽函数
	connect(ui->actionSearchHistory, SIGNAL(triggered()), this, SLOT(SearchHistory()));
	connect(ui->actionCloseHistory, SIGNAL(triggered()), this, SLOT(CloseHistory()));
	connect(ui->actionClearHistory, SIGNAL(triggered()), this, SLOT(ClearHistory()));
}

CalculatorMine::~CalculatorMine()
{
}

void CalculatorMine::NumButtonClicked(QAbstractButton* numButton) {
	// 用textShow接收显示器上的显示文本,用来执行判断等
	QString textShow = ui->textBrowser->toPlainText();
	// 如果上一个点击的是操作符按钮,那么就代表要输入第二个操作数了,此时清空显示,操作符标志置否。
	if (isOperatorClicked) {
		textShow.clear();
		isOperatorClicked = false;
	}
	// 如果输入的数字数量过多,那么就不能输入了,直接返回
	if (textShow.length() >= numLimit) {
		return;
	}
	// 为textShow追加按钮上的文本(0/1/2/3/4/5/6/7/8/9)
	textShow.append(numButton->text());
	// 将textShow的文本显示到计算器显示器上
	ui->textBrowser->setText(textShow);
}

void CalculatorMine::OperatorButtonClicked(QAbstractButton* operatorButton) {
	// 如果上一个点击的也是操作符,那么替换掉,将操作符存储在operatorChar中。
	if (isOperatorClicked) {
		operatorChar = operatorButton->text().at(0);
	}
	else {
		// 如果已经存储的有数字,那么证明输入了两个数字,可以运算了,进行运算。
		if (isStoredNum) {
			CalculateResult();
		}
		else {
			// 如果没存数字,证明是第一次点击操作符,那么把显示屏上的数字存起来,这是第一个操作数
			QString textShow = ui->textBrowser->toPlainText();
			storedNum = textShow.toDouble();
			isStoredNum = true;
		}
		// 操作符标志位设置为真,存储操作符
		isOperatorClicked = true;
		operatorChar = operatorButton->text().at(0);
	}
}

void CalculatorMine::CalculateResult() {
	// 用textShow记录显示器界面的数字。
	QString textShow = ui->textBrowser->toPlainText();
	// 第一个操作数是存储的操作数,第二个操作时为显示屏上显示的数字。
	double previousNum = storedNum;
	double presentNum = textShow.toDouble();
	// 根据操作符(+/-/*/÷)的不同,对两个操作数执行不同的运算,存储到resultNum中。
	if (operatorChar == '+') {
		resultNum = previousNum + presentNum;
	}
	else if (operatorChar == '-') {
		resultNum = previousNum - presentNum;
	}
	else if (operatorChar == '*') {
		resultNum = previousNum * presentNum;
	}
	else if (operatorChar == '/') {
		resultNum = previousNum / presentNum;
	}
	// 计算的结果可以作为下一次计算的第一个操作数,便于连续运算。
	storedNum = resultNum;
	// 将数字转为QString类型的字符串,限制其串长度,赋值给texxtShow,显示在显示屏上。
	textShow = QString::number(resultNum, 'g', numLimit);
	ui->textBrowser->setText(textShow);
	
	// 使用连接 "sqliteMine" 连入数据库,这样就可以访问我们创建的数据库HistoryData了
	QSqlDatabase db = QSqlDatabase::database("sqliteMine");
	// 使用db初始化一个数据库操作的对象,用来对数据库进行管理
	QSqlQuery query(db);
	// 定义一个字符串,字符串内容是SQLite的命令,用于创建表。
	// CREATE TABLE IF NOT EXISTS :标准的SQL命令,意味着如果后面这个表名 history 不存在的话,那么创建一个新表。
	// history是表的名字,previousNum是第一个列的列名,double是第一列的数据类型。很清楚,一共四列。
	QString createTableString = "CREATE TABLE IF NOT EXISTS history(previousNum double, operator varchar, presentNum double, resultNum double)";
	// 执行创建表的命令,如果创建不成功,在显示器中进行提示。
	bool success = query.exec(createTableString);
	if (!success) {
		ui->textBrowser->setText("can't create table");
	}
	// 再次定义一个SQLite命令的字符串,用于插入一行数据。
	// INSERT INTO :标准的SQL命令,向后面的表 history 中插入数据。
	// (previousNum, operator, presentNum, resultNum) : 插入数据列的列名,可以用不一样的顺序,但是列名一定是表中的列。
	// VALUES('%1', '%2', '%3', '%4') : VALUES里面就是插入数据的值,这里的‘%1’等是占位符,真正的值是arg()里面的数据。
	QString insertDataString = QString("INSERT INTO history(previousNum, operator, presentNum, resultNum) VALUES('%1', '%2', '%3', '%4')").arg(previousNum).arg(operatorChar).arg(presentNum).arg(resultNum);
	// 执行插入命令,如果插入不成功,那么在显示器中进行提示。
	success = query.exec(insertDataString);
	if (!success) {
		ui->textBrowser->setText("can't insert data");
	}
}

void CalculatorMine::PushButtonCClicked() {
	// 清除显示器和俩标志位即可
	ui->textBrowser->clear();
	isOperatorClicked = false;
	isStoredNum = false;
}

void CalculatorMine::PushButtonDelClicked() {
	// 删除显示器上的最后一个数字后再显示
	QString textShow = ui->textBrowser->toPlainText();
	if (textShow.length() == 0) {
		return;
	}
	textShow.chop(1);
	ui->textBrowser->setText(textShow);
}

void CalculatorMine::PushButonPercentClicked() {
	// 把显示器上的数字除以100之后再显示
	QString textShow = ui->textBrowser->toPlainText();
	double percentResult = 0.01 * textShow.toDouble();
	textShow = QString::number(percentResult, 'g', numLimit);
	ui->textBrowser->setText(textShow);
}

void CalculatorMine::PushButtonReverseClicked() {
	// 把显示器上的数字取负之后再显示
	QString textShow = ui->textBrowser->toPlainText();
	double reverseResult = -1 * textShow.toDouble();
	textShow = QString::number(reverseResult, 'g', numLimit);
	ui->textBrowser->setText(textShow);
}

void CalculatorMine::PushButtonEqualClicked() {
	// 如果符合运算标准,执行运算操作,操作数标志位置假
	QString textShow = ui->textBrowser->toPlainText();
	if (!isStoredNum || textShow.length() == 0 || isOperatorClicked) {
		return;
	}
	CalculateResult();
	isStoredNum = false;
}

void CalculatorMine::PushButtonPointClicked() {
	// 如果显示器上已经有了小数点,直接返回
	QString textShow = ui->textBrowser->toPlainText();
	if (textShow.length() >= (numLimit - 1) || textShow.contains('.', Qt::CaseSensitive)) {
		return;
	}
	// 如果显示器没有数字,那么那么就是0-1之间的小数,先加入一个0
	if (textShow.length() == 0) {
		textShow = "0";
	}
	// 给显示器的末尾添加一个小数点
	textShow.append('.');
	ui->textBrowser->setText(textShow);
}

void CalculatorMine::SearchHistory() {
	// 我们获取的数据共有四个列,分别记录了第一个操作数、操作符、第二个操作数、计算结果。
	// 这里我们设置最多取200条运算记录,定义4个数组存储
	double previousNum[200];
	QString operatorChar[200];
	double presentNum[200];
	double resultNum[200];
	
	// 连接数据库,初始化数据库操作对象
	QSqlDatabase db = QSqlDatabase::database("sqliteMine");
	QSqlQuery query(db);
	// 定义一个SQL语句的字符串,用于获取数据库中所有的记录
	// SELECT * FROM: 标准的SQL命令,用于从后面的表 history 中查询所有的数据
	QString selectDataString = "SELECT * FROM history";
	// 执行查询语句,如果不成功,在显示屏上进行提示
	bool success = query.exec(selectDataString);
	if (!success) {
		ui->textBrowser->setText("can't get history data");
	}

	// 将获取的查询结果放入我们事先准备好的数组中。
	int index = 0;
	while (query.next()) {
		previousNum[index] = query.value(0).toDouble();
		operatorChar[index] = query.value(1).toString();
		presentNum[index] = query.value(2).toDouble();
		resultNum[index] = query.value(3).toDouble();
		index++;
	}
	// 将历史记录一条一条的插入到我们的显示器中,格式为 IDx:操作数1 操作符 操作数2 = 运算结果。
	ui->textBrowser->clear();
	for (int i = 0; i < index; i++) {
		QString historyString = QString("ID%1:  %2 %3 %4 = %5").arg(i + 1).arg(previousNum[i]).arg(operatorChar[i]).arg(presentNum[i]).arg(resultNum[i]);
		ui->textBrowser->append(historyString);
	}
}

void CalculatorMine::CloseHistory() {
	// 直接清空显示器就好了
	ui->textBrowser->clear();
}

void CalculatorMine::ClearHistory() {
	// 连接数据库,建立数据库操作对象
	QSqlDatabase db = QSqlDatabase::database("sqliteMine");
	QSqlQuery query(db);
	// 定义一个SQL语句的字符串,用来删除表。
	// DROP TABLE : 标准SQL语句,用于删除后面的表 history 。
	QString dropTableString = "DROP TABLE history";
	// 执行删除表的语句,如果未成功,在显示器上提醒。
	bool success = query.exec(dropTableString);
	if (!success) {
		ui->textBrowser->setText("can't clear history data");
	}
	else {
		ui->textBrowser->clear();
	}
}

ui_CalculatorMine.h 这个是自动生成的文件,放出来也没啥用,截图给大家认识以下:

VS+QT+SQLite实现简单的计算器_第72张图片

11.2 整个工程(百度网盘)

我把编译产生的附加文件删了之后,整个工程只有10k,配置好环境后就可以直接运行,下面是资源:

链接: CalculatorMine.zip

提取码:qt6j

12. 多多点赞关注,常交流!

你可能感兴趣的:(C++代码,sqlite3,计算器,VS,QT)