欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于QT(c++)的家庭财务管理系统

程序员文章站 2022-04-28 09:02:25
...

题目:家庭财务管理系统

前言:

家庭财务管理收支管理是一个家庭日常生活中不可缺少一部分,也是财务管理的重要组成部分。

题目要求:

开发一个家庭财务管理系统,实现家庭财务信息的自动化。

系统主要功能:

1.登陆管理 :可以选一名家庭成员做管理员,普通用户只能查看自己的收支信息。

2. 家庭成员管理:成员的信息:姓名、性别、出身日期、年龄,身高,体重。

3. 收支项目管理可以设置收支项目,修改或者删除。收支项目要求分为两层,比如“车辆维护-保养费”;任意一层次都可作为收支项目记账,用户在不清楚支出是否属于“保养费”的时候,可以选择大类“车辆维护”作为支出项

5.家庭成员收支输出   显示每个成员每月的收支情况(时间、收支种类、金额、经手人)。

6.退出管理  

下面是系统功能示意图:

基于QT(c++)的家庭财务管理系统

 

 

 

 

 

 

 

 

系统的设计思路如下:

功能实现一:登录窗口实现

ui界面如下:

基于QT(c++)的家庭财务管理系统

 

1.管理员登录

  1. 管理员登录功能实现:在登录窗口类loginDlg定义私有成员:管理员账号与管理员密码,通过
    #include<QSettings>    //Qt提供用于写入注册表的类

    读写注册表。 

  2. 通过lineEdit行编辑输入用户名密码,在代码段中通过管理员登陆的Radio Button是否选中进行判断是否进行管理员登录。

2.管理员密码修改

  1. 通过点击左下角的管理员密码修改按钮进行密码修改(进入密码修改对话框),对话框界面如下:
  2. 基于QT(c++)的家庭财务管理系统

 

密码修改对话框具体功能实现在此先不做具体介绍,

注意:此处密码修改需要用到加密算法,这里使用QT提供用于密码加密的类:

#include<QCryptographicHash>    //Qt提供用于加密的类

3.普通用户登录:读取数据库

  1. 基于QSqlite轻量级数据库,未选中管理员登录Radio Button时,默认为普通用户登录。

以下为具体代码:

logindlg.h

#ifndef LOGINDLG_H
#define LOGINDLG_H

#include <QDialog>
#include<QSettings>
#include<QByteArray>
#include<QCryptographicHash>    //Qt提供用于加密的类
#include<QMessageBox>

#include <QTextCodec>       //unicode编码与其他编码转换
#include <QSqlDatabase>     //提供通过连接访问数据库的接口
#include <QSqlQuery>        //sql查询中创建、导航和检索数据所涉及的功能
#include <QTime>
#include <QSqlError>
#include <QDebug>
#include <QSqlDriver>
#include <QSqlRecord>
#include <QLabel>
#include <QDataWidgetMapper>
#include <QTemporaryFile>
#include <QFile>
#include <QByteArray>

#define SUB -1
#define MAIN 1

namespace Ui {
class loginDlg;
}

class loginDlg : public QDialog
{
    Q_OBJECT

public:
    explicit loginDlg(QWidget *parent = nullptr);
    ~loginDlg();
    void setName(QString name)  {Mng_Name = name;}
    void setPswd(QString pswd)  {Mng_Pswd = pswd;}
    bool createConnection();   //创建数据库链接
    bool queryAll(QString name, QString pswd);           //查找数据库
    void SetTabOrder();     //设置tab切换顺序
    int SubOrMain;          //主,从窗口切换标志
    QString NormalUser;                  //普通用户账号
private:
    Ui::loginDlg *ui;
    void readSettings();        //读取设置,注册表
    void writeSettings();       //写入设置,注册表
    int Mng_tryCount = 0;       //试错次数
    QString encrypt(const QString& str);    //字符串加密
    QString Mng_Name = "user";           //初始化用户名
    QString Mng_Pswd = "123456";         //初始化密码
    QSqlDatabase DB;


private slots:
    void on_LoginPushButton_clicked();
    void on_SignOutPushButton_clicked();
    void ChangePwd();        //修改密码
    void on_radioButton_clicked();
};

#endif // LOGINDLG_H

logindlg.cpp

#include "logindlg.h"
#include "ui_logindlg.h"

loginDlg::loginDlg(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::loginDlg)
{
    ui->setupUi(this);
    this->setWindowTitle("登陆窗口");
    this->setAttribute(Qt::WA_DeleteOnClose);
//    Mng_Pswd = encrypt("123456");
//    writeSettings();
    SetTabOrder();
    readSettings(); //初始化注册管理员用户名和密码
    createConnection();
    connect(ui->ChangePswd_PB, SIGNAL(clicked()), this, SLOT(ChangePwd()));
}

loginDlg::~loginDlg()
{
    delete ui;
}

bool loginDlg::createConnection()
{
    DB = QSqlDatabase::addDatabase("QSQLITE"); //添加 SQL LITE数据库驱动
    DB.setDatabaseName("../familyDb.db");
    if (!DB.open())   //打开数据库
    {
        QMessageBox::warning(this, "错误", "打开数据库失败",
                            QMessageBox::Ok,QMessageBox::NoButton);
        return false;
    }
    return true;
}

bool loginDlg::queryAll(QString name, QString pswd)
{
    DB = QSqlDatabase::database();      //使用默认连接
    QSqlQuery query(DB);
    query.exec("select * from familyBase");
    while(query.next())
    {
        if(query.value(6).toString()==name&&query.value(7).toString()==pswd)
            return true;
    }
    return false;
}

void loginDlg::SetTabOrder()
{
    setTabOrder(ui->IDLineEdit, ui->PassWordLineEdit);
    setTabOrder(ui->PassWordLineEdit, ui->LoginPushButton);
    setTabOrder(ui->LoginPushButton, ui->SignOutPushButton);
    setTabOrder(ui->SignOutPushButton, ui->radioButton);
    setTabOrder(ui->radioButton, ui->ChangePswd_PB);
    setTabOrder(ui->ChangePswd_PB, ui->radioButton);
}

void loginDlg::readSettings()
{//读取存储的用户名和密码, 密码是经过加密的
    QString organization = "TJJ-Qt";      //用于注册表
    QString appName = "FIO_System";       //app名字
    QSettings settings(organization, appName);
    Mng_Name = settings.value("Username","user").toString();
    QString defaultPSWD = encrypt("123456");        //缺省密码“123456”加密后的数据
    Mng_Pswd = settings.value("PSWD", defaultPSWD).toString();  //读取PSWD
}

void loginDlg::writeSettings()
{//保存用户名,密码等设置
    QSettings settings("TJJ-Qt", "FIO_System");      //注册表键组
    settings.setValue("Username",Mng_Name);          //将管理员账号存至设置
    settings.setValue("PSWD",Mng_Pswd);              //将管理员密码存至设置
    //指向的注册表目录是HKEY_CURRENT_USER/Software/TJJ-Qt/家庭收支管理系统
}

QString loginDlg::encrypt(const QString &str)
{ //字符串MD5算法加密
    QByteArray btArray;

    btArray.append(str);//加入原始字符串

    QCryptographicHash hash(QCryptographicHash::Md5);  //Md5加密算法

    hash.addData(btArray);  //添加数据到加密哈希值

    QByteArray resultArray =hash.result();  //返回最终的哈希值

    QString md5 =resultArray.toHex();//转换为16进制字符串

    return  md5;
}

void loginDlg::on_LoginPushButton_clicked()
{
    QString user = ui->IDLineEdit->text().trimmed();        //输入用户名
    QString pswd = ui->PassWordLineEdit->text().trimmed();  //输入密码

    QString encrptPSWD = encrypt(pswd);                     //对输入密码进行加密
    if(ui->radioButton->isChecked())
    {
        if ((user == Mng_Name)&&(encrptPSWD == Mng_Pswd))       //如果用户名和密码正确
        {
            writeSettings();  //保存设置
            SubOrMain = MAIN;
            this->accept();  //对话框accept(),关闭对话框
        }
        else
        {
            Mng_tryCount++; //错误次数
            if (Mng_tryCount>3)
            {
                QMessageBox::critical(this, "提示", "已达最大试错次数,程序退出");
                exit(1);
            }
            else
            {
                QMessageBox::warning(this, "错误提示", "用户名或密码错误");
                return;
            }
        }
    }
    else
    {
        if(queryAll(user,pswd))
        {
            NormalUser = user;
            QFile file("../UserNameFile.txt");
            //        if (file.open(QIODevice::ReadWrite | QIODevice::Text))
            //        {
            //           file.write(NormalUser.toLatin1());
            //           file.flush();
            //           file.close();
            //        }
            //        QFile file("要写的文件路径");
            if (file.open(QIODevice::WriteOnly | QIODevice::Text))
            {
                QTextStream stream(&file);
                stream.seek(file.size());
                QString qs;
                for (auto& i : user)
                {
                    qs.append(i);
                }
                stream << qs;
                file.close();
                SubOrMain = SUB;
                this->accept();  //对话框accept(),关闭对话框
            }
        }
        //QFile::setPermissions("UserNameFile.txt", QFileDevice::ReadUser);
        else
        {
            Mng_tryCount++; //错误次数
            if (Mng_tryCount>3)
            {
                QMessageBox::critical(this, "提示", "已达最大试错次数,程序退出");
                exit(1);
            }
            else
            {
                QMessageBox::warning(this, "错误提示", "用户名或密码错误");
                return;
            }
        }
    }
}

void loginDlg::on_SignOutPushButton_clicked()
{
    if(QMessageBox::question(this, "提示", "确定退出程序吗")==QMessageBox::Yes)
    {
        this->reject(); //退出
    }
    else
        return;
}

void loginDlg::ChangePwd()
{  //修改密码
    QSqlQuery query(DB);
    ChangePassword *dialog = new ChangePassword(this,"", &Mng_Pswd);
    if(dialog->exec() == QDialog::Accepted)
    {
        Mng_Pswd = encrypt(*dialog->GetNewPswd_Mng());
        QMessageBox::information(this, "提示", "密码修改成功" , QMessageBox::Ok);
    }
}

