QT上位机开发(会员管理软件)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        前面我们学习了ini文件的解析办法,通过QSettings类就可以很轻松地访问ini文件里面的数据。除了ini文件之外,另外一种经常出现的文件格式其实是json格式。一般来说,如果读写的数据不是很多,那么完全可以用json文件替换成数据库,实现数据的保存和加载工作。今天,我们通过编写一个会员管理软件的办法,正好学习下qt下面如何进行json数据的处理。当然,还可以借助这个小项目,多了解一下qt下面不同控件的用法和写法。

1、设计界面

        如果界面上的控件比较少,可以直接用c++语言编写,没有问题。但是如果控件比较多的话,那么建议还是用designer来进行设计。本次编写的会员管理软件,控件的数量稍微有点多,正好可以借这个机会把designer练一练。

        练习的过程当中,我们也发现,部分控件存在着排列层次的关系。比如左侧的operation,如果是后面加上去的,没有把它放到单选框、标签、输入框的最下面,那么生成窗口之后,其实不管是radioButton、还是textBox,都是没有办法进行输入的。这一点可能需要稍微注意下。另外,整个界面是删除菜单栏、工具栏和状态栏的。

2、QtWidgetsApplication.h头文件

        头文件中需要注意的部分,主要就是各个控件的回调函数。这里面有radioButton的回调函数、按钮的回调函数。其中radioButton虽然是4个,但是可以看成是一组,这样可以少写3个回调函数,编写上面比较方便一点。当然,除了界面之外,关联的业务数据也要根据实际情况及时添加上。

#pragma once

#include <string>
#include <vector>
using namespace std;

#include <QtWidgets/QMainWindow>
#include "ui_QtWidgetsApplication.h"

class QtWidgetsApplication : public QMainWindow
{
    Q_OBJECT

public:
    QtWidgetsApplication(QWidget *parent = nullptr);
    ~QtWidgetsApplication();

private:
    Ui::QtWidgetsApplicationClass ui;
	int mode_;
	int max_number_;
	vector<int> id_array_;
	vector<string> name_array_;

private:
	int findDataById(int id);
	void updateData();
	void loadFile();

private:
	void onRadioButtonToggled(bool checked);
	void onOkClicked();
	void onCancelClicked();
	void onSaveClicked();

};

3、QtWidgetsApplication.cpp文件设计

        到目前为止,这个cpp文件算得上是目前qt项目代码行数最多的文件,主要也是因为功能要求比较多。首先,它包含了基本的构造函数和析构函数。构造函数里面最主要的部分,就是把控件和它的回调函数关联在一起。其次,代码中涉及到json数据的加载和保存。和c# wpf不同,qt本身有相关的类来处理这些数据。最后,就是业务逻辑。业务逻辑一般比较复杂、麻烦一点,编写之前最好想清楚,比如插入数据的时候是不是需要检查一下是不是有同名id,删除的时候是不是考虑存在找不到的情况。crud的处理方式虽然比较简单,但是涉及到业务层面,还是要想清楚、搞明白,中间出错都没有关系,但是可以通过这个crud来提高自己的业务分析能力,也是不错的一种方式。

        另外,因为测试的时候涉及到了data.json文件,这部分大家可以先参考这个模板。将来使用的话,可以在这个模板之上进一步去拓展和延申,

{
    "count": 6,
    "items": [
        {
            "ID": 1,
            "NAME": "abcde"
        },
        {
            "ID": 2,
            "NAME": "bbb"
        },
        {
            "ID": 3,
            "NAME": "ccc"
        },
        {
            "ID": 5,
            "NAME": "ddd"
        },
        {
            "ID": 6,
            "NAME": "eee"
        },
        {
            "ID": 4,
            "NAME": "fff"
        }
    ]
}

        和ini文件一样,这个json文件也需要保存在h文件、cpp文件目录下面。最后,还是给出完整的cpp代码,虽然内容多了一点,但还是比较有借鉴意义的,可以耐心地去看一看、分析下。

