读Qt示例之Modbus Master example(一)

来源:互联网 发布:mac上安装apt get 编辑:程序博客网 时间:2024/06/08 05:53

读Qt示例之Modbus Master example(一)

本示例来自于Qt5.6.2

本篇主要看WriteRegisterModel这个模型类是怎么实现的
涉及知识点主要是model/view中的model
Modbus Master示例的界面

WriteRegisterModel有四个变量

public:    int m_number;            //读写的个数    int m_address;           //读写的起始位置    QBitArray m_coils;          //Coils    QVector<quint16> 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<Qt::CheckState>(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可以设置许多值,这就需要一个用以区分的标志,这个区分标志就叫角色。

原创粉丝点击