【问题标题】:Determine if QTableView has an open editor确定 QTableView 是否有打开的编辑器
【发布时间】:2011-03-26 12:08:53
【问题描述】:

有什么方法可以确定QTableView 在当前单元格中是否有打开的编辑器?我需要处理以下情况:

  • 用户双击单元格并编辑数据,但使单元格处于“编辑”状态
  • 在 UI 的另一部分,执行更改基础模型的选定行的操作。
  • 回到我的观点,我想确定新选择的行是否与打开的行相同。如果没有,我需要采取行动。 (提示用户?自动提交?还原?)

我知道如何获取当前项目,并且可以获取该项目的委托,但我没有看到任何我希望找到的 isEditMode() 属性。

有人能指出正确的方向吗?

【问题讨论】:

    标签: qt qtableview


    【解决方案1】:

    对您的委托进行子类化,使其包含一个访问器,该访问器会告诉您何时进行编辑:

    void MyDelegate::setEditorData ( QWidget * editor, const QModelIndex & index ) const {
        // _isEditing  will have to be mutable because this method is const
        _isEditing = true; 
        QStyledItemDelegate::setEditorData(editor, index);
    }
    
    void MyDelegate::setModelData ( QWidget * editor, QAbstractItemModel * model, const QModelIndex & index ) const {
        QStyledItemDelegate::setModelData(editor, model, index);
        _isEditing = false;
    }
    
    bool MyDelegate::isEditing() const { return _isEditing; }
    

    然后您可以检查委托以查看发生了什么。或者和/或如果您不喜欢 mutable,您可以发出信号,以便知道代表处于什么状态。

    【讨论】:

    • 请注意,我认为您的意思是 mutable,而不是 volatile
    • @Caleb - 你是对的。已更改 - 感谢您指出这一点。
    • 正如 Florian Kusche 在他的回答中已经指出的那样,这不起作用,因为 setModelData() 仅在提交编辑时才被调用,但在被取消时不会被调用。
    【解决方案2】:

    连接底层模型dataChanged信号

    void QAbstractItemModel::dataChanged ( const QModelIndex & topLeft, const QModelIndex & bottomRight )
    

    您可以检查数据发生变化的单元格是否与当前索引相同

    QModelIndex QAbstractItemView::currentIndex () const
    

    你无法直接知道当前单元格是否有打开的编辑器,但可以检查视图是否处于 QAbstractItemView::EditingState

    State QAbstractItemView::state () const
    

    做你想做的应该足够了。

    【讨论】:

      【解决方案3】:

      您可以继承QTableView 以便能够访问state() 函数,不幸的是,该函数受到保护。但是,我没有尝试过。

      如果您已经有一个QStyledItemDelegate 子类,您可以使用它来跟踪当前是否打开了一个编辑器。但是,您不能只使用setEditorData/setModelData,因为当用户取消编辑时不会调用setModelData。相反,您可以跟踪编辑器本身的创建和销毁。

      class MyItemDelegate : public QStyledItemDelegate
      {
          Q_OBJECT
      
      public:
          MyItemDelegate( QObject* parent = nullptr );
          ~MyItemDelegate();
      
          QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
          void setEditorData( QWidget* editor, const QModelIndex& index ) const;
          void setModelData( QWidget* editor, QAbstractItemModel* model, const QModelIndex& index ) const;
      
          bool isEditorOpen() const   { return *m_editorCount > 0; }
      
      protected:
          int* m_editorCount;
      
      protected slots:
          void onEditorDestroyed( QObject* obj );
      };
      

      实施:

      MyItemDelegate::MyItemDelegate( QObject* parent ) :
          QStyledItemDelegate( parent )
      {
          m_editorCount = new int;
          *m_editorCount = 0;
      }
      
      MyItemDelegate::~MyItemDelegate()
      {
          delete m_editorCount;
      }
      
      QWidget* MyItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
      {
          // create an editor, can be changed as needed
          QWidget* editor = QStyledItemDelegate::createEditor( parent, option, index );
      
          connect( editor, SIGNAL(destroyed(QObject*)), SLOT(onEditorDestroyed(QObject*)));
          printf( "editor %p created\n", (void*) editor );
          (*m_editorCount)++;
      
          return editor;
      }
      
      void MyItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
      {
          ...
      }
      
      void MyItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
      {
          ...
      }
      
      void MyItemDelegate::onEditorDestroyed( QObject* obj )
      {
          printf( "editor %p destroyed\n", (void*) obj );
          (*m_editorCount)--;
      }
      

      在某些情况下,例如当使用光标键移动到树中的下一个项目时,Qt 将首先创建新编辑器,然后销毁旧编辑器。因此,m_editorCount 必须是整数而不是布尔值。

      不幸的是,createEditor() 是一个 const 函数。因此,您不能创建int-member。相反,创建一个指向 int 的指针并使用它。

      【讨论】:

      • 不错。只有几个 cmets:最好使用 mutable int 而不是 int*。此外,无需在您提供的解决方案中重新实现 setEditorData() 和 setModelData(),因此为了清楚起见,您可以省略它们。
      • 是的,你是对的。可变整数会好一些。
      【解决方案4】:

      只检查是否返回值

      State QAbstractItemView::state () const
      

      QTableView::EditingState
      

      【讨论】:

      • 我不确定它是否处于该状态是否足以确定它是用于当前单元格
      【解决方案5】:

      这是一个想法,它甚至有助于在编辑开始之前获取编辑/组合小部件...

      只需发出一个信号并在主窗口中使用它...这是我在编辑之前在 QTableWidget 中使用的一个组合框...

      首先在 ComoBoxItemDelegate 中创建一个信号...

      signals:
         void OnComboEdit(QComboBox* pCombo) const;
      

      然后在 createEditor 方法中发出信号...

      QWidget* ComboBoxItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
      {
          // Create the combobox and populate it
          QComboBox* cb = new QComboBox(parent);
          emit OnComboEdit(cb);
          return cb;
      }
      

      并在 MainWindow 中声明一个函数来接收信号...

      void MainWindow::OnComboEidt(QComboBox *pCB) const
      {
          qDebug() << "Combo Eidt Singal Received";
      }
      

      那么最后在MainWindow的构造函数中连接它...

      ComboBoxItemDelegate* cbid = new ComboBoxItemDelegate(ui->tableWidget);
      connect(cbid, &ComboBoxItemDelegate::OnComboEdit, this, &MainWindow::OnComboEidt);
      ui->tableWidget->setItemDelegateForColumn(0, cbid);
      

      【讨论】:

        【解决方案6】:

        如果您知道正在编辑的项目的索引,您可以调用indexWidget() 并尝试投射它。如果它有效,您不仅知道您正在编辑,而且您的编辑器小部件也很方便。

        EditWidget *editWidget = qobject_cast<EditWidget*>(tableView->indexWidget(tableView->currentIndex()));
        if(editWidget)
        {
            //yep, ur editing bro
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-04-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-11-07
          相关资源
          最近更新 更多