Tkinter 相互関連があるCallbackをテストする


Hex SpinBoxとBin Editorを相互に操作させる

やりたい事


あっちを変えれば、こっちも変わる こっちを変えれば あっちも変わる
GUIを相互で操作させるのはちょっと面倒?

やった事

互いのハンドラにコールバック関数を登録させることで
お互いの変更を連絡できるようにしてみました。
もっと素直な実装方法があるかもしれませんが、先ずは相互動作ができました。

def callback(i): #コールバック関数の生成 それぞれのボックスに値を設定
hx.set(i)
be.set(i)

hx.setCallback(callback) #HexSpinboxにハンドラ登録 変更があった段階で callbackを呼出し
be.setCallback(callback) #BinEditorにハンドラ登録 変更があった段階で callbackを呼出し

MultiBinEditor.py
import tkinter as tk

class HexSpinbox(tk.Spinbox):
    def __init__(self, *args, **kwargs):
        self.var = tk.StringVar()
        self.bytenum = kwargs.pop('bytenum', 1)
        self.add_callback = None
        max_val = 0x1<<(self.bytenum*8)
        super().__init__(*args, **kwargs, textvariable=self.var, from_=0,to=max_val,
                         increment=1, command=self.callback )

    def set(self, val):
        s = "0x{:0%dx}" % (self.bytenum*2)
        self.var.set(s.format(int(val)))

    def get(self):
        hstr = super().get()
        return int(hstr, 16)

    def callback(self):
        val = super().get()
        self.set(val)
        self.add_callback(val) if self.add_callback != None else None

    def setCallback(self, func):
        self.add_callback = func

class BinEditFrame(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        self.val = 0x00
        self.bits = []
        self.add_callback = None
        for i in range(8):
            btn = tk.Button(self,text=str(i), relief='raised', command=self.callback(i))
            btn.pack(sid='right')
            self.bits.append(btn)

    def callback(self, i):
        def push():
            self.val ^= (1<<i)
            self.redraw()
            self.add_callback(self.val) if self.add_callback != None else None
        return push

    def redraw(self):
        #All Button Delete
        for bit in self.bits:
            bit.destroy()
        self.bits.clear()

        #All Button ReCreate
        for i in range(8):
            if (self.val & (1<<i) > 0):
                btn = tk.Button(self,text=str(i), relief='sunken',
                                command=self.callback(i) )
            else:
                btn = tk.Button(self,text=str(i), relief='raised',
                                command=self.callback(i) )
            btn.pack(sid='right')
            self.bits.append(btn)


    def setCallback(self, func):
        self.add_callback = func

    def set(self, val):
        self.val = int(val)
        self.redraw()

if __name__ == "__main__":
    print("BinHexEditor")
    win = tk.Tk()
    hx = HexSpinbox(win)
    hx.pack(side=tk.LEFT)
    be = BinEditFrame(win)
    be.pack(side=tk.LEFT)

    def callback(i):
        hx.set(i)
        be.set(i)

    hx.setCallback(callback)
    be.setCallback(callback)

    win.mainloop()