• QT7_视频知识点笔记_67_项目练习(页面以及对话框的切换,自定义数据类型,DB数据库类的自定义及使用)


    视频项目:7----汽车销售管理系统(登录,品牌车管理,新车入库,销售统计图表)-----项目视频没有,代码也不全,更改项目练习:学生信息管理系统。

    学生信息管理系统:简介:两个页面:主页面+学生信息添加页面(下面的例子仅举例学号和姓名)

    在这里插入图片描述
    在这里插入图片描述

    1.点击添加按钮弹出添加对话框

    添加一个继承自QDialog的QT界面类AddDialog(注意如果AddDialog是继承QWidget的话在主页面new 一个AddDialog的时候AddDialog页面会直接显示在主页面上)
    主页面:

    #include "adddialog.h"
    ...
    AddDialog *m_addDialog;  //添加学生信息窗口
    
    //构造函数:
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
        , ui(new Ui::Widget)
    {
        ui->setupUi(this);
    
        m_addDialog = new AddDialog(this);
    }
    void Widget::on_pushButton_add_clicked()
    {
        //点击按钮弹出新增窗口
        qDebug()<<"on_pushButton_add_clicked";
        
        m_addDialog->show();
    }
    

    2.添加按钮点击取消则关闭对话框

    void AddDialog::on_btnCancel_clicked()
    {
        qDebug()<<"on_btnCancel_clicked";
        this->close();
    }
    

    3.添加一个数据类定义需要存储数据类型(子界面存入,传递给主界面显示)

    添加Q_DECLARE_METATYPE(type)宏,能使type类型让所有基于模板的函数识别

    #ifndef CSTUDENTINFO_H
    #define CSTUDENTINFO_H
    
    #include 
    #include 
    
    class CStudentInfo
    {
    public:
        CStudentInfo();
    
        bool setData(int id,QString name);
    
        int id() const;
        void setId(int id);
    
        QString name() const;
        void setName(const QString &name);
    
    private:
        //此处举例仅用两个数据信息类
        int m_id;              //学生id 四位数字
        QString m_name;        //学生名称
    
    };
    
    Q_DECLARE_METATYPE(CStudentInfo)// 该宏放在类或结构体声明的最后面
    #endif // CSTUDENTINFO_H
    
    
    #include "cstudentinfo.h"
    
    CStudentInfo::CStudentInfo()
    {
    
    }
    
    bool CStudentInfo::setData(int id, QString name)
    {
        m_id = id;
        m_name = name;
        return true;
    }
    
    int CStudentInfo::id() const
    {
        return m_id;
    }
    
    void CStudentInfo::setId(int id)
    {
        m_id = id;
    }
    
    QString CStudentInfo::name() const
    {
        return m_name;
    }
    
    void CStudentInfo::setName(const QString &name)
    {
        m_name = name;
    }
    

    在子界面上按这个数据类存进入:

    void AddDialog::on_btnConfirm_clicked()
    {
        qDebug()<<"on_btnConfirm_clicked";
    	//......
        //把检测合格的数据添加进入
        int id = ui->edtId->text().toInt();
        QString name = ui->edtName->text();
    
        //数据类型
        CStudentInfo stuInfo;
        stuInfo.setData(id,name);
    
        //仅进行数据的修改到主页面,对话框不关闭
        emit sig_addStuInfo(stuInfo);
    }
    

    通过信号槽把数据类接收,并显示在主页面:
    信号槽传递:

    //关联槽函数
        connect(m_addDialog,&AddDialog::sig_addStuInfo,this,&Widget::slot_addStuInfo);
    
    bool Widget::slot_addStuInfo(CStudentInfo &stuInfo)
    {
        //收到添加对话框发出的信号,把添加的内容显示到UI上
        appendToModel(stuInfo);		//此处可以收到信号传来的
        return true;
    }
    

    主页面model模型显示:
    构造函数中:

    	//实例化model
        m_standardModel = new QStandardItemModel(this);
    
        //设置tableView 菜单策略 customContextMenuRequested(const QPoint &pos)
        ui->tableView_StudentInfo->setContextMenuPolicy(Qt::CustomContextMenu);
    
        //添加表头
        QStringList headerList;
        headerList<<"学号"<<"姓名";
        m_standardModel->setHorizontalHeaderLabels(headerList);
    
        ui->tableView_StudentInfo->setModel(m_standardModel);
    
    bool Widget::appendToModel(CStudentInfo &stuInfo)
    {
        QStandardItem *itemId = new QStandardItem(QString("%1").arg(stuInfo.id(),4,10,QLatin1Char('0')));
        itemId->setCheckable(true); //添加复选框
        itemId->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
    
        QStandardItem *itemName = new QStandardItem(stuInfo.name());
        itemName->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
    
        QList<QStandardItem*> rowItem;
        rowItem.append(itemId);
        rowItem.append(itemName);
    
        m_standardModel->appendRow(rowItem);
        return true;
    
    }
    

    效果:(后续需要添加学号是否存在验证等需另外再加入判断)在这里插入图片描述

    4.加入数据库进行数据的长期存储,主页面显示,子页面写入,以及删除功能

    先创建一个数据库的类CDataSQLite:

    #ifndef CDATASQLITE_H
    #define CDATASQLITE_H
    
    #include "cstudentinfo.h"
    #include 
    
    class CDataSQLite
    {
    public:
        CDataSQLite();
    
        /**
         * @brief 查询所有信息
         * @param stuInfos
         * @return
         */
         //用来遍历
        virtual bool selectStuInfos(QList<CStudentInfo> &stuInfoList) ;     
        //用来新增
        virtual bool addStuInfo(CStudentInfo &stuInfo) ;                    
        virtual bool updateStuInfo(CStudentInfo &stuInfo) ;
        //用来删除
        virtual bool deleteStuInfo(int id) ;                                
    private:
        QSqlDatabase m_db;  //数据库连接
    };
    
    #endif // CDATASQLITE_H
    

    CDataSQLite的构造函数:

    	//打开数据库
        m_db = QSqlDatabase::addDatabase("QSQLITE"); //QMYSQL
        m_db.setDatabaseName("./stuInfoDB_demo.db"); // 相对路径是相对于.exe所在的文件夹下(即bin文件夹下)
        if(!m_db.open())
        {
            qDebug() << "Failed to Open database";
            return;
        }
        qDebug() << "success Open ";
        
        //如果没有这个表则会创建
        QSqlQuery query;
        QString sql = QString("create table if not exists tb_stuInfo"
                              "(id int primary key not null,"
                              "name varchar(50),"
                              "overallScore real);");
        if(!query.exec(sql))
        {
            qDebug() << "Failed to create table";
            qDebug() << query.lastQuery();
            return;
        }
    
        //关闭数据库
        m_db.close();
    
    
    bool CDataSQLite::addStuInfo(CStudentInfo &stuInfo)
    {
    	//新增
        if(!m_db.open())
        {
            qDebug() << "Failed to Open Database : addStuInfo";
            return false;
        }
        QSqlQuery query;
        query.prepare("insert into tb_stuInfo (id,name)"
                      "values(:id,:name)");
        query.bindValue(":id",stuInfo.id());
        query.bindValue(":name",stuInfo.name());
        if(!query.exec())
        {
            qDebug() << query.lastQuery();
            m_db.close();
            return false;
        }
        m_db.close();
        return true;
    
    }
    
    
    bool CDataSQLite::selectStuInfos(QList<CStudentInfo> &stuInfoList)
    {
        //查询
        if(!m_db.open())
        {
            qDebug() << "Failed to Open Database : selectStuInfos";
            return false;
        }
        QSqlQuery query;
        QString sql = "Select * from tb_stuInfo;";
        if(!query.exec(sql))
        {
            qDebug() << "Failed to selcet tb_stuInfo;";
            return false;
        }
        while(query.next())
        {
            CStudentInfo stuInfo;
            int id = query.value("id").toInt();
            QString name = query.value("name").toString();
            stuInfo.setData(id,name);
            stuInfoList.append(stuInfo);
        }
        m_db.close();
        return true;
    }
    
    bool CDataSQLite::deleteStuInfo(int id)
    {
        if(!m_db.open())
        {
            qDebug() << "Failed to Open Database : deleteStuInfo";
            return false;
        }
        QSqlQuery query;
        QString sql = QString("delete from tb_stuInfo where id = %1").arg(id);
        if(!query.exec(sql))
        {
            qDebug() << "Failed to delete stuInfo!!!";
            m_db.close();
            return  false;
        }
    
        m_db.close();
        return true;
    }
    

    使用CDataSQLite数据库类:
    在主页面中,构造函数中会先实例化数据库类,然后进行遍历查询进行显示。

    //在.h文件中
    CDataSQLite  *m_dataSource;  //数据源
    
    
    //.cpp构造函数中
    //实例化数据源
        m_dataSource = new CDataSQLite();
    
        //查询数据
        QList<CStudentInfo> stuInfoList;
        bool res = m_dataSource->selectStuInfos(stuInfoList);
        if(!res)
        {
            QMessageBox::information(this,"提示","查询学生信息失败");
            return;
        }
        qDebug() << stuInfoList.size();
        for(int i=0;i<stuInfoList.size();++i)
        {
            appendToModel(stuInfoList[i]);
        }
    
    

    在新增页面点击确认发送信号之后,主页面接收到信号在槽函数中进行数据库类新增

    
    //接收到子页面的确认添加按钮发出的处理信号的槽函数
    bool Widget::slot_addStuInfo(CStudentInfo &stuInfo)
    {
        //把数据添加到数据库中
        bool res = m_dataSource->addStuInfo(stuInfo);
        if(!res)
        {
            QMessageBox::information(this,"提示","插入失败!!!");
            return false;
        }
        //收到添加对话框发出的信号,把添加的内容添加
        appendToModel(stuInfo);
        return true;
    }
    

    删除:主页面的删除按钮点击之后槽函数:on_pushButton_delate_clicked,会把勾选的数据从数据库中以及主页面中删除

    
    void Widget::on_pushButton_delate_clicked()
    {
        QMap<int,QStandardItem*> delRowsMap;  //待删除的行
        for(int row = 0;row<m_standardModel->rowCount();++row)
        {
            QStandardItem *item = m_standardModel->item(row);
            if(item->checkState() == Qt::Checked)
            {
                delRowsMap.insert(row,item);
            }
        }
    
        if(delRowsMap.size()<1)
            return;
    
        //弹出删除提示
        int res = QMessageBox::information(this,"提示","是否真的要删除",QMessageBox::Yes|QMessageBox::No);
        if(res == QMessageBox::No) return;
    
        QList<int> keyList = delRowsMap.keys();
        //1.删除数据库中的数据
        for(int key=keyList.size()-1;key>=0;--key)
        {
            if(m_dataSource->deleteStuInfo(delRowsMap.value(keyList[key])->text().toInt()))
            {
                //2.删除窗口中的数据
                m_standardModel->removeRow(keyList[key]);
            }
        }
    
    }
    

    在这里插入图片描述
    (存着自己看看)
    项目原例子源码:链接
    项目练习源码(跟博客相同,但是功能相比原例子不全):链接

  • 相关阅读:
    【常见SQL报错及解决办法】个人记录,自用
    阿里云 短信服务——发送短信验证码图文教程
    AJAX——跨域问题
    黄河水稻山东智慧 国稻种芯·中国水稻节:济南泉城米袋子
    3、Linux下安装
    【QT】Qt项目demo:数据在ui界面上显示,鼠标双击可弹窗显示具体信息
    【管理运筹学】第 5 章 | 整数规划(4,指派问题)
    历时一年,论文终于被国际顶会接收了
    Offer 经验分享 - 蚂蚁金服、字节跳动、PDD,蚂蚁金服面试 Java 后端经历
    进程间通信之匿名管道和命名管道
  • 原文地址:https://blog.csdn.net/xy_77777/article/details/139238147