使用QTableView,常常會遇到複選框,要實現一個好的複選框,除了常規的功能外,還應注意如下幾點:app
下面咱們介紹一下常見的實現方式:編輯器
編輯委託。
方式:利用委託重載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
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);