#include <QDebug>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QJsonArray>
#include <QMessageBox>
#include "QtWidgetsApplication.h"

QtWidgetsApplication::QtWidgetsApplication(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

	mode_ = 1; // add
	max_number_ = 100; // maximum number is 100
	ui.radioButton1->setChecked(true); // first radio button is checked right now

	loadFile(); // load data from json file

	connect(ui.radioButton1, &QRadioButton::toggled, this, &QtWidgetsApplication::onRadioButtonToggled);
	connect(ui.radioButton2, &QRadioButton::toggled, this, &QtWidgetsApplication::onRadioButtonToggled);
	connect(ui.radioButton3, &QRadioButton::toggled, this, &QtWidgetsApplication::onRadioButtonToggled);
	connect(ui.radioButton4, &QRadioButton::toggled, this, &QtWidgetsApplication::onRadioButtonToggled);

	connect(ui.pushButton1, &QPushButton::clicked, this, &QtWidgetsApplication::onOkClicked);
	connect(ui.pushButton2, &QPushButton::clicked, this, &QtWidgetsApplication::onCancelClicked);
	connect(ui.pushButton3, &QPushButton::clicked, this, &QtWidgetsApplication::onSaveClicked);

	updateData();
}


QtWidgetsApplication::~QtWidgetsApplication()
{}

void QtWidgetsApplication::onRadioButtonToggled(bool checked) 
{
	if (checked) 
	{
		if (sender() == ui.radioButton1)
		{
			mode_ = 1;
			ui.lineEdit2->setEnabled(true);
		}
		else if (sender() == ui.radioButton2)
		{
			mode_ = 2;
			ui.lineEdit2->setEnabled(false);
		}
		else if (sender() == ui.radioButton3)
		{
			mode_ = 3;
			ui.lineEdit2->setEnabled(true);
		}
		else if (sender() == ui.radioButton4)
		{
			mode_ = 4;
			ui.lineEdit2->setEnabled(false);
		}
		else
		{
			qDebug() << "Unknown option was selected";
		}
	}
}

void QtWidgetsApplication::onOkClicked()
{
	int id;
	string name;
	int pos;
	bool conversionOK;

	switch (mode_)
	{
	case 1: //add
		if (ui.lineEdit1->text() == "")
		{
			QMessageBox::information(nullptr, "Tips", "Id is empty!");
			return;
		}

		if (ui.lineEdit2->text() == "")
		{
			QMessageBox::information(nullptr, "Tips", "Name is empty!");
			return;
		}

		if (id_array_.size() >= max_number_)
		{
			QMessageBox::information(nullptr, "Tips", "Buffer is full!");
			return;
		}

		id = ui.lineEdit1->text().toInt(&conversionOK);
		if (findDataById(id) != -1)
		{
			QMessageBox::information(nullptr, "Tips", "Id already existed!");
			return;
		}
		name = ui.lineEdit2->text().toStdString();
		
		id_array_.push_back(id);
		name_array_.push_back(name);

		QMessageBox::information(nullptr, "Tips", "Successfully add data!");
		updateData();

		ui.lineEdit1->setText("");
		ui.lineEdit2->setText("");
		break;

	case 2://del
		if (ui.lineEdit1->text() == "")
		{
			QMessageBox::information(nullptr, "Tips", "Id is empty!");
			return;
		}

		id = ui.lineEdit1->text().toInt(&conversionOK);
		pos = findDataById(id);
		if(pos == -1)
		{
			QMessageBox::information(nullptr, "Tips", "Specified Id does not existed!");
			return;
		}

		id_array_.erase(id_array_.begin() + pos);
		name_array_.erase(name_array_.begin() + pos);

		QMessageBox::information(nullptr, "Tips", "Successfully del data!");
		updateData();

		ui.lineEdit1->setText("");
		ui.lineEdit2->setText("");
		break;

	case 3:// update
		if (ui.lineEdit1->text() == "")
		{
			QMessageBox::information(nullptr, "Tips", "Id is empty!");
			return;
		}

		if (ui.lineEdit2->text() == "")
		{
			QMessageBox::information(nullptr, "Tips", "Name is empty!");
			return;
		}

		id = ui.lineEdit1->text().toInt(&conversionOK);
	    pos = findDataById(id);
		if(pos == -1)
		{
			QMessageBox::information(nullptr, "Tips", "Specified Id does not existed!");
			return;
		}

		name = ui.lineEdit2->text().toStdString();
		name_array_[pos] = name;

		QMessageBox::information(nullptr, "Tips", "Successfully update data!");
		updateData();

		ui.lineEdit1->setText("");
		ui.lineEdit2->setText("");
		break;

	case 4: // search
		if (ui.lineEdit1->text() == "")
		{
			QMessageBox::information(nullptr, "Tips", "Id is empty!");
			return;
		}

		id = ui.lineEdit1->text().toInt(&conversionOK);
		pos = findDataById(id);
		if (pos == -1)
		{
			QMessageBox::information(nullptr, "Tips", "Specified Id does not existed!");
			return;
		}

		name = name_array_[pos];
		ui.lineEdit1->setText("");
		ui.lineEdit2->setText("");

		QMessageBox::information(nullptr, "Tips", QString::fromStdString(string("Name is ") + name + string("!")));
		break;

	default:
		break;
	}
}


void QtWidgetsApplication::onCancelClicked()
{
	this->close();
}

void QtWidgetsApplication::onSaveClicked()
{
	QJsonArray itemsArray;

	// save data to itemsArray
	for (int i = 0; i < id_array_.size(); i++) {
		QJsonObject itemObject;
		itemObject["ID"] = id_array_[i];
		itemObject["NAME"] = QString::fromStdString(name_array_[i]);
		itemsArray.append(itemObject);
	}

	// create jsonObject
	QJsonObject jsonObject;
	jsonObject["count"] = itemsArray.size();
	jsonObject["items"] = itemsArray;

	// transfer to jsonDocuent
	QJsonDocument jsonDocument(jsonObject);

	// save to json file
	QFile file("data.json");
	if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
		file.write(jsonDocument.toJson());
		file.close();
		QMessageBox::information(nullptr, "Tips", "Successfully save the json file!");
	}
	else {
		qDebug() << "Failed to save JSON file";
	}
}


void QtWidgetsApplication::loadFile()
{
	QFile file("data.json");
	if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
		qDebug() << "Failed to open JSON file";
		return;
	}

	QByteArray jsonData = file.readAll();
	file.close();

	QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonData);
	if (jsonDocument.isNull()) {
		qDebug() << "Failed to create JSON document";
		return;
	}

	QJsonObject jsonObject = jsonDocument.object();
	int num = jsonObject["count"].toInt();

	// get items
	QJsonArray itemsArray = jsonObject["items"].toArray();

	// read data from items
	for (int i = 0; i < itemsArray.size(); ++i) {
		QJsonValue itemValue = itemsArray.at(i);
		if (itemValue.isObject()) {
			QJsonObject itemObject = itemValue.toObject();

			// read data
			int id = itemObject["ID"].toInt();
			QString name = itemObject["NAME"].toString();

			id_array_.push_back(id);
			name_array_.push_back(name.toStdString());
		}
	}
}

int QtWidgetsApplication::findDataById(int id)
{
	int i;

	for (i = 0; i < id_array_.size(); i++)
	{
		if (id_array_[i] == id)
		{
			return i;
		}
	}

	return -1;
}

void QtWidgetsApplication::updateData()
{
	string s = "";
	int i;

	for (i = 0; i < id_array_.size(); i++)
	{
		s += std::to_string(id_array_[i]);
		s += " ";
		s += name_array_[i];
		s += "\n";
	}

	ui.textEdit1->setPlainText("");
	ui.textEdit1->setPlainText(QString::fromStdString(s));

}

