QTextEdit inside subwindow loses focus after application re activates
-
@ThThoma said in QTextEdit inside subwindow loses focus after application re activates:
Is there any way for the QTextEdit inside a subwindow to regain focus (if it had the focus) after the application deactivates and re activates?
Before you hide your window, save the current focused widget and call
setFocus
explicitly when you restore it. If you want to focus your TextEdit every time it's even easier.Connect to
visibleChanged(bool arg)
orvisibilityChanged
and do the handling in the connected slot.Edit:
There also might be a "cheat":
I dont know what widget is focused after you show your window again. I think it's the one which comes first in "TabOrder".
If you dont need a special tabbing order, you could try to set yourQTextEdit
first in TabOrder.
This might fix it, but could be "not intuitive" if yourQTextEdit
is placed somewhere in the middle of your window and the user starts tabbing though widgets. -
Hey @Pl45m4,
I am not sure its so simple as a
setFocus()
.First, let's resolve the "cheat" you mention with the
setTabOrder()
.
This is out of the question because, as you said, I don't want to disrupt the original tab order of my window/application.Now, on
setFocus()
.
I understood that Qt remembers the last widget to lose focus and when the application reactivates, the same widget receives afocusIn
event.If you run my example (you can also add object names, and apply the given filter to the application), you'll notice that :
if a QTextEdit inside an undocked window had focus,- if the application is minimized, the last widget to lose focus is the QTextEdit. However, when the application is re activated (restored), the QTextEdit lost the focus, and the focus widget is the first one that the main window can give it to.
- if the application is deactivated (alt+tab or click to another application, let's say click your internet browser), the last widget to lose focus is the QTextEdit again. However, when you re activate the application (alt+tab or click the qt application on the taskbar), the QTextEdit gets the focus as expected.
The above behavior continues even when I installed the following filter to my QTextEdit.
class GiveFocusToTE : public QObject { public: GiveFocusToTE(QObject *parent = nullptr) : QObject(parent) {} bool eventFilter(QObject *obj, QEvent *event) override { static bool te_hadFocus = false; // quick and dirty way QTextEdit *te = qobject_cast<QTextEdit*>(obj); if (te) { if (event->type() == QEvent::Hide) { if (te->hasFocus()) { te_hadFocus = true; } } if (event->type() == QEvent::Show) { if (te_hadFocus) { te->setFocus(); } } } return QObject::eventFilter(obj, event); } };
I assume this is what you meant by
setFocus()
. If not, please correct me. -
@ThThoma said in QTextEdit inside subwindow loses focus after application re activates:
I assume this is what you meant by setFocus(). If not, please correct me.
No quite... but I mistook that
QMainWindow
in comparison toQDockWidget
doesn't have thevisibilityChanged
signal... and as far as I understood, theQDockWidget
was only your test case... my bad :)Anyway... this should fix it:
Add some "memory" e.g. in form of a boolean to your class, to remember if your
QTextEdit
or something else had focus before the window was minimized.
Then reimplement bothshow-
andhideEvent
, which are the first and last functions to be called before the window dis-/appears.
Worked for me when switching to browser as well as when I just minimize the window by clicking the title bar.void MainWindow::showEvent(QShowEvent *ev) { if(TE_hasFocus) ui->textEdit->setFocus(Qt::FocusReason::ActiveWindowFocusReason); } void MainWindow::hideEvent(QHideEvent *ev) { // returns child which was focused last if(focusWidget() == ui->textEdit) TE_hasFocus = true; else TE_hasFocus = false; }
Edit:
My solution is similar to your eventFilter, but less code. Does it behave as expected now?
-
Thanks @Pl45m4,
this does work. But this way the main window needs to "know" the existence of my QTextEdit subclass.
Imagine having instances of this QTextEdit subclass in alot of places. Then the main window needs to hold logic for all these instances, and keep track of them (even thought they are not directly children of the main window).
So ideally, the main window, has no idea that my widget exist. I am hoping for a solution contained in my subclass. And it piqued my interest on different behavior when alt+tabbing (or clicking to a different application) vs minimizing.
-
@ThThoma said in QTextEdit inside subwindow loses focus after application re activates:
Imagine having instances of this QTextEdit subclass in alot of places. Then the main window needs to hold logic for all these instances
Ok, yeah, I thought you are talking about one specific
QTextEdit
which should get focus after hide()/show().So ideally, the main window, has no idea that my widget exist
It should. And it has, assuming your
QTextEdit
is somewhere on yourmainWindow
and not parentless floating around on your screen :) -
@Pl45m4 said in QTextEdit inside subwindow loses focus after application re activates:
It should. And it has, assuming your QTextEdit is somewhere on your mainWindow and not parentless floating around on your screen :)
I don't think I understood this...
Anyway, the QTextEdit is not parent-less floating around, it is a child of a QDockWidget that is undocked.
By printing the
windowFlags()
of the QDockWidget I noticed that it receives the flagQt::Tool
whilst undocked.So in this scenario, the QTextEdit, has a parent that is a
Qt::Tool
.And after a minimize and then restore of the application, even though the last widget to lose focus, was the QTextEdit, Qt decides to give the focus to the mainwindow (i.e. to first widget inside the mainwindow that can receive it).
I guess I am asking, what happened and even thought the QTextEdit was supposed to keep the focus, the mainwindow gets it back.
-
@ThThoma said in QTextEdit inside subwindow loses focus after application re activates:
I don't think I understood this...
The parent knows about its childs.
And after a minimize and then restore of the application, even though the last widget to lose focus, was the QTextEdit, Qt decides to give the focus to the mainwindow (i.e. to first widget inside the mainwindow that can receive it).
So when you have
mainWindow
->dockWidget
->dockWidgetContent
->QTextEdit
it doesn't work and the first widget inmainwindow
is focused again?!
Hm, interesting...So in this scenario, the QTextEdit, has a parent that is a Qt::Tool.
DockWidgets use this as default because the "standard use case" is something like that. Dockable Tool-widget, which you can move around, dock and undock.
Qt::Tool
is just the window "flag" / decoration for that and a Qt type (likeQWidget
orQWindow
). -
@Pl45m4 said in QTextEdit inside subwindow loses focus after application re activates:
So when you have mainWindow -> dockWidget -> dockWidgetContent -> QTextEdit it doesn't work and the first widget in mainwindow is focused again?!
Hm, interesting...First of all, thanks for the help and the interest in this question :)
Please do run the initial example, and note the behavior yourself. I tried to make it as minimal and complete as possible, no need to install event filters, just create the header and run it in the simplest
main()
:#include "mymainwindow.hpp" int main(int argc, char *argv[]) { QApplication a(argc, argv); MyMainWindow w; w.show(); return a.exec(); }
Once again, alt+tabbing or clicking without minimizing the application works as expected, the QTextEdit regains the focus.
However, minimizing messes the focus chain somehow... -
Made a test myself. There seems to be different behavior, when the widget is undocked, which might be somewhat unexpected.
I also found these topics:
- https://forum.qt.io/topic/96356/qdockwidget-problem-with-focus-when-undocked
- https://forum.qt.io/topic/109909/setting-focus-in-floating-qdockwidget
And this on StackO
The list with similar stuff goes on... :)
Maybe it's not intended to be used in this way (giving focus to a widget in an undocked dockWidget programmatically). Time to re-think the design ':|Note: I'm on 5.15, maybe something has changed between 6.0 and 6.5...
-
I searched this a bit more.
First of all the behavior might be depending on OS. (Noticed some differences on Unix vs Windows)
Secondly, I created a timer that every 2 seconds prints out
qApp->focusObject()
. It looks like after aQEvent::ApplicationStateChange
and aQEvent::WindowDeactivate
that all the widgets receive afterwards, theqApp->focusObject()
is alwaysnullptr
. And afternullptr
Qt selects the widget onMainWindow
that was the last widget to have focus, and gives focus there.So I feel that subwindows are ignored somehow...
I am leaving this open for a bit, in case someone has a good solution to track if a subwindow had focus, it should regain it after application re activation.
-