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


本站由 困困鱼 使用 Stellar 创建。