4、测试和验证

        相比较而言,测试和验证就容易得多。首先,加载的时候,看看json数据有没有全部加载到界界面里面。其次,看下增删改查的功能是否正常。如果一切都没有问题,那就基本ok了。有问题的话,单步去调试即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/287200.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

什么是数据销毁,为什么数据销毁很重要

当大多数人听到“数据破坏”时&#xff0c;他们的脸上都会表现出恐惧的表情。世界上大多数人最不想要的就是销毁他们计算机或移动设备上的数据。但现实情况是&#xff0c;无论您是大型、中型还是小型企业的所有者&#xff0c;总有一天您需要移除或更换旧媒体&#xff0c;并且您…

SpringBoot学习(二)-SpringBoot Web 开发

注&#xff1a;此为笔者学习狂神说SpringBoot的笔记&#xff0c;其中包含个人的笔记和理解&#xff0c;仅做学习笔记之用&#xff0c;更多详细资讯请出门左拐B站&#xff1a;狂神说!!! SpringBoot Web 开发 1、静态资源 1&#xff09;创建项目 2&#xff09;做项目都先测试一…

[每周一更]-(第52期):Go的函数式编程

参考地址 https://hedzr.com/golang/fp/golang-functional-programming-in-brief/https://silverrainz.me/blog/funtional-programming-in-go-generics.htmlhttps://zhuanlan.zhihu.com/p/436468481 函数式编程&#xff08;Functional Programming / FP&#xff09;作为一种编…

解决实用编程题目:单词拆分和分割等和子集--动态规划方式深度呈现

139. 单词拆分 题目描述 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 注意&#xff1a;不要求字典中出现的单词全部都使用&#xff0c;并且字典中的单词可以重复使用。 示例 1&#xff1a; 输入: s "lee…

OpenCV图像处理——C++实现亚像素尺寸标定板边缘轮廓提取

前言 标定模板&#xff08;Calibration Target&#xff09;在机器视觉、图像测量、摄影测量以及三维重建等应用中起着重要的作用。它被用于校正相机的畸变&#xff0c;确定物理尺寸和像素之间的换算关系&#xff0c;并建立相机成像的几何模型。通过使用相机拍摄带有固定间距图…

JavaScript中的数据缓存与内存泄露:解密前端性能优化与代码健康

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;JavaScript篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来JavaScript篇专栏内容:JavaScript-数据缓存与内存泄露 目录 说说你对事件循环的理解 一、是什么 二、宏…

Linux操作系统基础(7):Linux的文件路径

1. Linux文件路径的介绍 在Linux系统中&#xff0c;文件路径是用来定位文件或目录在文件系统中位置的一种表示方法&#xff0c;它能够帮助用户快速、准确地定位文件或目录&#xff0c;并进行相应的操作。 文件路径可以分为 绝对路径 和 相对路径 两种类型&#xff1a; 绝对路…

H266/VVC熵编码技术概述

熵编码 熵编码&#xff1a; 是指按信息熵原理进行的无损编码方式&#xff0c;无损熵编码也是有损视频编码中的一个关键模块&#xff0c;它处于视频压缩系统的最末端。熵编码把一列系用来表示视频序列的元素符号转变为一个用来传输或存储的压缩码流&#xff0c;输入的符号可能包…

提高开发效率的必备!超实用的VSCode插件推荐

前言 作为一个前端程序猿&#xff0c;我经常使用 VSCode 代码编辑器&#xff0c;但是每个开发者都有自己独特的工作风格和偏好。为了满足不同开发者的需求&#xff0c;VSCode 提供了丰富的插件生态系统。在本文中&#xff0c;我将为大家推荐一些强大的 VSCode 插件&#xff0c;…

Linux学习之系统编程3(进程及wait函数)

