Window shows up in a weird way when called in a different place
-
""" Python overlay """ import sys, window, threading from pynput.mouse import Listener as MouseListener from pynput.keyboard import Listener as KeyboardListener from PyQt5.QtWidgets import QApplication app = QApplication(sys.argv) mainwindow = window.MainWindow() log_list = [''] def on_press(key) -> None: prev = log_list[-1] if hasattr(prev, 'char') and prev.char == 'p' and hasattr(key, 'char') and key.char == '[': print('wow') mainwindow.show() mainwindow.activateWindow() log_list.append(key) def on_click(x, y, button, pressed): if not pressed: return mainwindow.hide() print('Mouse clicked at ({0}, {1}) with {2}'.format(x, y, button)) keyboard_listener = KeyboardListener(on_press=on_press) mouse_listener = MouseListener(on_click=on_click) def thread(): keyboard_listener.start() mouse_listener.start() keyboard_listener.join() mouse_listener.join() THREAD = threading.Thread(target=thread) THREAD.start() mainwindow.show() app.exec_()
When I have the
mainwindow.show()
before theapp.exec_()
it shows normally, as it normally does, but when I pressp
and[
to trigger the check, it doesnt display correctly. the window is just invisible and doesnt show upfrom PyQt5 import QtGui, QtCore from PyQt5 import QtWidgets from PyQt5.QtWidgets import QMainWindow class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.setWindowFlags( QtCore.Qt.WindowStaysOnTopHint | QtCore.Qt.FramelessWindowHint | QtCore.Qt.X11BypassWindowManagerHint ) self.setGeometry( QtWidgets.QStyle.alignedRect( QtCore.Qt.LeftToRight, QtCore.Qt.AlignCenter, QtCore.QSize(220, 32), QtWidgets.qApp.desktop().availableGeometry() )) def mousePressEvent(self, event): QtWidgets.qApp.quit()
I'm trying to make an overlay
-
@Caeden You cannot and should not modify the GUI from another thread, in this case it is better to use signals so that the method is invoked in the GUI thread:
import sys from pynput.mouse import Listener as MouseListener from pynput.keyboard import Listener as KeyboardListener from PyQt5.QtCore import QObject, pyqtSignal from PyQt5.QtWidgets import QApplication import window class KeyMonitor(QObject): foo_signal = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) self.previous = "" self.listener = KeyboardListener(on_press=self.on_press) def on_press(self, key): if hasattr(key, "char") and key.char is not None: if self.previous == "p" and key.char == "[": self.foo_signal.emit() print("OK") self.previous = key.char else: self.previous = "" def stop_monitoring(self): self.listener.stop() def start_monitoring(self): self.listener.start() class MouseMonitor(QObject): clicked = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) self.previous = "" self.listener = MouseListener(on_click=self.on_click) def on_click(self, x, y, button, pressed): if not pressed: return self.clicked.emit() print("Mouse clicked at ({0}, {1}) with {2}".format(x, y, button)) def stop_monitoring(self): self.listener.stop() def start_monitoring(self): self.listener.start() def main(): app = QApplication(sys.argv) mainwindow = window.MainWindow() mainwindow.show() key_monitor = KeyMonitor() key_monitor.foo_signal.connect(mainwindow.show) key_monitor.foo_signal.connect(mainwindow.activateWindow) key_monitor.start_monitoring() mouse_monitor = MouseMonitor() mouse_monitor.clicked.connect(mainwindow.hide) mouse_monitor.start_monitoring() app.exec_() if __name__ == "__main__": main()
-
@Caeden said in Window shows up in a weird way when called in a different place:
[ abbreviated code ]import sys, window, threading from pynput.mouse import Listener as MouseListener from pynput.keyboard import Listener as KeyboardListener from PyQt5.QtWidgets import QApplication app = QApplication(sys.argv) mainwindow = window.MainWindow() def on_press(key) -> None: mainwindow.show() keyboard_listener = KeyboardListener(on_press=on_press) def thread(): keyboard_listener.start() keyboard_listener.join() THREAD = threading.Thread(target=thread) THREAD.start()
This is a threading violation. QWidgets can only be accessed from QApplication's thread.
Why not use Qt's input system?
-
@jeremy_k The OP wants to listen to the keyboard and mouse events even when no Qt window has focus, a possible solution in the Qt style can be using nativeEventFilter but in python there are other simpler options such as pyinput, you just have to respect the rules that Qt indicates like the GUI is not thread-safe.
-
@eyllanesc said in Window shows up in a weird way when called in a different place:
@jeremy_k The OP wants to get the keyboard and mouse events even when no Qt window has focus, a possible solution in the Qt style can be using nativeEventFilter but in python there are other simpler options such as pyinput, you just have to respect the rules indicated by Qt as the GUI is not thread-safe.
Something in the application must have focus for pyinput to receive the event.
Running two event loops is a different definition of simpler...
-
@jeremy_k The simpler always depends, for example Qt does many things so it is not simple from the point of view of its complexity but those of us who use Qt is simpler because everything underneath is hidden.
Nothing has to have the focus, pyinput just like Qt subscribes to the OS events only it discards the events that are not handled by it, potentially Qt can perform the pyinput task through native event filter but in pyinput already It is done so it saves us work.