void loginDlg::on_radioButton_clicked()
{
    ui->IDLineEdit->setFocus();
}

二、管理员窗口实现


基于QT(c++)的家庭财务管理系统

一:综述:此界面利用tabWidget实现,三个管理标签页采用同样的实现方式,即采用View和model的形式,设置手动提交操作(利用下方四个按钮实现)。第四页界面如下:

基于QT(c++)的家庭财务管理系统

第四页功能设计思路:

  1. 使用TreeWidget实现月份与姓名的分类,通过点击TreeWidget中的Item实现右边收入项目与支出项目的TableView显示。
  2. 以下采用不可编辑的lineEdit显示计算出来的月总收入与月总支出。

主要代码如下:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include    <QMainWindow>
#include    <QLabel>
#include    <QSqlTableModel>
#include    <QtSql>
#include    <QDataWidgetMapper>
#include    <QSqlRecord>
#include    <QSqlError>
#include    <QSqlQuery>
#include    <QDateTime>
#include    <QDate>
#include    <QDebug>
#include    <QTreeWidgetItem>
#include    <QMessageBox>
#include    "infoentry.h"
#include    "changepassword.h"


namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    QSqlDatabase  DB;//数据库连接

    QSqlTableModel  *FamilyBaseTabModel;  //数据模型
    QSqlTableModel  *InItemTabModel;  //数据模型
    QSqlTableModel  *OutItemTabModel;  //数据模型
    QSqlTableModel  *PrintInModel;    //收入项目数据模型
    QSqlTableModel  *PrintOutModel;    //支出项目数据模型

    QItemSelectionModel *theSelection; //选择模型
    QDataWidgetMapper   *dataMapper; //数据映射

    void DBconnectAndCreateTable();     //连接数据库以及创建表
    void    openTable();                //打开数据表

    void    InitFamilyBaseView();             //初始化家庭成员基本信息视图
    void    InitInItemView();                 //初始化收入项目视图
    void    InitOutItemView();                //初始化输出项目视图
    void    InitPrintAllTab();                //初始化打印家庭成员信息标签页

    QString encrypt(const QString& str);    //字符串加密

    InfoEntry *InfoEntryDialog;     //信息输入窗口指针


private slots:
    void    SignOut();              //重新登陆
    void    on_ActionEntry_triggered();    //对信息输入action反应
    void    TreeWidgetsItemChanged(QTreeWidgetItem*, int);      //切换TreeWidget槽函数
    void    ShowCopyRight();        //版权:谭俊杰

    void on_CertainDLTMem_PB_clicked();
    void on_CertainDLTIncome_PB_clicked();
    void on_AddMember_PB_clicked();
    void on_AddInItems_PB_clicked();
    void on_OUT_CertainButton_clicked();
    void on_OUT_CancelButton_clicked();
    void on_Out_AddButton_clicked();
    void on_CancelDLTMem_PB_clicked();
    void on_ConcelDLTIn_PB_clicked();
    void on_DeleteMember_PB_clicked();
    void on_DLTInItems_PB_clicked();
    void on_Out_DeleteButton_clicked();

//    void on_pushButton_7_clicked();     //无效
//    void on_IN_CertainButton_clicked(); //无效
//    void on_pushButton_5_clicked();     //无效
    void on_pushButton_clicked();       //查找月份
};

#endif // MAINWINDOW_H

mainwindow.cpp

void MainWindow::DBconnectAndCreateTable()
{
    DB = QSqlDatabase::addDatabase("QSQLITE"); //添加 SQL LITE数据库驱动
    DB.setDatabaseName("../familyDb.db");      //设置数据库名
    if (!DB.open())   //打开数据库
    {
        qDebug()<<"数据库无法打开!";
        return ;
    }
    else
    {
        qDebug()<<"数据库成功打开!";
    }
    QSqlQuery query;
    //家庭成员基本信息,包括姓名,年龄,性别,出生日期,身高,体重,以及账号,密码。
    query.exec("create table familyBase(name varchar(20), age int, sex varchar(4),"
               "BirthTime varchar(40), tall int, height int, "
               "Username varchar(50), Password varchar(50));");

    //家庭收入项目,包括工资,租金,股息利息,社会福利,以及其他
    query.exec("create table familyIn(wage varchar(50), "
               "rent varchar(50), Interest varchar(50), welfare varchar(50),"
               "others varchar(50));");

    //家庭支出项目,包括食品,生活用品,交通,住房,教育,医疗保健以及其他
    query.exec("create table familyOut(food varchar(50), "
               "life varchar(50), traffic varchar(50), house varchar(50),"
               "educate varchar(50), Medical varchar(50), others varchar(50));");

    //家庭收支信息,包括日期,收支人姓名,收支项目,金额
    query.exec("create table familyIOInfo(IODate varchar(20), name varchar(20), "
               "Items varchar(30), MoneyAmount double);");

    //日期表的创建,方便根据日期加载TreeWidget
    query.exec("create table DateTable(IODate varchar(20));");
}
void MainWindow::TreeWidgetsItemChanged(QTreeWidgetItem* Item, int column)
{
    QSqlQuery query(DB);
//    QString sqlOp;
//    if(Item->parent() == nullptr)
//        sqlOp = QString("select Items,MoneyAmount from familyIOInfo where IODate = '%1'").arg(Item->text(column));
//    else
//        sqlOp = QString("select Items,MoneyAmount from familyIOInfo where IODate = '%1' and name = '%2'").arg(Item->parent()->text(0)).arg(Item->text(column));

//    if(!query.exec(sqlOp))
//        qDebug() << query.lastError();

    PrintInModel = new QSqlTableModel(this);
    PrintOutModel = new QSqlTableModel(this);
    PrintInModel->setTable("familyIOInfo");
    PrintOutModel->setTable("familyIOInfo");
    if(Item->parent() == nullptr)
    {
        PrintInModel->setFilter(QString("IODate = '%1' and MoneyAmount > 0").arg(Item->text(column))); //根据日期进行筛选
        PrintOutModel->setFilter(QString("IODate = '%1' and MoneyAmount < 0").arg(Item->text(column))); //根据日期进行筛选
    }
    else
    {
        PrintInModel->setFilter(QString("IODate = '%1' and name = '%2' and MoneyAmount > 0").arg(Item->parent()->text(column)).arg(Item->text(column))); //根据日期和姓名进行筛选
        PrintOutModel->setFilter(QString("IODate = '%1' and name = '%2' and MoneyAmount < 0").arg(Item->parent()->text(column)).arg(Item->text(column))); //根据日期和姓名进行筛选
    }

    PrintInModel->select(); //显示结果
    ui->InPrintView->setModel(PrintInModel);

    PrintOutModel->select();  //显示结果
    ui->OutPrintView->setModel(PrintOutModel);

    if(Item->parent() == nullptr)
    {
        ui->InPrintView->setColumnHidden(0,true);    //选中日期时,表中不应隐藏姓名
        ui->OutPrintView->setColumnHidden(0,true);    //选中日期时,表中不应隐藏姓名
    }

    else
    {
        ui->InPrintView->setColumnHidden(0,true);
        ui->InPrintView->setColumnHidden(1,true);    //选中姓名时,就可以隐藏姓名
        ui->OutPrintView->setColumnHidden(0,true);
        ui->OutPrintView->setColumnHidden(1,true);    //选中姓名时,就可以隐藏姓名
    }

    PrintInModel->setHeaderData(1, Qt::Horizontal, "姓名");
    PrintInModel->setHeaderData(2, Qt::Horizontal, "项目");
    PrintInModel->setHeaderData(3, Qt::Horizontal, "金额");
    PrintOutModel->setHeaderData(1, Qt::Horizontal, "姓名");
    PrintOutModel->setHeaderData(2, Qt::Horizontal, "项目");
    PrintOutModel->setHeaderData(3, Qt::Horizontal, "金额");

    //设置收入lineEdit和支出lineEdit
    int InRowNum = PrintInModel->rowCount();
    int OutRowNum = PrintOutModel->rowCount();
    double InValueSum = 0;
    double OutValueSum = 0;
    for(int i= 0; i < InRowNum; i++)
    {
        QModelIndex InIndex = PrintInModel->index(i,3);
        InValueSum += PrintInModel->data(InIndex).toDouble();
    }
    for(int i= 0; i < OutRowNum; i++)
    {
        QModelIndex OutIndex = PrintOutModel->index(i,3);
        OutValueSum += PrintOutModel->data(OutIndex).toDouble();
    }
    qDebug() << InValueSum << OutValueSum;
    ui->InLineEdit->setText(QString::number(InValueSum));
    ui->OutLineEdit->setText(QString::number(OutValueSum));
}
void MainWindow::on_pushButton_clicked()
{       //查找月份
    QSqlQuery query(DB);        //使用DB数据库连接
    query.exec("select * from DateTable");
    int count = 0;
    while(query.next())
    {
        if(ui->dateEdit->text() == query.value(0).toString())
        {
            emit ui->treeWidget->itemClicked(ui->treeWidget->topLevelItem(count), 0);
            ui->treeWidget->clearSelection();
            ui->treeWidget->topLevelItem(count)->setSelected(true);
            return;
        }
        count++;
    }
    QMessageBox::warning(this, "提示", "查找失败", QMessageBox::Ok);
}

信息录入窗口实现:

ui界面如下:

基于QT(c++)的家庭财务管理系统

  1. 通过Combox下拉框显示收支项目,右边double spinbox输入金额,如果用户切换到其他项目,则已更改的项目的字体会切换为橙色,表示已经更改。
  2. 通过上方的成员姓名下拉框加载需要录入信息的成员姓名,同时,通过更改输入格式的DateEdit输入录入的月份。
  3. 以上全部信息录入到数据库。

具体代码如下:

infoentry.h

#ifndef INFOENTRY_H
#define INFOENTRY_H

#include <QDialog>
#include    <QtSql>
#include    <QDataWidgetMapper>
#include    <QSqlRecord>
#include    <QSqlError>
#include    <QSqlQuery>
#include    <QMessageBox>
#include    <QCompleter>
#include    <QStringList>
#include    <QDateTime>
#include    <QPalette>
#include    <QStandardItemModel>
#include    <QDebug>
#include    <QVariantList>

struct FamilyIOInfo
{
    QString Name;         //姓名字段储存
    QStringList *InItemStringList; //收入项目列表
    QVariantList *InValuesList;     //收入项目值
    QStringList *OutItemStringList;//支出项目列表
    QVariantList *OutValuesList;    //支出项目值
    FamilyIOInfo(QString &name, QStringList* &InStrings, QVariantList* &InValue, QStringList* &OutStrings, QVariantList* &OutValue)
    {
        Name = name;
        InItemStringList = InStrings;
        InValuesList = InValue;
        OutItemStringList = OutStrings;
        OutValuesList = OutValue;
    }
};


namespace Ui {
class InfoEntry;
}

class InfoEntry : public QDialog
{
    Q_OBJECT

public:
    explicit InfoEntry(QWidget *parent = nullptr);
    ~InfoEntry();
    bool createConnection();   //创建数据库链接
    void setCombox();          //设置下拉框字段
    void updateFamilyDb();     //根据输入金额更新数据库
    void InitialFamily();      //初始化家庭成员收支信息储存结构体family
private:
    Ui::InfoEntry *ui;

    QStringList *InItemstrings; //收入项目列表
    QVariantList *InValues;     //收入项目值
    QStringList *OutItemstrings;//支出项目列表
    QVariantList *OutValues;    //支出项目值

    int InCurrentIndex[5] = {0, 0, 0, 0, 0};    //保存收入下拉框目前index
    int OutCurrentIndex[7] = {0, 0, 0, 0, 0, 0, 0}; //保存支出下拉框目前index

    bool InSpinBoxIsChange[5] = {false, false, false, false, false};    //设置输入项目Spinbox更改标志
    bool OutSpinBoxIsChange[7] = {false, false, false, false, false, false, false}; //设置输出项目SpinBox更改标志

    QSqlDatabase DB;                    //数据库连接
    QStandardItemModel *pItemModel;     //通过model设置下拉框文本颜色
private slots:
    void on_SureButton_clicked();           //确定按钮槽函数
    void on_CancelButton_clicked();         //取消按钮槽函数

    void on_WageComboBox_currentIndexChanged(const QString &arg1);  //工资下拉框字段改变反应
    void on_RentComboBox_currentIndexChanged(int index);            //租金下拉框字段改变反应
    void on_InterestComboBox_currentIndexChanged(int index);        //股息利息下拉框字段改变反应
    void on_WelfareComboBox_currentIndexChanged(int index);         //社会福利下拉框字段改变反应
    void on_InOtherComboBox_currentIndexChanged(int index);         //收入其他项下拉框字段改变反应
    void on_FoodComboBox_currentIndexChanged(int index);            //食品下拉框字段改变反应
    void on_LifeUseComboBox_currentIndexChanged(int index);         //生活用品下拉框字段改变反应
    void on_TrafficComboBox_currentIndexChanged(int index);         //交通下拉框字段改变反应
    void on_HouseComboBox_currentIndexChanged(int index);           //住房下拉框字段改变反应
    void on_EducateComboBox_currentIndexChanged(int index);         //教育下拉框字段改变反应
    void on_MedicalComboBox_currentIndexChanged(int index);         //医疗保健下拉框字段改变反应
    void on_OutOtherComboBox_currentIndexChanged(int index);        //支出其他项目下拉框字段改变反应

    void on_WageSpinBox_valueChanged(double arg1);
    void on_RentSpinBox_valueChanged(double arg1);
    void on_InterestSpinBox_valueChanged(double arg1);
    void on_WelfareSpinBox_valueChanged(double arg1);
    void on_InOtherSpinBox_valueChanged(double arg1);
    void on_FoodSpinBox_valueChanged(double arg1);
    void on_LifeUseSpinBox_valueChanged(double arg1);
    void on_TrafficSpinBox_valueChanged(double arg1);
    void on_HouseSpinBox_valueChanged(double arg1);
    void on_EducateSpinBox_valueChanged(double arg1);
    void on_MedicalSpinBox_valueChanged(double arg1);
    void on_OutOtherSpinBox_valueChanged(double arg1);

};

#endif // INFOENTRY_H

infoentry.cpp

