2

外部ウィジェットにバインドされているウィンドウを破棄するときに問題が発生します。

たとえば、1 つのルート ウィンドウと多くの異なるサブウィンドウがあります (コード内では、単純にするために同じものを使用しています)。

ルートからサブウィンドウを開くと。ウィンドウを作成し、ルート ウィンドウからのシグナルにバインドします。すべてのサブウィンドウは、この同じシグナルにバインドされますが、異なるコールバック (サブウィンドウごとに 1 つ) にバインドされます。

次に、このサブウィンドウを破棄すると (上隅の [X] をクリック)、バインドがまだ生きているということは、サブウィンドウがまだ生きていることを意味します。

問題は、バインドされたサブウィンドウを破棄して、他のコールバックを有効にするにはどうすればよいかということです。

subwindow _destroy メソッドで、試しました

root.unbind("<<EverybodyDoSomething>>", self.bind1) 

しかし、私はエラーが発生します

TclError: Tcl コマンドを削除できません

そして、私が使用する場合

root.unbind("<<EverybodyDoSomething>>")

シグナルに関連付けられたすべてのコールバックがバインド解除されます。

import Tkinter as Tk

root = Tk.Tk()
i_window = 0

def generate_dosomething_signal():
    root.event_generate('<<EverybodyDoSomething>>', when = 'tail')

def subwindow():
    SubWindow()

class SubWindow(Tk.Tk):
    def __init__(self):
        global i_window
        Tk.Tk.__init__(self)
        self.i = str(i_window)
        i_window += 1
        l = Tk.Label(master=self, text='This is s Sub Window %s!!!!'%self.i)
        l.pack()
        self.bind1 = root.bind('<<EverybodyDoSomething>>', 
                               self.callback_from_sub_window, '+')

        self.bind('<Destroy>', self._destroy)

    def _destroy(self, *args):
#        root.unbind('<<EverybodyDoSomething>>', self.bind1)
#        root.unbind('<<EverybodyDoSomething>>')
        pass

    def callback_from_sub_window(self, *args):
        print 'callback from Sub Window ' + self.i

bStartWindow = Tk.Button(master=root, text='Start Sub Window', command=subwindow)
bStartWindow.pack()

bDoSomethingEverywhere = Tk.Button(master=root, text='Do something everywhere', 
                                   command = generate_dosomething_signal)
bDoSomethingEverywhere.pack()

root.mainloop()
4

2 に答える 2

0

あなたの言うことは、Tkinter の通常の動作ではありません。通常、ウィジェットを破棄すると、その子ウィジェットもすべて破棄されます。それらが破壊されると、バインディングも一緒に移動します。

おそらく、問題の根本原因は、ルート ウィジェットの複数のインスタンスを作成しているという事実にあります。あなたは単にこれを行うことはできません. Tkinter アプリケーションは、 のインスタンスを 1 つだけ持つ必要がTkあり、実行中の のインスタンスを 1つだけ持つ必要がありますmainloop

複数のトップ レベル ウィンドウが必要な場合は、2 つ目以降のウィンドウ用にToplevelのインスタンスを作成します。

bind(...,"+")また、このタスクを実行するために を使用しないでください。あなたが発見したように、そのようなバインディングを削除する方法はありません。へのすべてのバインドを完全に削除できますが<<EverybodyDoSomething>>、 で追加された 1 つの部分だけを削除することはできませんbind(..."+")

代わりに行う必要があるのは、単一の関数を呼び出す単一のバインディングを用意することです。この関数は、トップレベル ウィンドウのリストを反復処理して、各ウィンドウにイベントを送信できます。存在しなくなったウィンドウは単純にスキップできます。イントロスペクションを使用してトップレベル ウィンドウのリストを取得するか、コードでウィンドウ参照を作成するたびにウィンドウ参照を追加して、このリストを手動で維持することができます。

于 2012-10-31T19:07:42.777 に答える
0

これはあなたが望むものを達成します:

import Tkinter as Tk

root = Tk.Tk()
i_window = 0

def generate_dosomething_signal():
    global root
    root.event_generate('<<EverybodyDoSomething>>', when = 'tail')

def subwindow():
    global root
    SubWindow(root)

class SubWindow():
    def __init__(self, root):
        global i_window
        self.root = root

        self.subwindow = Tk.Toplevel()
        self.i = str(i_window)
        self.destroyed = False
        i_window += 1
        l = Tk.Label(master=self.subwindow, text='This is s Sub Window %s!!!!'%self.i)
        l.pack()
        self.bind1 = self.root.bind('<<EverybodyDoSomething>>', 
                               self.callback_from_sub_window, '+')
        self.subwindow.protocol("WM_DELETE_WINDOW", self._destroy)
        #self.subwindow.bind('<Destroy>', self._destroy)

    def _destroy(self, *args):
        self.subwindow.destroy()
        self.destroyed = True
        print "Destroyed ", self.i


    def callback_from_sub_window(self, *args):
        if self.destroyed == False:
            print 'callback from Sub Window ' + self.i


bStartWindow = Tk.Button(master=root, text='Start Sub Window', command=subwindow)
bStartWindow.pack()

bDoSomethingEverywhere = Tk.Button(master=root, text='Do something everywhere', 
                                   command = generate_dosomething_signal)
bDoSomethingEverywhere.pack()

root.mainloop()

間違いなく、サブウィンドウをトップレベルとして作成する必要があると言われました。さらに、Subwindow() Python オブジェクトが作成されるたびに、それはルート ウィンドウへのポインターであり、< < EveryoneDoSomething > > イベントにバインドされ、関数 callback_from_sub_window() のローカル インスタンスをコールバックとしてアタッチします。 . ウィンドウは (Tk の観点から) 破棄されますが、そのようなサブウィンドウの Subwindow() オブジェクトはまだ存在するため、その callback_from_sub_window() 関数が存在します。イベントに反応するルート ウィンドウと同様に、作成された (および/または破棄された) サブウィンドウの「プライベート」 callback_from_sub_window() 関数を実行します。Subwindow() クラスに self.destroyed フラグをインストールすると、破棄されたサブウィンドウがコールバックとして反応するのを防ぐことができます。

于 2012-10-31T23:46:11.157 に答える