Qt model / view - a simple example

Posted by *Lynette on Sat, 30 Oct 2021 18:18:41 +0200


This article will describe the relationship between model, view and delegate in Qt and their respective usage through a simple example (variable viewing window in low configuration version).

1 function introduction

This paper imitates the variable view window of IAR and makes a variable view window of low configuration version. The effects are as follows:


There are three columns in the variable view window, corresponding to variable name, variable value and variable value format. After clicking the in the last line, you can enter the variable name. After entering, a line will be added at the end of the variable view window to monitor the variable just entered. When you click and delete a variable name, the variable view window will delete this line.

2 specific implementation

In order to clearly describe the relationship between model, view and delegate, this paper will use custom model, view and delegate to implement variable view window. Because the commonly used variable names actually correspond to the addresses in memory, it is necessary to establish a mapping relationship between variable names and memory addresses, and the display format of variable names also establishes such a mapping relationship:

namespace {
    //Variable name. The variable name in the model is stored in the form of address. Suppose we define the following variables
    constexpr int varColumn[3] = {1000, 2000, 1060};    //Variable address (value actually stored in the model)
    const QString varStr[3] = {QString("click"), QString("size"), QString("volume")};//Variable name used to display
    //The variable value format is edited by using the drop-down box (formatColumn [] is the data actually stored in the model). The data meaning corresponding to the drop-down box, that is, the index 0 of the drop-down box represents hexadecimal
    constexpr int formatColumn[3] = {10, 2, 16};
    const QString formatStr[3] = {QString("10 Base system"), QString("2 Base system"), QString("16 Base system")};
}

Then define three classes in the program: WatchView, WatchDelegate and WatchModel, which are used to realize the functions of view, delegate and model. The following is the implementation of main():

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    WatchView watch;         //view
    WatchDelegate delegate;  //entrust
    WatchModel model;        //Model
    delegate.setTailIndex(model.getTailIndex());  //Delegates need to save the index of the last line of the model < Click to add >
    //When you click < Click to add >, a line of monitoring data will be added to the model
    watch.connect(&delegate, &WatchDelegate::clickToAdd, &model, &WatchModel::appendRow);
    watch.setItemDelegate(&delegate);   //Set custom delegates for views
    watch.setModel(&model);             //Set model for view
    watch.show();

    return a.exec();
}

The following will explain the confusion of these three classes. The complete procedure is attached in the appendix.

View:

View is mainly used to display data items in the model, so its implementation is relatively simple. It only needs to be responsible for the overall layout and rendering of some interfaces:

/*******************************************************************
* Class name: WatchView
* Description: View variables (view)
*******************************************************************/
class WatchView : public QTableView
{
    Q_OBJECT
public:
    //Constructor
    explicit WatchView(QWidget *parent = nullptr):QTableView(parent)
    {
        setEditTriggers(QAbstractItemView::CurrentChanged | //Change or double-click the Trigger Editor
                        QAbstractItemView::DoubleClicked);
        //Simple interface design
        setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); //Display scroll bars as needed
        setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
        setGridStyle(Qt::DashLine);                          //Grid styles within tables
        show();
    }
    //Destructor
    ~WatchView(){}
};

Model:
Model class is used to directly manage data, such as data insertion, deletion, change, etc.. What is difficult to understand in the model is the model index and item role. What do they do? How should model items be structured? Why can different item roles make model items present different values.

entrust:
Delegate provides some special display effects for the data in the model, and is responsible for providing an editor. There is a description about the role of delegation in Qt help document:

Using a delegate for this purpose allows the display and editing mechanisms to be customized and developed independently from the model and view

At the same time, Qt recommends using qstyleditemtdelegate to implement custom delegation:

Note that QStyledItemDelegate has taken over the job of drawing Qt's item views. We recommend the use of QStyledItemDelegate when creating new delegates

Several key virtual functions that need to be overridden for custom delegates:

//Create an editor control for index. Parent is used to specify the parent object of the editor,
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
//
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
//Set data for editor
void setEditorData(QWidget *editor, const QModelIndex &index) const;
//Set data for model items
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
//Update editor size
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index)const;

For the calling sequence and specific functions of these functions, please refer to Custom delegation of QT model view.

reference resources

[1] QAbstractItemModel of Qt series articles
[2] Custom delegation of QT model view

Appendix: complete code

Environmental Science: Qt 5.9.0
 Project Name: watch
 File structure:
watch
   |---------watch.pro
   |---------livewatch.h
   |---------livewatch.cpp
   |---------main.cpp

mian.cpp file:

#include "livewatch.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    WatchView watch;         //view
    WatchDelegate delegate;  //entrust
    WatchModel model;        //Model
    delegate.setTailIndex(model.getTailIndex());  //Delegates need to save the index of the last line of the model < Click to add >
    //When you click < Click to add >, a line of monitoring data will be added to the model
    watch.connect(&delegate, &WatchDelegate::clickToAdd, &model, &WatchModel::appendRow);
    watch.setItemDelegate(&delegate);   //Set custom delegates for views
    watch.setModel(&model);             //Set model for view
    watch.show();

    return a.exec();
}

livewatch.h file:

#ifndef LIVEWATCH_H
#define LIVEWATCH_H

#include <QWidget>
#include <QAbstractItemModel>
#include <QTableView>
#include <QItemDelegate>
#include <QVector>
/*******************************************************************
* Class name: WatchView
* Description: View variables (view)
*******************************************************************/
class WatchView : public QTableView
{
    Q_OBJECT
public:
    //Constructor
    explicit WatchView(QWidget *parent = nullptr):QTableView(parent)
    {
        setEditTriggers(QAbstractItemView::CurrentChanged | //Change or double-click the Trigger Editor
                        QAbstractItemView::DoubleClicked);
        //Simple interface design
        setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); //Display scroll bars as needed
        setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
        setGridStyle(Qt::DashLine);                          //Grid styles within tables
    }
    //Destructor
    ~WatchView(){}
};
/*******************************************************************
* Class name: WatchDelegate
* Description: View variables (delegates)
*******************************************************************/
class WatchDelegate : public QItemDelegate
{
    Q_OBJECT
public:
    explicit WatchDelegate(QObject *parent = 0);
    ~WatchDelegate();
    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const override;
    void setEditorData(QWidget *editor, const QModelIndex &index ) const override;
    void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const override;
    void updateEditorGeometry(QWidget * editor, const QStyleOptionViewItem &option, const QModelIndex &index ) const override;
    void paint(QPainter* painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const override;
    bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index )override;
    void setTailIndex(const QModelIndex &index);             //Set trailing model index
signals:
    void clickToAdd(QString addr) const;                     //Edit the last line to trigger

private:
    //The index of the last row (clickToAdd) of the table. Because it will be used for a long time, QPersistentModelIndex is used
    QPersistentModelIndex *tailIndex;
};

/*******************************************************************
* Class name: WatchModel
* Description: View variables (models)
*******************************************************************/
class WatchModel : public QAbstractItemModel
{
    Q_OBJECT
public:
    enum layout{          //Parameter monitoring interface layout (label position)
        columns = 3,      //Total number of columns
        varPos = 0,       //Variable column position
        valuePos = 1,     //Variable value column position
        formatPos = 2,    //Variable value format column position
    };

    explicit WatchModel(QObject *parent = Q_NULLPTR);    //Constructor
    ~WatchModel();                                       //Destructor

    //Get header information
    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
    //Set header
    bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override;
    // Construct the index of the parent node and the child node
    QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
    // Get parent node index from child node index
    QModelIndex parent(const QModelIndex &child) const override;
    // Gets the number of rows of parent and child nodes
    int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    // Gets the number of child node columns of the parent node
    int columnCount(const QModelIndex &parent = QModelIndex()) const override;
    // Get node data
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    //Set model item data
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
    //Return the model item flag of index (such as editable)
    Qt::ItemFlags flags(const QModelIndex &index) const override;
    //Insert count row data
    bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
    //Delete count row data
    bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
    //Get the index of the last row < Click to add >
    QModelIndex getTailIndex(void) const;

public slots:
    void appendRow(QString name);      //Append a line

protected:
    QString editToDisplay(int row, int column) const;   //Convert Qt::EditRole type to Qt::DisplayRole
    quint16 displayToEdit(QString display, int row = 0, int column = 0) const;//Convert Qt::DisplayRole type to Qt::EditRole

private:
    //The parameter table to be monitored (the last row is reserved for adding rows), which is stored according to Qt::EditRole type.
    QVector<QVector<quint16> > *tab;
    QStringList VHeader;                //Column header

};
#endif // LIVEWATCH_H
/**********************************END OF FILE**********************************/

livewatch.cpp file:

#include "livewatch.h"
#include <QComboBox>
#include <QEvent>
#include <QModelIndex>
#include <QLineEdit>
#include <QDebug>

namespace {
    //Variable name. The variable name in the model is stored in the form of address. Suppose we define the following variables
    constexpr int varColumn[3] = {1000, 2000, 1060};    //Variable address (value actually stored in the model)
    const QString varStr[3] = {QString("click"), QString("size"), QString("volume")};//Variable name
    //The variable value format is edited by the drop-down box (which is also the real data stored in the corresponding model). The data meaning of the drop-down box, that is, the index 0 of the drop-down box represents hexadecimal
    constexpr int formatColumn[3] = {10, 2, 16};
    const QString formatStr[3] = {QString("10 Base system"), QString("2 Base system"), QString("16 Base system")};
}

//------------------------------The following is the implementation of WatchDelegate class------------------------------


/*******************************************************************
 * Function name: MonitorDelegate()
 * Function Description: constructor
 *******************************************************************/
WatchDelegate::WatchDelegate(QObject *parent/* = 0*/)
    :QItemDelegate(parent), tailIndex(Q_NULLPTR)
{

}
/*******************************************************************
 * Function name: ~ MonitorDelegate()
 * Function Description: destructor
 *******************************************************************/
WatchDelegate::~WatchDelegate()
{
    delete tailIndex;
    tailIndex = Q_NULLPTR;
}

/*******************************************************************
 * Function name: createEditor()
 * Function Description: generate editor
 *******************************************************************/
QWidget *WatchDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option,
                                     const QModelIndex &index ) const
{
    if(index.column() == WatchModel::formatPos)//The variable value format column is edited using the drop-down box
    {
        QComboBox *comboBox = new QComboBox(parent);
        comboBox->addItem(formatStr[0], formatColumn[0]);
        comboBox->addItem(formatStr[1], formatColumn[1]);
        comboBox->addItem(formatStr[2], formatColumn[2]);
        return(comboBox);
    }
    else if(index.column() == WatchModel::varPos
            || index.column() == WatchModel::valuePos)
    {   //Variable columns and variable value columns are edited by QLineEdit
        QLineEdit *lineEdit = new QLineEdit(parent);
        return(lineEdit);
    }

    return QItemDelegate::createEditor(parent, option, index);     //The default editor is used for other columns
}
/*******************************************************************
 * Function name: setEditorData()
 * Function Description: extract the data in the model into the editor
 *******************************************************************/
void WatchDelegate::setEditorData(QWidget *editor, const QModelIndex &index ) const
{
    if(index.column() == WatchModel::formatPos)   //Variable value format column
    {
        QComboBox *comboBox = dynamic_cast<QComboBox *>(editor);
        comboBox->setCurrentIndex(comboBox->findData(index.data(Qt::EditRole)));
    }
    else if(index.column() == WatchModel::varPos
            || index.column() == WatchModel::valuePos) //Variable columns and variable value format columns
    {
        QLineEdit *lineEdit = dynamic_cast<QLineEdit*>(editor);
        //If the last line is < Click to add >, the original text will be cleared, otherwise the text content in the index will be obtained normally
        (index != (*tailIndex)) ? lineEdit->setText(index.data(Qt::DisplayRole).toString())    //Last line < clicktoadd >
                                : lineEdit->clear();
    }
    else
        QItemDelegate::setEditorData(editor, index);
}
/*******************************************************************
 * Function name: setModelData()
 * Function Description: set model data
 *******************************************************************/
void WatchDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
                                 const QModelIndex &index ) const
{
    if(index.column() == WatchModel::formatPos)//Variable value format column
    {   //The variable value itself is of type int, so Qt::EditRole is directly used to set the model data to be more open
        QComboBox *comboBox = dynamic_cast<QComboBox *>(editor);
        model->setData(index, comboBox->currentData(), Qt::EditRole);
    }
    else if(index.column() == WatchModel::varPos) //Variable list
    {
        QLineEdit *lineEdit = dynamic_cast<QLineEdit*>(editor);

        if(false == lineEdit->isModified()) return;    //If the content has not changed, return directly

        if(lineEdit->text().isEmpty() && index != (*tailIndex))
        {   //If the content is empty and not the last line, the line is deleted
            model->removeRows(index.row(), 1);
            return;
        }
        //The rest is either not empty or the last line
        if(index != (*tailIndex))
            model->setData(index, lineEdit->text(), Qt::DisplayRole);
        else if(!(lineEdit->text().isEmpty()) )   //The last line may need to be appended
            emit clickToAdd(lineEdit->text());
    }
    else if(index.column() == WatchModel::valuePos)   //Parameter value column
    {   //If the parameter value column is also edited, the parameter may be written
        QLineEdit *lineEdit = dynamic_cast<QLineEdit*>(editor);

        if(false == lineEdit->isModified()) return;    //If the content has not changed, return directly

        WatchModel *monitorModel = dynamic_cast<WatchModel *>(model);
        monitorModel->setData(index, lineEdit->text(), Qt::DisplayRole);
    }
    else
        QItemDelegate::setModelData(editor, model, index);
}
/*******************************************************************
* Function name: updateEditorGeometry()
* Function Description: set editor component size
*******************************************************************/
void WatchDelegate::updateEditorGeometry(QWidget * editor, const QStyleOptionViewItem &option,
                                         const QModelIndex &index ) const
{
    editor->setGeometry(option.rect);
}
/*******************************************************************
 * Function name: paint()
 * Function Description: customize the data display method
 *******************************************************************/
void WatchDelegate::paint(QPainter* painter, const QStyleOptionViewItem &option,
                          const QModelIndex &index ) const
{
    QItemDelegate::paint(painter, option, index);
}
/*******************************************************************
 * Function name: editorEvent()
 * Function Description: Editor event
 *******************************************************************/
bool WatchDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
                                const QStyleOptionViewItem &option, const QModelIndex &index )
{
    return QItemDelegate::editorEvent(event, model, option, index);
}
/*******************************************************************
 * Function name: setTailIndex()
 * Function Description: set tail line model index
 * Function parameter: index - the index of the last line < Click to add > model item
 *******************************************************************/
void WatchDelegate::setTailIndex(const QModelIndex &index)
{
    if(!index.isValid())
        return;

    if(Q_NULLPTR == tailIndex)
        tailIndex = new QPersistentModelIndex();

    (*tailIndex) = index;
}


//------------------------------The following is the implementation of the WatchModel class------------------------------


/*******************************************************************
 * Function name: WatchModel()
 * Function Description: constructor
 *******************************************************************/
WatchModel::WatchModel(QObject *parent/* = Q_NULLPTR*/)
    :QAbstractItemModel(parent), tab{new QVector<QVector<quint16> >()}
{
    VHeader << "variable" << "Value" << "Format";   //Column header

    tab->append(QVector<quint16>(columns));   //Add last line first
}
/*******************************************************************
 * Function name: ~ WatchModel()
 * Function Description: destructor
 *******************************************************************/
WatchModel::~WatchModel()
{
    delete tab;
    tab = Q_NULLPTR;
}

/*******************************************************************
 * Function name: headerData()
 * Function Description: get header information
 *******************************************************************/
QVariant WatchModel::headerData(int section, Qt::Orientation orientation,
                                int role/* = Qt::DisplayRole*/) const
{
    if(role != Qt::DisplayRole)   //Currently, the header only supports Qt::DisplayRole type item roles
        return QVariant();

    if(orientation == Qt::Vertical)
        return QString("%1").arg(section + 1);   //Vertical titles are numbers (starting from 1)
    else
        return VHeader.at(section);              //Horizontal title
}
/*******************************************************************
 * Function name: setHeaderData()
 * Function Description: set header
 *******************************************************************/
bool WatchModel::setHeaderData(int section, Qt::Orientation orientation,
                               const QVariant &value, int role/* = Qt::EditRole*/)
{
    if((role != Qt::EditRole) || (orientation == Qt::Vertical))
        return false;

    VHeader.replace(section, value.toString());
    emit headerDataChanged(orientation, section, section);//Send a change signal after the change
    return true;
}

/*******************************************************************
 * Function name: index()
 * Function Description: returns the indexes of parent nodes and child nodes
 *******************************************************************/
QModelIndex WatchModel::index(int row, int column,
                              const QModelIndex &parent/* = QModelIndex()*/) const
{
    if((row < 0) || (row >= tab->length()) ||
       (column < 0) || column >= columns)
        return QModelIndex();
    //createIndex() is used to create a model index. I was still confused when I saw this function just now:
    //I only provided a row and column number. How can it help me build the model index? This index is
    //To access model items? What does the data look like in the model I designed? Actually write to data()
    //Function, the index is interpreted by the date() function, that is, the model created here
    //The specific meaning of the index should be explained by ourselves.
    return createIndex(row, column);
}
/*******************************************************************
 * Function name: parent()
 * Function Description: obtain the parent node index through the child node index. Because it is a table model, we directly return an invalid node
 *******************************************************************/
QModelIndex WatchModel::parent(const QModelIndex &child) const
{
    return QModelIndex();
}
/*******************************************************************
 * Function name: rowCount()
 * Function Description: get the number of rows of parent nodes and child nodes
 *******************************************************************/
int WatchModel::rowCount(const QModelIndex &parent/* = QModelIndex()*/) const
{
    return tab->length();
}
/*******************************************************************
 * Function name: columnCount()
 * Function Description: gets the number of parent node and child node columns
 *******************************************************************/
int WatchModel::columnCount(const QModelIndex &parent/* = QModelIndex()*/) const
{
    return columns;
}
/*******************************************************************
 * Function name: data()
 * Function Description: get node index data according to item role.
 * Note: this function only supports Qt::EditRole and Qt::DisplayRole,
 * Qt::EditRole is really saved in the model, and Qt::DisplayRole is only provided for view display
 *******************************************************************/
QVariant WatchModel::data(const QModelIndex &index, int role/* = Qt::DisplayRole*/) const
{
    if((!index.isValid()) || (index.row() >= tab->length()) ||
       (index.column() >= columns) || (role != Qt::EditRole && role != Qt::DisplayRole))
        return QVariant();

    if(role == Qt::EditRole)      //Qt::EditRole
        return(tab->at(index.row()).at(index.column()));

    if(index.row() < tab->length() - 1)       //Normally display the rows of variables
        return editToDisplay(index.row(), index.column());
    else if(index.row() == (tab->length() - 1) && index.column() == varPos)   //Display of the last line < Click to add >
        return(QString("<click to add>"));
    else if(index.row() == (tab->length() - 1) && index.column() != varPos)   //Last line
        return(QString(""));
    else
        return QVariant();
}
/*******************************************************************
 * Function name: WatchModel::setData()
 * Function Description: set model item data
 *******************************************************************/
bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int role/* = Qt::EditRole*/)
{
    quint16 data;        //Data to be saved

    if((!index.isValid()) || (index.row() >= tab->length()) ||
       (index.column() >= columns) )
        return false;

    if(role == Qt::EditRole)
    {   //Qt::EditRole type can be stored directly
        data = value.toUInt();
        (*tab)[index.row()].replace(index.column(), data);
    }
    else if(role == Qt::DisplayRole)
    {   //Convert Qt::DisplayRole to Qt::EditRole type in
        data = displayToEdit(value.toString(), index.row(), index.column() );
        (*tab)[index.row()].replace(index.column(), data);
    }
    else
        return false;
    //After modification, be sure to send the dataChanged() signal
    emit dataChanged(index, index, QVector<int>() << role);
    return true;
}
/*******************************************************************
 * Function name: flags()
 * Function Description: returns the model item flag of index (such as editable)
 *******************************************************************/
Qt::ItemFlags WatchModel::flags(const QModelIndex &index) const
{
    if((!index.isValid()) || (index.row() >= tab->length()) ||
       (index.column() >= columns) )
        return Qt::NoItemFlags;

    if((index.row() == tab->length() - 1) && index.column() != varPos)
        return (Qt::NoItemFlags | Qt::ItemIsSelectable);    //The last line cannot be edited except the 0 th element
    //Except the last row, the data of other rows can be edited
    return (QAbstractItemModel::flags(index) | Qt::ItemIsEditable);
}
/*******************************************************************
 * Function name: insertRows()
 * Function Description: insert count row data, return true if successful, and false if failed
 * If row is 0, the rows are prepended to any existing rows in the parent.
 * If row is rowCount(), the rows are appended to any existing rows in the parent.
 *******************************************************************/
bool WatchModel::insertRows(int row, int count, const QModelIndex &parent/* = QModelIndex()*/)
{
    QVector<quint16> rowData(columns);   //Default row to insert

    if(row < 0 || row > tab->length() || count < 1)
        return false;

    rowData[varPos] = varColumn[0];
    rowData[valuePos] = 0;
    rowData[formatPos] = formatColumn[0];

    beginInsertRows(parent, row, row + count - 1);
    for(int i = 0; i < count; ++i)
        tab->insert(row, rowData);
    endInsertRows();     //beginInsertRows(),endInsertRows() must be used together, or the program will crash

    return true;
}
/*******************************************************************
 * Function name: removeRows()
 * Function Description: when deleting count row data, true is returned for success, and false is returned for failure
 * Note that this function will not delete the last line, and < Click to add > cannot be deleted
 *******************************************************************/
