0

電子コンポーネントの UI の動作と、電子コンポーネントの内部状態を報告する LED とのユーザー インタラクション (ボタンを押す必要があります) をエミュレートするソリューションを探しています。

そのために python と tKinter モジュールを使用しています。

コードが実行され、GUI ウィンドウが正しく表示されます。ただし、ボタンを数回押すと、動作が期待どおりになりません。

各 LED には 4 つの可能な状態 (オフ、オン、(点滅) 遅い、(点滅) 速い) があります。状態に影響を与えることができる4つのボタンがあります。各ボタンには、私が定義したウィジェット クラスで定義された相互作用関数があり、この各関数が呼び出されると、ウィジェットの内部状態が再定義されます。

LED の点滅を制御するために、1 つのループと 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これにより、メソッドの最後の呼び出しを介して単一の再帰ループが設定されます。ただし、ボタンをクリックして状態を変更するたびに同じメソッド呼び出すと、ボタンをクリックするたびに新しいループが設定され、新しいループが最初のループと同期する場合と同期しない場合があります。

この可能性のある競合を処理するために考えられる方法がいくつかあります。1 つは、 への新しい呼び出しを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 に答える