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. Focus stealing progress dialog
Forum Update on Monday, May 27th 2025

Focus stealing progress dialog

Scheduled Pinned Locked Moved Solved General and Desktop
31 Posts 4 Posters 741 Views
  • 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.
  • P Offline
    P Offline
    Perdrix
    wrote 27 days ago last edited by Perdrix
    #1

    550c9b37-22b4-4fa9-8442-f4ce596624f7-image.png

    I have a progress dialogue as shown above. Whenever it updates its contents, it steals Focus which is most anti-social.

    I changed the code to add:

    	//
    	// Set the window so that it does not take focus
    	// 
    	setAttribute(Qt::WA_ShowWithoutActivating);
    

    as it appeared that this might prevent that happening, but unfortunately it still misbehaves.

    What do I need to change to stop this focus thief :)?

    Thanks
    David

    1 Reply Last reply
    0
    • A Offline
      A Offline
      Axel Spoerl
      Moderators
      wrote 21 days ago last edited by Axel Spoerl 5 Feb 2025, 19:00
      #28

      It happens in the ProcessDialog class, because it's implemented that way.
      The methods below are called on each update of the progress bar.
      While the method name suggests, that they are called only once at the start, they are actually hit on every update.
      Calling raise() raises them.

      void ProgressDlg::applyStart1Text(const QString& strText)
      {
      	ui->ProcessText1->setText(strText);
      	raise(); // <----- HERE
      }
      
      void ProgressDlg::applyStart2Text(const QString& strText)
      {
      	ui->ProcessText2->setText(strText);
      	setProgress2Range(0, m_total2);
      	if (m_total2 == 0)
      	{
      		setItemVisibility(true, false);
      	}
      	else
      	{
      		setItemVisibility(true, true);
      		applyProgress2(0);
      	}
      	raise(); // <----- AND HERE
      }
      ``

      Software Engineer
      The Qt Company, Oslo

      1 Reply Last reply
      2
      • S Offline
        S Offline
        SGaist
        Lifetime Qt Champion
        wrote 27 days ago last edited by
        #2

        Hi,

        You seem to have multiple progress bars so likely a custom dialog, am I correct ?
        Do you update only the progress bar or is something else happening ?
        Did you made Cancel the default button ?

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply
        0
        • P Offline
          P Offline
          Perdrix
          wrote 27 days ago last edited by Perdrix
          #3

          Yes, very much a custom dialogue. And yes, the Cancel button has the "autoDefault" attribute set. The code that updates the progress bars is driven by two member functions, Progress1, and Progress2:

          void ProgressDlg::Progress1(const QString& text, int achieved)
          {
          	QMetaObject::invokeMethod(this, "slotProgress1", Qt::AutoConnection,
          		Q_ARG(const QString&, text),
          		Q_ARG(int, achieved));
          }
          
          void ProgressDlg::Progress2(const QString& text, int achieved)
          {
          	QMetaObject::invokeMethod(this, "slotProgress2", Qt::AutoConnection,
          		Q_ARG(const QString&, text),
          		Q_ARG(int, achieved));
          }
          

          which can be driven from non-UI threads. Those slots just do some book-keeping, update the text fields and the sliders, and finally invoke QCoreApplication::processEvents(); which I am told was found necessary to ensure the progress dialogue was updated properly (no I didn't write this code). They do call raise(), but do not call (e.g.) setFocus(). The only time setFocus() is used is when the dialogue is initially created.

          1 Reply Last reply
          0
          • S Offline
            S Offline
            SGaist
            Lifetime Qt Champion
            wrote 26 days ago last edited by
            #4

            Would it be possible to share the implementation of the dialog ?

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            P 1 Reply Last reply 26 days ago
            0
            • S SGaist
              26 days ago

              Would it be possible to share the implementation of the dialog ?

              P Offline
              P Offline
              Perdrix
              wrote 26 days ago last edited by Perdrix
              #5

              @SGaist Certainly:
              https://www.dropbox.com/scl/fo/yzyyeijwip3pil9poly4p/ALZGlamwAtpuC5NrqMfkTUg?rlkey=4r29ofptuf5zzqdia027av71s&dl=1

              PS Removing autoDefault from the Cancel button changed nothing.
              PPS Same problem on both Windows and macOS
              PPPS If a shared debug session would help you will be welcome to connect to my system using e.g. Chrome Remote Desktop

              1 Reply Last reply
              0
              • S Offline
                S Offline
                SGaist
                Lifetime Qt Champion
                wrote 25 days ago last edited by
                #6

                Nothing obvious jumps to my eyes.

                Would it be possible to have the same dialog but buildable so I can test it on my machine ?

                Interested in AI ? www.idiap.ch
                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                1 Reply Last reply
                0
                • P Offline
                  P Offline
                  Perdrix
                  wrote 24 days ago last edited by
                  #7

                  I thought that I had sent you enough to build it - with judicious removal of pch,h and adding includes for Qt and stdlib stuff.

                  1 Reply Last reply
                  0
                  • P Offline
                    P Offline
                    Perdrix
                    wrote 23 days ago last edited by
                    #8

                    Hmmm! Odder and odder the focus stealing doesn't happen on my Windows system but does on many ?? It also happens consistently on both Linux and Mac. It's not related to the QWidget::raise() calls as they only happen when the text of the dlg is updated. The focus is stolen by the progress bar updates.

                    1 Reply Last reply
                    0
                    • P Offline
                      P Offline
                      Perdrix
                      wrote 23 days ago last edited by Perdrix
                      #9

                      @SGaist I'm creating a stand-alone Creator project for this problem, and I am almost there, but can't work out how to pass the /openmp:experimental command line flag to MS Visual C++

                      How do I configure the project to do this?
                      D

                      1 Reply Last reply
                      0
                      • P Offline
                        P Offline
                        Perdrix
                        wrote 22 days ago last edited by Perdrix 5 Jan 2025, 12:11
                        #10

                        @SGaist The Creator Project is here:
                        https://www.dropbox.com/scl/fi/h929bym63f2sf1y3904fw/DSS_ProgressDlg.zip?rlkey=vhhntwxapk347ipc6ng2hkf59&dl=0

                        It's setup to use MSVC2022_x64 on Windows.

                        Focus theft only seems to occur on some Windows systems?? Go figure.

                        Moving the dialog - it always snaps back to where it started - commenting the calls to QWidget::show() in applyStart1Text() and applyStart2Text() prevents that problem.

                        It is still a focus thief on Linux and MacOS. To build on MacOS you'll need to install:
                        https://mac.r-project.org/openmp/openmp-19.1.0-darwin20-Release.tar.gz
                        so the files end up in /usr/local/include and /usr/local/lib. For example:

                        cd ~/Downloads
                        curl -O https://mac.r-project.org/openmp/openmp-19.1.0-darwin20-Release.tar.gz
                        sudo tar -zxvf openmp-19.1.0-darwin20-Release.tar.gz -C /
                        

                        For more details see:
                        https://mac.r-project.org/openmp/

                        You will likely want to change the .pro file so it looks like (not necessarily 100% correct - I'm not totally familiar with qmake):

                        unix:!macx: QMAKE_CXXFLAGS+=-fopenmp
                        macx: QMAKE_CXXFLAGS+=-Xclang -fopenmp
                        win32: QMAKE_CXXFLAGS+=/openmp:experimental
                        
                        # Default rules for deployment.
                        qnx: target.path = /tmp/$${TARGET}/bin
                        else: unix:!android: target.path = /opt/$${TARGET}/bin
                        !isEmpty(target.path): INSTALLS += target
                        
                        unix:!macx: LIBS += -L/usr/lib/x86_64-linux-gnu/ -lomp5
                        
                        macx: LIBS += -L/usr/local/lib/ -lomp
                        
                        INCLUDEPATH += /usr/local/include
                        DEPENDPATH += /usr/local/include
                        
                        

                        I build for Linux on Lubuntu 22.04 FWIW.

                        David

                        1 Reply Last reply
                        0
                        • P Offline
                          P Offline
                          Perdrix
                          wrote 22 days ago last edited by
                          #11

                          @Axel-Spoerl This may interest you ...

                          1 Reply Last reply
                          0
                          • A Offline
                            A Offline
                            Axel Spoerl
                            Moderators
                            wrote 22 days ago last edited by
                            #12

                            Thanks @Perdrix for pinging.
                            Generally, a QProgressBar doesn't claim focus. My suspicion is that it happens on Window manager level. So the progress bar is the beneficiary of focus theft, but somebody else does the stealing ;-)
                            I also wonder who has told you the lie, that you need to call processEvents() for anything to happen. Unless an application implements blocking code, that's not necessary.

                            I wonder if you could isolate the antisocial behaviour into a small reproducer...

                            Software Engineer
                            The Qt Company, Oslo

                            1 Reply Last reply
                            0
                            • P Offline
                              P Offline
                              Perdrix
                              wrote 22 days ago last edited by
                              #13

                              This is a small a demo as I can manage. We do need the calls to processEvents()- try commenting the calls out and see what happens - the code we are tracking the progress of is running primarily on the GUI thread with ancillary threads created by openmp.

                              David

                              Christian EhrlicherC 1 Reply Last reply 22 days ago
                              0
                              • P Perdrix
                                22 days ago

                                This is a small a demo as I can manage. We do need the calls to processEvents()- try commenting the calls out and see what happens - the code we are tracking the progress of is running primarily on the GUI thread with ancillary threads created by openmp.

                                David

                                Christian EhrlicherC Offline
                                Christian EhrlicherC Offline
                                Christian Ehrlicher
                                Lifetime Qt Champion
                                wrote 22 days ago last edited by
                                #14

                                @Perdrix said in Focus stealing progress dialog:

                                This is a small a demo as I can manage.

                                So you tell us that you need openmp to reproduce the issue?
                                provide a minimal, compileable example of the problem so we can take a look on it.

                                Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                                Visit the Qt Academy at https://academy.qt.io/catalog

                                1 Reply Last reply
                                1
                                • P Offline
                                  P Offline
                                  Perdrix
                                  wrote 22 days ago last edited by Perdrix 5 Jan 2025, 16:06
                                  #15

                                  No - you don't need openmp - just comment out the openmp pragma in dialog.cpp and remove references to openmp in the .pro file It will then run single threaded - and display the same problem. I wanted to include a complete example of our dialog in full use just in case...

                                  1 Reply Last reply
                                  0
                                  • A Offline
                                    A Offline
                                    Axel Spoerl
                                    Moderators
                                    wrote 22 days ago last edited by
                                    #16
                                    namespace DSS
                                    {
                                    	void ProgressBase::UpdateProcessorsUsed()
                                    	{
                                            int currentThreadCount = omp_get_num_threads();	// Returns 1 if outside parallel region, else will return threads/cores used!
                                            applyProcessorsUsed(currentThreadCount);
                                    	}
                                    }
                                    

                                    This doesn't compile without openmp.

                                    Please provide a minimal compilable example.
                                    It has to be small enough to post it here. I normally don't download stuff from dropbox.

                                    Software Engineer
                                    The Qt Company, Oslo

                                    1 Reply Last reply
                                    1
                                    • P Offline
                                      P Offline
                                      Perdrix
                                      wrote 21 days ago last edited by
                                      #17

                                      I did say a few minor changes to remove openmp - I wanted to be SURE that you guys had all the code
                                      Just change that mf to read:

                                      	void ProgressBase::UpdateProcessorsUsed()
                                      	{
                                                     applyProcessorsUsed(1);
                                      	}
                                      
                                      1 Reply Last reply
                                      0
                                      • P Offline
                                        P Offline
                                        Perdrix
                                        wrote 21 days ago last edited by
                                        #18

                                        Believe me I have tried to reduce this to a totally trivial case that causes the focus theft I've burned weeks on this problem which is why I'm passing the code over to minds who have forgotten more about Qt than I ever knew.

                                        A 1 Reply Last reply 21 days ago
                                        0
                                        • A Offline
                                          A Offline
                                          Axel Spoerl
                                          Moderators
                                          wrote 21 days ago last edited by Axel Spoerl 5 Feb 2025, 09:28
                                          #19

                                          Here's the proof, that focus isn't stolen (tested on Windows, macOS and Linux)

                                          #include <QApplication>
                                          #include <QThread>
                                          #include <QProgressBar>
                                          #include <QLineEdit>
                                          #include <QTimer>
                                          #include <QVBoxLayout>
                                          
                                          class Updater : public QObject
                                          {
                                              Q_OBJECT
                                          public:
                                              Updater(QProgressBar *bar, QObject *parent = nullptr) : QObject(parent), bar(bar)
                                              {}
                                          
                                          public slots:
                                              void update()
                                              {
                                                  emit valueChanged(++value);
                                              }
                                          
                                              void onValueChanged(int v)
                                              {
                                                  value = v;
                                                  if (!QThread::currentThread()->isInterruptionRequested())
                                                      QTimer::singleShot(400, this, [&]{ update(); });
                                              }
                                          
                                          signals:
                                              void valueChanged(int value);
                                          
                                          private:
                                              QProgressBar *bar;
                                              int value = 0;
                                          };
                                          
                                          int main(int argc, char *argv[])
                                          {
                                              QApplication a(argc, argv);
                                              QWidget w;
                                              auto *lay = new QVBoxLayout;
                                              auto *edit = new QLineEdit;
                                              auto *bar = new QProgressBar;
                                              lay->addWidget(edit);
                                              lay->addWidget(bar);
                                              w.setLayout(lay);
                                              auto *u = new Updater(bar, &a);
                                              QObject::connect(edit, &QLineEdit::textChanged, u, &Updater::update);
                                              QObject::connect(bar, &QProgressBar::valueChanged, u, &Updater::onValueChanged);
                                              QObject::connect(u, &Updater::valueChanged, bar, &QProgressBar::setValue);
                                              QThread t(&a);
                                              u->moveToThread(&t);
                                              t.start();
                                              w.show();
                                              bar->setValue(1);
                                              const int ret = a.exec();
                                              t.requestInterruption();
                                              t.quit();
                                              t.wait();
                                              return ret;
                                          }
                                          
                                          #include "main.moc"
                                          
                                          

                                          Software Engineer
                                          The Qt Company, Oslo

                                          1 Reply Last reply
                                          1
                                          • P Offline
                                            P Offline
                                            Perdrix
                                            wrote 21 days ago last edited by Perdrix 5 Feb 2025, 11:52
                                            #20

                                            Try running the code I pointed you to on Dropbox. The focus IS definitely stolen - that's why I am here - I tried trivial test cases like what you just posted and they caused no problems. I can't see (and I can tell you I have looked until I am blue in the face) what is wrong with the code for DSS::ProgressDlg but something is clearly causing focus to be stolen whenever the progress bars are updated.

                                            It's truly dis-heartening when you go somewhere for help and get told that there's no problem, when clearly there is - it's just that neither you nor I yet know what code is causing it.

                                            I've now burnt about 7 weeks on this and it's driving me nuts.

                                            I have spent quite some time to re-package that dual progress dialog so it would work outside my projects - time well spent I think. But it would be nice if someone would help in trying to work out what the problem is - I am completely out of ideas which I why I came here in the first place.

                                            A 1 Reply Last reply 21 days ago
                                            0

                                            1/31

                                            26 Apr 2025, 16:43

                                            • Login

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