Background
Hi guys. I've made a custom widget with QLineEdit
and several QPushButtons
to use it with custom item delegate:
class LineEditor : public QWidget
{
public:
explicit LineEditor(QWidget *parent = 0) : QWidget(parent) {
setLayout(new QHBoxLayout);
layout()->setContentsMargins(0, 0, 0, 0);
layout()->setSpacing(0);
QLineEdit *edit = new QLineEdit(this);
layout()->addWidget(edit);
layout()->addWidget(new QPushButton(this));
layout()->addWidget(new QPushButton(this));
setFocusProxy(edit);
}
};
class PropertyDelegate : public QItemDelegate
{
public:
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const {
return new LineEditor(parent);
}
bool eventFilter(QObject *object, QEvent *event) {
if (event->type() == QEvent::KeyPress) {
qDebug() << "KeyPress";
}
if (event->type() == QEvent::ShortcutOverride) {
qDebug() << "ShortcutOverride";
}
return QItemDelegate::eventFilter(object, event);
}
};
I'm going to bind them with QListView
and QStandardItemModel
like this:
QStandardItemModel *model = new QStandardItemModel;
model->appendRow(new QStandardItem("1"));
model->appendRow(new QStandardItem("2"));
model->appendRow(new QStandardItem("3"));
QListView w;
w.setItemDelegate(new PropertyDelegate);
w.setModel(model);
w.show();
Question
Why in the PropertyDelegate::eventFilter
when Tab
key is pressed there is only QEvent::ShortcutOverride
event, but pressing of any other key emits both QEvent::ShortcutOverride
and QEvent::KeyPress
events?
UPD: I want to implement the moving between lines by pressing Tab
and Backtab
like with standard widgets.
Well, finally I've done some research about that.
Explanation
When a view calls
createEditor
function of delegate it also installs the delegate event filter to editor.However the delegate can catch only events of editor widget, but not events of its children. When the
Tab
key is pressed theQWidget::event
function is called, it uses it to change focus to another widget:Accordingly in my case the focus is set to next
QPushButton
afterQLineEdit
and event isn't propagated to the parent (LineEditor
).Solving
The right way to solve the problem is like
QSpinBox
does it. Because it is also hasQLineEdit
. In constructor of widget it sets focus proxy for line edit:So all of focus events will reach the main widget. Also the
focusPolicy
property must be set because it'sNoFocus
by default:All we need to do in this moment it is to propagate necessary events to
QLineEdit
from main widget like this:This should be enough.
Tricky
As it's said above the delegate can't catch events of editor's children. So to make editor's behavior like "native" I have to duplicate events from children to editor.
LineEditor
installs event filter toQLineEdit
in constructor:Implementation of filter looks like this:
It's also possible to use
qApp->notify(this, event)
forQKeyEvent
instead ofQApplication::postEvent
because we filter this events anyway. But it's not possible forQFocusEvent
becausenotify
will redirect the event and it will not reach a child.Note that the standard (
QItemDelegate
orQStyledItemDelegate
) delegate will care about situation when focus is changed internally by itself: