我们在Qt 4.6.3中使用QTableView
,并且需要一个在每个单元格中只有一个复选框的列。我们使用QAbstractTableModel
的自定义子类作为QTableView
的模型。现在,我们通过设置Qt::ItemIsUserCheckable
标志来设置复选框。但我们无法弄清楚如何摆脱复选框旁边的空白文本框!
我们如何才能使列列有一个复选框,没有别的?
答案 0 :(得分:17)
这是一个解决方案。为了使其正常工作,您的列应不设置Qt::ItemIsEditable
或Qt::ItemIsUserCheckable
标记。这将从Qt::DisplayRole
读取布尔值,并使用setData()
调用Qt::EditRole
(即不 Qt::CheckStateRole
。)
#include "check_box_delegate.h"
#include <QtGui/QApplication>
#include <QtGui/QMouseEvent>
static QRect CheckBoxRect(const QStyleOptionViewItem &view_item_style_options) {
QStyleOptionButton check_box_style_option;
QRect check_box_rect = QApplication::style()->subElementRect(
QStyle::SE_CheckBoxIndicator,
&check_box_style_option);
QPoint check_box_point(view_item_style_options.rect.x() +
view_item_style_options.rect.width() / 2 -
check_box_rect.width() / 2,
view_item_style_options.rect.y() +
view_item_style_options.rect.height() / 2 -
check_box_rect.height() / 2);
return QRect(check_box_point, check_box_rect.size());
}
CheckBoxDelegate::CheckBoxDelegate(QObject *parent)
: QStyledItemDelegate(parent) {
}
void CheckBoxDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const {
bool checked = index.model()->data(index, Qt::DisplayRole).toBool();
QStyleOptionButton check_box_style_option;
check_box_style_option.state |= QStyle::State_Enabled;
if (checked) {
check_box_style_option.state |= QStyle::State_On;
} else {
check_box_style_option.state |= QStyle::State_Off;
}
check_box_style_option.rect = CheckBoxRect(option);
QApplication::style()->drawControl(QStyle::CE_CheckBox,
&check_box_style_option,
painter);
}
// This is essentially copied from QStyledItemEditor, except that we
// have to determine our own "hot zone" for the mouse click.
bool CheckBoxDelegate::editorEvent(QEvent *event,
QAbstractItemModel *model,
const QStyleOptionViewItem &option,
const QModelIndex &index) {
if ((event->type() == QEvent::MouseButtonRelease) ||
(event->type() == QEvent::MouseButtonDblClick)) {
QMouseEvent *mouse_event = static_cast<QMouseEvent*>(event);
if (mouse_event->button() != Qt::LeftButton ||
!CheckBoxRect(option).contains(mouse_event->pos())) {
return false;
}
if (event->type() == QEvent::MouseButtonDblClick) {
return true;
}
} else if (event->type() == QEvent::KeyPress) {
if (static_cast<QKeyEvent*>(event)->key() != Qt::Key_Space &&
static_cast<QKeyEvent*>(event)->key() != Qt::Key_Select) {
return false;
}
} else {
return false;
}
bool checked = index.model()->data(index, Qt::DisplayRole).toBool();
return model->setData(index, !checked, Qt::EditRole);
}
答案 1 :(得分:9)
注意:Dave的答案也适用于使用PySide或PyQt4的Python。我翻译了它,效果很好。此外,我添加了复选框不接受用户输入的功能,如果单元格不可编辑,则显示为ReadOnly状态。 谢谢戴夫的代码!
class CheckBoxDelegate(QStyledItemDelegate):
def createEditor(self, parent, option, index):
'''
Important, otherwise an editor is created if the user clicks in this cell.
'''
return None
def paint(self, painter, option, index):
'''
Paint a checkbox without the label.
'''
checked = bool(index.model().data(index, Qt.DisplayRole))
check_box_style_option = QStyleOptionButton()
if (index.flags() & Qt.ItemIsEditable) > 0:
check_box_style_option.state |= QStyle.State_Enabled
else:
check_box_style_option.state |= QStyle.State_ReadOnly
if checked:
check_box_style_option.state |= QStyle.State_On
else:
check_box_style_option.state |= QStyle.State_Off
check_box_style_option.rect = self.getCheckBoxRect(option)
if not index.model().hasFlag(index, Qt.ItemIsEditable):
check_box_style_option.state |= QStyle.State_ReadOnly
QApplication.style().drawControl(QStyle.CE_CheckBox, check_box_style_option, painter)
def editorEvent(self, event, model, option, index):
'''
Change the data in the model and the state of the checkbox
if the user presses the left mousebutton or presses
Key_Space or Key_Select and this cell is editable. Otherwise do nothing.
'''
if not (index.flags() & Qt.ItemIsEditable) > 0:
return False
# Do not change the checkbox-state
if event.type() == QEvent.MouseButtonRelease or event.type() == QEvent.MouseButtonDblClick:
if event.button() != Qt.LeftButton or not self.getCheckBoxRect(option).contains(event.pos()):
return False
if event.type() == QEvent.MouseButtonDblClick:
return True
elif event.type() == QEvent.KeyPress:
if event.key() != Qt.Key_Space and event.key() != Qt.Key_Select:
return False
else:
return False
# Change the checkbox-state
self.setModelData(None, model, index)
return True
def setModelData (self, editor, model, index):
'''
The user wanted to change the old state in the opposite.
'''
newValue = not bool(index.model().data(index, Qt.DisplayRole))
model.setData(index, newValue, Qt.EditRole)
def getCheckBoxRect(self, option):
check_box_style_option = QStyleOptionButton()
check_box_rect = QApplication.style().subElementRect(QStyle.SE_CheckBoxIndicator, check_box_style_option, None)
check_box_point = QPoint (option.rect.x() +
option.rect.width() / 2 -
check_box_rect.width() / 2,
option.rect.y() +
option.rect.height() / 2 -
check_box_rect.height() / 2)
return QRect(check_box_point, check_box_rect.size())