学习《QT5.9 c++ 开发指南》第5章学习笔记3 QStandardItemModel

本章讲述了  QStandardItemModel  的使用方法,以及基本文件的读写。

QStandardItemModel   通常与QTabView 组合使用。

书上例子主要使用3个类:

QStandardItemModel   : 基于项数据的标准数据模型,可以处理二维数据。维护一个二维的项数据数组,每一个项

都是QStandardItem 类的变量,用于存储数据,字体格式,对齐方式等。

QTabView : 二维数据表示图的组件,有多行与多列。

QItemSelectionModel  :  用来跟踪视图组件的单元格选择的单元格选择状态的类,为单元格操作提供方便。

话不多说了,先看运行的结果图吧:

下面的是界面布局,与控件命名的图:

下图为Action编辑器所编辑的图:

有关action 添加这里就不细讲了,第4章节有详细讲解。

ok,接下来我们看看代码部分:

在mainWindow.h 文件中:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QLabel>
#include    <QStandardItemModel>
#include    <QItemSelectionModel>

#define FixedColumnCount 6  //文件固定6列

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
private:
    QLabel *LabCurFile;  //当前文件
    QLabel *LabCellPos;  //当前单元格行列号
    QLabel  *LabCellText;   //当前单元格内容

    QStandardItemModel *theModel;//数据模型
    QItemSelectionModel *theSelection;//Item选择模型

    void iniModelFormStringList(QStringList &);

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


private slots:
    void on_actFontBold_triggered(bool checked);

    void on_actAlignRight_triggered();

    void on_actModelData_triggered();

    void on_actOpen_triggered();

    void on_actSave_triggered(); //

    void on_actAppend_triggered();

    void on_actInsert_triggered();

    void on_actDelete_triggered();

    void on_actExit_triggered();

    void on_actAlignLeft_triggered();

    void on_actAlignCenter_triggered();

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

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

其中   void on_currentChanged(const QModelIndex &current, const QModelIndex &previous); 是手动添加,

自定义的 on_currentChanged(); 用于在TableView 上选择单元格的发生变化时,更新状态栏中的信息显示。

首先在cpp文件中添加对应的头文件

#include    <QFileDialog>
#include    <QTextStream>

1. 系统初始化部分

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    theModel = new QStandardItemModel(2,FixedColumnCount,this);  //数据模型
    theSelection = new QItemSelectionModel(theModel); //Item选择类型

    //选择当前单元格变化时的信号与槽
    connect(theSelection,SIGNAL(currentChanged(QModelIndex,QModelIndex)),
                this,SLOT(on_currentChanged(QModelIndex,QModelIndex)));

    //为tableView设置数据模型
    ui->tableView->setModel(theModel);//设置数据模型
    ui->tableView->setSelectionModel(theSelection); //设置选择模型
    ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);

    setCentralWidget(ui->splitter);
    //创建状态栏组件
    LabCurFile = new QLabel("当前文件",this);
    LabCurFile->setMinimumWidth(200);

    LabCellPos = new QLabel("当前单元格:",this);
    LabCellPos->setMinimumWidth(180);
    LabCellPos->setAlignment(Qt::AlignHCenter);

    LabCellText = new QLabel("单元格内容:",this);
    LabCellText->setMinimumWidth(180);

    ui->statusBar->addWidget(LabCurFile);
    ui->statusBar->addWidget(LabCellPos);
    ui->statusBar->addWidget(LabCellText);

}

首先, theModel = new QStandardItemModel(2,FixedColumnCount,this);

选择为2行 6列的格式,然后通过   theSelection = new QItemSelectionModel(theModel);

把数据选择模型 与 theModel相互关联起来。

2.  on_currentChanged()

void MainWindow::on_currentChanged(const QModelIndex &current, const QModelIndex &previous)
{
  //选择单元格变化时的响应
    Q_UNUSED(previous)
    if(current.isValid())
    {
        LabCellPos->setText(QString::asprintf("当前单元格: %d行, %d列",current.row(),current.column()));
        QStandardItem * aItem = theModel->itemFromIndex(current);
        this->LabCellText->setText("单元格内容: "+aItem->text());
        QFont font = aItem->font();
        ui->actFontBold->setChecked(font.bold());
    }
}

