Change focusOutEvent
-
@Vlad02 said in Change focusOutEvent:
Do you know where I can intercept the Tab button press? The KeyPressEvent does not capture in LineEdit.
I don't know about your large code. But just to answer this:
#include <QApplication> #include <QDebug> #include <QKeyEvent> #include <QLineEdit> class MyLineEdit: public QLineEdit { void keyPressEvent(QKeyEvent* event) override { if (event->key() == Qt::Key_Tab) { qDebug() << "tabPressed"; return; } QLineEdit::keyPressEvent(event); } }; int main(int argc, char *argv[]) { QApplication a(argc, argv); MyLineEdit w; w.setFocusPolicy(Qt::NoFocus); // with or without this line w.show(); return a.exec(); }
Tested with Qt
5.155.12 under Ubuntu 22.04, all I have. Doubt it's any different at Qt6.@JonB
I'm working with Qt 5.6 on Windows 10, and it's the problem that when I press Tab when I'm working with LineEdit, KeyPressEvent doesn't work, I've already tried it. It seems that it is intercepted somewhere higher, not in LineEdit itself.P.S. Okay, I'll try to work with LineEdit as a separate widget first, maybe something will come to mind
-
@JonB
I'm working with Qt 5.6 on Windows 10, and it's the problem that when I press Tab when I'm working with LineEdit, KeyPressEvent doesn't work, I've already tried it. It seems that it is intercepted somewhere higher, not in LineEdit itself.P.S. Okay, I'll try to work with LineEdit as a separate widget first, maybe something will come to mind
@Vlad02
If you really are using Qt 5.6, why?? That is really old (March 2016!). (I corrected my earlier post, of course I did not mean Qt 5.15 as that is commercial only.) At least consider moving to Qt 5.12.Start by testing your behaviour on my code. It should work. Assuming it does, you must find out what is different about your situation. Maybe it's to do with being inside a
QTableWidget
and that grabbing the Tab without letting it through to theQLineEdit
, I don't know. If so, produce a truly minimal but complete example (i.e. the absolute fewest number of lines of code to reproduce!). I have not thought it through, but we may be able/have to intercept the Tab in theQTableWidget
'seventFilter()
instead of the subclassedQLineEdit
'skeyPressEvent
. BTW,QTableWidget
inherits QAbstractItemView::setTabKeyNavigation(bool enable), I don't know if you might need to set this tofalse
maybe for your situation. -
@Vlad02
If you really are using Qt 5.6, why?? That is really old (March 2016!). (I corrected my earlier post, of course I did not mean Qt 5.15 as that is commercial only.) At least consider moving to Qt 5.12.Start by testing your behaviour on my code. It should work. Assuming it does, you must find out what is different about your situation. Maybe it's to do with being inside a
QTableWidget
and that grabbing the Tab without letting it through to theQLineEdit
, I don't know. If so, produce a truly minimal but complete example (i.e. the absolute fewest number of lines of code to reproduce!). I have not thought it through, but we may be able/have to intercept the Tab in theQTableWidget
'seventFilter()
instead of the subclassedQLineEdit
'skeyPressEvent
. BTW,QTableWidget
inherits QAbstractItemView::setTabKeyNavigation(bool enable), I don't know if you might need to set this tofalse
maybe for your situation.@JonB
Yes, I know that this is a rather old version of Qt. I had some problems in the new version with the display of my table (for some reason I couldn't get the dimensions I needed, and the table was with a ScrollBar).As for your example, yes, it does work. I tried to do it a little differently, here is the code:
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QTableWidget *table = new QTableWidget(ui->centralWidget); MyLineEdit *lineEdit = new MyLineEdit(table); } MainWindow::~MainWindow() { delete ui; } #include "mylineedit.h" #include <QDebug> MyLineEdit::MyLineEdit(QWidget *parent) : QLineEdit(parent) { } void MyLineEdit::keyPressEvent(QKeyEvent *event) { if(event->key() == Qt::Key_Tab) qDebug() << "Key Tab pressed"; }
MyLineEdit is located in a separate file, so there are several inlinks. In this form, Tab no longer works if the LineEdit is inside a QTableWidget. It seems that the table intercepts this event before.
-
@JonB
Yes, I know that this is a rather old version of Qt. I had some problems in the new version with the display of my table (for some reason I couldn't get the dimensions I needed, and the table was with a ScrollBar).As for your example, yes, it does work. I tried to do it a little differently, here is the code:
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QTableWidget *table = new QTableWidget(ui->centralWidget); MyLineEdit *lineEdit = new MyLineEdit(table); } MainWindow::~MainWindow() { delete ui; } #include "mylineedit.h" #include <QDebug> MyLineEdit::MyLineEdit(QWidget *parent) : QLineEdit(parent) { } void MyLineEdit::keyPressEvent(QKeyEvent *event) { if(event->key() == Qt::Key_Tab) qDebug() << "Key Tab pressed"; }
MyLineEdit is located in a separate file, so there are several inlinks. In this form, Tab no longer works if the LineEdit is inside a QTableWidget. It seems that the table intercepts this event before.
-
@Vlad02
For a quick try, I just appended aboutsetTabKeyNavigation()
to my previous post, you could try that in 5 seconds. Otherwise I'm thinking theeventFilter()
for theQTableWidget
.@JonB
Yes, if I use the eventFilter, it will intercept the Tab button press. We need to somehow force this event to be skipped so that it is passed to LineEditbool MyTableWidget::eventFilter(QObject *obj, QEvent *event) { if(obj == this && event->type() == QEvent::KeyPress){ QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); if(keyEvent->key() == Qt::Key_Tab){ qDebug() << "Tab"; return true; } } return QTableWidget::eventFilter(obj, event); }
-
@JonB
Yes, if I use the eventFilter, it will intercept the Tab button press. We need to somehow force this event to be skipped so that it is passed to LineEditbool MyTableWidget::eventFilter(QObject *obj, QEvent *event) { if(obj == this && event->type() == QEvent::KeyPress){ QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); if(keyEvent->key() == Qt::Key_Tab){ qDebug() << "Tab"; return true; } } return QTableWidget::eventFilter(obj, event); }
@Vlad02
In that case, identify the relevant line edit in the event filter and call
QApplication::sendEvent(lineEdit, event);
You need to make sure of course, that the line edit handles and accepts the event. -
@Vlad02
In that case, identify the relevant line edit in the event filter and call
QApplication::sendEvent(lineEdit, event);
You need to make sure of course, that the line edit handles and accepts the event.@Axel-Spoerl
Yes, I managed to pass the event from the TableWidget to the LineEdit. Thank you very much, I will continue to try to define my own implementation!@JonB and @SimonSchroeder thank you too
-
@Vlad02
In that case, identify the relevant line edit in the event filter and call
QApplication::sendEvent(lineEdit, event);
You need to make sure of course, that the line edit handles and accepts the event.@Axel-Spoerl
Still, the problem remains. If I create a LineEdit for a delegate that is bound to my table, where exactly should I catch the Tab press? Because when a cell is edited, the TableWidget does not catch this Tab.I think I understand. Most likely, the LineEdit is not applied to the table, but to the QTableWidgetItem, that's the problem
-
@Axel-Spoerl
Still, the problem remains. If I create a LineEdit for a delegate that is bound to my table, where exactly should I catch the Tab press? Because when a cell is edited, the TableWidget does not catch this Tab.I think I understand. Most likely, the LineEdit is not applied to the table, but to the QTableWidgetItem, that's the problem
@Vlad02
I don't think it will be aQTableWidgetItem
because that is not aQWidget
or even aQObject
. If you need to find the parent, I think you are doing editing (and only editing), take a look at parameter to
QWidget *QStyledItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const. I thought it would be theQTableWidget
, but you say not. You'll have to do some digging. -
@Vlad02
I don't think it will be aQTableWidgetItem
because that is not aQWidget
or even aQObject
. If you need to find the parent, I think you are doing editing (and only editing), take a look at parameter to
QWidget *QStyledItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const. I thought it would be theQTableWidget
, but you say not. You'll have to do some digging.@JonB
I tried to print the following inside the createEditor:qDebug() << parent->parent(); qDebug() << editor->parent();
As a result, I got this:
MyTable(0x7aace8)
QWidget(0x7a3188, name = "qt_scrollarea_viewport")
I don't really understand whatqt_scrollarea_viewport
is.If I use
CustomLineEdit *editor = new CustomLineEdit(old_str, parent);
I get the following cell editing (as I need):
If I try it this way
CustomLineEdit *editor = new CustomLineEdit(old_str, parent->parentWidget());
then the result is as follows:
-
@JonB
I tried to print the following inside the createEditor:qDebug() << parent->parent(); qDebug() << editor->parent();
As a result, I got this:
MyTable(0x7aace8)
QWidget(0x7a3188, name = "qt_scrollarea_viewport")
I don't really understand whatqt_scrollarea_viewport
is.If I use
CustomLineEdit *editor = new CustomLineEdit(old_str, parent);
I get the following cell editing (as I need):
If I try it this way
CustomLineEdit *editor = new CustomLineEdit(old_str, parent->parentWidget());
then the result is as follows:
@Vlad02
The table widget will have aQScrollArea
. That will have a viewport, QWidget *QAbstractScrollArea::viewport() const. It looks like that is the parent of the edit widget. Maybe that is what grabs the Tabs. I don't know where that leaves you with regard toeventFilter()
.You never gave a complete, minimal example. I take it you are saying you have a
QLineEdit
-derived widget for editing only in aQTableWidget
, and there you cannot deal with Tab, and that's the whole thing. -
@Vlad02
The table widget will have aQScrollArea
. That will have a viewport, QWidget *QAbstractScrollArea::viewport() const. It looks like that is the parent of the edit widget. Maybe that is what grabs the Tabs. I don't know where that leaves you with regard toeventFilter()
.You never gave a complete, minimal example. I take it you are saying you have a
QLineEdit
-derived widget for editing only in aQTableWidget
, and there you cannot deal with Tab, and that's the whole thing.@JonB said in Change focusOutEvent:
I take it you are saying you have a QLineEdit-derived widget for editing only in a QTableWidget, and there you cannot deal with Tab, and that's the whole thing.
That's right. I can provide the code of the derived class if necessary.
I tried to look at the parent hierarchy of my
LineEdit
and got the following:QWidget(0x2ef34a8, name="qt_scrollarea_viewport")
MyTable(0x2efa8f8)
QWidget(0x14094b0, name="centralWidget")
MainWindow(0x61fde0, name="MainWindow") -
@JonB said in Change focusOutEvent:
I take it you are saying you have a QLineEdit-derived widget for editing only in a QTableWidget, and there you cannot deal with Tab, and that's the whole thing.
That's right. I can provide the code of the derived class if necessary.
I tried to look at the parent hierarchy of my
LineEdit
and got the following:QWidget(0x2ef34a8, name="qt_scrollarea_viewport")
MyTable(0x2efa8f8)
QWidget(0x14094b0, name="centralWidget")
MainWindow(0x61fde0, name="MainWindow")@Vlad02
I have spent two hours so far this morning! I'm not going to lie, it's complex, and I don't have a solution and don't know whether I will get one/how long it will take!Basically the
QTableView
/QTableWidget
is grabbing the Tab and dealing with it, without it getting to yourQLineEdit
.Some further information/clues from https://forum.qt.io/topic/97293/qtableview-navigation-with-tab.
Also see bool QStyledItemDelegate::eventFilter(QObject *editor, QEvent *event), which tells you Tab is among the "special" keys handled by theQStyledItemDelegate
, but not what you/I can do about it if we don't like it and want it to go to the line edit instead.... -
@Vlad02
I have spent two hours so far this morning! I'm not going to lie, it's complex, and I don't have a solution and don't know whether I will get one/how long it will take!Basically the
QTableView
/QTableWidget
is grabbing the Tab and dealing with it, without it getting to yourQLineEdit
.Some further information/clues from https://forum.qt.io/topic/97293/qtableview-navigation-with-tab.
Also see bool QStyledItemDelegate::eventFilter(QObject *editor, QEvent *event), which tells you Tab is among the "special" keys handled by theQStyledItemDelegate
, but not what you/I can do about it if we don't like it and want it to go to the line edit instead.... -
@JonB
Okay, thanks, these are useful links. I will try something else. This Tab is so ugly :)I will read about
QTextEdit
, maybe I can replace myLineEdit
with it without any problems.@Vlad02
AQTextEdit
is a different widget from aQLineEdit
: it is multiline, and consumes Tabs & Returns itself. It is not "right" to replace your single line edit with a multi line just so you can deal with the Tab key the way you want.In have also come across https://stackoverflow.com/questions/12145522/why-pressing-of-tab-key-emits-only-qeventshortcutoverride-event, which shows how hairy all this stuff is!
What is that you want do with the Tab key anyway? Normally it commits the data in the editor to the model and moves to the next cell. Explain (in no more than two words!) what it is you want to do/change about this behaviour?
-
@JonB
Okay, thanks, these are useful links. I will try something else. This Tab is so ugly :)I will read about
QTextEdit
, maybe I can replace myLineEdit
with it without any problems.@Vlad02
I can present a couple of code approaches which will stop the Tab key from doing its default, i.e. when editing in aQTableWidget
it normally commits data from editor and moves to next cell, we can make it do "nothing". What I cannot do (if it's supposed to be possible) is then get the Tab key press to arrive at theQLineEdit
'skeyPressEvent()
.I'd really like to hear what exactly it is you do want to happen when Tab pressed now, per my previous request. Sooner you answer more likely I am to look at it :)
[Looking earlier maybe all you want is it to do
emit editingFinished();
? Or thecommitData()
it does by default but not the move to another cell? Or what? I'm really not getting what you want to do, or why the default behaviour isn't perfectly good as it is?] -
@Vlad02
AQTextEdit
is a different widget from aQLineEdit
: it is multiline, and consumes Tabs & Returns itself. It is not "right" to replace your single line edit with a multi line just so you can deal with the Tab key the way you want.In have also come across https://stackoverflow.com/questions/12145522/why-pressing-of-tab-key-emits-only-qeventshortcutoverride-event, which shows how hairy all this stuff is!
What is that you want do with the Tab key anyway? Normally it commits the data in the editor to the model and moves to the next cell. Explain (in no more than two words!) what it is you want to do/change about this behaviour?
@JonB said in Change focusOutEvent:
Explain (in no more than two words!) what it is you want to do/change about this behaviour?
-
The cell selection behavior differs from the one I implemented;
-
There are cases when I can only use cells of the first row and Tab should not move to the next rows
-
-
@Vlad02
I can present a couple of code approaches which will stop the Tab key from doing its default, i.e. when editing in aQTableWidget
it normally commits data from editor and moves to next cell, we can make it do "nothing". What I cannot do (if it's supposed to be possible) is then get the Tab key press to arrive at theQLineEdit
'skeyPressEvent()
.I'd really like to hear what exactly it is you do want to happen when Tab pressed now, per my previous request. Sooner you answer more likely I am to look at it :)
[Looking earlier maybe all you want is it to do
emit editingFinished();
? Or thecommitData()
it does by default but not the move to another cell? Or what? I'm really not getting what you want to do, or why the default behaviour isn't perfectly good as it is?]@JonB said in Change focusOutEvent:
Or the commitData() it does by default but not the move to another cell?
Partially yes, I answered above. It should also finish editing the cell, save the data, and move on to the next one. But it is not always allowed to move to the next line
-
@JonB said in Change focusOutEvent:
Or the commitData() it does by default but not the move to another cell?
Partially yes, I answered above. It should also finish editing the cell, save the data, and move on to the next one. But it is not always allowed to move to the next line
@Vlad02
OK. Sounds a lot like you only want to change where Tab moves you to next (commit data behaviour to be observed as-is).I'm too tired now to type in complete code. I think you can figure from this.
What I played with is: the Qt code behind already does an
installEventFilter()
on yourQStyledItemDelegate
. So you can add your owneventFilter() override
into it. You get Tabs there. If youreturn true
that will filter it out from being passed on.That was dealing with it close to the delegate. Another way is shown by @VRonin in https://forum.qt.io/topic/97293/qtableview-navigation-with-tab, which I asked you to look at earlier. He overrides the
QTableView
/QTableWidget
'skeyPressEvent()
. If it's a Tab he accepts that event and creates a new key move event instead. Might be close/related to what you will want. -
@Vlad02
OK. Sounds a lot like you only want to change where Tab moves you to next (commit data behaviour to be observed as-is).I'm too tired now to type in complete code. I think you can figure from this.
What I played with is: the Qt code behind already does an
installEventFilter()
on yourQStyledItemDelegate
. So you can add your owneventFilter() override
into it. You get Tabs there. If youreturn true
that will filter it out from being passed on.That was dealing with it close to the delegate. Another way is shown by @VRonin in https://forum.qt.io/topic/97293/qtableview-navigation-with-tab, which I asked you to look at earlier. He overrides the
QTableView
/QTableWidget
'skeyPressEvent()
. If it's a Tab he accepts that event and creates a new key move event instead. Might be close/related to what you will want.