0

我正在寻找一种解决方案来模拟电子组件的 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()

如果有人对此有任何建议,那将非常受欢迎。

4

1 回答 1

1

我不知道为什么这没有早点跳出来,但我认为问题列在您自己的问题文本中,参考toggleLeds方法:

这个是通过 self.after 函数递归调用的,在我为每个按钮定义的交互函数结束时。

当程序最初运行时,我假设您在toggleLeds某个地方调用以启动 LED 的初始模式。self.after这通过方法末尾的调用设置了一个递归循环。但是,如果每次单击按钮更改状态时调用相同的方法,则每次单击按钮都会设置一个新循环,并且每个新循环可能与您的初始循环同步,也可能不同步。

我可以想到几种方法来处理这种可能的冲突。一种是避免对 进行新的调用toggleLeds,但这样在按钮单击和新的 LED 模式之间可能会有延迟。如果您不介意延迟,那可能是最好的解决方案。

如果您希望灯光/闪烁模式立即改变,您需要中断当前循环并使用新的灯光/闪烁状态开始一个新循环。根据New Mexico Tech 制作的 Tkinter 参考资料after方法:

...返回一个整数“后标识符”,如果要取消回调,可以将其传递给 .after_cancel() 方法。

这是您可以利用它的方法。首先确保在调用after方法时存储了该标识符:

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

然后更改您的toggleLeds方法定义以接受可选的“中断”参数,并在after该参数为时取消现有循环True

def toggleLeds(self, interrupt=False):
    if interrupt:
        self.after_cancel(self.after_id)
    # Existing code follows

最后,True在单击按钮后调用方法时传递给该参数:

# Existing button processing code here
self.toggleLeds(interrupt=True)

有了这些更改,每次单击按钮都会取消当前after循环并开始一个新循环,从而防止一次运行多个循环,这应该使 LED 保持同步。

于 2013-06-07T14:09:56.990 回答