将值从函数传递给标签

问题描述 投票:0回答:2

我想将函数的值传递或存储到变量,然后使用该变量放入标签。

我尝试对变量进行全局赋值,但它给出了错误:未定义名称“num”。您的意思是:'sum'?.

global num


def takeWeight():
    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()


weightDisplay = ttk.Label(startScan_frame, text=num)
weightDisplay.grid(column=2, row=4)
weightDisplay.grid_configure(pady=20)
python-3.x tkinter pyserial
2个回答
1
投票

所以你走对了!但是您对全局变量的处理方式有点错误。 您在函数外定义的任何变量都存在于全局范围内。您使用 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 一起使用,并且会导致您的 GUI 挂起。幸运的是,这也是可以修复的!

tkinter 有一个名为

after

 的方法,它让您基本上可以将函数调用插入到 GUI 事件循环中。这样,您可以在保持 GUI 运行的同时轮询串行端口以获取新信息。您只需要修改
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)
现在请注意,

ser.close()

 不再被 
takeWeight
 调用 - 你必须稍微不同地处理这个问题!在这种情况下,您可以只定义一个
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
 函数,a la 
takeWeight()
.


1
投票
您可以通过将全局变量放在函数内部来引用全局变量,因为全局声明在它之外没有做任何事情。下面是我的意思的一个例子。

num = None def takeWeight(): global num ...
通过进行此更改,您可以从函数内部更新全局变量,而无需更改函数的功能。问题是您只会更新全局变量而不更新标签内的文本。要解决此问题,您可以通过更改其文本来引用标签本身,将其添加回网格,然后更新窗口。下面是可以使用的代码。

def takeWeight(): ser = serial.Serial('COM3', 57600, timeout=1) while True: line = ser.readline() # read a byte if line: weightDisplay.grid_forget() weightDisplay.configure(text = line.decode().strip()) weightDisplay.grid(column=2, row=4, pady=20) # then add your_window_name.update() and your_window_name.update_idletasks() ser.close() weightDisplay = ttk.Label(startScan_frame, text="default text for label") weightDisplay.grid(column=2, row=4, pady=20)
通过删除标签并将其重新添加到网格中,您可以确保它得到更新并正确显示。您也不需要全局变量。只要确保你有办法停止在函数中创建的无限 while 循环。

© www.soinside.com 2019 - 2024. All rights reserved.