此函数过程主要显示状态栏中的数据.

3.准备好对应的文本文件:1.txt

测深(m)        垂深(m)        方位(。)    总位移(m)    固井质量    测井取样    
252        252        241.27        0.51        优        1
275        275        241.27        0.72        优        1
300        300        235.82        0.9        良        1
325        325        239.23        1.09        良        1
350        350        243.02        1.27        一般        1
375        375        245.25        1.48        一般        1
400        399.99        243.12        1.72        优        1
425        424.99        238.72        1.93        优        1
450        449.99        242.6        2.22        良        1
475        474.99        239.52        2.51        良        1
500        499.99        228.03        2.83        一般        0
525        524.99        237.27        3.21        一般        0
550        549.98        249.85        3.76        优        0
575        574.95        254.77        4.88        优        0
600        599.87        258.18        6.84        良        1
625        624.83        274.63        8.13        良        1
650        649.79        302.42        9.08        一般        1
675        674.79        344.37        9.14        一般        1
700        699.78        89.22        8.55        优        0
725        724.77        116.77        8.07        优        0
750        749.77        92.9        7.46        良        0
775        774.76        95.93        6.98        良        0
800        799.76        206.45        7.07        一般        0
825        824.76        206.45        7.17        一般        0
850        849.76        211.82        7.25        优        0

4.打开文件 按钮槽函数代码:

void MainWindow::on_actOpen_triggered()
{
    //打开文件
    QString curPath = QCoreApplication::applicationFilePath(); //获取应用程序的路径
    QString aFileName = QFileDialog::getOpenFileName(this,"打开一个文件",
                   curPath,"井数据文件(*.txt);;所有文件(*.*)");
    if(aFileName.isEmpty())
        return; //如果未选择文件,退出

     QStringList fFileContent;//文件内容字符串列表
     QFile aFile(aFileName);
     if(aFile.open(QIODevice::ReadOnly|QIODevice::Text))
     {
        QTextStream aStram(&aFile);//用文本流读取文件
        ui->plainTextEdit->clear();//清空
        while(!aStram.atEnd())
        {
            QString str = aStram.readLine(); //读取文件的一行
            ui->plainTextEdit->appendPlainText(str); //添加到文本框显示
            fFileContent.append(str); //添加到 StringList
        }

        aFile.close();//关闭文件
        this->LabCurFile->setText("当前文件:"+aFileName); //状态栏显示
        ui->actAppend->setEnabled(true); //更新Actions的enable属性
        ui->actInsert->setEnabled(true);
        ui->actDelete->setEnabled(true);
        ui->actSave->setEnabled(true);

        iniModelFormStringList(fFileContent); //从StringList的内容初始化数据模型

     }

}

这段的代码让用户选择需要打开的数据文本文件,然后只读和文本格式打开,逐行读取内容,在讲每行的字符串显示到界面

plainTextEdit里,并添加到一个临时的QStringList 类中,然后调用 iniModelFormStringList();

5.iniModelFormStringList()函数

void MainWindow::iniModelFormStringList(QStringList & aFileContent)
{
    //从一个StringList 获取数据,初始化数据Model
    int rowCnt = aFileContent.count(); //文本行数,第1行是标题
    theModel->setSortRole(rowCnt-1);//实际数据行数
    //设置表头
    QString header = aFileContent.at(0); //第1行是表头
    QStringList headerList = header.split(QRegExp("\\s+"),QString::SkipEmptyParts);
    theModel->setHorizontalHeaderLabels(headerList);//设置表头

    //设置单元数据
    int j = 0;
    QStandardItem *aItem;
    for (int i = 1;i<rowCnt;i++)
    {
        QString aLineText = aFileContent.at(i);
        //一个或多个空格、TAB等分隔符隔开的字符串, 分解为一个StringList
        QStringList  tmpList = aLineText.split(QRegExp("\\s+"),QString::SkipEmptyParts);
        for (j = 0;j<FixedColumnCount -1;j++) //不需要最后一行
        {
            aItem = new QStandardItem(tmpList.at(j));
            theModel->setItem(i-1,j,aItem);//为模型的某个行列位置设置Item
        }
        aItem=new QStandardItem(headerList.at(j));//最后一列是Checkable,需要设置
        aItem->setCheckable(true); //设置为Checkable
        if(tmpList.at(j)== "0" )
            aItem->setCheckState(Qt::Unchecked);
        else
            aItem->setCheckState(Qt::Checked);

        theModel->setItem(i-1,j,aItem);

    }


}

