0

How would I adjust my code to run the following loop while a radio button is selected? The idea is to create a program that clicks the left mouse button every 20 seconds or so to prevent idle. I think I'm so close I just don't quite understand how the mainloop() event stuff works. Does my loop code need to go in the main loop or something? Also, what is value=val).pack(anchor=tk.W)? I have a feeling that is a piece I don't get as well. Here is my current code:

import tkinter as tk, pyautogui, time  # This is the prefered way to call tkinter, don't use wildcards. 
    
my_ui_window = tk.Tk() # TK
my_ui_window.title('Radio Button Example')
v = tk.IntVar()
v.set(1)  # initializing the choice

on_or_off = [
    ("Enabled"),
    ("Disabled")
]

def ExecuteChoice():
    choice = (v.get())
    while choice == 0:
        time.sleep(20)
        pyautogui.click()
    else:
            print ('waiting...')
            time.sleep(3)

for val, i in enumerate(on_or_off):
    tk.Radiobutton(my_ui_window, 
                  text=i,
                  borderwidth = 2,
                  indicatoron= 0,
                  width = 20,
                  padx = 50, 
                  variable=v, 
                  command=ExecuteChoice(),
                  value=val).pack(anchor=tk.W)

my_ui_window.mainloop()
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
jphempen
  • 11
  • 4
  • Here is a pretty good explanation about ```mainloop()``` https://stackoverflow.com/questions/29158220/tkinter-understanding-mainloop I would say by reading the first answer you will get an idea of what to do good luck :) – Shad0w Nov 25 '20 at 18:50
  • By the way, is pyautogui working to prevent PC sleeping? For me it didn't work. Ardino device like mouse jiggler is working fine. – shimo Nov 25 '20 at 18:51
  • 1
    @shimo It doesn't work for mouse movement but it does seem to prevent sleep when using mouse click. I'm aware mouse jiggler exists I'm just learning some Python. – jphempen Nov 25 '20 at 19:06

2 Answers2

1

Here is my code re-written appropriate to tkinter. I was making several mistakes. The main one is you typically do not run loops inside tkinter and you definitely don't use sleep. Instead we use the .after class. Here is a better way. It's now heavily commented for anyone lost.

import tkinter as tk # This is the prefered way to call tkinter, don't use wildcards. 
import pyautogui # This allows mouse stuff
import time # This allows sleep commands

my_ui_window = tk.Tk() # make tk.Tk() into just a single object.
my_ui_window.title('Radio Button Example')
v = tk.IntVar() # This becomes the index of sorts for our radio elements.
v.set(1)  # initializing radio button to off

on_or_off = [ # Creates an array to represent the radio buttons needed.
    ("Enabled"),
    ("Disabled")
]

def every_20_seconds(): # Calls this function which clicks if the radio button is set to index 0. It then tells my_ui_window to wait 20 seconds using the .after method before calling itself again. In the meantime, it gives control back to the mainloop() which is always searching for an event change on the UI.
    if v.get() == 0:
        pyautogui.click()
    my_ui_window.after(20000, every_20_seconds)


for val, i in enumerate(on_or_off): # This builds the UI for us.
    tk.Radiobutton(my_ui_window, 
                  text=i,
                  borderwidth = 2,
                  indicatoron= 0,
                  width = 20,
                  padx = 50, 
                  variable=v, 
                  value=val).pack(anchor=tk.W)


every_20_seconds()
my_ui_window.mainloop()
jphempen
  • 11
  • 4
-1

This should do pretty much what you want, even though it's not perfect yet:

    import tkinter as tk,pyautogui,time 
    import threading
    
    my_ui_window = tk.Tk() # TK
    my_ui_window.title('Radio Button Example')
    v = tk.IntVar()
    v.set(0)  # initializing the choice
    
    on_or_off = [
        (1, "Enabled"),
        (0, "Disabled")
    ]
    
    def ExecuteChoice():
        choice = v.get()
        if choice == 1:
            print("CLICK")
            threading.Timer(5.0, ExecuteChoice).start()
        else:
            print ('waiting...')
            pass
    
    for val, name in on_or_off:
        tk.Radiobutton(my_ui_window,
                      text=name,
                      borderwidth = 2,
                      indicatoron= 0,
                      width = 20,
                      padx = 50,
                      variable=v,
                      command=ExecuteChoice,
                      value=val).pack(anchor=tk.W)
    
    my_ui_window.mainloop()

There were two issues with your code:

  1. You used command=ExecuteChoice() instead of command=ExecuteChoice. Thus, you call the function when initializing your RadioButtons instead of setting this function as a parameter
  2. Yourwhile loop in ExecuteChoice was blocking, i.e. it is the only thing running. The GUI will not update anymore. Hence, you need to call my_ui_window.update() and choice = v.get() in the loop so to update the GUI and check whether the user has changed his choice of Radio-Buttons Thus, we exchange it with an if and an asynchronous timer instead of sleep()

/e: Comment is right. As mentioned, this is not best practice but the closest to the code of the poster to still make it work. I've made a little additional adjustment, to not block anymore. That doesn't mean its best practice. This would include rewriting the code more.

mc51
  • 1,883
  • 14
  • 28
  • You shouldn't be calling `time.sleep()` in the main thread of a GUI. It will do exactly what it says, causing the entire program to go to sleep. While it's sleeping it can't process any events. – Bryan Oakley Nov 26 '20 at 10:13