I am trying to make a small app with python tkinter. in which i will need a ping command to constantly check for connection to a certain device example '192.168.1.21' and tells me if the device is connected or not real time. Nota: i am using ping3 this is my program:
root = Tk()
root.geometry("400x400")
label_1 = Label(root, text = "Not connected")
label_1.pack()
def testing(label):
if ping('192.168.1.21', timeout=0.5) != None: #To test the connection 1 time
label.config(text = "Connected")
else:
label.config(text = "Not Connected")
label.after(500, lambda : testing(label_1))
def popup(): #A popup that does the same thing
top = Toplevel(root)
top.geometry("150x150")
label_2 = Label(top, text = "Not connected")
label_2.pack()
label_2.after(500, lambda : testing(label_2))
top.mainloop()
btn = Button(root, text = "Popup", command=popup)
btn.pack()
testing(label_1)
root.mainloop()
How can i make it not freeze and keep testing while letting the rest of the program run smoothly. Thank you and sorry if I made mistakes in the code, i am still new to python in generale.
CodePudding user response:
You can achieve this using threading. This allows the tkinter mainloop and the pinging to happen concurrently which means the GUI doesn't freeze.
import threading, time, sys
root = Tk()
root.geometry("400x400")
label_1 = Label(root, text = "Not connected")
label_1.pack()
current_value = None
continue_thread = True
def doPing():
global current_value, continue_thread
while continue_thread:
current_value = ping('192.168.1.21', timeout=0.5)
time.sleep(0.5) # 500ms delay before pinging again
sys.exit() # Stop thread when window is closed
def testing(label):
global current_value
if current_value != None: #To test the connection 1 time
label.config(text = "Connected")
else:
label.config(text = "Not Connected")
label.after(500, lambda : testing(label))
def popup(): #A popup that does the same thing
top = Toplevel(root)
top.geometry("150x150")
label_2 = Label(top, text = "Not connected")
label_2.pack()
label_2.after(500, lambda : testing(label_2))
top.mainloop()
btn = Button(root, text = "Popup", command=popup)
btn.pack()
ping_thread = threading.Thread(target = doPing)
ping_thread.start()
testing(label_1)
root.mainloop()
continue_thread = False # end thread after window is closed
The program now uses a thread, ping_thread
, which runs doPing
. doPing
calls ping
, updates current_value
and then waits 500ms before calling itself again. Then in the main thread testing
updates the label every 500ms using the value of current_value
. When the window is closed and root.mainloop
has finished continue_thread
is set to false so then sys.exit
is called, stopping the thread.
There are 2 global variables current_value
and continue_thread
. The first allows you to access the return value of ping
in testing
and the second allows the main thread to tell the ping thread to stop when the Tkinter window is closed. Global variables are not good programming practice and I'd advise using classes instead. I've used them here for the sake of simplicity.