写在前面&#xff1a; 我的Linux的学习之路非常坎坷。第一次学习Linux是在大一下的开学没多久&#xff0c;结果因为不会安装VMware就无疾而终了&#xff0c;可以说是没开始就失败了。第二次学习Linux是在大一下快放暑假&#xff08;那个时候刚刚过完考试周&#xff09;&#xf…

SpringFrameWork

SpringFrameWork简介 介绍springFrameWork框架 Spring Framework是一个为企业级应用程序开发提供全面基础设施支持的开源框架&#xff0c;通过集成IoC、DI和AOP等技术&#xff0c;使得应用程序的开发更加灵活、可维护和可扩展。Spring MVC、SpringBoot、Spring Cloud、Spring D…

java实现大文件分片上传

背景&#xff1a; 公司后台管理系统有个需求&#xff0c;需要上传体积比较大的文件&#xff1a;500M&#xff0d;1024M&#xff1b;此时普通的文件上传显然有些吃力了&#xff0c;加上我司服务器配置本就不高&#xff0c;带宽也不大&#xff0c;所以必须考虑多线程异步上传来提…

数据结构与算法python版本之线性结构之队列Quene

什么是队列&#xff1f; 队列是一种有次序的数据集合&#xff0c;其特征是&#xff1a;新数据项的添加总发生在一端&#xff08;通常称为“尾rear”端&#xff09;&#xff0c;而现存数据项的移除总发生在另一端&#xff08;通常称为“首front”端&#xff09;&#xff1b;当数…

缓存数据一致性策略如何分类?

一、概述 数据库与缓存数据一致性问题&#xff0c;一直以来都是大家比较关注的问题。针对一致性的解决方案也是非常多&#xff0c;以下主要针对方案的梳理与分类&#xff1a; 数据库数据与缓存数据一致性的方案&#xff0c;可以从不同的角度来分类&#xff0c;比如&#xff1…

稳定币记录

稳定币&#xff1a; 稳定币&#xff08;Stablecoin&#xff09;是一种加密货币&#xff0c;其设计目的是维持相对稳定的价值&#xff0c;通常与某种法定货币&#xff08;如美元、欧元&#xff09;或其他资产&#xff08;如黄金&#xff09;挂钩。稳定币通过将加密货币与相应的…

Flink-【时间语义、窗口、水位线】

1. 时间语义 1.1 事件时间&#xff1a;数据产生的事件&#xff08;机器时间&#xff09;&#xff1b; 1.2 处理时间&#xff1a;数据处理的时间&#xff08;系统时间&#xff09;。 &#x1f330;&#xff1a;可乐 可乐的生产日期 事件时间&#xff08;可乐产生的时间&…

计算机毕业设计 SpringBoot的停车场管理系统 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

逻辑回归算法到底能做什么

逻辑回归&#xff08;Logistic Regression&#xff09;是一种广义的线性回归分析模型&#xff0c;常用于数据挖掘、疾病自动诊断、经济预测等领域。它根据给定的自变量数据集来估计事件的发生概率。变量的范围在0和1之间&#xff0c;通常用于二分类问题&#xff0c;最终输出的预…

Opencv(C++)学习之cv::calcHist 任意bin数量进行直方图计算

**背景&#xff1a;**当前网上常见的直方图使用方法都是默认使用256的范围&#xff0c;而对于使用特定范围的直方图方法讲的不够清楚。仔细研究后总结如下&#xff1a; 1、常见使用方法&#xff0c;直接对灰度图按256个Bin进行计算。 Mat mHistUn; int channels[1] { 0 }; {…

键盘数字键打不出来怎么解锁?收藏好这4个简单方法!

“我在使用电脑进行办公时&#xff0c;突然发现我电脑键盘的数字键无法输入&#xff0c;这该怎么办呢&#xff1f;我应该如何解锁呢&#xff1f;请给我出出主意吧&#xff01;” 在日常使用电脑时&#xff0c;很多用户都需要使用键盘输入文字。但有时候部分用户也会遇到键盘数字…