传进来的参数 aFileContent 是文本文件构成的所有StirngList,第1行是表头文字,数据在第2行开始。

6.添加行

void MainWindow::on_actAppend_triggered()
{
  //在表格最后添加行
  QList<QStandardItem *> aItemList; //列表容器
  QStandardItem   *aItem;
  for (int i = 0;i<FixedColumnCount-1;i++)
  {
      aItem = new QStandardItem("0");
      aItemList << aItem;
  }
  //获取最后一列的表头文字
  QString str = theModel->headerData(theModel->columnCount()-1,Qt::Horizontal,Qt::DisplayRole).toString();
  //创建 "测井取样"Item
  aItem = new QStandardItem(str);
  aItem->setCheckable(true);
  aItemList<<aItem;   //添加到容器

  theModel->insertRow(theModel->rowCount(),aItemList); //插入一行,需要每个Cell的Item

  QModelIndex curIndex = theModel->index(theModel->rowCount()-1,0);//创建最后一行的ModelIndex
  theSelection->clearSelection();
  theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);//设置刚插入的行为当前选择行
}

7.插入行:

void MainWindow::on_actInsert_triggered()
{
    QList<QStandardItem *> aItemList; //列表容器
    QStandardItem   *aItem;
    for (int i = 0;i<FixedColumnCount-1;i++)
    {
        aItem = new QStandardItem("0");
        aItemList << aItem;
    }
    //获取最后一列的表头文字
    QString str = theModel->headerData(theModel->columnCount()-1,Qt::Horizontal,Qt::DisplayRole).toString();
    //创建 "测井取样"Item
    aItem = new QStandardItem(str);
    aItem->setCheckable(true);
    aItemList<<aItem;   //添加到容器

    //插入到制定的
     QModelIndex curIndex=theSelection->currentIndex(); //获取当前选中项的模型索引
     theModel->insertRow(curIndex.row(),aItemList);
     theSelection->clearSelection();//清除已有选择
     theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);

}

8.删除行:

void MainWindow::on_actDelete_triggered()
{
    QModelIndex curIndex = theSelection->currentIndex();
    if(curIndex.row() == theModel->rowCount()-1)
    {
        theModel->removeRow(curIndex.row());//删除最后一行
    }
    else
    {
        theModel->removeRow(curIndex.row());//删除一行,并重新设置当前选择行
        theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);
    }
}

9.文字居左  居中  居右 :

void MainWindow::on_actAlignLeft_triggered()
{
    //左对齐
    if(!theSelection->hasSelection())//没有选择的项
        return;

    QModelIndexList selectedIndex = theSelection->selectedIndexes();
    for (int i = 0; i<selectedIndex.count();i++) {
        QModelIndex aIndex = selectedIndex.at(i); //获取其中的一个模型索引
        QStandardItem * aItem = theModel->itemFromIndex(aIndex);
        aItem->setTextAlignment(Qt::AlignLeft);
    }
}

void MainWindow::on_actAlignCenter_triggered()
{
    if(!theSelection->hasSelection())//没有选择的项
        return;

    QModelIndexList selectedIndex = theSelection->selectedIndexes();
    for (int i = 0; i<selectedIndex.count();i++) {
        QModelIndex aIndex = selectedIndex.at(i); //获取其中的一个模型索引
        QStandardItem * aItem = theModel->itemFromIndex(aIndex);
        aItem->setTextAlignment(Qt::AlignCenter);
    }
}

