Application of C/C++ Qt StandardItemModel data model

Posted by salih0vicX on Sun, 05 Dec 2021 17:34:46 +0100

QStandardItemModel is a standard data management method based on M/V model with item data as unit. Model/View is a data arrangement structure in Qt, in which model represents model, View represents View, View is an interface component for displaying and editing data, and model is the interface between View and original data, Generally, this kind of structure is mostly used in the database. For example, the model structure is responsible for reading or writing to the database, and the View structure is responsible for displaying the data. It is clear and easy to write code for maintenance.

The QStandardItemModel component is usually used together with the TableView component. When the records in the database or text change, it will be automatically synchronized to the component. First, draw the UI interface.

Secondly, bind the top ToolBar menu and add the description of corresponding function attributes to the menu respectively.


Initialize constructor: when the program runs, we need to initialize the controls in the page one by one, and bind the Table and model by calling UI - > tableview - > setmodel (model).

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

#include <iostream>
#include <QLabel>
#include <QStandardItem>
#include <QItemSelectionModel>

#include <QFileDialog>
#include <QTextStream>

#include <QList>

// Default constructor 
// https://www.cnblogs.com/lyshark
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // Initialization part
    model = new QStandardItemModel(3,FixedColumnCount,this);  // Data model initialization
    selection = new QItemSelectionModel(model);               // Item selection model

    // Set data model for TableView
    ui->tableView->setModel(model);               // Set data model
    ui->tableView->setSelectionModel(selection);  // Set selection model

    // All Action options are disabled by default, leaving only open
    ui->actionSave->setEnabled(false);
    ui->actionView->setEnabled(false);
    ui->actionAppend->setEnabled(false);
    ui->actionDelete->setEnabled(false);
    ui->actionInsert->setEnabled(false);

    // Create a status bar component to display cell positions
    LabCurFile = new QLabel("Current file:",this);
    LabCurFile->setMinimumWidth(200);

    LabCellPos = new QLabel("Current cell:",this);
    LabCellPos->setMinimumWidth(180);
    LabCellPos->setAlignment(Qt::AlignHCenter);

    LabCellText = new QLabel("Cell content:",this);
    LabCellText->setMinimumWidth(150);

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

    //Select the signal and slot when the current cell changes
    connect(selection,SIGNAL(currentChanged(QModelIndex,QModelIndex)),this,SLOT(on_currentChanged(QModelIndex,QModelIndex)));
}

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

When initializing, you need to bind an on at the same time_ Current changed (qmodelandex, qmodelandex) signal, when the user selects the specified cell, the corresponding user.

// Select the response when the cell changes, and trigger it by binding the signal and slot function in the constructor
// https://www.cnblogs.com/lyshark
void MainWindow::on_currentChanged(const QModelIndex &current, const QModelIndex &previous)
{
   Q_UNUSED(previous);

    if (current.isValid()) //The current model index is valid
    {
        LabCellPos->setText(QString::asprintf("Current cell:%d that 's ok,%d column",current.row(),current.column())); //Displays the row and column numbers of the model index
        QStandardItem   *aItem;
        aItem=model->itemFromIndex(current); //Get Item from model index
        this->LabCellText->setText("Cell content:"+aItem->text()); //Displays the text content of the item
    }
}

When the page is initialized, the default interface is as follows:


Open and fill components: triggered when the open file in the toolbar is clicked. When the file is opened, it is opened through aFile.open, the file is read in circularly, and the contents of the file are added to QStringList fFileContent line by line. When the addition is completed, iniModelFromStringList(fFileContent) is called directly; Complete the initialization of the page TableView component, and set the status of other controls to clickable.

