0

I would like to ping every second in my network a certain hostname and change in return the name of the corresponding button. For now I have this :

import tkinter as tk
import time

# variables
hostname = ("ASUS-PC")
mot= "inactif"

class test(tk.Tk):
    # make buttons on grid
    def __init__(self):
        tk.Tk.__init__(self)

        self.button = list()
        for i in range(10):
            i=i+1
            RN = ('RN '+str(i))
            self.button.append(tk.Button(text=RN))
            self.button[-1].grid(row=0,column=i)
    # ping hostname every second
    def ping(self):
        import subprocess
        import os
        result=subprocess.Popen(["ping", "-n", "1", "-w", "200", hostname],shell=True).wait()
        if result == 0:
            print (hostname, "active")
        else:
            B = self.button[0] 
            B ['text'] = mot

        time.sleep(1)
    while True:
        ping()

app = test ()
app.mainloop() 

It doesn't work and I don't know why. At beginning it was a "self" problem but now it seems to be related to how I ping every second (I took it from there What is the best way to repeatedly execute a function every x seconds in Python?) If someone know the answer...

Thanks for your help

Community
  • 1
  • 1
  • The variable `button` is out of scope when it is referenced. Related: http://stackoverflow.com/questions/291978/short-description-of-python-scoping-rules – Kyle Pittman Oct 06 '15 at 21:51
  • Did you mean to make that `self.button` (note you're even missing the appropriate argument on `ping`)? Local variables in functions are inaccessible from outside, **on purpose**. – jonrsharpe Oct 06 '15 at 21:52

2 Answers2

0

The reason your code "doesn't work" is that you have an infinite loop that calls sleep. This prevents the event loop from processing any events, including events that tell Tkinter to refresh the display. Your program is actually working, you just can't see any results.

The solution is to use after to call your function once a second. Between those calls, tkinter will have time to update the display without you having to do any extra work.

All you need to do is remove the call to sleep, and add a call to after. Once you do that, remove your while loop, and call this function once. Tkinter will then call this function once every second (approximately)

It looks something like this:

def ping(self):
    <all your other code>
    self.after(1000, self.ping)

It looks a bit like recursion, but it's not. You're simply adding an event on the queue of events managed by Tkinter. When the time comes, it pulls the item off of the queue and executes it.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • I'm a beginner in Python. Could you write me a little example of what you describe please ? Like that I won't make mistake and understand better the method. Thanks :D – Jonathan Ramelli Oct 07 '15 at 14:59
0

Thanks a lot everyone ! Now it works :

...
    # ping hostname every second
    def ping(self):
        import subprocess
        import os
        result=subprocess.Popen(["ping", "-n", "1", "-w", "200", hostname],shell=True).wait()
        if result == 0:
            print (hostname, "active")
        else:
            print (hostname, "inactive")
            B = self.button[0] 
            B ['text'] = mot

        self.after(1000, self.ping)

app = test ()
app.ping()
app.mainloop() 
  • I see you're new to stackoverflow. If you haven't read it yet, please read http://stackoverflow.com/help/someone-answers. – Bryan Oakley Oct 07 '15 at 16:04