Qt5.9 玩轉數據庫之QSqlQueryModel的使用

先上結果圖:

         QSqlQueryModel 是 QSqlTableModel 的父類。QSqlQueryModel 封裝了執行 SELECT 語句從數據庫查詢數據的功能,但

是 QSqlQueryModel 只能作爲只讀數據源使用,不可以編輯數據 。

         這個界面佈局跟 QSqlTableModel 的佈局是一樣的,需要看到話,可以在我博客了找下。

老規矩:

工程文件:

QT       += sql

 

對應的頭文件:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include    <QLabel>
#include    <QString>

#include    <QtSql>
#include    <QDataWidgetMapper>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

private:
    QLabel  *LabInfo;

    QSqlDatabase  DB; //數據庫

    QSqlQueryModel  *qryModel; //數據模型

    QItemSelectionModel *theSelection; //選擇模型

    QDataWidgetMapper   *dataMapper;//數據界面映射

    void    openTable();//打開數據表
    void    refreshTableView();//移動記錄時刷新TableView的當前行
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
//    void on_primeInsert(int row, QSqlRecord &record);//插入記錄時,用於設置缺省字段數據

//    void on_currentChanged(const QModelIndex &current, const QModelIndex &previous);

// QTableView的SelectionModel的行發生了變化,進行處理
    void on_currentRowChanged(const QModelIndex &current, const QModelIndex &previous);
///////////////////////
    void on_actOpenDB_triggered();

//    void on_actPhoto_triggered();

//    void on_actPhotoClear_triggered();

    void on_actRecFirst_triggered();

    void on_actRecPrevious_triggered();

    void on_actRecNext_triggered();

    void on_actRecLast_triggered();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

 

cpp代碼解析部分:

初始化程序:


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    LabInfo=new QLabel("記錄條數",this);
    LabInfo->setMinimumWidth(200);
    ui->statusBar->addWidget(LabInfo);

    this->setCentralWidget(ui->splitter);

    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
    ui->tableView->setAlternatingRowColors(true);
    //    ui->tableView->resizeColumnsToContents();
    //    ui->tableView->horizontalHeader()->setStretchLastSection(true);

}

 基本記錄了文件狀態欄的,還有tableview 的屬性

打開數據庫:

void MainWindow::on_actOpenDB_triggered()
{//打開數據庫
    QString aFile=QFileDialog::getOpenFileName(this,"選擇數據庫文件","",
                             "SQL Lite數據庫(*.db *.db3)");
    if (aFile.isEmpty())
       return;

//打開數據庫
    DB=QSqlDatabase::addDatabase("QSQLITE"); //添加 SQL LITE數據庫驅動
    DB.setDatabaseName(aFile); //設置數據庫名稱
//    DB.setHostName();
//    DB.setUserName();
//    DB.setPassword();
    if (!DB.open())   //打開數據庫
    {
        QMessageBox::warning(this, "錯誤", "打開數據庫失敗",
                                 QMessageBox::Ok,QMessageBox::NoButton);
        return;
    }

//打開數據表
    openTable();
}

 

打開數據表的代碼:

