Mauricio Mauricio - 14 days ago 5
Python Question

python tkinter: how to iterate with rather specific times (root.after not working)

im writing an autoclicker. ive sperated my clicks by time between mouse down and mouse up, and time between clicks (those times are stored in a csv file). basic idea, i want to run the program, and a window pops up with a start and a stop button(accomplished). i want to be able to hit start, and run a 'loop' of clicks ('iterating' through a list with the times saved) until i hit pause. i say 'loop' and 'iterate' because i know you cant run a seperate loop inside the main loop of tkinter. i tried used root.after to wait the time between clicks, then call a function that performs a click, but root.after doesnt take times that are as specific as i want. any ideas? heres the full script, and ill give a sample of the csv file as well. Im open to using other modules besides tkinter/other languages, if anything pops into your mind

import csv
import time
from tkinter import *
from PyWinMouse import *


root = Tk()
start_button = Button(root, text="start", width="7")
pause_button = Button(root, text="pause", width="7")
start_button.pack()
pause_button.pack()

# holds times for clicks[time_between_up_down, time_between_clicks]
click_info = []
info_length = 0
clicker = Mouse()
paused = True
iterateVar = 0


def get_csv():
global click_info, info_length
file = open("times.csv", 'r')
reader = csv.reader(file, delimiter=",")
for row in reader:
click_info.append(row)
info_length = len(click_info)


def click():
global iterateVar
if iterateVar < (info_length - 1) and paused is False:
clicker.left_down()
time.sleep(click_info[iterateVar][0])
clicker.left_up()
iterateVar += 1


def pause_button_function(event):
global paused
paused = True


def start_button_function(event):
global paused
paused = False


get_csv()
pause_button.bind("<Button-1>", pause_button_function)
start_button.bind("<Button-1>", start_button_function)
root.after(float(click_info[iterateVar][1]), click)
root.mainloop()


this error is given:

Traceback (most recent call last):
File
"C:/Users/Owner/PycharmProjects/NaturalHumanBehaviorClickInfoGatherer/ActualClic ker.py", line 52, in <module>
root.after(float(click_info[iterateVar][1]), click)
File "C:\Users\Owner\AppData\Local\Programs\Python\Python35\lib\tkinter\__init__.py", line 604, in after
return self.tk.call('after', ms, name)
_tkinter.TclError: bad argument "1.0223703384399414": must be cancel, idle, info, or an integer


snapshot of what the csv file looks like(ignore the 'False', that's for other stuff):

0.0948493480682373,1.0223703384399414,False
0.09569144248962402,0.17647409439086914,False
0.06346511840820312,0.14343690872192383,False
0.09652972221374512,0.08008456230163574,False
0.07996273040771484,0.07998061180114746,False
0.09551239013671875,0.0805819034576416,False
0.08001160621643066,0.04780721664428711,False

Answer

after method accepts time as a integer form (in milliseconds). You need to convert the value into int (multiplied by 1000 to mean milliseconds):

ms = int(click_info[iterateVar][1] * 1000)
root.after(ms, click)

NOTE

  1. after make the fucntion called once. If you want to call it repeatedly, you need to call it again (maybe inside the callback click).
  2. Do not call time.sleep inside the callback function. It make UI freezing.
Comments