Qt: start editing of cell after one click
Asked Answered
M

5

25

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.

Monofilament answered 16/9, 2013 at 15:2 Comment(4)
tableView->setEditHint(QAbstractItemView::SelectedClicked);Showroom
@ratchetfreak I didn't find setEditHint here harmattan-dev.nokia.com/docs/library/html/qt4/…Monofilament
my bad it's editTriggersShowroom
@ratchetfreak thank you it worked. As I understand it is not possible to set editTriggers for a column onlyMonofilament
B
19

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.

Burtis answered 17/9, 2013 at 12:53 Comment(0)
C
27

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.

Charentemaritime answered 3/7, 2015 at 3:33 Comment(2)
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.Gesticulation
This is non-intuitive since none of the 5 triggers alone actually does an edit simply from selection, but enabling AllEditTriggers seems to add this extra hidden trigger.Carliecarlile
B
19

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.

Burtis answered 17/9, 2013 at 12:53 Comment(0)
A
4

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);
}
Adduct answered 30/3, 2016 at 9:31 Comment(0)
S
2

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;
};
Spoofery answered 14/11, 2018 at 15:53 Comment(0)
I
0

If you override QStyledItemDelegate::createEditor() then you can expand the combo box after it is created.

Ill answered 16/9, 2013 at 20:25 Comment(2)
In the createEditor() the view doesn't know enough information to expand the combobox. For example its rect. But your idea may be used shomehowMonofilament
@Monofilament 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.Protocol

© 2022 - 2024 — McMap. All rights reserved.