pyautogui mouseDown() не работает для автоматического движения мыши

В главе 20 книги «Автоматизация скучных вещей» есть пример, использующий pyautogui для рисования спирали. Код использует .drag() для рисования каждого сегмента, но в каждом углу мышь отпускает курсор и начинает новую строку. Это создает разрыв в каждом углу для любого типа кисти, которую вы используете.

введите здесь описание изображения

Чтобы решить эту эстетическую проблему, я попытался изменить код, чтобы использовать вместо него .mouseDown() и .move(). Однако это закончилось тем, что ничего не рисовалось, кроме линии, идущей из верхнего левого угла в нижний левый угол, как если бы каждая итерация цикла while повторяла щелчок.

По тестированию:

while True:
    pyautogui.mouseDown()

В mspaint функция .mousedown() действительно работает правильно, когда я сам перемещаю мышь.

Пытающийся:

while True:
    pyautogui.mouseDown()
    pyautogui.move(300, 0, duration=0.5)

Также правильно рисует линию, но делает это кусками по 300 пикселей. т.е. каждый раз, когда цикл повторялся, сегмент линии загружался в mspaint.

Повторение этого эксперимента в квадрате:

while True:
    pyautogui.mouseDown()
    pyautogui.move(300, 0, duration=0.5)
    pyautogui.move(0, 300, duration=0.5)
    pyautogui.move(-300, 0, duration=0.5)
    pyautogui.move(0, -300, duration=0.5)

В итоге ничего не нарисовал.

Что здесь происходит? Почему поведение .mouseDown() такое непоследовательное? Как заставить мой код рисовать красивую непрерывную спираль?

Полный исходный код для справки здесь:

#! python3
# spiralDraw.py - draws a spiral in mspaint

import pyautogui
import time

time.sleep(5)   # give time to go to paint app
distance = 300
change = 20
pyautogui.mouseDown()

while distance > 0:
    pyautogui.move(distance, 0, duration=0.5)   
    distance = distance - change
    pyautogui.move(0, distance, duration=0.5)   
    pyautogui.move(-distance, 0, duration=0.5)  
    distance = distance - change
    pyautogui.move(0, -distance, duration=0.5)
    
if distance == 0:
    pyautogui.mouseUp()

person Cambuchi    schedule 02.01.2021    source источник


Ответы (2)


Я обнаружил, что вы должны использовать drag для рисования линии, потому что функция move только перемещает указатель, не выполняя щелчок вниз (документация).

Однако вы по-прежнему можете использовать функцию mouseDown вместо функции click, поскольку она делает то же самое, что и щелчок левой кнопкой мыши (документация).

Функция drag (по крайней мере, в последней версии пакета) нуждается в параметре с именем button, который может быть "left", "right" или "middle", представляющим каждый из трех щелчков мыши (документация).

Основываясь на предыдущей информации, код:

import pyautogui
import time

time.sleep(5)  # give time to go to paint app
distance = 300
change = 20
pyautogui.mouseDown()

while distance > 0:
    pyautogui.drag(distance, 0, duration=0.5, button='left')
    distance = distance - change
    pyautogui.drag(0, distance, duration=0.5, button='left')
    pyautogui.drag(-distance, 0, duration=0.5, button='left')
    distance = distance - change
    pyautogui.drag(0, -distance, duration=0.5, button='left')

if distance < 0:
    pyautogui.mouseUp()
person Lucas Belfanti    schedule 02.01.2021
comment
Это по-прежнему приводит к сломанным углам результата, если вы используете непиксельный тип кисти. Ваш код дает мне следующее: i.imgur.com/tGJnpC3.png - person Cambuchi; 03.01.2021
comment
Я нашел способ реализовать предполагаемое поведение, включающее многопоточность, но я понятия не имею, почему код не работает без него. Я разместил ответ в этой ветке вопросов. - person Cambuchi; 03.01.2021

Хотя я не уверен, почему это так, желаемого результата можно достичь, разделив удержание мыши и движения мыши на отдельные потоки и запустив их одновременно.

Вот вывод не многопоточного кода с кистью-карандашом, обратите внимание на блочные углы, реализованные перетаскиванием, поскольку каждая строка представляет собой отдельное нажатие мыши:

введите здесь описание изображения

А вот результат от кода, который разделяет задачи на два потока и запускает их одновременно, как видите углы сглажены, и это все одна длинная строка, так как когда я нажимаю ctrl+z весь рисунок исчезает:

введите здесь описание изображения

Вот код, который просто реализует многопоточность:

import pyautogui
import time
import threading

def mouseHoldDown():
    global distance
    while distance > 0:
        pyautogui.mouseDown()
    if distance == 0:
        time.sleep(1)
        pyautogui.mouseUp()
    
def movingSpiralMouse():
    global distance
    change = 20
    while distance > 0:
        pyautogui.move(distance, 0, duration=0.25)
        distance = distance - change
        pyautogui.move(0, distance, duration=0.25)
        pyautogui.move(-distance, 0, duration=0.25)
        distance = distance - change
        pyautogui.move(0, -distance, duration=0.25)

distance = 300
time.sleep(5)

mouseObj = threading.Thread(target=mouseHoldDown)
mouseObj.start()

moveObj = threading.Thread(target=movingSpiralMouse)
moveObj.start()

Я все равно был бы очень признателен за объяснение того, почему это необходимо разделить на несколько потоков для достижения желаемых результатов.

person Cambuchi    schedule 02.01.2021