Python, слушатель клавиатуры в цикле, позиция указателя: я не могу найти свою ошибку в коде [дубликат]

Вопрос или проблема

Вызов метода getPointerPos из моего класса WindowManager:

def main():
    from WindowManager import *
    MyWind = WindowManager()
    MyWind.getPointerPos()
if __name__ == '__main__':
    main()

Метод getPointerPos, определенно плохо написан (метод класса WindowManager):

   def getPointerPos(self):
        # сравниваем pyautogui и win32
        import win32api, pyautogui, pynput 
        print_r("","ОТЛАДКА КЛАССА: РЕКОРДЕР ДЕЙСТВИЙ: Нажмите 'q' для выхода")
        keepGoing = True
 
        def StopCallBack():
            KeepGoing = False
            h.stop()

        while keepGoing :
            x_win, y_win = win32api.GetCursorPos()
            x_pynput, y_pynput = pyautogui.position()
            print(f"win32: ({x_win}, {y_win})\t pynput:({x_pynput}, {y_pynput}) (нажмите 'q' для выхода)")
            sleep(0.5)
            with pynput.keyboard.GlobalHotKeys({
                'q': StopCallBack,
                '<ctrl>+c': quit}) as h: h.join()

Что это делает:
позиция указателя блокируется, пока я не нажму ‘q’. Затем она отображается, пока я снова не нажму ‘q’ и так далее. Цикл while никогда не прерывается.

Что ожидается достичь:
позиция указателя должна постоянно выводиться в консоль, а этот while цикл должен остановиться, когда я нажму ‘q’.

Мысли
Я подозреваю, что цикл while keepGoing не останавливается, так как нет команды break, чтобы прервать цикл while. Я ожидал, что цикл прервется, взяв значение булевой переменной keepGoing на лету. Тем не менее, я хочу сохранить этот метод “самостоятельным” и “простым” (не создавать много сложных слушателей только для нажатия символа ‘q’) в классе.

Буду признателен за любую помощь.

Ответ или решение

Ваша проблема заключается в том, что переменная keepGoing в методе getPointerPos на самом деле не изменяется в функции StopCallBack, что приводит к тому, что цикл while никогда не прерывается. Ниже приведён исправленный код, а также объяснение, как это работает.

Исправленный код

import win32api
import pyautogui
import pynput
from time import sleep

class WindowManager:
    def getPointerPos(self):
        print("DEBUGGING CLASS: ACTION RECORDER: Press 'q' to exit")
        keepGoing = True

        def StopCallBack():
            nonlocal keepGoing  # Используем nonlocal для изменения переменной в замыкании
            keepGoing = False

        # Инициализируем глобальные горячие клавиши
        with pynput.keyboard.GlobalHotKeys({
            'q': StopCallBack,
            '<ctrl>+c': quit}) as h:
            while keepGoing:
                x_win, y_win = win32api.GetCursorPos()
                x_pynput, y_pynput = pyautogui.position()
                print(f"win32: ({x_win}, {y_win})\t pynput:({x_pynput}, {y_pynput}) (press 'q' to exit)")
                sleep(0.5)

            h.stop()  # Останавливаем слушатель после выхода из цикла

def main():
    MyWind = WindowManager()
    MyWind.getPointerPos()

if __name__ == '__main__':
    main()

Объяснение изменений

  1. Использование nonlocal: Чтобы изменить значение переменной keepGoing в функции StopCallBack, мы используем ключевое слово nonlocal. Это позволяет функции доступа к переменной из внешней области видимости (в данном случае — из метода getPointerPos).

  2. Глобальные горячие клавиши: Перемещение инициализации горячих клавиш вне цикла while позволяет избежать повторной инициализации на каждой итерации, что упрощает код и потенциально повышает производительность.

  3. Стоп Listening: После выхода из цикла while, вызывается h.stop(), чтобы корректно остановить слушатель горячих клавиш.

Итог

Теперь, когда вы запустите данный код, он будет следить за положением указателя мыши и печатать его постоянно, пока вы не нажмёте клавишу ‘q’. Как только вы ее нажмёте, программа остановится.

Если у вас есть дополнительные вопросы или проблемы, пожалуйста, дайте знать!

Оцените материал
Добавить комментарий

Капча загружается...