import platform
import subprocess
from tkinter import *
###IPs to use
iptoscan = {
'test': '8.8.8.8',
'test 2' : '7.7.7.7',
'test 3' : '1.1.1.1'
}
###Ping function
def ping(ipAddr: object, timeout: object = 100) -> object:
if platform.system().lower() == 'windows':
numFlag = '-n'
else:
numFlag = '-c'
global completedPing
completedPing = subprocess.run(['ping', numFlag, '1', '-w', str(timeout), ipAddr],
stdout=subprocess.PIPE, # Capture standard out
stderr=subprocess.STDOUT) # Capture standard error
if completedPing.returncode == 0: # I need this if command to send the IP address and a True command
pingstatus = "Network Active " # Active ping response
else: # I need this to send the IP plus a False command
pingstatus = "Network Error " # No ping response
print(pingstatus + ipAddr)
return (completedPing.returncode == 0) and (b'TTL=' in completedPing.stdout)
###Function to ping from dictionary
def multiping():
for ips in iptoscan:
ping(iptoscan[ips])
if completedPing.returncode == 0:
return True
else:
print("notworking")
我的问题
我没有使用“ButtonPress”,而是希望使用ping的结果更改框,true变为绿色false保持红色。所以基本上一旦代码运行,我希望它从字典中ping,如果结果为真,我希望它改变每个框的颜色。
class OneSquare():
def __init__(self, can, start_x, start_y, size):
self.can=can
self.id = self.can.create_rectangle((start_x, start_y,
start_x+size, start_y+size), fill="red")
self.can.tag_bind(self.id, "<ButtonPress-1>", self.set_color)
self.color_change=True
def set_color(self, event=None):
self.color_change = not self.color_change
color="red"
if not self.color_change:
color="green"
self.can.itemconfigure(self.id, fill=color)
root = Tk()
canvas = Canvas(root)
canvas.grid(column=1, row=1, sticky=(N, S, E, W))
#Boxes to display the network status
IP1=OneSquare(canvas, 1, 1, 30)
IP2=OneSquare(canvas, 1, 50, 30)
IP3=OneSquare(canvas, 1, 100, 30)
#Exit button
Button(root, text="Exit", bg="orange",
command=root.quit).grid(row=2)
multiping()
root.mainloop()
答案 0 :(得分:1)
这是一个有点棘手的问题,因为当目标设备无法访问时,从OS调用的ping请求可能会有延迟。这将导致循环过程中持续的tkinter冻结和程序延迟。为了避免这种情况,最简单的方法是使用线程(tkinter不喜欢)。
你需要有一个单独的线程来不断地执行这些请求,并在tkinter执行时结束。确保您没有从该线程到您的小部件进行任何调用,因为这会导致意外错误和崩溃。
以下是一个可以应用于代码的简单示例:
import subprocess, time
from tkinter import *
from threading import Thread
iptoscan = { # Your IP list
'test': '8.8.8.8',
'test 2' : '7.7.7.7',
'test 3' : '1.1.1.1'
}
def startPing():
while root:
for id in iptoscan:
process = subprocess.Popen(['ping', iptoscan[id], '-n', '1'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # This is just for windows OS (the system i'm testing on), -n 1 if for sending only one ping request
#labels[id][1] = process.stdout.read().split('\r\n')[2] # for python 2.x
labels[id][1] = str(process.stdout.read()).split('\\r\\n')[2]
time.sleep(1) # Delay between ping requests
def updateLabels():
for id in labels:
if 'time=' in labels[id][1]: # This could be our trigger for knowing if ping was successful
labels[id][0].configure(bg = 'green', text = 'IP: ' +iptoscan[id] + ', time: ' + labels[id][1].split('time=')[1].split(' ')[0] ) # I'm updating the names also as you can see
else:
labels[id][0].configure(bg = 'dark orange', text = 'IP: ' +iptoscan[id] + ' ' +labels[id][1] ) # If the requst fails, display the message
root.after(100, updateLabels) # Continue the loop
root = Tk()
root.geometry('300x120')
labels = {} # We'll store the label widget and ping response in this dictionary
for id in iptoscan:
label = Label(root, text = 'IP: ' + iptoscan[id] )
label.pack(side='bottom',pady=10)
labels[id] = [label, ''] # First element will be the widget and second one the response
Thread(target = startPing).start() # Starting the thread to perform ping requests
root.after(100, updateLabels) # Starting to loop the function that will update ping responses to our widgets
root.mainloop()
root = None