Python 如何每半秒钟更新tkinter文本标签?如何避免.main循环,以便程序的其余部分可以执行?

Python 如何每半秒钟更新tkinter文本标签?如何避免.main循环,以便程序的其余部分可以执行?,python,tkinter,Python,Tkinter,我正在使用Kvaser Leaf Professional,并试图通过Python编码从摩托车读取can总线数据,以便能够使用数据查看值在哪里变化,哪些值保持不变 目前,我正努力在tkinter上显示数据,并在每次读取/更新数据后进行更新,因为数据每隔几微秒就会发生变化。正常使用.after()的方法似乎无法100%正常工作,或者我只是做错了什么。还是有比显示更新数据更好的方法 我遇到的另一个问题是,当我显示tkinter时,它使用root.mailoop()来运行窗口,当这种情况发生时,它进入

我正在使用Kvaser Leaf Professional,并试图通过Python编码从摩托车读取can总线数据,以便能够使用数据查看值在哪里变化,哪些值保持不变

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

我遇到的另一个问题是,当我显示
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)
导入键盘
导入时间
导入系统
将tkinter作为tk导入
导入binascii
从canlib导入canlib,帧
从canlib.canlib导入通道数据
root=tk.tk()
def设置通道(通道,
openFlags=canlib.canOPEN\u ACCEPT\u VIRTUAL,
比特率=canlib.canBITRATE_500K,
bitrateFlags=canlib.canDRIVER\u正常值):
ch=canlib.openChannel(通道,openFlags)
打印(“使用频道:%s,EAN:%s”%(频道数据(频道)。频道名称,
信道数据(信道)。卡(upc\U编号)
)
ch.setBusOutputControl(比特率标志)
ch.setBusParams(比特率)
布森先生()
返回ch
def拆卸通道(ch):
布索夫先生()
第三章结束()
定义文本(t):
tx=binascii.hexlify(t).解码('utf-8')
n=2
txt=[tx[i:i+n]表示范围内的i(0,len(tx),n)]
返回文本
def计数器():
尽管如此:
尝试:
cnt=1
frame=ch0.read()
firstID=frame.id
尽管如此:
frame=ch0.read()
cnt+=1
如果frame.id==firstID:
打破
通过
除(canlib.canNoMsg)外:
打破
除了(canlib.canError):
打印(“重新运行”)
通过
返回cnt
打印(“canlib版本:”,canlib.dllversion())
ch0=设置通道(通道=0)
ch1=设置通道(通道=1)
frame=frame(id=100,data=[1,2,3,4],flags=canlib.canMSG\u EXT)
ch1.写入(帧)
打印(帧)
cnt=计数器()
打印(“计数器:%d”%(cnt))
时间。睡眠(1)
尽管如此:
尽管如此:
尝试:
show=“”
i=1

而我你不需要使用多线程或任何复杂的东西。只需使用widget.after()方法,该方法在所需时间后调用您选择的另一个函数/方法。在下面的例子中,时间是1秒->1000毫秒。只需在主循环之前调用该类,它就会开始工作

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)

阅读后,您可能会通过使用多个线程来改进。请看我对这个问题的回答。注意:我怀疑每隔几微秒更新tkinter GUI的可能性,因此您可能能做的最好的事情是以更慢的速度。我尝试实现您的示例,但现在它抛出了更多错误,我对Python的了解还不够,无法完全理解我做错了什么。你能告诉我如何用我已有的代码实现它吗?我将显示代码移动到一个函数,并在主循环中调用它,这是我应该通过
.after()
调用的函数吗?