2017-08-03 4 views
0

Eclipseベースのツール用のUIパネルをいくつかビルドしようとしています。ツールのためのAPIは、例えば、以下のネクタイcallbackOpenのでa_panel_objectの開口部に、デコレータに基づいてイベント処理するための機構を有している:これは正常に動作しますPython:OOPでAPIイベントハンドラを使用する

@panelOpenHandler(a_panel_object) 
def callbackOpen(event): 
    print "opening HERE!!" 

が、私は私のイベントハンドラのすべてをラップしたかったですクラスの背後にあるパネルの実際のデータ処理が含まれます。それが呼び出すときデコレータのみeventを供給しているとき、私は、それを両方selfeventを取るコールバックを与えているので、私はおそらく考えて、

class Test(object): 
    def __init__(self): 
     # initialise some data here 

    @panelOpenHandler(a_panel_object) 
    def callbackOpen(self, event): 
     print "opening HERE!!" 

しかし、これは動作しません。理想的には私のような何かをしたいと思います(注:私はpanelOpenHandlerにソースコードへのアクセス権がなく、それは非常によく文書化されていません...また、エラーメッセージはEclipse/jythonによってどこかで飲み込まれています)。

複数の引数を取る関数で装飾される関数に1つの引数を提供するライブラリデコレータを使用する方法はありますか?何らかの形でlambdasを使用してself引数をバインドし、それを暗黙的にすることはできますか?

私はherehereというアプローチのいくつかのバリエーションを組み込もうとしましたが、全く同じ問題ではないと思います。

答えて

0

この問題の回避策が見つかりました。より洗練されたソリューションがあるかどうかはわかりませんが、基本的には、コールバック関数をglobal()スコープに公開してから、f()(g)構文を使用してAPIデコレータでデコレートしてください。この方法は、関数をラップし、それをCallbackRegistererのインスタンスごとに一意のIDを(私がUIパネルの数を開封しております与えます -

したがって、私は、任意の派生クラスにbindHandler()方法を提供する基本クラス(CallbackRegisterer)を、書きました同じ時間):私は、このからクラスを派生し、正しくAPIデコレータ使用して装飾することであろう、私のコールバックに渡すことができます

class CallbackRegisterer(object): 

    __count = 0 

    @classmethod 
    def _instanceCounter(cls): 
     CallbackRegisterer.__count += 1 
     return CallbackRegisterer.__count 

    def __init__(self): 
     """ 
     Constructor 
     @param eq_instance 0=playback 1=record 2=sidetone. 
     """ 
     self._id = self._instanceCounter() 
     print "instantiating #%d instance of %s" % (self._id, self._getClassName()) 


    def bindHandler(self, ui_element, callback, callback_args = [], handler_type = None, 
           initialize = False, forward_event_args = False, handler_id = None): 

     proxy = lambda *args: self._handlerProxy(callback, args, callback_args, forward_event_args) 
     handler_name = callback.__name__ + "_" + str(self._id) 
     if handler_id is not None: 
      handler_name += "_" + str(handler_id) 
     globals()[handler_name] = proxy 

     # print "handler_name: %s" % handler_name 

     handler_type(ui_element)(proxy) 
     if initialize: 
      proxy() 

    def _handlerProxy(self, callback, event_args, callback_args, forward_event_args): 
     try: 
      if forward_event_args: 
       new_args = [x for x in event_args] 
       new_args.extend(callback_args) 
       callback(*new_args) 
      else: 
       callback(*callback_args) 
     except: 
      print "exception in callback???" 
      self.log.exception('In event callback') 
      raise 

    def _getClassName(self): 
     return self.__class__.__name__ 

:私も導き出すことができ、

class Panel(CallbackRegisterer): 
    def __init__(self): 

     super(Panel, self).__init__() 

     # can bind from sub classes of Panel as well - different class name in handle_name 
     self.bindHandler(self.controls.test_button, self._testButtonCB, handler_type = valueChangeHandler) 

     # can bind multiple versions of same function for repeated ui elements, etc. 
     for idx in range(0, 10): 
      self.bindHandler(self.controls["check_box_"+str(idx)], self._testCheckBoxCB, 
         callback_args = [idx], handler_type = valueChangeHandler, handler_id = idx) 

    def _testCheckBoxCB(self, *args): 
     check_box_id = args[0] 
     print "in _testCheckBoxCB #%d" % check_box_id 

    def _testButtonCB(self): 
     """ 
     Handler for test button 
     """ 
     print "in _testButtonCB" 


panel = Panel() 

注意をさらなるサブクラスPanelから、そこにバインドされたコールバックはクラス名stringに基づいて独自のhandler_nameを取得します。

0

あなたのデコレータは、後で呼び出される関数を登録しているようです。したがって、メソッドを呼び出すクラスのインスタンスが分からないため、クラスメソッドでの使用は完全に不適切です。

これを実行できる唯一の方法は、バインドされたメソッドを特定のクラスインスタンスから手動で登録することです。これはデコレータ構文を使用して行うことはできません。たとえば、クラスの定義の後にこれを置いてください。

panelOpenHandler(context.controls.PerformanceTuneDemoPanel)(Test().callbackOpen) 
+0

ありがとうございます。しかし、これは今私に次のエラーを与えています。 'AttributeError: 'instancemethod'オブジェクトに属性 'panelOpenHandler''がありません – Aidenhjj

+0

コードを正しくコピーしていないと思います(スタンドアローンステートメントと思われます)。属性として' panelOpenHandler'を検索する必要はありません。 – jasonharper

+0

私はそれが 'panelOpenHandler'デコレータ内で実行される操作だと思います。あなたのコードを正しくコピーしました。 – Aidenhjj

関連する問題