QAbstractTableModel使用详解&数据单条更新&整体更新

1、入门

实现一个最简单的model需要实现如下函数

//QTableView使用model的时候,根据这个函数获取表格有多少行。
virtual int    rowCount(const QModelIndex & parent = QModelIndex()) const;  
//QTableView使用model的时候,根据这个函数获取表格有多少列。
virtual int columnCount(const QModelIndex & parent = QModelIndex()) const;
//QTableView使用model的时候,根据这个函数获取单元格的数据。
virtual QVariant    data(const QModelIndex & index, int role = Qt::DisplayRole) const;
//QTableView使用model的时候,根据这个函数获取表头的数据,自己可以实现水平表头和垂直表头数据。
virtual QVariant    headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;

model实现完成之后,设置给QTableView,假设 QTableView *table = new QTableView;

CustomTableModel * model = New CustomTableModel(table);
table->setModel(model);

//想table好看点就需要做一些设置,列举一点,根据需要自己选用
table->verticalHeader()->setVisible(false);    //设置垂直表头不可见
table->setEditTriggers(QAbstractItemView::AllEditTriggers);    //任意动作都可出发编辑
table->resizeColumnsToContents();    //设置表格的列宽以内容宽度为准
table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);    //设置表头可拉伸,这样的话会填充整个画面可填充宽度。

2、进阶

数据的整体更新,单条更新,单条插入,单条删除等,参考代码如下。

想更新的时候,就直接调用model接口就行

QList<CustomTableItem> list = ;    //你需要更新的 items
model->updateAllItems(list);

CustomTableModel.h中的实现如下

写一个最基本的tablemodel给Qtableview用,需要重写如下几个函数。

//自定义数据存储格式,如果数据比较简单,就不需要这个数据结构。
//这里支持四个字段,属性名(strPropertyName),属性值(strPropertyValue),属性值的类型(strPropertyType),属性值的范围(strPropertyRange)。
struct CustomTableItem
{
    CustomTableItem(const QString &_strName, const QVariant &_strValue, const QString &_strType, const QString &_strRange)
:strPropertyName(_strName),strPropertyValue(_strValue),strPropertyType(_strType),strPropertyRange(_strRange)
    QString strPropertyName;
    QString strPropertyValue;
    QString strPropertyType;
    QString strPropertyRange;
};

class CustomTableModel :public QAbstractTableModel
{
    Q_OBJECT
public:
    enum CustomColumn {
        CustomColumn_PropertyName = 0,
        CustomColumn_PropertyValue,
    }
    enum CustomRole {
        CustomRole_PropertyType = Qt::DisplayRole + 300,//只要不与Qt重复即可
        CustomRole_PropertyType = Qt::DisplayRole + 301,
    }

    CustomTableModel(QObject *parent);
    ~CustomTableModel();

    //来自QAbstractTableModel的父类QAbstractItemModel的几个虚函数需要实现

    //QTableView使用model的时候,根据这个函数获取表格有多少行。
    virtual int	rowCount(const QModelIndex & parent = QModelIndex()) const;  
  
     //QTableView使用model的时候,根据这个函数获取表格有多少列。
    virtual int columnCount(const QModelIndex & parent = QModelIndex()) const; 

     //QTableView使用model的时候,根据这个函数获取单元格的数据。
    virtual QVariant	data(const QModelIndex & index, int role = Qt::DisplayRole) const;

    //QTableView使用model的时候,根据这个函数获取表头的数据,自己可以实现水平表头和垂直表头数据。
    virtual QVariant	headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;

    //这个是可选函数,如果表格使用了渲染即delegate,那么这个函数可以设置哪一些行列可以编辑。
    virtual Qt::ItemFlags	flags(const QModelIndex & index) const;


