C/C++ Qt 数据库与TableView多组件联动

2023-03-09 存储AndroidListView

qt 数据库组件与tableview组件实现联动,以下案例中实现了,当用户点击并选中tableview组件内的某一行时,我们通过该行中的name字段查询并将查询结果关联到listview组件内,同时将tableview中选中行的字段分别显示在窗体底部的lineedit编辑内,该案例具体实现细节如下。

首先在ui界面中绘制好需要的控件,左侧放一个tableview组件,右侧是一个listview组件,底部放三个lineedit组件,界面如下:

我们还是需要创建两张表结构,表student用于存储学生的基本信息,表studenttimetable存储的是每个学生所需要学习的课程列表,执行后创建数据表。

void initmultiplesql()
{
    qsqldatabase db = qsqldatabase::adddatabase("qsqlite");
    db.setdatabasename("./lyshark.db");
     if (!db.open())
     {
            std::cout << db.lasterror().text().tostdstring()<< std::endl;
            return;
     }

    // 执行sql创建表
    db.exec("drop table student");
    db.exec("create table student ("
                    "id integer primary key autoincrement, "
                    "name varchar(40) not null, "
                    "age integer not null)"
         );

    // 批量创建数据
    // https://www.cnblogs.com/lyshark
    qstringlist name_list; name_list << "lyshark" << "lisi" << "wangwu";
    qstringlist age_list; age_list << "25" << "34" << "45";

    // 绑定并插入数据
    qsqlquery query;
    query.prepare("insert into student(name,age) ""values (:name, :age)");

    if(name_list.size() == age_list.size())
    {
        for(int x=0;x< name_list.size();x++)
        {
            query.bindvalue(":name",name_list[x]);
            query.bindvalue(":age",age_list[x]);
            query.exec();
        }
    }

    // ------------------------------------------------
    // 创建第二张表,与第一张表通过姓名关联起来
    db.exec("drop table studenttimetable");
    db.exec("create table studenttimetable("
            "id integer primary key autoincrement, "
            "name varchar(40) not null, "
            "timetable varchar(128) not null"
            ")");

    db.exec("insert into studenttimetable(name,timetable) values ('lyshark','aaa')");
    db.exec("insert into studenttimetable(name,timetable) values ('lyshark','bbb')");
    db.exec("insert into studenttimetable(name,timetable) values ('lyshark','ccc')");

    db.exec("insert into studenttimetable(name,timetable) values ('lisi','qqq')");
    db.exec("insert into studenttimetable(name,timetable) values ('lisi','www')");

    db.exec("insert into studenttimetable(name,timetable) values ('wangwu','eee')");

    db.commit();
    db.close();
}

程序运行后,构造函数mainwindow::mainwindow(qwidget *parent)内初始化表格,查询student表内记录,将查询到的指针绑定到theselection模型上,绑定后再将绑定指针加入到datamapper组件映射中,即可实现初始化,其初始化代码如下:

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <qsqldatabase>
#include <qsqlerror>
#include <qsqlquery>
#include <qsqlrecord>
#include <iostream>
#include <qstringlist>
#include <qstring>
#include <qvariant>
#include <qdatawidgetmapper>
#include <qtsql>
#include <qstandarditem>
#include <qstringlist>
#include <qstringlistmodel>

qsqlquerymodel *qrymodel;          // 数据模型
qitemselectionmodel *theselection; // 选择模型
qdatawidgetmapper *datamapper;     // 数据界面映射

mainwindow::mainwindow(qwidget *parent) :qmainwindow(parent),ui(new ui::mainwindow)
{
    ui->setupui(this);

    qsqldatabase db = qsqldatabase::adddatabase("qsqlite");
    db.setdatabasename("./lyshark.db");
     if (!db.open())
     {
            std::cout << db.lasterror().text().tostdstring()<< std::endl;
            return;
     }

     // 查询数据表中记录
     qrymodel=new qsqlquerymodel(this);
     qrymodel->setquery("select * from student order by id");
     if (qrymodel->lasterror().isvalid())
     {
         return;
     }

     // 设置tableview表头数据
     qrymodel->setheaderdata(0,qt::horizontal,"id");
     qrymodel->setheaderdata(1,qt::horizontal,"name");
     qrymodel->setheaderdata(2,qt::horizontal,"age");

     // 将数据绑定到模型上
     theselection=new qitemselectionmodel(qrymodel);
     ui->tableview->setmodel(qrymodel);
     ui->tableview->setselectionmodel(theselection);
     ui->tableview->setselectionbehavior(qabstractitemview::selectrows);

     // 创建数据映射
     datamapper= new qdatawidgetmapper();
     datamapper->setsubmitpolicy(qdatawidgetmapper::autosubmit);
     datamapper->setmodel(qrymodel);
     datamapper->addmapping(ui->lineedit_id,0);
     datamapper->addmapping(ui->lineedit_name,1);
     datamapper->addmapping(ui->lineedit_age,2);
     datamapper->tofirst();

     // 绑定信号,当鼠标选择时,在底部编辑框中输出
     // https://www.cnblogs.com/lyshark
     connect(theselection,signal(currentrowchanged(qmodelindex,qmodelindex)),this,slot(on_currentrowchanged(qmodelindex,qmodelindex)));
}

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

