1

When Windows focus-follows-mouse-without-raising-the-window is enabled by either of the two methods linked to below, I consistently get PyQt5 GUI 'freezes' where you have to type any character in the terminal that you ran python from in order to unfreeze the GUI; complete description and test case (Windows 10, Python 3.6.1, PyQt5) is here: pyqt5 click in terminal causes GUI freeze

To enable the focus-follows-mouse-without-raise behavior, try either of these - they both work in Windows 10:

So - a few questions:

  1. can anyone reproduce the issue? It seems 100% reproducible for me, but it would be great to hear the same from someone else.
  2. is there a way to change the python code to detect-and-circumvent focus-follows-mouse, or just to be immune to it, i.e. maybe by ensuring the GUI application always takes focus back again when you - for example - click in a dialog or qmessagebox owned by the main GUI window, or by some other means? (Is the object hierarchy set up optimally, and if not, maybe this could all be resolved by correcting the ownership structure?)
Tom Grundy
  • 736
  • 5
  • 26

1 Answers1

0

The brute-force solution seems to work, though I'd like to leave this question open to see if someone knows of a more optimal solution; it took a fair amount of searching to figure out the right way; mainly by taking a look a the open-source code for X-Mouse. Basically, this method takes effect immediately, whereas the registry hack doesn't take effect until reboot.

New version of pyqt_freeze_testcase.py (the file from the referenced stackoverflow question); the changes are only additions, noted between lines of hash marks:

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

import sys
####################### added begin:
import win32gui
import win32con
####################### added end

# import the UI file created with pyuic5
from minimal_ui import Ui_Dialog

class MyWindow(QDialog,Ui_Dialog):
    def __init__(self,parent):
        QDialog.__init__(self)
        self.parent=parent
        self.ui=Ui_Dialog()
        self.ui.setupUi(self)
        ################################# added begin:
        self.initialWindowTracking=False
        try:
            self.initialWindowTracking=win32gui.SystemParametersInfo(win32con.SPI_GETACTIVEWINDOWTRACKING)
        except:
            pass
        if self.initialWindowTracking:
            print("Window Tracking was initially enabled.  Disabling it for now; will re-enable on exit.")
            win32gui.SystemParametersInfo(win32con.SPI_SETACTIVEWINDOWTRACKING,False)
        ################################# added end

    def showMsg(self):
        self.really1=QMessageBox(QMessageBox.Warning,"Really?","Really do stuff?",
            QMessageBox.Yes|QMessageBox.No,self,Qt.WindowTitleHint|Qt.WindowCloseButtonHint|Qt.Dialog|Qt.MSWindowsFixedSizeDialogHint|Qt.WindowStaysOnTopHint)
        self.really1.show()
        self.really1.raise_()
        if self.really1.exec_()==QMessageBox.No:
            print("nope")
            return
        print("yep")

        ################################## added begin:
    def closeEvent(self,event):
        if self.initialWindowTracking:
            print("restoring initial window tracking behavior ("+str(self.initialWindowTracking)+")")
            win32gui.SystemParametersInfo(win32con.SPI_SETACTIVEWINDOWTRACKING,self.initialWindowTracking)
        ################################## added end

def main():
    app = QApplication(sys.argv)
    w = MyWindow(app)
    w.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
Tom Grundy
  • 736
  • 5
  • 26