bool WatchModel::removeRows(int row, int count, const QModelIndex &parent/* = QModelIndex()*/)
{
    if(row < 0 || row > tab->length() || count < 1)
        return false;

    if(row + count >= tab->length())    //Check whether the deletion range has exceeded the total length
        count = tab->length() - row - 1;//The last line cannot be deleted

    if(count <= 0) return false;

    beginRemoveRows(parent, row, row + count - 1);
    tab->remove(row, count);
    endRemoveRows();     //beginRemoveRows(), endRemoveRows() must be used together, or the program will crash

    return true;
}
/*******************************************************************
 * Function name: getTailIndex()
 * Function Description: get the index of the last line < Click to add >
 *******************************************************************/
QModelIndex WatchModel::getTailIndex(void) const
{
    int row = 0;

    if(!tab->isEmpty()) row = tab->length() - 1;
    return index(row, varPos, QModelIndex());
}
/*******************************************************************
 * Function name: appendRow()
 * Function Description: slot function, add a line
 * Function parameter: var - variable name
 *******************************************************************/
void WatchModel::appendRow(QString name)
{
    int row = 0;
    QModelIndex i;    //New row, index of varPos column
    if(!tab->isEmpty()) row = tab->length() - 1;
    insertRows(row, 1);
    i = index(row, varPos);
    setData(i, name, Qt::DisplayRole);
}
/*******************************************************************
 * Function name: editToDisplay()
 * Function Description: change Qt::EditRole type to Qt::DisplayRole.
 *          Convert the model items in row and column of tab to Qt::DisplayRole type
 *******************************************************************/
QString WatchModel::editToDisplay(int row, int column) const
{
    if(row < 0 || row >= tab->length() || column >= columns || column < 0)
        return QString();

    if(column == varPos)    //Variable name
    {
        switch(tab->at(row).at(varPos))
        {
        case varColumn[0]:return varStr[0];
        case varColumn[1]:return varStr[1];
        case varColumn[2]:return varStr[2];
        default:return QString();
        }
    }
    if(column == valuePos)  //Variable value
    {
        if((*tab)[row].at(formatPos) == formatColumn[0] ||
           (*tab)[row].at(formatPos) == formatColumn[1] ||
           (*tab)[row].at(formatPos) == formatColumn[2] )
            return( QString::number((*tab)[row].at(valuePos), (*tab)[row].at(formatPos)) );
    }
    if(column == formatPos)  //Variable format
    {
        switch(tab->at(row).at(formatPos))
        {
        case formatColumn[0]:return formatStr[0];
        case formatColumn[1]:return formatStr[1];
        case formatColumn[2]:return formatStr[2];
        default:return QString();
        }
    }
    return QString();
}
/*******************************************************************
 * Function name: displayToEdit()
 * Function Description: change Qt::DisplayRole type to Qt::EditRole
 *           tab The model items in row and column are displayed as display. This function can convert them to the corresponding Qt::EditRole type
 *******************************************************************/
quint16 WatchModel::displayToEdit(QString display, int row/* = 0*/,
                                  int column/* = 0*/) const
{
    if(row < 0 || row >= tab->length() || column >= columns || column < 0)
        return 0;

    if(column == varPos)    //Parameter address
    {
        if(display == varStr[0]) return(varColumn[0]);
        if(display == varStr[1]) return(varColumn[1]);
        if(display == varStr[2]) return(varColumn[2]);
    }


    if(column == valuePos)     //Parameter value
    {
        if((*tab)[row].at(formatPos) == formatColumn[0] || 
           (*tab)[row].at(formatPos) == formatColumn[1] ||
           (*tab)[row].at(formatPos) == formatColumn[2] )
            return( display.toInt(Q_NULLPTR, (*tab)[row].at(formatPos)) );
    }

    if(column == formatPos)    //Parameter format
    {
        if(display == formatStr[0]) return(formatColumn[0]);
        if(display == formatStr[1]) return(formatColumn[1]);
        if(display == formatStr[2]) return(formatColumn[2]);
    }

    return 0;
}

/**********************************END OF FILE**********************************/

Topics: Qt