此时这个程序运行后会得到表内数据:

接着我们需要绑定tableview表格的on_currentrowchanged()事件,当用户点击tableview表格中的某个属性是则自动触发该函数,在此函数内我们完成对其他组件的填充.

1.通过currentindex方法获取到当前表所在行2.通过当前行号查询表中姓名,并带入studenttimetable表查该表中记录3.循环获取该用户的数据,并将timetable字段提取出来放入qstringlist容器4.将数据直接关联到listview数据表中
// 鼠标点击后的处理槽函数
void mainwindow::on_currentrowchanged(const qmodelindex &current, const qmodelindex &previous)
{
    q_unused(previous);
    if (!current.isvalid())
    {
        return;
    }

    datamapper->setcurrentmodelindex(current);

    // 获取到记录开头结尾
    bool first=(current.row()==0);                    // 是否首记录
    bool last=(current.row()==qrymodel->rowcount()-1);// 是否尾记录
    std::cout << "isfirst: " << first << "islast: " << last << std::endl;


    // 获取name字段数据
    int currecno=theselection->currentindex().row();  // 获取当前行号
    qsqlrecord currec=qrymodel->record(currecno);     // 获取当前记录
    qstring uname = currec.value("name").tostring();
    std::cout << "student name = " << uname.tostdstring() << std::endl;

    // 查studenttimetable表中所有数据
    // 根据姓名过滤出该用户的所有数据
    qsqlquery query;
    query.prepare("select * from studenttimetable where name = :x");
    query.bindvalue(":x",uname);
    query.exec();

    // 循环获取该用户的数据,并将timetable字段提取出来放入qstringlist容器
    // https://www.cnblogs.com/lyshark
    qsqlrecord rec = query.record();
    qstringlist the_data;

    while(query.next())
    {
        int index = rec.indexof("timetable");
        qstring data = query.value(index).tostring();

        std::cout << "user timetable = " << data.tostdstring() << std::endl;
        the_data.append(data);
    }

    // 关联到listview数据表中
    qstringlistmodel *model;
    model = new qstringlistmodel(the_data);
    ui->listview->setmodel(model);
    ui->listview->setedittriggers(qabstractitemview::noedittriggers);
}

当绑定选中事件时,程序运行效果如下:

针对底部按钮处理事件相对来说较为简单,其实现原理就是调用了tableview默认提供的一些函数而已,代码如下:

// 刷新tableview的当前选择行
// https://www.cnblogs.com/lyshark
void mainwindow::refreshtableview()
{
    int index=datamapper->currentindex();
    qmodelindex curindex=qrymodel->index(index,0);      // 定位到低0行0列
    theselection->clearselection();                     // 清空选择项
    theselection->setcurrentindex(curindex,qitemselectionmodel::select);//设置刚插入的行为当前选择行
}

// 第一条记录
void mainwindow::on_pushbutton_clicked()
{
    datamapper->tofirst();
    refreshtableview();
}
// 最后一条记录
void mainwindow::on_pushbutton_2_clicked()
{
    datamapper->tolast();
    refreshtableview();
}

// 前一条记录
void mainwindow::on_pushbutton_3_clicked()
{
    datamapper->toprevious();
    refreshtableview();
}

// 下一条记录
void mainwindow::on_pushbutton_4_clicked()
{
    datamapper->tonext();
    refreshtableview();
}

最终运行效果如下所示:

上一篇:C/C++ Qt 数据库与ComBox多级联动

下一篇:C/C++ Qt 数据库与SqlTableModel组件应用