如何每半秒钟更新一次tkinter文本标签?如何避免.mainloop以便其余程序可以执行?

时间:2019-12-12 12:19:20

标签: python tkinter

我正在使用Kvaser Leaf Professional,并尝试通过 Python编码从摩托车读取 can-bus 数据,以便能够使用这些数据来查看哪些值更改,哪些值保持不变。

此刻,我正努力在tkinter上显示数据,并在每次读取/更新数据后都对其进行更新,因为它每隔几微秒就会变化一次。正常使用.after()的方法似乎无法100%正常工作,或者我只是做错了什么。还是有比tkinter更好的显示更新数据的方法?

我遇到的另一个问题是,当我显示tkinter时,它使用root.mailoop()来运行窗口,当它发生时,它将进入该主循环,而不会退出并运行其余部分程序,也将无法更新窗口上显示的现有数据。有没有办法绕过root.mainloop()

任何见解都会有所帮助和/或我在代码中犯的小错误。我仅在两天前才开始使用Python,但我仍然学到很多东西,并且还不了解所有内容。 预先谢谢你。

到目前为止,这是我的整个程序:

import keyboard
import time
import sys
import tkinter as tk
import binascii

from canlib import canlib, Frame
from canlib.canlib import ChannelData

root = tk.Tk()

def setUpChannel(channel,
                 openFlags=canlib.canOPEN_ACCEPT_VIRTUAL,
                 bitrate=canlib.canBITRATE_500K,
                 bitrateFlags=canlib.canDRIVER_NORMAL):
    ch = canlib.openChannel(channel, openFlags)
    print("Using channel: %s, EAN: %s" % (ChannelData(channel).channel_name,
                                          ChannelData(channel).card_upc_no)
                                                )
    ch.setBusOutputControl(bitrateFlags)
    ch.setBusParams(bitrate)
    ch.busOn()
    return ch

def tearDownChannel(ch):
    ch.busOff()
    ch.close()

def text(t):
    tx = binascii.hexlify(t).decode('utf-8')
    n = 2
    txt = [tx[i:i+n] for i in range(0, len(tx), n)]
    return txt

def counter():
    while True:
        try:
            cnt = 1
            frame = ch0.read()
            firstID = frame.id
            while True:
                frame = ch0.read()
                cnt += 1
                if frame.id == firstID:
                    break
            pass    
        except (canlib.canNoMsg):
            break        
        except (canlib.canError):
            print("Rerun")
    pass
    return cnt

print("canlib version:", canlib.dllversion())

ch0 = setUpChannel(channel=0)
ch1 = setUpChannel(channel=1)

frame = Frame(id_=100, data=[1, 2, 3, 4], flags=canlib.canMSG_EXT)
ch1.write(frame)
print(frame)

cnt = counter()
print("Counter: %d" %(cnt))
time.sleep(1)

while True:
    while True:
        try:
            show = ""
            i = 1
            while i <= cnt:
                frame = ch0.read()
                show = show +("%s\t%s\n" %(frame.id, text(frame.data)))
                i += 1
            print(show)          
            T = tk.Text(root, height=6, width=80)
            T.config(state="normal")
            T.insert(tk.INSERT, show)
            T.pack()
            root.mainloop()
            break
        except (canlib.canNoMsg) as ex:
            pass
        except (canlib.canError) as ex:
            print(ex)
        pass

tearDownChannel(ch0)
tearDownChannel(ch1)

您可以根据需要编辑我的代码,如果我能更好地实现代码,这将对您大有帮助。

1 个答案:

答案 0 :(得分:0)

您不需要使用多线程或任何令人费解的东西。只需使用widget.after()方法在所需时间后调用您选择的另一个函数/方法即可。在以下情况下,时间为1秒-> 1000毫秒。只需在mainloop之前调用该类,它将开始工作。

class UI:
    def __init__(self, parent):
        # variable storing time
        self.seconds = 0
        # label displaying time
        self.label.configure(text="%i s" % self.seconds)
        # start the timer
        self.label.after(1000, self.refresh_label)


    def refresh_label(self):
        #refresh the content of the label every second
        # increment the time
        self.seconds += 1
        # display the new time
        self.label.configure(text="%i s" % self.seconds)
        # request tkinter to call self.refresh after 1s (the delay is given in ms)
        self.label.after(1000, self.refresh_label)