void InfoEntry::setCombox()
{   //设置下拉框字段
    //设置收入项目字段
    QSqlQuery InQuery(DB);
    InQuery.exec("select * from familyIn");
    QSqlRecord InRecord = InQuery.record();
    InItemstrings = new QStringList[InRecord.count()];
    InValues = new QVariantList[InRecord.count()];
    while(InQuery.next())
    {
        for(int i = 0; i < InRecord.count(); i++)
        {
            if(InQuery.value(i).toString() != "")
            {
                InItemstrings[i] << InQuery.value(i).toString();
                InValues[i].append(0.0);
            }

        }
    }
    ui->WageComboBox->clear();
    ui->WageComboBox->addItems(InItemstrings[0]);
    ui->WageComboBox->setCurrentIndex(0);

    ui->RentComboBox->clear();
    ui->RentComboBox->addItems(InItemstrings[1]);
    ui->RentComboBox->setCurrentIndex(0);

    ui->InterestComboBox->clear();
    ui->InterestComboBox->addItems(InItemstrings[2]);
    ui->InterestComboBox->setCurrentIndex(0);

    ui->WelfareComboBox->clear();
    ui->WelfareComboBox->addItems(InItemstrings[3]);
    ui->WelfareComboBox->setCurrentIndex(0);

    ui->InOtherComboBox->clear();
    ui->InOtherComboBox->addItems(InItemstrings[4]);
    ui->InOtherComboBox->setCurrentIndex(0);

    //设置支出项目字段
    QSqlQuery queryOut(DB);
    queryOut.exec("select * from familyOut");
    QSqlRecord OutRecord = queryOut.record();
    OutItemstrings = new QStringList[OutRecord.count()];
    OutValues = new QVariantList[OutRecord.count()];
    while(queryOut.next())
    {
        for(int i = 0; i < OutRecord.count(); i++)
        {
            if(queryOut.value(i).toString() != "")
            {
                OutItemstrings[i] << queryOut.value(i).toString();
                OutValues[i].append(0.0);
            }

        }
    }
    ui->FoodComboBox->clear();
    ui->FoodComboBox->addItems(OutItemstrings[0]);
    ui->FoodComboBox->setCurrentIndex(0);

    ui->LifeUseComboBox->clear();
    ui->LifeUseComboBox->addItems(OutItemstrings[1]);
    ui->LifeUseComboBox->setCurrentIndex(0);

    ui->TrafficComboBox->clear();
    ui->TrafficComboBox->addItems(OutItemstrings[2]);
    ui->TrafficComboBox->setCurrentIndex(0);

    ui->HouseComboBox->clear();
    ui->HouseComboBox->addItems(OutItemstrings[3]);
    ui->HouseComboBox->setCurrentIndex(0);

    ui->EducateComboBox->clear();
    ui->EducateComboBox->addItems(OutItemstrings[4]);
    ui->EducateComboBox->setCurrentIndex(0);

    ui->MedicalComboBox->clear();
    ui->MedicalComboBox->addItems(OutItemstrings[5]);
    ui->MedicalComboBox->setCurrentIndex(0);

    ui->OutOtherComboBox->clear();
    ui->OutOtherComboBox->addItems(OutItemstrings[6]);
    ui->OutOtherComboBox->setCurrentIndex(0);

    //设置姓名字段
    QSqlQuery query(DB);
    query.exec("select * from familyBase");
    QSqlRecord record = query.record();
    QStringList stringList;
    while(query.next())
    {
        if(query.value(0).toString() != "")
            stringList << query.value(0).toString();
    }
    ui->NameComboBox->addItems(stringList);

}
void InfoEntry::on_SureButton_clicked()
{       //确定按钮槽函数
    if(QMessageBox::question(this, "提问" , "确定更改吗") == QMessageBox::Yes)
    {
        //保存目前收入项目的值
        InValues[0].replace(InCurrentIndex[0], ui->WageSpinBox->value());      //储存该值
        InValues[1].replace(InCurrentIndex[1], ui->RentSpinBox->value());      //储存该值
        InValues[2].replace(InCurrentIndex[2], ui->InterestSpinBox->value());      //储存该值
        InValues[3].replace(InCurrentIndex[3], ui->WelfareSpinBox->value());      //储存该值
        InValues[4].replace(InCurrentIndex[4], ui->InOtherSpinBox->value());      //储存该值

        //保存目前支出项目的值
        OutValues[0].replace(OutCurrentIndex[0], ui->FoodSpinBox->value());      //储存该值
        OutValues[1].replace(OutCurrentIndex[1], ui->LifeUseSpinBox->value());      //储存该值
        OutValues[2].replace(OutCurrentIndex[2], ui->InterestSpinBox->value());      //储存该值
        OutValues[3].replace(OutCurrentIndex[3], ui->HouseSpinBox->value());      //储存该值
        OutValues[4].replace(OutCurrentIndex[4], ui->EducateSpinBox->value());      //储存该值
        OutValues[5].replace(OutCurrentIndex[5], ui->MedicalSpinBox->value());      //储存该值
        OutValues[6].replace(OutCurrentIndex[6], ui->OutOtherSpinBox->value());      //储存该值


        //保存即将存入数据库中的数据,他们包括
        //Items:收支项目
        //Values:对应金额
        //FamilyName:收支人姓名
        //DateString:收支日期
        QStringList Items;          //收支项目
        QVariantList Values;         //对应金额
        QStringList DateString;     //储存日期
        QStringList FamilyName;     //姓名字段储存
        for(int i = 0; i < 5; i++)
        {
            for(int j = 0; j < InValues[i].length(); j++)
            {
                if(InValues[i][j] != 0)
                {
                    FamilyName << ui->NameComboBox->currentText();
                    DateString << ui->dateEdit->text();
                    Items << InItemstrings[i][j];
                    Values << InValues[i][j].toDouble();
                }

            }
        }
        for(int i = 0; i < 7; i++)
        {
            for(int j = 0; j < OutValues[i].length(); j++)
            {
                if(OutValues[i][j] != 0)
                {
                    FamilyName <<ui->NameComboBox->currentText();
                    DateString << ui->dateEdit->text();
                    Items << OutItemstrings[i][j];
                    Values << -OutValues[i][j].toDouble();  //支出项目变成支出形式(即负数)
                }
            }
        }

        //判断空否,若空则未做修改,给出提示框
        if(Items.isEmpty())
        {
            if(QMessageBox::warning(this, "警告", "您并未进行修改,请问是否继续修改?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
                return;
            else
               this->close();
        }


        //将数据写入数据库
        QSqlQuery query(DB);

        //写入到日期表
        query.exec("select * from DateTable");
        //QSqlRecord Record = query.record();
        //qDebug() << Record.count();
        //将日期存入日期表
        QStringList NewDateList;
        query.next();
        if(query.value(0).toString() == "")     //表空则直接插入
        {
            qDebug() << "这个表是空的";
            NewDateList << ui->dateEdit->text();
            query.prepare("insert into DateTable(IODate) values(:IODate)");
            query.bindValue(0, NewDateList);
            if(!query.exec())
                qDebug() << query.lastError();
        }
        else
        {   //不空则按顺序插入
            qDebug() << "进来了";
            query.previous();
            int tableLength = 0;
            while(query.next())
            {
                tableLength++;
                NewDateList.insert(tableLength - 1, query.value(0).toString());
            }
            for(int i = 0; i < tableLength; i++)
            {
                if(NewDateList[i].compare(ui->dateEdit->text()) < 0)
                {
                    NewDateList.insert(i,ui->dateEdit->text());
                    break;
                }
            }
            qDebug() << NewDateList;
            query.prepare("delete from DateTable");
            if(!query.exec())
                qDebug() << query.lastError();

            query.prepare("insert into DateTable(IODate) values(:IODate)");
            query.addBindValue(NewDateList);
            if(!query.execBatch())
                qDebug() << query.lastError();
        }

        //写入到家庭收支信息表
        query.prepare("insert into familyIOInfo(IODate, name, Items, MoneyAmount) values(:IODate, :name, :Items, :MoneyAmount)");

        query.addBindValue(DateString); //写入日期
        query.addBindValue(FamilyName); //写入姓名
        query.addBindValue(Items);      //写入项目
        query.addBindValue(Values);     //写入对应金额

        if(!query.execBatch())
            qDebug() << query.lastError();

        this->close();
    }
    else
        return;
}
void InfoEntry::on_WageComboBox_currentIndexChanged(const QString &arg1)
{       //工资下拉框字段改变反应
    if(InSpinBoxIsChange[0] == true)
    {
        int OldIndex = InCurrentIndex[0];
        pItemModel = qobject_cast<QStandardItemModel*>(ui->WageComboBox->model());
        pItemModel->item(OldIndex)->setForeground(QColor(255, 97, 0));     //修改文本颜色
        InValues[0].replace(OldIndex, ui->WageSpinBox->value());      //储存该值
        InCurrentIndex[0] = ui->WageComboBox->findText(arg1);
        ui->WageSpinBox->setValue(InValues[0][ui->WageComboBox->findText(arg1)].toDouble());
        InSpinBoxIsChange[0] = false;
        return;
    }
    else
    {
        ui->WageSpinBox->setValue(InValues[0][ui->WageComboBox->findText(arg1)].toDouble());
        InSpinBoxIsChange[0] = false;
        return;
    }
}
void InfoEntry::on_WageSpinBox_valueChanged(double arg1)
{
    InSpinBoxIsChange[0] = true;
}

普通用户窗口

  1. 该窗口类似于管理员窗口,只需要根据登录窗口获取用户账号,显示用户信息。并将View设置为不可编辑。

界面如下:

基于QT(c++)的家庭财务管理系统

具体代码如下:

subwindow.h

 

#ifndef SUBWINDOW_H
#define SUBWINDOW_H

#include <QMainWindow>
#include <QSqlDatabase>
#include <QTreeWidgetItem>
#include <QSqlTableModel>
#include <QDate>
#include <QMessageBox>
#include <QProcess>
#include <QDir>
#include <QSqlError>
#include <QDialog>
#include "changepassword.h"

namespace Ui {
class SubWindow;
}

class SubWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit SubWindow(QWidget *parent = nullptr);
    ~SubWindow();
    void setUserName(QString user){
        userName = user;
    }
public slots:
    void CheckMonth();          //月份查找响应槽函数
    void TreeWidgetsItemChanged(QTreeWidgetItem*, int);     //点击treewidget
private slots:
    void on_dateEdit_userDateChanged(const QDate &date);
    void SignOut();             //登出
    void ChangePwd();      //修改密码
    void on_pushButton_clicked();
    void ShowCopyRight();   //版权:谭俊杰

private:
    Ui::SubWindow *ui;
    QSqlDatabase  DB;//数据库连接
    QString name;    //用户姓名(非账号)
    QString userName;           //用户账号
    QDate CheckDate;          //查找月份
    QSqlTableModel *PrintInModel;  //收入项目模型
    QSqlTableModel *PrintOutModel;  //支出项目模型
    double InValueSum;              //收入项目总值
    double OutValueSum;             //支出项目总值
    void  InitUI();             //初始化界面
    void InitialNameAndTitle(); //初始化用户名与窗口标题
};

#endif // SUBWINDOW_H

subwindow.cpp

void SubWindow::TreeWidgetsItemChanged(QTreeWidgetItem *Item, int column)
{

    PrintInModel->setTable("familyIOInfo");
    PrintInModel->setFilter(QString("IODate = '%1' and name = '%2' and MoneyAmount > 0").arg(Item->text(column)).arg(name)); //根据日期和姓名进行筛选
    PrintInModel->select(); //读取数据库
    //PrintInModel->removeColumn(0);  //隐藏日期列
    //PrintInModel->removeColumn(1);  //隐藏姓名列
    ui->PrintInItemsView->setModel(PrintInModel);
    ui->PrintInItemsView->setColumnHidden(0,true);
    ui->PrintInItemsView->setColumnHidden(1,true);

    PrintOutModel->setTable("familyIOInfo");
    PrintOutModel->setFilter(QString("IODate = '%1' and name = '%2' and MoneyAmount < 0").arg(Item->text(column)).arg(name)); //根据日期和姓名进行筛选
    PrintOutModel->select(); //显示结果
    //PrintOutModel->removeColumn(0); //隐藏日期列
    //PrintOutModel->removeColumn(1); //隐藏姓名列
    ui->PrintOutItemsView->setModel(PrintOutModel);
    ui->PrintOutItemsView->setColumnHidden(0,true);
    ui->PrintOutItemsView->setColumnHidden(1,true);

    //更改model
    PrintInModel->setHeaderData(2, Qt::Horizontal, "收入项目");
    PrintInModel->setHeaderData(3, Qt::Horizontal, "金额");
    PrintOutModel->setHeaderData(2, Qt::Horizontal, "支出项目");
    PrintOutModel->setHeaderData(3, Qt::Horizontal, "金额");

    int InRowNum = PrintInModel->rowCount();
    int OutRowNum = PrintOutModel->rowCount();
    InValueSum = 0;
    OutValueSum = 0;
    for(int i= 0; i < InRowNum; i++)
    {
        QModelIndex InIndex = PrintInModel->index(i,3);
        InValueSum += PrintInModel->data(InIndex).toDouble();
    }
    for(int i= 0; i < OutRowNum; i++)
    {
        QModelIndex OutIndex = PrintOutModel->index(i,3);
        OutValueSum += PrintOutModel->data(OutIndex).toDouble();
    }
    qDebug() << InValueSum << OutValueSum;
    ui->InlineEdit->setText(QString::number(InValueSum));
    ui->OutlineEdit->setText(QString::number(OutValueSum));
}
void SubWindow::InitialNameAndTitle()
{
    QString userName;
    //指定文件
    QFile file( "../UserNameFile.txt" );
    //指定为GBK
    QTextCodec *codec = QTextCodec::codecForName("GBK");
    //如果打开文件失败,直接退出
    if(!file.open(QIODevice::ReadOnly|QIODevice::Text))
        return;
    //当未到达文件结束位置
    while(!file.atEnd())
    {
        //读取一行文本数据
        QByteArray line = file.readLine();
        //将读取到的行数据转换为Unicode
        userName = codec->toUnicode(line);
    }
    file.close();
    if(QFile::remove("../UserNameFile.txt"))    //删除用于信息传递的文件
        qDebug() << "你已删除文件!";
    else
        qDebug() << "文件未删除";

    DB = QSqlDatabase::addDatabase("QSQLITE"); //添加 SQL LITE数据库驱动
    DB.setDatabaseName("../familyDb.db");      //设置数据库名
    if (!DB.open())   //打开数据库
    {
        qDebug()<<"数据库无法打开!";
        return ;
    }
    else
    {
        qDebug()<<"数据库成功打开!";
    }

    QSqlQuery query(DB);
    QString sqlOp = QString("select * from familyBase where Username = '%1'").arg(userName);
    query.exec(sqlOp);
    while (query.next())
    {
        qDebug() << query.value(0).toString();
        if(query.value(6).toString() == userName)
        {
            name = query.value(0).toString();
            this->setWindowTitle("用户:"+name);
            break;
        }
    }
}

 

系统测试情况:

  1. 经测试,系统运行无强制退出错误,且实现基本功能,未发现bug。

 

系统的优点与改进:

  1. 优点:通过TreeWidget将成员信息显示,更加清晰明了。
  2. 优点:添加了退出登录计算金额总量功能,方便用户查看信息。
  3. 改进:界面设计不足:单调切无图标,背景等,可以在这方面进行优化
  4. 改进:在对话框信息返回时由于初始思路匮乏以及Qt传递QString信息错误,使用了临时文件储存信息的方法,其实可以使用指针。

 

感想:

通过这样一个程序,真正初步认识带有图形界面的windows应用程序开发。明白了qt的信号和槽机制,以及qt的控件和储存结构的相关知识,让我更加产生进行更强大系统功能实现的兴趣。