Qt: start editing of cell after one click

17,052

Solution 1

Edit after one click You can reimplement mousePressEvent in view you are using

void YourView::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        QModelIndex index = indexAt(event->pos());
        if (index.column() == 0) { // column you want to use for one click
            edit(index);
        }
    }
    QTreeView::mousePressEvent(event);
}

Expanded QCombobox when edit You should imlement setEditorData in your subclass of QItemDelegate and at the end call showPopup.

But it has some unexpected behaviour. QComboBox disappears when mouse leave its area. But for me it is advantage. I can select different item with single click and release.

void IconDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    Q_UNUSED(index);
    QComboBox *comboBox = qobject_cast<QComboBox*>(editor);
    // Add data
    comboBox->addItem(QIcon(":/icons/information16.png"), "info");
    comboBox->addItem(QIcon(":/icons/warning16.png"), "warning");
    comboBox->addItem(QIcon(":/icons/send16.png"), "send");
    comboBox->addItem(QIcon(":/icons/select16.png"), "select");
    comboBox->showPopup(); // <<<< Show popup here
}

Together it works fast way. Click and hold to choose item and commit data on release ( Just one click and release )

If you want click to show expanded qcombobox and next click to choose/hide, I do not know solution for now.

Solution 2

You can just set edit trigger use this function setEditTriggers

C++

yourView->setEditTriggers(QAbstractItemView::AllEditTriggers)

Python:

yourView.setEditTriggers(QAbstractItemView.AllEditTriggers)

enum QAbstractItemView::EditTrigger flags QAbstractItemView::EditTriggers

This enum describes actions which will initiate item editing.

Constant    Value   Description
QAbstractItemView::NoEditTriggers   0   No editing possible.
QAbstractItemView::CurrentChanged   1   Editing start whenever current item changes.
QAbstractItemView::DoubleClicked    2   Editing starts when an item is double clicked.
QAbstractItemView::SelectedClicked  4   Editing starts when clicking on an already selected item.
QAbstractItemView::EditKeyPressed   8   Editing starts when the platform edit key has been pressed over an item.
QAbstractItemView::AnyKeyPressed    16  Editing starts when any key is pressed over an item.
QAbstractItemView::AllEditTriggers  31  Editing starts for all above actions.

The EditTriggers type is a typedef for QFlags. It stores an OR combination of EditTrigger values.

Solution 3

Based on the idea provided by Jason, I came up with this solution.

To launch the editor on single click, I connected QAbstractItemView::clicked(const QModelIndex &index) signal of my view, to QAbstractItemView::edit(const QModelIndex &index) slot of that same view.

If you use Qt4, you need to create a slot in your delegate. Pass your combobox as an argument to this slot. In this slot you call QComboBox::showPopup. So it will look like this:

void MyDelegate::popUpComboBox(QComboBox *cb)
{
    cb->showPopup();
}

But first we need to register the QComboBox* type. You can call this in the constructor of your delegate:

qRegisterMetaType<QComboBox*>("QComboBox*");

The reason we need this slot, is because we can't show the pop up straight away in MyDelegate::createEditor, because the position and the rect of the list view are unknown. So what we do is in MyDelegate::createEditor, we call this slot with a queued connection:

QComboBox *cb = new QComboBox(parent);
// populate your combobox...
QMetaObject::invokeMethod(const_cast<MyDelegate*>(this), "popUpComboBox", Qt::QueuedConnection, Q_ARG(QComboBox*, cb));

This will show the list view of the combobox correctly when the editor is activated.

Now if you are using Qt5, the slot is not needed. All you do is call QComboBox::showPopup with a queued connection from MyDelegate::createEditor. The easiest way to do this is with a QTimer:

QTimer::singleShot(0, cb, &QComboBox::showPopup);

For some extra information, this is how you can paint the combobox so it is shown all the time, not only when the editor is shown:

void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if(index.column() == 1) // show combobox only in the second column
    {
        QStyleOptionComboBox box;
        box.state = option.state;

        box.rect = option.rect;
        box.currentText = index.data(Qt::EditRole).toString();

        QApplication::style()->drawComplexControl(QStyle::CC_ComboBox, &box, painter, 0);
        QApplication::style()->drawControl(QStyle::CE_ComboBoxLabel, &box, painter, 0);
        return;
    }
    QStyledItemDelegate::paint(painter, option, index);
}

Solution 4

This solution works perfeclty for me. Single click on a cell, and the combo pops up.

class GFQtComboEnumItemDelegate : public QStyledItemDelegate
{
    void setEditorData(QWidget *editor, const QModelIndex &index) const
    {
        QComboBox* pE = qobject_cast<QComboBox*>(editor);
        ... // init the combo here
        if(m_must_open_box)
        {
            m_must_open_box = false;
            pE->showPopup();
        }
    }


    bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
    {
        if (event->type() == QEvent::MouseButtonRelease)
        {
            QMouseEvent* pME = static_cast<QMouseEvent*>(event);
            if(pME->button() == Qt::LeftButton)
            {
                QAbstractItemView* pView = qobject_cast<QAbstractItemView*>( const_cast<QWidget*>(option.widget) );
                if(pView != nullptr)
                {
                    emit pView->setCurrentIndex(index);
                    m_must_open_box = true;
                    emit pView->edit(index);
                }
                return true;
            }
        }
        return QStyledItemDelegate::editorEvent(event, model, option, index);
    }
    mutable bool m_must_open_box;
};
Share:
17,052

Related videos on Youtube

Ashot
Author by

Ashot

Updated on November 15, 2020

Comments

  • Ashot
    Ashot over 3 years

    By default the cell in QTableView starts being edited after double click. How to change this behavior. I need it to start editing after one click.

    I have set combo-box delegate to the cell. When clicking the cell it only selects it. When double clicking on the cell the QComboBox editor is activated but not expanded. I want it to expand after just one click as if I added QComboBox by setCellWidget function of QTableWidget. I need the same effect by using model-view-delegate.

    • ratchet freak
      ratchet freak almost 11 years
      tableView->setEditHint(QAbstractItemView::SelectedClicked);
    • Ashot
      Ashot almost 11 years
      @ratchetfreak I didn't find setEditHint here harmattan-dev.nokia.com/docs/library/html/qt4/…
    • ratchet freak
      ratchet freak almost 11 years
      my bad it's editTriggers
    • Ashot
      Ashot almost 11 years
      @ratchetfreak thank you it worked. As I understand it is not possible to set editTriggers for a column only
  • Ashot
    Ashot almost 11 years
    In the createEditor() the view doesn't know enough information to expand the combobox. For example its rect. But your idea may be used shomehow
  • C--
    C-- over 6 years
    This has a specific behaviour. Click on a cell -> edit -> exit edit mode -> click on the same cell again, will not enter edit mode, but rather just selects it. Observed in 5.8.x. So, I would simply connect(tableView, SIGNAL(clicked(modelIndex), tableView, SLOT(edit(modelIndex))); works fine.
  • Spencer
    Spencer about 2 years
    @Ashot you just need to delay the popup using a QTimer set to 0 seconds. This gives Qt the chance it needs to calculate such things.