void MainWindow::on_actAlignRight_triggered()
{
    if(!theSelection->hasSelection())//没有选择的项
        return;

    QModelIndexList selectedIndex = theSelection->selectedIndexes();
    for (int i = 0; i<selectedIndex.count();i++) {
        QModelIndex aIndex = selectedIndex.at(i); //获取其中的一个模型索引
        QStandardItem * aItem = theModel->itemFromIndex(aIndex);
        aItem->setTextAlignment(Qt::AlignRight);
    }
}

10.粗体:

void MainWindow::on_actFontBold_triggered(bool checked)
{
    //设置字体粗体
        if (!theSelection->hasSelection())
            return;

    //获取选择单元格的模型索引列表
        QModelIndexList selectedIndex=theSelection->selectedIndexes();

        for (int i=0;i<selectedIndex.count();i++)
        {
            QModelIndex aIndex=selectedIndex.at(i); //获取一个模型索引
            QStandardItem* aItem=theModel->itemFromIndex(aIndex);//获取项数据
            QFont font=aItem->font(); //获取字体
            font.setBold(checked); //设置字体是否粗体
            aItem->setFont(font); //重新设置字体
        }
}

11.模型导出:

void MainWindow::on_actModelData_triggered()
{
    //模型数据导出到PlainTextEdit显示
        ui->plainTextEdit->clear(); //清空
        QStandardItem   *aItem;
        QString str = "";
    //获取表头文字
        int i,j;
        for (i=0;i<theModel->columnCount();i++)
        { //
            aItem=theModel->horizontalHeaderItem(i); //获取表头的一个项数据
            str=str+aItem->text()+"\t"; //用TAB间隔文字
        }
        ui->plainTextEdit->appendPlainText(str); //添加为文本框的一行
   //获取数据区的每行
       for (i=0;i<theModel->rowCount();i++)
       {
           str="";
           for(j=0;j<theModel->columnCount()-1;j++)
           {
               aItem = theModel->item(i,j);
               str=str+aItem->text()+QString::asprintf("\t"); //以 TAB分隔
           }
           aItem=theModel->item(i,j); //最后一行是逻辑型
           if (aItem->checkState()==Qt::Checked)
               str=str+"1";
           else
               str=str+"0";
           ui->plainTextEdit->appendPlainText(str);
       }

}

12.文件另存为:

void MainWindow::on_actSave_triggered()
{
  //保存为文件
    QString curPath = QCoreApplication::applicationDirPath();
    QString aFileName = QFileDialog::getSaveFileName(this,"选择一个文件",curPath,
                           "井斜数据文件(*.txt);;所有文件(*.*)");
    if(aFileName.isEmpty()) //未选择文件,退出
        return;
    QFile aFile;
    if(!(aFile.open(QIODevice::ReadWrite|QIODevice::Text|QIODevice::Truncate))) //Truncate 截短的
        return; //以读写、覆盖原有内容方式打开文件

    QTextStream aStream(&aFile); //用文本流读取文件
    QStandardItem *aItem;
    int i,j;
    QString str="";
    ui->plainTextEdit->clear();
    //获取表头文字
    for (i = 0;i < theModel->columnCount(); i++) {
        aItem = theModel->horizontalHeaderItem(i); //获取表头的项数据
        str=str+aItem->text()+"\t\t";  //以TAB见隔开
    }
    aStream << str << "\n";  //文件里需要加入换行符 \n
    ui->plainTextEdit->appendPlainText(str);
    //获取数据区域的文字
    for (i=0;i<theModel->rowCount();i++)
    {
        str="";
        for(j=0;j<theModel->columnCount()-1;j++)
        {
            aItem = theModel->item(i,j);
            str=str+aItem->text()+QString::asprintf("\t"); //以 TAB分隔
        }
        aItem=theModel->item(i,j); //最后一行是逻辑型
        if (aItem->checkState()==Qt::Checked)
            str=str+"1";
        else
            str=str+"0";
        ui->plainTextEdit->appendPlainText(str);
        aStream << str << "\n";
    }
}

        已上就是全部的函数功能模块了,仔细看看对应的函数,对以后会有很大的进步,文件已经上传,需要的小伙伴可以下载,

让我们一起加油与进步。

发布了8 篇原创文章 · 获赞 2 · 访问量 274

猜你喜欢

转载自blog.csdn.net/weixin_42126427/article/details/103998942