读Qt示例之Modbus Master example(一)

读Qt示例之Modbus Master example(一)

本示例来自于Qt5.6.2

本篇主要看WriteRegisterModel这个模型类是怎么实现的
涉及知识点主要是model/view中的model
读Qt示例之Modbus Master example(一)_第1张图片

WriteRegisterModel有四个变量

public:
    int m_number;            //读写的个数
    int m_address;           //读写的起始位置
    QBitArray m_coils;          //Coils
    QVector m_holdingRegisters;//HoldlingRegister

Modbus 一共有四组变量,其中可写的是 Coils,HoldingRegisters
该示例每组变量一共有10个值,m_address是起始位置,m_number是从起始位置开始读几个。

实现只读功能

该模型是二维的,因此除了构造函数以外,只需要实现三个函数:rowCount(),columnCount()和data()函数。如果是字符串列表那样一维的,则只需实现rowCount()和data()函数。如果模型是树状图那样的层次结构,还需要实现index()和parent()函数.
其中rowCount(),columnCount()返回模型的行列数,data()返回指定模型索引的数据项。
也可以实现headerData()函数,它是显示表头的。

先看看构造函数

WriteRegisterModel::WriteRegisterModel(QObject *parent)
    : QAbstractTableModel(parent),
      m_coils(RowCount, false), m_holdingRegisters(RowCount, 0u)
{
}

还有rowCount(),columnCount()

int WriteRegisterModel::rowCount(const QModelIndex &/*parent*/) const
{
    return RowCount;
}

int WriteRegisterModel::columnCount(const QModelIndex &/*parent*/) const
{
    return ColumnCount;
}

这几个没啥好说的
data()函数:

QVariant WriteRegisterModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || index.row() >= RowCount || index.column() >= ColumnCount)
        return QVariant();//要求索引有效,行列号在大小范围之内

    Q_ASSERT(m_coils.count() == RowCount);
    Q_ASSERT(m_holdingRegisters.count() == RowCount);

    if (index.column() == NumColumn && role == Qt::DisplayRole)//NumColumn被枚举为0
        return QString::number(index.row());//第一列返回行号

    if (index.column() == CoilsColumn && role == Qt::CheckStateRole) // coils
        return m_coils.at(index.row()) ? Qt::Checked : Qt::Unchecked;//返回是否被选中(at返回该位置的值)

    else if (index.column() == HoldingColumn && role == Qt::DisplayRole) //holding registers
        return QString("0x%1").arg(QString::number(m_holdingRegisters.at(index.row()), 16));//以十六进制返回指定位置的值

    return QVariant();

}

headerData()函数:

QVariant WriteRegisterModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role != Qt::DisplayRole)
        return QVariant();

    if (orientation == Qt::Horizontal) {
        switch (section) {
        case NumColumn:
            return QStringLiteral("#");
        case CoilsColumn:
            return QStringLiteral("Coils  ");
        case HoldingColumn:
            return QStringLiteral("Holding Registers");
        default:
            break;
        }
    }
    return QVariant();
}

添加写功能

为了使模型可编辑,需要另外两个函数flags()和setData()
flags():

Qt::ItemFlags WriteRegisterModel::flags(const QModelIndex &index) const
{
    if (!index.isValid() || index.row() >= RowCount || index.column() >= ColumnCount)
        return QAbstractTableModel::flags(index);

    Qt::ItemFlags flags = QAbstractTableModel::flags(index);
    if ((index.row() < m_address) || (index.row() >= (m_address + m_number)))//如果index小于起始位置,大于结束位置,则返回0
        flags &= ~Qt::ItemIsEnabled;//?不懂返回为什么这么写?

    if (index.column() == CoilsColumn) //coils
        return flags | Qt::ItemIsUserCheckable;
    if (index.column() == HoldingColumn) //holding registers
        return flags | Qt::ItemIsEditable;

    return flags;
}

委托在创建编辑器以前会检测项目是否是可编辑的,模型必须让委托知道它的项目是可编辑的,这里为模型中的每一个项目返回一个正确的标识来达到这个目的。
setData():

bool WriteRegisterModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!index.isValid() ||  index.row() >= RowCount || index.column() >= ColumnCount)
        return false;

    Q_ASSERT(m_coils.count() == RowCount);//如果()里为0,返回警告
    Q_ASSERT(m_holdingRegisters.count() == RowCount);

    if (index.column() == CoilsColumn && role == Qt::CheckStateRole) { // coils
        auto s = static_cast(value.toUInt());//?这里的类型转换为什么要这样?
        s == Qt::Checked ? m_coils.setBit(index.row()) : m_coils.clearBit(index.row());
        emit dataChanged(index, index);
        return true;
    }

    if (index.column() == HoldingColumn && Qt::EditRole) { // holding registers
        bool result = false;
        quint16 newValue = value.toString().toUShort(&result, 16);//?还有这里?
        if (result)
            m_holdingRegisters[index.row()] = newValue;

        emit dataChanged(index, index);
        return result;
    }

    return false;
}

注意,我们并不需要知道委托是怎样执行真正的编辑操作的,而只需要为委托向模型中设置一条途径,这个是通过setData()函数实现的(个人理解,这里不需要知道是怎样执行的是指:比如我没有找到setData函数被调用的地方,应该就是这种吧)
当数据被设置后,模型必须让视图知道有数据已经改变了,这就是最后都有个emit dataChanged(index, index);的意义

setData函数就是给这个item设置一个QVariant的值,但是,这个函数有两个参数,第一个QVariant自然是需要设置的值,另一个是一个int型数据,Qt中把这个称为role角色,所谓角色,是指设定进item的这个Qvariant所扮演的角色,实际就是对设定值的标定,因为item可以设置许多值,这就需要一个用以区分的标志,这个区分标志就叫角色。

你可能感兴趣的:(Qt)