QAbstractTableModel 和委托的结合使用

来源:互联网 发布:张伯伦生涯场均数据 编辑:程序博客网 时间:2024/06/05 11:04


分析QAbstractTableModel 和委托的结合使用,自制一个复选框,并进行点击和数据的更新。


图片的展示效果图如下


#ifndef TABLEMODEL_H

#define TABLEMODEL_H
#include <QString>
#include <QAbstractTableModel>
#include <QList>
struct FileRecord
{
   bool bChecked;
   QString strFilePath;
};


class TableModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    explicit TableModel(QObject *parent = 0);
    ~TableModel();
    Qt::ItemFlags flags(const QModelIndex &index) const;
    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
    QVariant data(const QModelIndex &index, int role) const;
    bool setData(const QModelIndex &index, const QVariant &value, int role);
    int columnCount(const QModelIndex &parent) const;
    int rowCount(const QModelIndex &parent) const;
    void updateData(QList<FileRecord> recordList);


signals:


public slots:
private:
    QList<FileRecord> m_recordList;




};


#endif // TABLEMODEL_H


#include "tablemodel.h"
#include <QColor>
#include <QDebug>
#define CHECK_BOX_COLUMN 0
#define File_PATH_COLUMN 1
TableModel::TableModel(QObject *parent)
    : QAbstractTableModel(parent)
{


}


TableModel::~TableModel()
{


}


// 更新表格数据
void TableModel::updateData(QList<FileRecord> recordList)
{
    m_recordList = recordList;


    beginResetModel();//开始重置模型,相当于刷新功能,从模型中从新获取数据
    endResetModel();//完成上面的过程,一般用在模型中开始的时候没有数据,然后需要重新刷新设置的模型,从中读取数据,在这个案例中,没有这两句话,是不能显示数据的。
}


// 行数
int TableModel::rowCount(const QModelIndex &parent) const
{
    return m_recordList.count();
}


// 列数
int TableModel::columnCount(const QModelIndex &parent) const
{
    return 2;
}


// 设置表格项数据,设置数据显示中的数据,一种是界面设置,一种是代码设置
bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role)//value数据可以从界面获取。
{
    if (!index.isValid())
    {


        return false;
        qDebug()<<"index is valid";
    }


    int nColumn = index.column();
    FileRecord record = m_recordList.at(index.row());
    switch (role)
    {
    case Qt::DisplayRole:  //显示模式不能对数据进行更改
    {
        if (nColumn == File_PATH_COLUMN)
        {
            record.strFilePath = value.toString();
            qDebug()<<"value.toString():"<<value.toString();


            m_recordList.replace(index.row(), record);
            emit dataChanged(index, index);
            return true;
        }
    }
//    case Qt::EditRole:  //编写模式,可以对数据进行更改
//    {
//        if (nColumn == File_PATH_COLUMN)
//        {
//        record.strFilePath = value.toString();
//        qDebug()<<"value.toString():"<<value.toString();
//        qDebug()<<"***************************";


//        m_recordList.replace(index.row(), record);
//        emit dataChanged(index, index);
//        return true;
//        }
//    }
//    case Qt::CheckStateRole: //根据状态修改数据库中的数据
//    {
//        if (nColumn == CHECK_BOX_COLUMN)
//        {
//            record.bChecked = (value.toInt() == Qt::Checked);
//            qDebug()<<"value.toInt():"<<value.toInt();
//            m_recordList.replace(index.row(), record);
//            emit dataChanged(index, index);
//            return true;
//        }
//    }


    case Qt::UserRole: //用户模式后,才能进行选中第一栏的数据
    {
        if (nColumn == CHECK_BOX_COLUMN)
        {
            record.bChecked = value.toBool();


            m_recordList.replace(index.row(), record);
            emit dataChanged(index, index);
            return true;
        }
    }
    default:
        return false;
    }
    return false;
}


// 表格项数据的获取:动态的从数据结构中获取数据,并将数据显示出来。
QVariant TableModel::data(const QModelIndex &index, int role) const
{
    //i++;
    if (!index.isValid())
    {
        qDebug()<<"index is not valid";
        return QVariant();
    }


    int nRow = index.row();
    int nColumn = index.column();
    FileRecord record = m_recordList.at(nRow);
    qDebug()<<record.bChecked;
    qDebug()<<record.strFilePath;
    //每个角色都是对应所有列的。
    switch (role)
    {
    case Qt::TextColorRole:
    {


        qDebug()<<"Qt::TextColorRole";


        return QColor(Qt::green);
    }
    case Qt::TextAlignmentRole:
    {
        qDebug()<<"Qt::TextAlignmentRole";
        return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
    }
    case Qt::DisplayRole://直接把数据显示出来。
    {
        qDebug()<<"Qt::DisplayRole";
        if (nColumn == File_PATH_COLUMN)
            return record.strFilePath;//根据记录中的数据显示在图表中。
        return "";
    }
//    case Qt::EditRole: //只有选中的时候且双击才会显示出来。
//    {
//        qDebug()<<"Qt::EditRole";
//        if (nColumn == File_PATH_COLUMN)
//            return record.strFilePath;
//        return "";
//    }
//    case Qt::CheckStateRole: //这一行语句在第一列显示方格
//    {
//        qDebug()<<"Qt::CheckStateRole";
//        if (nColumn == CHECK_BOX_COLUMN)
//            return record.bChecked ? Qt::Checked : Qt::Unchecked;


//    }
    case Qt::UserRole:
      {
          if (nColumn == CHECK_BOX_COLUMN)
              return record.bChecked;
      }
    default:
    {
        qDebug()<<"default";
        return QVariant();
    }
    }


    return QVariant();
}


// 表头数据,表头数据没有从数据结构中获取,而是写死的。
QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    switch (role)
    {
    case Qt::TextAlignmentRole:
        return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
    case Qt::DisplayRole:
    {
        if (orientation == Qt::Horizontal)
        {
            if (section == CHECK_BOX_COLUMN)
                return QStringLiteral("状态");


            if (section == File_PATH_COLUMN)
                return QStringLiteral("文件路径");
        }
    }
    default:
        return QVariant();
    }


    return QVariant();
}


// 表格可选中、可复选
Qt::ItemFlags TableModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return QAbstractItemModel::flags(index);


    Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;//ItemIsEnabled,表明这一项可以使用,ItemIsSelectable 表明这一项可以选中。


//    flags |= Qt::ItemIsUserCheckable|Qt::ItemIsEditable;
   // Qt::ItemFlags tempFlag =Qt::ItemIsSelectable;
   // return tempFlag;
   if (index.column() == CHECK_BOX_COLUMN)//增加第一列的控制选项。
     flags |= Qt::ItemIsUserCheckable|Qt::ItemIsEditable;
    return flags;


}



#ifndef CHECKBOXDELEGATE_H
#define CHECKBOXDELEGATE_H


#include <QStyledItemDelegate>
#include <QPainter>
#include <QStyleOptionViewItem>
#include <QModelIndex>
#include <QEvent>
#include <QMouseEvent>
#include <QCheckBox>
class CheckBoxDelegate : public QStyledItemDelegate
{
    Q_OBJECT
public:
    explicit CheckBoxDelegate(QObject *parent = 0);
    ~CheckBoxDelegate();


    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);




signals:


public slots:
private:
    int row;


};


#endif // CHECKBOXDELEGATE_H




#include "checkboxdelegate.h"
#include <QApplication>
#include <QDebug>
#include <QWidget>
#define CHECK_BOX_COLUMN 0
CheckBoxDelegate::CheckBoxDelegate(QObject *parent)
    : QStyledItemDelegate(parent)
{
    row =0;
}


CheckBoxDelegate::~CheckBoxDelegate()
{


}
// 绘制复选框后面必须有const,没有const修饰,则不能显示自制矩形框,有const后,则内部不能修改数据,是一个只读的结构
void CheckBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyleOptionViewItem viewOption(option);
    initStyleOption(&viewOption, index);
    /*initialize option with the values using the index index. This method is useful for subclasses
    when they need a QStyleOptionViewItem, but don't want to fill in all the information themselves.*/
    if (option.state.testFlag(QStyle::State_HasFocus))
    {


       viewOption.state = viewOption.state ^ QStyle::State_HasFocus;


    }


    QStyledItemDelegate::paint(painter, viewOption, index);//必须放在这里,不能放在下面,
    if (index.column() == CHECK_BOX_COLUMN)
    {
        bool data = index.model()->data(index, Qt::UserRole).toBool();//从模型中获取指定索引处的值
        qDebug()<<"paint data:"<<data;
        QStyleOptionButton checkBoxStyle;//设置自制按钮样式
        checkBoxStyle.state = data ? QStyle::State_On : QStyle::State_Off;//一个是选中打勾状态,另一个则是没有选中打勾状态。
        checkBoxStyle.state |= QStyle::State_Enabled;//使得自制的矩形框可以凸显出来
        checkBoxStyle.iconSize = QSize(20, 20);
        checkBoxStyle.rect = option.rect;//设置在第一栏显示矩形框,大小为第一列的宽度,没有这一句话,第一列将没有矩形框
        //checkBoxStyle.rect = QRect(0,0,30,30);//这句话在第一栏设置一个矩形框,大小30,30,靠近第一栏的最左边显示出来,
        //大小固定,不会变化。但是只能显示一行
        qDebug()<<"row:"<<row;


        QWidget widget;
        //QApplication::style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &checkBoxStyle, painter, &checkBox);
        //在widget上面绘制出矩形框
        QApplication::style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &checkBoxStyle, painter, &widget);
    }


    //  row += 35;//由于paint是一个只读结构,不能更改
}


// 响应鼠标事件,更新数据。处理鼠标左键或者右键动作,以此来更新数据。
//对自制框进行操作时,才会触发editorEvent事件
bool CheckBoxDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
    QRect decorationRect = option.rect;//用于判断鼠标是否落在矩形框内。


    QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
    if (event->type() == QEvent::MouseButtonPress && decorationRect.contains(mouseEvent->pos()))
    {
        if (index.column() == CHECK_BOX_COLUMN)//由于视图显示设置为选择一行,如果这个没有判断,会发生选择第二列的时候,不断的刷新,点击第二列并不会对第一列的model数据进行更改。
            //所以利用索引进行控制,在第一列。读取第一列的每个索引的数据,并进行重置第一列的每个数据。
        {
            bool data = model->data(index, Qt::UserRole).toBool();
            qDebug()<<"editorEvent:****************"<<data;
            model->setData(index, !data, Qt::UserRole);
        }


//        bool data = model->data(index, Qt::UserRole).toBool();
//        qDebug()<<"editorEvent:****************"<<data;
//        model->setData(index, !data, Qt::UserRole);
    }


    return QStyledItemDelegate::editorEvent(event, model, option, index);
}




#include <QApplication>
#include "tablemodel.h"
#include <QTableView>
#include <QHeaderView>
#include <QSqlTableModel>


#include "checkboxdelegate.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);




    QTableView *pTableView = new QTableView;
    TableModel *pModel = new TableModel;
   // QSqlTableModel *pModel = new QSqlTableModel;
    CheckBoxDelegate *pDelegate = new CheckBoxDelegate;
   // pModel->setHeaderData(1,Qt::Vertical,Qt::DisplayRole);


    // 设置单行选中、最后一列拉伸、表头不高亮、无边框等
    pTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    pTableView->horizontalHeader()->setStretchLastSection(true);
    pTableView->horizontalHeader()->setHighlightSections(false);//当选中表中数据时,表头是否会高亮,显示已经选中状态。
    pTableView->verticalHeader()->setVisible(true);
    pTableView->setShowGrid(true); //是否显示网格线
    pTableView->setFrameShape(QFrame::NoFrame);
    pTableView->setSelectionMode(QAbstractItemView::SingleSelection);
    pTableView->setModel(pModel);


    pTableView->setItemDelegate(pDelegate);
    // 加载数据、更新界面
    QList<FileRecord> recordList;
    for (int i = 0; i < 5; ++i)
    {
        FileRecord record;
        record.bChecked = false;
        record.strFilePath = QString("E:/Qt/image_%1.png").arg(i + 1);
        recordList.append(record);
    }
    pModel->updateData(recordList);
    pTableView->resize(800,800);
    pTableView->show();
    return a.exec();
}



0 0
原创粉丝点击