    //自定义函数
    //更新所有数据,假设传入的数据就是和model定义的数据相同,这里不同也没关系,可以自己在函数里面写解析数据就行。
    void updateAllItems(const QList<CustomTableItem> &allitems);
    //更新单条数据,分为三种,插入,删除,更新
    void insertSingleItem(const QModelIndex &index,const CustomTableItem &item) ;   //插入
    void deleteSingleItem(const QModelIndex &index,const CustomTableItem &item) ;   //删除
    void updateSingleItem(const QModelIndex &index,const CustomTableItem &item) ;   //更新

private:
    QList<CustomTableItem> m_data;    //数据
    QStringList m_horizontalHeader;    //自定义水平表头,有需要才定义
    QStringList m_verticalHeader;        //自定义水平表头,有需要才定义

};

CustomTableModel.cpp中的实现如下

//函数的作用这里不细说了,在CustomTableModel.h文件里面已经有说明了

CustomTableModel::CustomTableModel(QObject *parent):QAbstractTableModel(parent)
{
    //水平表头追加内容,加了两列
    m_horizontalHeader << tr("元件属性名") << tr("元件属性值");
    //垂直表头类似,自己可以加,此处我就不加了
    //m_verticalHeader<< tr("xxxxx") << tr("xxxxx");
}

CustomTableModel::~CustomTableModel() {}


//QTableView使用model的时候,根据这个函数获取表格有多少行。
int	CustomTableModel::rowCount(const QModelIndex & parent /*= QModelIndex()*/) const
{
    return m_data.count();
} 
  
//QTableView使用model的时候,根据这个函数获取表格有多少列。
int CustomTableModel::columnCount(const QModelIndex & parent = QModelIndex()) const
{
    return m_horizontalHeader.count();
}

//QTableView使用model的时候,根据这个函数获取单元格的数据。
QVariant	CustomTableModel::data(const QModelIndex & index, int role /*= Qt::DisplayRole*/) const
{
    if(!index.isValid()) {
        return QVariant();
    }

    int row = index.row();
    if(row < m_data.count()) {
        if(Qt::DisplayRole == role || Qt::EditRole == role) {    //可以根据role和index的行列返回需要的值,比如这些值不需要显示
            switch(index.column()) {
            case CustomColumn_PropertyName:
                return m_data[row].strPropertyName;
            case CustomColumn_PropertyValue:
                return m_data[row].strPropertyValue;
            default:
                return QVariant();
            }
        } else if(CustomRole_PropertyType == role) {    //可以根据role不同返回需要的值,比如这些值不需要显示
            return m_data[row].strPropertyType;
        } else if(CustomRole_PropertyRange == role) {    //可以根据role不同返回需要的值,比如这些值不需要显示
            return m_data[row].strPropertyRange;
        }
        
    }
    return QVariant();
}

//QTableView使用model的时候,根据这个函数获取表头的数据,自己可以实现水平表头和垂直表头数据。
QVariant	CustomTableModel::headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const
{
    if(orientation == Qt::Horizontal) {    //水平表头
        if(Qt::DisplayRole == role && section < m_horizontalHeader.count()) {
            return m_horizontalHeader[section];
        }
    } else if(orientation == Qt::Vertical) {
        //操作差不多,返回垂直表头,如果需要的话
    }
    return QAbstractTableModel::headerData(section,orientation,role);
}

//这个是可选函数,如果表格使用了渲染即delegate,那么这个函数可以设置哪一些行列可以编辑。
Qt::ItemFlags	CustomTableModel::flags(const QModelIndex & index) const
{
     if(!index.isValid()) {
        return QVariant();
    }
     if(index.column() == CustomColumn_PropertyValue) {    //设置只有value行可以编辑
        return Qt::ItemIsEnabled|Qt::ItemIsSelectable|Qt::ItemIsEditable;
    }
    return QAbstractTableModel::flags(index);
}


//自定义函数
//更新所有数据,假设传入的数据就是和model定义的数据相同,这里不同也没关系,可以自己在函数里面写解析数据就行。
void CustomTableModel::updateAllItems(const QList<CustomTableItem> &allitems)
{
    //修改数据前后,用beginResetModel()和endResetModel()。
    beginResetModel();    //通过这个告诉我要开始修改model了
    if(!index.isValid()) {
        return;
    }
    m_data.clear();
     for (int i = 0;i < allitems.count();++i) {
        m_data.append(allitems[i]);
    }
    endResetModel();    //通过这个告诉我修改model结束了
}
//更新单条数据,分为三种,插入,删除,更新
void CustomTableModel::insertSingleItem(const QModelIndex &index,const CustomTableItem &item)   //插入
{
    //插入行前后,使用beginInsertRows()和endInsertRows(),与之相同,列也是类似,插入列前后,使用beginInsertColumns()和endInsertColumns()。不过实现复杂一点
    if(!index.isValid()) {
        return;
    }
    beginInsertRows();
    m_data.insert(index.row(),item);
    endInsertRows();
}
void CustomTableModel::deleteSingleItem(const QModelIndex &index,const CustomTableItem &item)   //删除
{
    
    //删除行前后,使用beginRemoveRows()和endRemoveRows(),与之类似,删除列前后,使用beginRemoveColumns()和endRemoveColumns()。
    if(!index.isValid()) {
        return;
    }
    beginRemoveRows();
    m_data.removeAt(index.row());
    endRemoveRows();
}

void CustomTableModel::updateSingleItem(const QModelIndex &index,const CustomTableItem &item)    //更新
{
    if(!index.isValid()) {
        return;
    }
    m_data.replace(index.row(),item);
    emit dataChanged(index.sibling(index.row(),0),index.sibling(index.row(),columnCount());    //这句话告诉框架我改数据了,他会去刷新
}

使用 AbstractTableModel 构建Table 在表格中添加JButton按钮,之前在网上找了2天没有找到好用的程序,最终终于找到一个好用的例子。 不要使,我退你们分。。 sing the Swing JTable class can quickly become a sticky business when you want to customize it to your specific needs. First you must become familiar with how the JTable class is organized. Individual cells are rendered by TableCellRenderer implementations. The table contents are represented by an implementation of the TableModel interface. By default, JTable uses DefaultTableCellRenderer to draw its cells. DefaultTableCellRenderer recognizes a few primitive types, rendering them as strings, and can even display Boolean types as checkboxes. But it defaults to displaying the value returned by toString() for types it does not specifically handle. You have to provide your own TableCellRenderer implementation if you want to display buttons in a JTable. The TableCellRenderer interface contains only one method, getTableCellRendererComponent(...), which returns a java.awt.Component that knows how to draw the contents of a specific cell. Usually, getTableCellRendererComponent() will return the same component for every cell of a column, to avoid the unnecessary use of extra memory. But when the contents of a cell is itself a component, it is all right to return that component as the renderer. Therefore, the first step towards having JButtons display correctly in a JTable is to create a TableCellRenderer implementation that returns the JButton contained in the cell being rendered. In the accompanying code listing, JTableButtonRenderer demonstrates how to do this. Even after creating a custom TableCellRenderer, you&#39;re still not done. The TableModel associated with a given JTable does not only keep track of the contents of each cell, but it also keeps track of the class of data stored in each column. DefaultTableModel is designed to work with DefaultTableCellRenderer and will return java.lang.String.class for columns containing data types that it does not specifically handle. The exact method that does this is getColumnClass(int column). Your second step is to create a TableModel implementation that returns JButton.class for cells that contain JButtons. JTableButtonModel shows one way to do this. It just returns the result of getClass() for each piece of cell data. At this point, you&#39;re almost done, but not quite. What&#39;s the use of putting a JButton in a JTable if you can&#39;t press the darn thing? By default, JTable will not forward mouse events to components contained in its cells. If you want to be able to press the buttons you add to JTable, you have to create your own MouseListener that forwards events to the JButton cells. JTableButtonMouseListener demonstrates how you could do this.
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值