1. 如何使得QCheckBox居中
在ItemDelegate中对特定列的paint函数进行修改,以及实现editorEvent
void XXX::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const{
//去掉Focus
QStyleOptionViewItem viewOption(option);
initStyleOption(&viewOption, index);
if( option.state.testFlag(QStyle::State_HasFocus) ){
viewOption.state = viewOption.state ^ QStyle::State_HasFocus;
}
int column = index.column();
if(true){ // is checked column
bool checked = index.data(Qt::CheckStateRole) == Qt::Checked;
QStyleOptionButton checkBoxOption;
QRect checkBoxRect = QApplication::style()->subElementRect(QStyle::SE_CheckBoxIndicator,&checkBoxOption, option.widget);
checkBoxRect.moveCenter(option.rect.center());
checkBoxOption.rect = checkBoxRect;
checkBoxOption.state = checked ? QStyle::State_On : QStyle::State_Off;
checkBoxOption.state |= QStyle::State_Enabled;
QApplication::style()->drawControl(QStyle::CE_CheckBox, &checkBoxOption, painter,option.widget);
}else{ // for other column
QStyledItemDelegate::paint(painter, viewOption, index);
}
}
bool XXX::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index){
if(event->type() == QEvent::MouseButtonDblClick)//禁止双击编辑
return false;
if (event->type() == QEvent::MouseButtonRelease) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if(mouseEvent->modifiers() != Qt::NoModifier ) return false; //去除对多选的影响
{ // 这里修复了点击到未选中的勾选框时会直接导致触发编辑 从而导致改变了checkbox的状态,故必须先选中该行后,二次点击才可改变状态
QModelIndexList indexes = m_pView->getBeforePressSelectedRowIndexs();
bool bCanEdit = false;
for(const auto& i : indexes){
if(i.row() == index.row()){
bCanEdit = true;
break;
}
}
if(!bCanEdit) return false;
}
QRect checkBoxRect = QApplication::style()->subElementRect(QStyle::SE_CheckBoxIndicator, &option, option.widget);
if(checkBoxRect.contains(mouseEvent->pos())){
return false;
}
checkBoxRect.moveCenter(option.rect.center() );
if (checkBoxRect.contains(mouseEvent->pos())) {
// 改变选中状态
Qt::CheckState checked = model->data(index, Qt::CheckStateRole).value<Qt::CheckState>();
model->setData(index, checked == Qt::Checked ? Qt::Unchecked : Qt::Checked, Qt::CheckStateRole);
return true;
}
}
return QStyledItemDelegate::editorEvent(event, model, option, index); // 对于其他事件,保持默认处理
}
tableview中需处理下 mousePressEvent以及 mouseReleaseEvent 用于记录对应的索引位置
class TableView: public QTableView{
...
public:
QModelIndexList getBeforePressSelectedRowIndexs() const{return m_beforePressSelectedRowIndexs;}
private:
void mousePressEvent(QMouseEvent* event) override{
m_beforePressSelectedRowIndexs = selectionModel()->selectedRows();
QTableView::mousePressEvent(event);
}
void mouseReleaseEvent(QMouseEvent* event) override{
QTableView::mouseReleaseEvent(event); // trigger delegate editorEvent
m_beforePressSelectedRowIndexs.clear();
}
private:
QModelIndexList m_beforePressSelectedRowIndexs;
XXXDelegate* m_pDelegate = nullptr;
};
2. 当代理使用了QLineEdit时 默认的回车按钮不会退出,只响应了Esc
在ItemDelegate 中 提交数据并关闭编辑器
// Edited for brevity.
bool QItemDelegate::eventFilter(QObject *object, QEvent *event)
{
QWidget *editor = qobject_cast<QWidget*>(object);
if (event->type() == QEvent::KeyPress) {
switch (static_cast<QKeyEvent *>(event)->key()) {
case Qt::Key_Enter:
case Qt::Key_Return:
QMetaObject::invokeMethod(this, "_q_commitDataAndCloseEditor",
Qt::QueuedConnection, Q_ARG(QWidget*, editor));
return false;
}
}
3. QTableView 点击空白处清空选中并提交正在编辑的数据
自定义代理实现 重点 是利用createEditor 和 destoryEditor记录当前的编辑器
Delegate
class XXXDelegate: public QStyledItemDelegate{
Q_OBJECT
public:
//
....
//
QWidget* currentEditor() const{ return m_pEditor; }
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override{
auto w = QStyledItemDelegate::createEditor(parent, option, index);
m_pEditor = w;
return w;
}
void destroyEditor(QWidget* editor, const QModelIndex& index) const override{
QStyledItemDelegate::destroyEditor(editor, index);
m_pEditor = nullptr;
}
private:
mutable QWidget* m_pEditor = nullptr;
};
TableView
class XXXTableView: public QTableView{
Q_OBJECT
public:
XXXTableView(QWidget* parent = nullptr): QTableView(parent){
setItemDelegate(m_pDelegate = new XXXDelegate(this));
installEventFilter(this);
viewport()->installEventFilter(this);
}
~XXXTableView(){
removeEventFilter(this);
removeEventFilter(viewport());
}
private:
bool eventFilter(QObject* obj, QEvent* event) override{
if( obj == this || obj == viewport() ){
// when click blank area, clear selection
if( event->type() == QEvent::MouseButtonPress ){
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
if( mouseEvent->button() == Qt::LeftButton ){
QModelIndex index = indexAt(mouseEvent->pos());
if( !index.isValid() ){
if( state() == QAbstractItemView::EditingState && m_pDelegate->currentEditor()){
QMetaObject::invokeMethod(m_pDelegate, "_q_commitDataAndCloseEditor",
Qt::QueuedConnection, Q_ARG(QWidget*, m_pDelegate->currentEditor()));
}
clearSelection();
return true;
}
}
}
}
return QTableView::eventFilter(obj, event);
}
private:
XXXDelegate* m_pDelegate = nullptr;
}