猿问

Python Tkinter用于模拟多个按钮之间的交互闪烁

我正在寻找一种解决方案,以模拟电子组件的UI行为和带有LED的用户交互(应该是按钮),以报告电子组件的内部状态。


我正在使用python和tKinter模块来执行此操作。


我的代码运行,并且我的GUI窗口正确显示。但是,当我按几次按钮时,行为不符合预期。


每个LED有4种可能的状态(关闭,打开,(闪烁)慢速,(闪烁)快速)。我有4个可以影响状态的按钮。每个按钮都有一个在我定义的小部件类中定义的交互功能,并且一旦调用此功能,每个按钮都会重新定义小部件的内部状态。


为了控制LED的闪烁,我使用了一个单循环和self.after(..)函数。该功能如下:


def toggleLeds(self):

    for led in [self.ledTxIP, self.ledRxIP, self.ledTxRS, self.ledRxRS, self.ledPower, self.ledRun, self.ledStatus, self.ledConfig]:

        if (((led[1] == "SLOW") and (self._FastBlinking == 0)) or (led[1] =="FAST")):

            bg = led[0].cget("background")

            bg = "green" if bg == "black" else "black"

            led[0].configure(background=bg)

        elif((led[1] == "OFF") and (self._update == 1)):

            led[0].configure(background="black")

            self._update = 0

        elif (self._update == 1):

            led[0].configure(background="green")

            self._update = 0

    self._FastBlinking = (self._FastBlinking + 1)%2

    self.update_idletasks()

    self.after(self._FastBlinkTime, self.toggleLeds)

通过self.after函数递归调用此函数,在交互函数的末尾,我为每个按钮定义了该函数。


这是我定义单个LED的方式:


    self.ledTxIP     = [tk.Label(self, width=1, borderwidth=2, relief="groove"),"OFF"]

以下是按钮交互功能的示例:


def pushMode(self):

    if (re.search("Reset",self.state) == None):

        if (self.clickModCnt == 0):

            self.state = "Status"

            self._stateTimer = int(time.gmtime()[5])

        elif (self.clickModCnt == 1):

            if(int(time.gmtime()[5]) - self._stateTimer < 3):

                self.state = "Config"

            else:

                self.state = "RunMode"

        else:

            self.state = "RunMode"

    self.clickModCnt = (self.clickModCnt + 1)%3

    self._update = 1

    self.updateLedState()

如果有人对此有任何建议,那就太受欢迎了。


慕雪6442864
浏览 266回答 1
1回答

四季花海

我不知道为什么这没有早点让我明白,但是我认为问题在您自己的问题文本中列出,是指toggleLeds方法:通过self.after函数递归调用此函数,在交互函数的末尾,我为每个按钮定义了该函数。程序最初运行时,我假设您在toggleLeds某个地方调用以启动LED的初始模式。这将通过self.after方法末尾的调用来建立单个递归循环。但是,如果您每次单击按钮来更改状态时也调用相同的方法,则每次单击按钮都将建立一个新循环,并且每个新循环可能与初始循环同步,也可能不同步。我可以想到几种方法来解决这种可能的冲突。一种是避免对进行新的调用toggleLeds,但是那样在单击按钮和新的LED模式之间可能会有延迟。如果您不介意延迟,那可能是最好的解决方案。如果要立即更改灯光/闪烁模式,则需要中断当前循环并以新的灯光/闪烁状态开始一个新的循环。根据New Mexico Tech生产的Tkinter参考,该after方法为:...返回一个整数“之后标识符”,如果您想取消回调,可以将其传递给.after_cancel()方法。这就是您可以利用的方法。首先,请确保在调用after方法时存储了该标识符:self.after_id&nbsp;=&nbsp;self.after(self._FastBlinkTime,&nbsp;self.toggleLeds)然后更改您的toggleLeds方法定义以接受可选的“ interrupt”参数,after如果该参数为,则取消现有循环True:def toggleLeds(self, interrupt=False):&nbsp; &nbsp; if interrupt:&nbsp; &nbsp; &nbsp; &nbsp; self.after_cancel(self.after_id)&nbsp; &nbsp; # Existing code follows最后,True在单击按钮后调用方法时传递给该参数:# Existing button processing code hereself.toggleLeds(interrupt=True)完成这些更改后,每次单击按钮将取消当前after周期并开始一个新的周期,从而防止一次运行多个周期,这应使LED保持同步。
随时随地看视频慕课网APP

相关分类

Python
我要回答