2016-08-04 6 views
1

私は、やっかいなGUIを持っています。私は、プロジェクトが進むにつれて、リファクタリングと機能の追加を続けたいと考えています。この理由から、アプリケーションのさまざまなウィジェット間の結合を可能な限り緩やかにしたいと思います。私は(そのようなツリービューウィジェット内の項目を選択するか、キャンバスの一部をクリックすると)1つのウィジェットに何らかのアクションを実行できるようにしたいと思いtkinterの親ウィジェットと子ウィジェットの間のシグナリング

import tkinter as tk 

class Application(tk.Tk): 
    def __init__(self, *args, **kwargs): 
     super().__init__(*args, **kwargs) 
     self.instance_a = ClassA(self) 
     self.instance_b = ClassB(self) 
     # ... # 

class ClassA(tk.Frame): 
    def __init__(self, *args, **kwargs): 
     super().__init__(*args, **kwargs) 
     # ... # 

class ClassB(tk.Frame): 
    def __init__(self, *args, **kwargs): 
     super().__init__(*args, **kwargs) 
     # ... # 

def main(): 
    application = Application() 
    application.mainloop() 

if __name__ == '__main__': 
    main() 

私のアプリケーションは、このようなものを構成されています他のウィジェットの状態を変更します。

これを行う1つの方法は、クラスAに次のコードを持つことです:クラスBで添付コードで

self.bind('<<SomeEvent>>', self.master.instance_b.callback()) 

def callback(self): print('The more that things change, ') 

私はこのアプローチを持っている問題がありますこのプロジェクトはまだプロトタイプなので、私はいつもものを変更しています。callbackの名前を変更したり、クラスBに属するウィジェットを完全に削除したりしたいと考えています。 instance_aをいくつかの子にするPanedWindowオブジェクト(この場合、masterwinfo_toplevel()に置き換える必要があります)。

class Application(tk.Tk): 
    # ... # 
    def application_callback(): 
     self.instance_b.callback() 

、クラスA中の結合イベントを変更:

別のアプローチは、いくつかのイベントがトリガされるたびに呼び出されたアプリケーション・クラス内のメソッドを置くことです

self.bind('<<SomeEvent>>', self.master.application_callback()) 

これは間違いですメンテナンスは簡単ですが、より多くのコードが必要です。また、アプリケーションクラスは、クラスBで実装されたメソッドについて知る必要があり、instance_bはウィジェットの階層にあります。私は1つのウィジェットでアクションを実行する場合は、第二のウィジェットが自動的にせずに、いくつかの方法に応答するために知っているだろう、

# in class A: 
self.bind('<<SomeEvent>>', lambda _: self.event_generate('<<AnotherEvent>>')) 

# in class B: 
self.bind('<<AnotherEvent>>', callback) 

その方法:完璧な世界では、私はこのような何かをできるようにしたいと思いますいずれかのウィジェットは、他の実装の詳細について知っている。いくつかのテストとヘッドスクラッチの後、私はtkinterのイベントシステムを使ってこの種の動作が不可能であるという結論に達しました。だから、ここに私の質問があります:

  1. この望ましい動作は本当に不可能ですか?
  2. それは良いアイデアですか?
  3. 私が望むモジュール性の程度を達成する良い方法はありますか?
  4. tkinterの組み込みイベントシステムの代わりに、どのようなモジュール/ツールを使用できますか?

答えて

0

answerのコードでは、クラスAがクラスBの内部について知っている必要があるハンドラオブジェクトのメソッドを呼び出すことを回避します。 Scannerの次のコードメソッドでは、ScanWindowインスタンスの内部について知る必要はありません。Scannerクラスのインスタンスは、ハンドラクラスのインスタンスへの参照を含み、ScannerWindowのインスタンスとHandlerクラスのメソッドを使用して通信します。

# this class could be replaced with a class inheriting 
# a Tkinter widget, threading is not necessary 
class Scanner(object): 
    def __init__(self, handler, *args, **kw): 
     self.thread = threading.Thread(target=self.run) 
     self.handler = handler 

    def run(self): 
     while True: 
      if self.handler.need_stop(): 
       break 

      img = self.cam.read() 
      self.handler.send_frame(img) 

class ScanWindow(tk.Toplevel): 
    def __init__(self, parent, *args, **kw): 
     tk.Toplevel.__init__(self, master=parent, *args, **kw) 

     # a reference to parent widget if virtual events are to be sent 
     self.parent = parent 
     self.lock = threading.Lock() 
     self.stop_event = threading.Event() 
     self.frames = [] 

    def start(self): 
     class Handler(object): 
      # note self and self_ are different 
      # self refers to the instance of ScanWindow 
      def need_stop(self_): 
       return self.stop_event.is_set() 

      def send_frame(self_, frame): 
       self.lock.acquire(True) 
       self.frames.append(frame) 
       self.lock.release() 

       # send an event to another widget 
       # self.parent.event_generate('<<ScannerFrame>>', when='tail') 

      def send_symbol(self_, data): 
       self.lock.acquire(True) 
       self.symbols.append(data) 
       self.lock.release() 

       # send an event to another widget 
       # self.parent.event_generate('<<ScannerSymbol>>', when='tail') 

     self.stop_event.clear() 
     self.scanner = Scanner(Handler()) 
+0

回答の基本的な特徴をよりよく理解するために、いくつかの説明をしたいと思います。スレッド化モジュールの使用は絶対に必要ですか(OpenCV以外のアプリケーションの場合)?生成しているスキャナイベントにはどのような機能がありますか?どのオブジェクトがその行の親ですか? –

+0

この興味深いパターンをありがとう、私は私の質問に記載されたモジュール性の種類をどのように達成するかわかりません。 'Scanner'クラスは、' ScanWindow'のスコープ内で定義されたクラスである 'Handler'のメソッドを呼び出します。私が間違っていれば私を訂正してください。しかし、これは 'ScanWindow'のメソッドを直接呼び出すことに相当すると思います。 'Scanner 'は' ScanWindow'について知ることはできませんが、手のひらを通すだけです。目標は、階層内の他のウィジェットから1つのウィジェットでイベントをトリガーし、イベント名のみを共通にすることでした。 –

関連する問題