所以你走上了正确的道路!但你对全球的看法有点错误.
您定义的任何outside a function变量都存在于全局作用域中.您可以使用关键字global
inside您的函数来允许该函数修改该全局变量的值
def takeWeight():
global num # allow this function to modify the value of 'num'
ser = serial.Serial('COM3', 57600, timeout=1)
while True:
line = ser.readline() # read a byte
if line:
num = line.decode().strip()
print(num)
ser.close()
num = '' # declare 'num' as a placeholder in the global scope
weightDisplay = ttk.Label(startScan_frame, text=num)
weightDisplay.grid(column=2, row=4)
weightDisplay.grid_configure(pady=20)
也就是说,由于这是tkinter,您真正想要的是将您的Label
的textvariable
属性绑定到tk.StringVar()
那么这意味着什么呢?
def takeWeight():
ser = serial.Serial('COM3', 57600, timeout=1)
while True:
line = ser.readline() # read a byte
if line:
num.set(line.decode().strip()) # call 'set' to update the value of 'num'
print(num.get()) # call 'get' to retrieve the current value of 'num'
ser.close()
num = tk.StringVar() # create an instance of 'StringVar' to store your value
# and then bind that variable to your label - this way, whenever you update 'num'
# using 'num.set('whatever'), your label will update automatically!
weightDisplay = ttk.Label(startScan_frame, textvariable=num)
weightDisplay.grid(column=2, row=4)
weightDisplay.grid_configure(pady=20)
到目前一切尚好!不幸的是,您在这里仍然会遇到一个问题,因为While
循环!阻塞操作和循环不能很好地处理tkinter,并且会导致您的图形用户界面挂起.幸运的是,这也是可以修复的!
Tkinter有一个名为after
的方法,它允许您基本上将函数调用插入到图形用户界面事件循环中.这样,您可以轮询您的串口的新信息,同时保持您的图形用户界面运行.您只需修改takeWeight
即可使用after
# 'ser' doesn't need to be declared *every* time 'takeWeight' is called,
# so let's move it into the global scope (this also lets us refer to 'ser'
# in the 'close' method described below!)
ser = serial.Serial('COM3', 57600, timeout=1)
# let's also declare a placeholder that will store the id of the 'after' call
serial_loop_id = None
def takeWeight():
global serial_loop_id
line = ser.readline() # read a byte
if line:
num.set(line.decode().strip())
# use 'after' to call this function again after 100mS
serial_loop_id = root.after(100, takeWeight)
请注意,现在takeWeight
不再调用ser.close()
--您必须稍微改变一下处理方式!在本例中,您可以只定义一个close
函数来停止takeWeight
循环,然后调用ser.close
.你准备好了就打close()
.
def close():
root.after_cancel(serial_loop_id) # stop the 'takeWeight' polling loop
ser.close() # close the serial port
注意:root.after()
和root.after_cancel()
假定tk.Tk
的主实例称为root
.如果你做了像mainwindow = tk.Tk()
这样的事情,那就用mainwindow.after()
吧!
最后要注意的是,在某个地方实际调用takeWeight
函数之前,takeWeight
中的连续轮询不会开始.