Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closing the splash screen sends PySide6 message boxes to the back on Windows #8338

Open
bersbersbers opened this issue Feb 29, 2024 · 4 comments
Labels
triage Please triage and relabel this issue

Comments

@bersbersbers
Copy link
Contributor

Description of the issue

In some modes, my PySide6 app exits with nothing more than a message box. However, when I deploy my app with a splash screen, that message box is hidden behind all other windows.

Context information (for bug reports)

  • Output of pyinstaller --version: 6.4.0
  • Version of Python: 3.12.2
  • Platform: Windows 11, 23H2 (also WIndows 10)
  • How you installed Python: scoop
  • Did you also try this on another platform? Yes, it seems to work on Ubuntu via WSL.
  • try the latest development version, using the following command: Same thing

A minimal example program which shows the error

import sys

from PySide6.QtWidgets import QApplication, QMessageBox, QWidget

app = QApplication()

if hasattr(sys, "_MEIPASS"):
    import pyi_splash

    pyi_splash.close()

    # from PySide6.QtCore import QTimer
    # QTimer.singleShot(1000, pyi_splash.close)

QMessageBox.information(QWidget(), "Title", "Message")

Then run

python bug.py

or even

pythonw bug.py

In both cases, the message box opens in the foreground.

You can also remove pyi_splash.close() and run

pyinstaller -y bug.py && dist\bug\bug.exe

But restore the original code above and run

pyinstaller -y --splash bug.png bug.py && dist\bug\bug.exe

Notice how the message box is opened in the background.

I tried closing the splash screen after opening the message box (using the QTimer code), but that also sends the message box to the background.

@bersbersbers bersbersbers added the triage Please triage and relabel this issue label Feb 29, 2024
@rokm
Copy link
Member

rokm commented Feb 29, 2024

Hmm, the message box seems to display as expected on my test systems, but it could be a timing issue.

Either way, if you are using splash in onedir mode, you are essentially mixing tkinter and PySide6 in the same process, and I'm not really sure if that's supposed to work.

What happens if you close the splash before instantiating QApplication? Or even before importing PySide6?

@bersbersbers
Copy link
Contributor Author

bersbersbers commented Feb 29, 2024

Hmm, the message box seems to display as expected on my test systems

Two questions:

  • Are these Windows systems? Because I do not see the same issue on Linux. (Just making sure...)
  • Also, to make that crystal clear: I do see the message box (unfocused, but visibly) if I launch an app from the desktop, with no other window open. But when I open it from VS Code, the message box is opened behind VS Code (not minimized, but behind VS Code in z order). So I can Alt-Tab to the message box, and I can minimize VS Code to see it, too. But you have to expect that message box, otherwise it's easy to miss.

but it could be a timing issue.

I doubt that, because ...

What happens if you close the splash before instantiating QApplication? Or even before importing PySide6?

You mean like this?

import sys

if hasattr(sys, "_MEIPASS"):
    import pyi_splash

    pyi_splash.close()

from PySide6.QtWidgets import QApplication, QMessageBox, QWidget

app = QApplication()
QMessageBox.information(QWidget(), "Title", "Message")

Exactly the same thing, in both cases.

When doing the opposite, namely, closing the splash screen long after the message box has appeared ...

import sys

from PySide6.QtWidgets import QApplication, QMessageBox, QWidget

app = QApplication()

if hasattr(sys, "_MEIPASS"):
    import pyi_splash
    from PySide6.QtCore import QTimer

    QTimer.singleShot(5000, pyi_splash.close)

QMessageBox.information(QWidget(), "Title", "Message")

... I can observe the following:

  • The message box and the splash screen are opened visibly, in front of whatever is the launching window (VS Code)
  • The message box does not have focus.
  • When the splash screen is closed, the message box disappears behind VS Code
  • When I focus the message before the message box appears, it stays where it is, focused, when the splash screen closes.

So I think there are two sub-issues here:

  1. The message box does not start focused, probably because it senses another foreground window.
  2. The closing splash screen sends any unfocused windows to the back.

I care about the first issue more than the second, because that is one I can influence. This works, for example, at the expense of having another unnecessary window open:

import sys

from PySide6.QtWidgets import QApplication, QMessageBox, QWidget

app = QApplication()

if hasattr(sys, "_MEIPASS"):
    import pyi_splash
    from PySide6.QtCore import QTimer

    QTimer.singleShot(5000, pyi_splash.close)

widget = QWidget()
widget.showMinimized()
widget.activateWindow()
QMessageBox.information(widget, "Title", "Message")

But this is not too bad - it's basically a limitation of QMessageBox. If I was using a QWindow instead, I would be done already.

@rokm
Copy link
Member

rokm commented Feb 29, 2024

Are these Windows systems? Because I do not see the same issue on Linux. (Just making sure...)

Yes - since the report was about Windows, I tried to reproduce it there (Win 10 and Win 11 VMs, and Win 10 on my notebook).

Also, to make that crystal clear: I do see the message box (unfocused, but visibly) if I launch an app from the desktop, with no other window open. But when I open it from VS Code, the message box is opened behind VS Code (not minimized, but behind VS Code in z order). So I can Alt-Tab to the message box, and I can minimize VS Code to see it, too. But you have to expect that message box, otherwise it's easy to miss.

Aha, that makes more sense. I'm running the build and program from the command-prompt, and while I can see the dialog, it is indeed unfocused. If I do a onefile build with splash screen instead, the dialog is focused - because the splash is displayed in the parent process and the PySide dialog in the child process, so there is no overlap between the two.

FWIW, I don't think that using PyInstaller's splash makes much sense in onedir applications that use Qt bindings, since you can show up a Qt-based splash at the start of your program. (Whereas in onefile, the splash is there to inform users that something is happening while the program is unpacking itself, so before you could show your own splash screen from the program).

@bersbersbers
Copy link
Contributor Author

Aha, thanks for the further explanations. I can confirm that it does not happen in onefile mode, so I think you are right. I'll try removing the splash screen from onedir mode: pyi_splash.is_alive seems to be helpful for a codebase supporting both modes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
triage Please triage and relabel this issue
Projects
None yet
Development

No branches or pull requests

2 participants