void MainWindow::on_actionOpen_triggered()
{
    QString curPath=QCoreApplication::applicationDirPath(); // Gets the path of the application
    
    // Call the open file dialog box to open a file
    // https://www.cnblogs.com/lyshark
    QString aFileName=QFileDialog::getOpenFileName(this,"Open a file",curPath,"data file(*.txt);;All documents(*.*)");
    if (aFileName.isEmpty())
    {
        return; // If no file is selected, exit
    }

    QStringList fFileContent;                              // File content string list
    QFile aFile(aFileName);                                // Read as file
    if (aFile.open(QIODevice::ReadOnly | QIODevice::Text)) // Open file as read-only text
    {
        QTextStream aStream(&aFile);       // Read file with text stream
        ui->plainTextEdit->clear();        // clear list 

        // Loop read as long as it is not empty
        while (!aStream.atEnd())
        {
            QString str=aStream.readLine();          // Read one line of the file
            ui->plainTextEdit->appendPlainText(str); // Add to text box display
            fFileContent.append(str);                // Add to StringList
        }
        aFile.close();                               // Close file

        iniModelFromStringList(fFileContent);        // Initialize the data model from the contents of the StringList
    }

    // After opening the file, you can open all actions
    ui->actionSave->setEnabled(true);
    ui->actionView->setEnabled(true);
    ui->actionAppend->setEnabled(true);
    ui->actionDelete->setEnabled(true);
    ui->actionInsert->setEnabled(true);

    // After opening the file successfully, set the current file column of the status bar
    this->LabCurFile->setText("Current file:"+aFileName);//Status bar display
}

As above, iniModelFromStringList(fFileContent); The function is added later. We need to implement it ourselves. The function is used to obtain data from the incoming StringList and initialize the data into the TableView model. The implementation code is as follows.

void MainWindow::iniModelFromStringList(QStringList& aFileContent)
{
    int rowCnt=aFileContent.count();     // Number of text lines, line 1 is the title
    model->setRowCount(rowCnt-1);        // The number of actual data rows, minus 1 from the title

    // Set header
    QString header=aFileContent.at(0);         // Line 1 is the header

    // A string separated by one or more spaces, tabs, etc. is decomposed into a StringList
    // https://www.cnblogs.com/lyshark
    QStringList headerList=header.split(QRegExp("\\s+"),QString::SkipEmptyParts);
    model->setHorizontalHeaderLabels(headerList); // Set header text

    // Set data in table
    int x = 0,y = 0;
    QStandardItem *Item;

    // Cycle as many times as there are columns of data
    // https://www.cnblogs.com/lyshark
    for(x=1; x < rowCnt; x++)
    {
        QString LineText = aFileContent.at(x);    // Gets a row in the data area

        // A string separated by one or more spaces, tabs, etc. is decomposed into a StringList
        QStringList tmpList=LineText.split(QRegExp("\\s+"),QString::SkipEmptyParts);

        // The number of circular columns, that is, the circular FixedColumnCount, in which the content in tmpList is also
        for(y=0; y < FixedColumnCount-1; y++)
        {
            Item = new QStandardItem(tmpList.at(y)); // Create item
            model->setItem(x-1,y,Item);              // Set Item for a row / column position of the model
        }

        // The last data needs to be taken out for judgment and set the status separately
        Item=new QStandardItem(headerList.at(y));   // The last column is Checkable, which needs to be set
        Item->setCheckable(true);                   // Set to Checkable

        // Judge whether the last value is 0
        if (tmpList.at(y) == "0")
            Item->setCheckState(Qt::Unchecked);   // Set check status according to data
        else
            Item->setCheckState(Qt::Checked);

        model->setItem(x-1,y,Item); //Set Item for a row / column position of the model
    }
}

After initializing the component, the effect is as follows:


Add a row of data: add a row of data for TableView and insert it at the end of the file.

void MainWindow::on_actionAppend_triggered()
{
    QList<QStandardItem *> ItemList;   // Create temporary container
    QStandardItem *Item;

    // Simulate adding a column of data
    for(int x=0; x<FixedColumnCount-1; x++)
    {
        Item = new QStandardItem("test(Append row)");    // Cycle through each column
        ItemList << Item;                          // Add to linked list
    }

    // Create the last column element. Because it is a selection box, it needs to be created separately
    // https://www.cnblogs.com/lyshark
    // 1. Get the header subscript of the last column, and the last subscript is 6
    QString str = model->headerData(model->columnCount()-1,Qt::Horizontal,Qt::DisplayRole).toString();

    Item=new QStandardItem(str); // Create "qualified" field
    Item->setCheckable(true);    // Set status to true
    ItemList << Item;            // The last option is appended

    model->insertRow(model->rowCount(),ItemList);                 // Insert a row, and the Item of each Cell is required
    QModelIndex curIndex=model->index(model->rowCount()-1,0);     // Create the ModelIndex of the last row

    selection->clearSelection();                                      // Clear the currently selected item
    selection->setCurrentIndex(curIndex,QItemSelectionModel::Select); // Sets the currently selected item as the currently selected row
}

Insert code to demonstrate the effect:


Insert a row of data: insert a row of data for TableView (insert data anywhere in the file)

// https://www.cnblogs.com/lyshark
void MainWindow::on_actionInsert_triggered()
{
    QList<QStandardItem*> ItemList;       // List class of QStandardItem
    QStandardItem *Item;

    // Simulate inserting the first five columns of data
    for(int i=0;i<FixedColumnCount-1;i++)
    {
        Item= new QStandardItem("test(Insert row)");  // Create a new QStandardItem
        ItemList << Item;                        // Add to list class
    }

    QString str;                               // Get header text
    str=model->headerData(model->columnCount()-1,Qt::Horizontal,Qt::DisplayRole).toString();
    Item=new QStandardItem(str);      // Create Item
    Item->setCheckable(true);         // Set to use CheckBox
    ItemList<<Item;                   // Add to list class

    QModelIndex curIndex=selection->currentIndex(); // Gets the index of the currently selected item
    model->insertRow(curIndex.row(),ItemList);      // Inserts a row before the current row
    selection->clearSelection();                                       // Clear the currently selected item
    selection->setCurrentIndex(curIndex,QItemSelectionModel::Select);  // Sets the currently selected item as the currently selected row
}

Insert code to demonstrate the effect:


To delete a row of data: before deleting data, you need to determine the currently selected row through selection - > currentindex() and remove it through model - > removerrow().

// https://www.cnblogs.com/lyshark
void MainWindow::on_actionDelete_triggered()
{
    QModelIndex curIndex = selection->currentIndex();  // Gets the model index of the currently selected cell

    // First judge whether it is the last line
    if (curIndex.row()==model->rowCount()-1)
    {
        model->removeRow(curIndex.row()); //Delete last line
    }
    else
    {
        model->removeRow(curIndex.row());//Deletes a row and resets the currently selected row
        selection->setCurrentIndex(curIndex,QItemSelectionModel::Select);
    }
}

Delete code effect demonstration:


Realize font data alignment: the fonts in the table can be aligned in a variety of ways. The alignment methods are divided into center alignment, left alignment and right alignment.

// Set table center alignment
void MainWindow::on_pushButton_clicked()
{
    if (!selection->hasSelection())
        return;

    QModelIndexList selectedIndex=selection->selectedIndexes();

    QModelIndex Index;
    QStandardItem *Item;

    for (int i=0; i<selectedIndex.count(); i++)
    {
        Index=selectedIndex.at(i);
        Item=model->itemFromIndex(Index);
        Item->setTextAlignment(Qt::AlignHCenter);
    }
}

// Set table left alignment
// https://www.cnblogs.com/lyshark
void MainWindow::on_pushButton_2_clicked()
{
    if (!selection->hasSelection()) //No items selected
        return;

//Gets the model index list of the selected cell, which can be multiple
    QModelIndexList selectedIndex=selection->selectedIndexes();

    for (int i=0;i<selectedIndex.count();i++)
    {
        QModelIndex aIndex=selectedIndex.at(i); //Gets one of the model indexes
        QStandardItem* aItem=model->itemFromIndex(aIndex);//Gets the item data object of a cell
        aItem->setTextAlignment(Qt::AlignLeft);//Set text alignment
    }
}

// Set table right alignment
void MainWindow::on_pushButton_3_clicked()
{
    if (!selection->hasSelection())
        return;

    QModelIndexList selectedIndex=selection->selectedIndexes();

    QModelIndex aIndex;
    QStandardItem *aItem;

    for (int i=0;i<selectedIndex.count();i++)
    {
        aIndex=selectedIndex.at(i);
        aItem=model->itemFromIndex(aIndex);
        aItem->setTextAlignment(Qt::AlignRight);
    }
}

Alignment code effect demonstration:


Bold font data: bold the font of the selected line.

// Set font bold display
// https://www.cnblogs.com/lyshark
void MainWindow::on_pushButton_4_clicked()
{
    if (!selection->hasSelection())
        return;

//Gets the list of model indexes for the selected cell
    QModelIndexList selectedIndex=selection->selectedIndexes();

    for (int i=0;i<selectedIndex.count();i++)
    {
        QModelIndex aIndex=selectedIndex.at(i); //Get a model index
        QStandardItem* aItem=model->itemFromIndex(aIndex);//Get item data
        QFont font=aItem->font(); //Get font
        font.setBold(true); //Sets whether the font is bold
        aItem->setFont(font); //Reset font
    }
}

Bold code effect demonstration:


Save file: triggered when the save file is clicked, by facilitating the data in the TableWidget model component, and passing the data through astream < < STR < < "\ n"; Write it down in Notepad.

// https://www.cnblogs.com/lyshark
// [save file]
void MainWindow::on_actionSave_triggered()
{
    QString curPath=QCoreApplication::applicationDirPath(); // Gets the path of the application

    // Call the open file dialog box to select a file
    QString aFileName=QFileDialog::getSaveFileName(this,tr("Select a file"),curPath,"data file(*.txt);;All documents(*.*)");

    if (aFileName.isEmpty()) // If no file is selected, exit directly
        return;

    QFile aFile(aFileName);

    // Open the file by reading, writing and overwriting the original content
    if (!(aFile.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)))
        return;

    QTextStream aStream(&aFile);    // Read file with text stream
    QStandardItem *Item;
    QString str;
    int x = 0,y = 0;

    ui->plainTextEdit->clear();

// Get header text
    for (x=0; x<model->columnCount(); x++)
    {
        Item=model->horizontalHeaderItem(x);     // Get item data in header
        str= str + Item->text() + "\t\t";        // Separated by TAB tabs
    }
    aStream << str << "\n";                      // Line breaks need to be added to the file \ n
    ui->plainTextEdit->appendPlainText(str);

// Get data area text
    for ( x=0; x < model->rowCount(); x++)
    {
        str = "";
        for( y=0; y < model->columnCount()-1; y++)
        {
            Item=model->item(x,y);
            str=str + Item->text() + QString::asprintf("\t\t");
        }

        // The last column needs to be converted. If it is judged to be selected, write 1; otherwise, write 0
        Item=model->item(x,y);
        if (Item->checkState()==Qt::Checked)
            str= str + "1";
        else
            str= str + "0";

         ui->plainTextEdit->appendPlainText(str);
         aStream << str << "\n";
    }
}

// [export Txt file]: export the data in TableView to PlainTextEdit display
void MainWindow::on_actionView_triggered()
{
        ui->plainTextEdit->clear();
        QStandardItem *Item;
        QString str;

    //Get header text
        int x=0,y=0;
        for (x=0; x<model->columnCount(); x++)
        { //
            Item=model->horizontalHeaderItem(x);
            str= str + Item->text() + "\t";
        }
        ui->plainTextEdit->appendPlainText(str);

    //Gets each row of the data area
        for (x=0; x<model->rowCount(); x++)
        {
            str="";
            for(y=0; y<model->columnCount()-1; y++)
            {
                Item=model->item(x,y);
                str= str + Item->text() + QString::asprintf("\t");
            }

            Item=model->item(x,y);
            if (Item->checkState()==Qt::Checked)
                str= str + "1";
            else
                str= str + "0";

             ui->plainTextEdit->appendPlainText(str);
        }
}

The file is saved as follows: