Qt之QTableView添加複選框(QAbstractTableModel)

簡述

使用QTableView,常常會遇到複選框,要實現一個好的複選框,除了常規的功能外,還應注意如下幾點:app

  1. 三態:不選/半選/全選
  2. 自定義風格(樣式)

下面咱們介紹一下常見的實現方式:編輯器

  • 編輯委託。 
    方式:利用委託重載createEditor(),激活QCheckBox。 
    特色:必須雙擊/選中,才能顯示CheckBox控件。通常不知足實際中的直接顯示的須要。函數

  • 使用QTableView的setIndexWidget(const QModelIndex &index, QWidget *widget)來實現。 
    此功能用來顯示可視區域內對應一個數據項的靜態內容。若是想顯示自定義的動態內容或執行自定義編輯器部件,子類化QItemDelegate代替。也就是說,這隻適合作靜態數據的顯示,不適合作一些插入、更新、刪除操做的數據顯示。this

  • 自定義模型QAbstractTableModel,經過flags()函數來實現。 
    方式:經過將flags()設置爲Qt::ItemIsUserCheckable實現可選中,而後配合setData()與data()來實現。 
    特色:直接顯示,可定義樣式,默認左對齊,很難實現居中、右對齊。url

  • 自定義委託QAbstractItemDelegate,經過paint()函數來實現。 
    方式:經過控制editorEvent()實現鼠標的點擊進行全選/半選/不選,而後由paint()實時繪製。 
    特色:這種方式比較複雜,但適合擴展,除了能夠嵌入複選框,還能夠繪製其它控件-按鈕、圖片等。spa

 

 

效果

這裏寫圖片描述

下面咱們來介紹如何利用QAbstractTableModel的flags()函數來實現複選功能。.net

QAbstractTableModel

源碼

table_model.cppcode

#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)
{
    if (!index.isValid())
        return false;

    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();

            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);

            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
{
    if (!index.isValid())
        return QVariant();

    int nRow = index.row();
    int nColumn = index.column();
    FileRecord record = m_recordList.at(nRow);

    switch (role)
    {
    case Qt::TextColorRole:
        return QColor(Qt::white);
    case Qt::TextAlignmentRole:
        return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
    case Qt::DisplayRole:
    {
        if (nColumn == File_PATH_COLUMN)
            return record.strFilePath;
        return "";
    }
    case Qt::CheckStateRole:
    {
        if (nColumn == CHECK_BOX_COLUMN)
            return record.bChecked ? Qt::Checked : Qt::Unchecked;
    }
    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;
    if (index.column() == CHECK_BOX_COLUMN)
        flags |= Qt::ItemIsUserCheckable;

    return flags;
}

接口說明

  • updateData 
    主要用於更新數據,刷新界面。blog

  • data 
    用來顯示數據,根據角色(顏色、文本、對齊方式、選中狀態等)判斷須要顯示的內容。接口

  • setData 
    用來設置數據,根據角色(顏色、文本、對齊方式、選中狀態等)判斷須要設置的內容。

  • headerData 
    用來顯示水平/垂直表頭的數據。

  • flags 
    用來設置單元格的標誌(可用、可選中、可複選等)。

樣式

QSS不只能夠設置表格、表格項樣式(背景、文本等),也能夠經過indicator來設置複選框的樣式:

QTableView {
        border: 1px solid rgb(50, 50, 50);
        background: rgb(57, 58, 60);
        gridline-color: rgb(60, 60, 60);
}
QTableView::item {
        border: none;
        border-bottom: 1px solid rgb(50, 50, 50);
}
QTableView::item:selected {
        background: rgb(0, 160, 230);
}
QTableView::indicator {
        width: 17px;
        height: 17px;
}
QTableView::indicator:enabled:unchecked {
        image: url(:/Images/checkBox);
}
QTableView::indicator:enabled:unchecked:hover {
        image: url(:/Images/checkBoxHover);
}
QTableView::indicator:enabled:unchecked:pressed {
        image: url(:/Images/checkBoxPressed);
}
QTableView::indicator:enabled:checked {
        image: url(:/Images/checkBoxChecked);
}
QTableView::indicator:enabled:checked:hover {
        image: url(:/Images/checkBoxCheckedHover);
}
QTableView::indicator:enabled:checked:pressed {
        image: url(:/Images/checkBoxCheckedPressed);
}
QTableView::indicator:enabled:indeterminate {
        image: url(:/Images/checkBoxIndeterminate);
}
QTableView::indicator:enabled:indeterminate:hover {
        image: url(:/Images/checkBoxIndeterminateHover);
}
QTableView::indicator:enabled:indeterminate:pressed {
        image: url(:/Images/checkBoxIndeterminatePressed);
}

使用

QTableView *pTableView = new QTableView(this);
TableModel *pModel = new TableModel(this);

// 設置單行選中、最後一列拉伸、表頭不高亮、無邊框等
pTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
pTableView->horizontalHeader()->setStretchLastSection(true);
pTableView->horizontalHeader()->setHighlightSections(false);
pTableView->verticalHeader()->setVisible(false);
pTableView->setShowGrid(false);
pTableView->setFrameShape(QFrame::NoFrame);
pTableView->setSelectionMode(QAbstractItemView::SingleSelection);
pTableView->setModel(pModel);

// 加載數據、更新界面
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);
相關文章
相關標籤/搜索