void MainWindow::openTable()
{//打開數據表
    qryModel=new QSqlQueryModel(this);
    qryModel->setQuery("SELECT empNo, Name, Gender, Height, Birthday, Mobile, Province, City, Department, "
                       " Education, Salary FROM employee ORDER BY empNo");
    if (qryModel->lastError().isValid())
    {
        QMessageBox::critical(this, "錯誤", "數據表查詢錯誤,錯誤信息\n"+qryModel->lastError().text(),
                                 QMessageBox::Ok,QMessageBox::NoButton);
        return;
    }

   LabInfo->setText(QString::asprintf("記錄條數:%d",qryModel->rowCount()));

    qryModel->setHeaderData(0,Qt::Horizontal,"工號");
    qryModel->setHeaderData(1,Qt::Horizontal,"姓名");
    qryModel->setHeaderData(2,Qt::Horizontal,"性別");
    qryModel->setHeaderData(3,Qt::Horizontal,"身高");
    qryModel->setHeaderData(4,Qt::Horizontal,"出生日期");
    qryModel->setHeaderData(5,Qt::Horizontal,"手機");
    qryModel->setHeaderData(6,Qt::Horizontal,"省份");
    qryModel->setHeaderData(7,Qt::Horizontal,"城市");
    qryModel->setHeaderData(8,Qt::Horizontal,"部門");
    qryModel->setHeaderData(9,Qt::Horizontal,"學歷");
    qryModel->setHeaderData(10,Qt::Horizontal,"工資");

//    qryModel->setHeaderData(11,Qt::Horizontal,"照片");
//    qryModel->setHeaderData(12,Qt::Horizontal,"備註");

    theSelection=new QItemSelectionModel(qryModel);
    //選擇行變化時
    connect(theSelection,SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
                this,SLOT(on_currentRowChanged(QModelIndex,QModelIndex)));

//    connect(theSelection,SIGNAL(currentChanged(QModelIndex,QModelIndex)),
//            this,SLOT(on_currentChanged(QModelIndex,QModelIndex)));

    ui->tableView->setModel(qryModel);
    ui->tableView->setSelectionModel(theSelection);
//    ui->tableView->setColumnHidden(11,true);//"照片",隱藏列
//    ui->tableView->setColumnHidden(12,true);//"備註",隱藏列
//    ui->tableView->resizeColumnsToContents();
//    ui->tableView->horizontalHeader()->setStretchLastSection(true);

//創建數據映射
    dataMapper= new QDataWidgetMapper();
    dataMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
    dataMapper->setModel(qryModel);
//    dataMapper->setItemDelegate(new QSqlRelationalDelegate(this)); //含有外鍵的
    dataMapper->addMapping(ui->dbSpinEmpNo,0);//"empNo";
    dataMapper->addMapping(ui->dbEditName,1);//"Name";
    dataMapper->addMapping(ui->dbComboSex,2);//"Gender";

    dataMapper->addMapping(ui->dbSpinHeight,3);//"Height";
    dataMapper->addMapping(ui->dbEditBirth,4);//"Birthday";
    dataMapper->addMapping(ui->dbEditMobile,5);//"Mobile";

    dataMapper->addMapping(ui->dbComboProvince,6);//"Province";
    dataMapper->addMapping(ui->dbEditCity,7);//"City";
    dataMapper->addMapping(ui->dbComboDep,8);//"Department";

    dataMapper->addMapping(ui->dbComboEdu,9);//"Education";
    dataMapper->addMapping(ui->dbSpinSalary,10);//"Salary";

//    dataMapper->addMapping(ui->dbEditMemo,tabModel->fieldIndex("Memo"));

//    dataMapper->addMapping(ui->dbPhoto,tabModel->fieldIndex("Photo")); //圖片無法直接映射
    dataMapper->toFirst();

    ui->actOpenDB->setEnabled(false);
//    ui->actRecAppend->setEnabled(true);
//    ui->actRecInsert->setEnabled(true);
//    ui->actRecDelete->setEnabled(true);
//    ui->actScan->setEnabled(true);
}

      程序首先創建了 QSqlQueryModel 類型的私有變量 qryModel ,然後調用 setQuery() 函數設置了SELECT 查詢語句, SELECT 語句從 employe巳表裏查詢除了 Memo 和 Photo 之外的所有其他字段。
      使用 setHeaderData()函數爲每個字段設置顯示標題,爲使代碼簡化,這裏直接使用了宇段的序號。爲 qryMode l 創建了邊擇模型 theSelection ,並且將其 currentRowChanged()信號與自定義槽函數 on_currentRowChanged()關聯起來 。這個自定義槽函數用來在記錄移動時 , 查詢出 Memo 和 Photo字段的內容,並在界面上顯示出來 。

 

void MainWindow::on_currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
{
    Q_UNUSED(previous);
    if (!current.isValid())
    {
        ui->dbLabPhoto->clear();
        return;
    }

    dataMapper->setCurrentModelIndex(current);
//    dataMapper->setCurrentIndex(current.row());

    bool first=(current.row()==0); //是否首記錄
    bool last=(current.row()==qryModel->rowCount()-1);//是否尾記錄

    ui->actRecFirst->setEnabled(!first); //更新使能狀態
    ui->actRecPrevious->setEnabled(!first);
    ui->actRecNext->setEnabled(!last);
    ui->actRecLast->setEnabled(!last);

//    QModelIndex curIndex=theSelection->currentIndex();//獲取當前選擇單元格的模型索引
    int curRecNo=theSelection->currentIndex().row();
    QSqlRecord  curRec=qryModel->record(curRecNo); //獲取當前記錄
    int empNo=curRec.value("EmpNo").toInt();

    QSqlQuery query; //查詢當前empNo的Memo和Photo字段的數據
    query.prepare("select EmpNo, Memo, Photo from employee where EmpNo = :ID");
    query.bindValue(":ID",empNo);
    query.exec();
    query.first();

    QVariant    va=query.value("Photo");//
    if (!va.isValid())  //圖片字段內容爲空
       ui->dbLabPhoto->clear();
    else
    {//顯示照片
        QByteArray data=va.toByteArray();
        QPixmap pic;
        pic.loadFromData(data);
        ui->dbLabPhoto->setPixmap(pic.scaledToWidth(ui->dbLabPhoto->size().width()));
    }

    QVariant    va2=query.value("Memo");//顯示備註
    ui->dbEditMemo->setPlainText(va2.toString());
}

記錄移動

void MainWindow::on_actRecFirst_triggered()
{ //首記錄
    dataMapper->toFirst();
    refreshTableView();
}

void MainWindow::on_actRecPrevious_triggered()
{ //前一條記錄
    dataMapper->toPrevious();
    refreshTableView();
}

void MainWindow::on_actRecNext_triggered()
{//後一條記錄
    dataMapper->toNext();
    refreshTableView();
}

void MainWindow::on_actRecLast_triggered()
{//最後一條記錄
    dataMapper->toLast();
    refreshTableView();
}

 

刷新tableView的當前選擇行

 

void MainWindow::refreshTableView()
{//刷新tableView的當前選擇行
    int index=dataMapper->currentIndex();
    QModelIndex curIndex=qryModel->index(index,1);//
    theSelection->clearSelection();//清空選擇項
    theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);//設置剛插入的行爲當前選擇行
}

本文例子的連接:

鏈接:https://pan.baidu.com/s/1iMqXLQCVLqPr0luiKleHEA   提取碼:fy14

喜歡的可以關注我博客,更多驚喜等你喲。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章