Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QTextEdit inside subwindow loses focus after application re activates
Forum Updated to NodeBB v4.3 + New Features

QTextEdit inside subwindow loses focus after application re activates

Scheduled Pinned Locked Moved Solved General and Desktop
focusqtexteditwindow flags
11 Posts 2 Posters 1.4k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T ThThoma

    Hello,

    I have a QTextEdit inside a subwindow (let's say Qt::Tool flag) and I noticed the following:

    • I give focus to the QTextEdit,
    • I minimize the application (clicking on the OS taskbar)
    • I re activate the application (QEvent::WindowStateChange, QEvent::Show, ..., QEvent::ApplicationActivate, ..., QEvent::ApplicationStateChange, QEvent::FocusIn)
    • The QEvent::FocusIn goes to the first widget inside my main window that can receive it.

    I played around with the following filter (installed to the QApplication) to figure these things out:

    class FocusEventFilter : public QObject
    {
    public:
        bool eventFilter(QObject *obj, QEvent *event) override
        {
            if (event->type() == QEvent::FocusIn) {
                QWidget *widget = qobject_cast<QWidget *>(obj);
                if (widget) {
                    qDebug() << "FocusIn:" << widget << widget->objectName();
                }
                QObject *focusedObject = qApp->focusObject();
                if (focusedObject) {
                    const QMetaObject *metaObject = focusedObject->metaObject();
                    const char *className = metaObject->className();
                    qDebug() << "focusedObject class:" << focusedObject << className;
                }
            }
            if  (event->type() == QEvent::FocusOut) {
                QWidget *widget = qobject_cast<QWidget *>(obj);
                if (widget) {
                    qDebug() << "FocusOut:" << widget->objectName();
                }
                QObject *focusedObject = qApp->focusObject();
                if (focusedObject) {
                    const QMetaObject *metaObject = focusedObject->metaObject();
                    const char *className = metaObject->className();
                    qDebug() << "focusedObject class:" << focusedObject << className;
                }
            }
            return QObject::eventFilter(obj, event);
        }
    };
    

    And I found that I can reproduce this behavior with a QTextEdit inside a QDockWidget:

    class MyMainWindow : public QMainWindow
    {
        Q_OBJECT
    public:
        explicit MyMainWindow(QWidget *parent = nullptr)
            : QMainWindow(parent)
        {
            QWidget *central = new QWidget(this);
            setCentralWidget(central);
    
            // this will get the focus after re-activation
            QLineEdit *le = new QLineEdit;
            QVBoxLayout *lay = new QVBoxLayout;
            lay->addWidget(le);
    
            central->setLayout(lay);
            setupDockWindow();
        }
    
    
    private:
        void setupDockWindow()
        {
            QDockWidget *dock = new QDockWidget("Text Area Dock", this);
            // I want this to hold the focus after application reactivation
            QTextEdit *te = new QTextEdit;
            dock->setWidget(te);
            addDockWidget(Qt::LeftDockWidgetArea, dock);
        }
    
    };
    
    

    The steps here are:

    • Un-dock the dock widget.
    • Give focus to the text edit.
    • minimize the application (Alt+Tab, seems to work fine)
    • activate the application again -> the text edit will have lost focus.

    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?

    And can this behavior be achieved inside a QTextEdit subclass (or via a filter)?

    Pl45m4P Offline
    Pl45m4P Offline
    Pl45m4
    wrote on last edited by Pl45m4
    #2

    @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) or visibilityChanged 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 your QTextEdit first in TabOrder.
    This might fix it, but could be "not intuitive" if your QTextEdit is placed somewhere in the middle of your window and the user starts tabbing though widgets.

    • https://doc.qt.io/qt-6/qwidget.html#setTabOrder

    If debugging is the process of removing software bugs, then programming must be the process of putting them in.

    ~E. W. Dijkstra

    T 1 Reply Last reply
    0
    • Pl45m4P Pl45m4

      @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) or visibilityChanged 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 your QTextEdit first in TabOrder.
      This might fix it, but could be "not intuitive" if your QTextEdit is placed somewhere in the middle of your window and the user starts tabbing though widgets.

      • https://doc.qt.io/qt-6/qwidget.html#setTabOrder
      T Offline
      T Offline
      ThThoma
      wrote on last edited by
      #3

      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 a focusIn 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.

      Pl45m4P 1 Reply Last reply
      0
      • T ThThoma

        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 a focusIn 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.

        Pl45m4P Offline
        Pl45m4P Offline
        Pl45m4
        wrote on last edited by Pl45m4
        #4

        @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 to QDockWidget doesn't have the visibilityChanged signal... and as far as I understood, the QDockWidget 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 both show- and hideEvent, 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?


        If debugging is the process of removing software bugs, then programming must be the process of putting them in.

        ~E. W. Dijkstra

        T 1 Reply Last reply
        0
        • Pl45m4P Pl45m4

          @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 to QDockWidget doesn't have the visibilityChanged signal... and as far as I understood, the QDockWidget 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 both show- and hideEvent, 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?

          T Offline
          T Offline
          ThThoma
          wrote on last edited by
          #5

          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.

          Pl45m4P 1 Reply Last reply
          0
          • T ThThoma

            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.

            Pl45m4P Offline
            Pl45m4P Offline
            Pl45m4
            wrote on last edited by
            #6

            @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 your mainWindow and not parentless floating around on your screen :)


            If debugging is the process of removing software bugs, then programming must be the process of putting them in.

            ~E. W. Dijkstra

            T 1 Reply Last reply
            0
            • Pl45m4P Pl45m4

              @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 your mainWindow and not parentless floating around on your screen :)

              T Offline
              T Offline
              ThThoma
              wrote on last edited by
              #7

              @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 flag Qt::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.

              Pl45m4P 1 Reply Last reply
              0
              • T ThThoma

                @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 flag Qt::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.

                Pl45m4P Offline
                Pl45m4P Offline
                Pl45m4
                wrote on last edited by
                #8

                @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 in mainwindow 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 (like QWidget or QWindow).

                • https://doc.qt.io/qt-6/qt.html#WindowType-enum

                If debugging is the process of removing software bugs, then programming must be the process of putting them in.

                ~E. W. Dijkstra

                T 1 Reply Last reply
                0
                • Pl45m4P Pl45m4

                  @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 in mainwindow 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 (like QWidget or QWindow).

                  • https://doc.qt.io/qt-6/qt.html#WindowType-enum
                  T Offline
                  T Offline
                  ThThoma
                  wrote on last edited by
                  #9

                  @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...

                  Pl45m4P 1 Reply Last reply
                  0
                  • T ThThoma

                    @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...

                    Pl45m4P Offline
                    Pl45m4P Offline
                    Pl45m4
                    wrote on last edited by Pl45m4
                    #10

                    @ThThoma

                    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

                    • https://stackoverflow.com/questions/59401073/qt-setting-focus-on-a-floating-qdockwidget

                    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...


                    If debugging is the process of removing software bugs, then programming must be the process of putting them in.

                    ~E. W. Dijkstra

                    1 Reply Last reply
                    0
                    • T Offline
                      T Offline
                      ThThoma
                      wrote on last edited by
                      #11

                      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 a QEvent::ApplicationStateChange and a QEvent::WindowDeactivate that all the widgets receive afterwards, the qApp->focusObject() is always nullptr. And after nullptr Qt selects the widget on MainWindow 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.

                      1 Reply Last reply
                      0
                      • T ThThoma has marked this topic as solved on

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved