1

Qt/PySide を使用して GUI を開発しており、さまざまなウィジェットを処理する個別のクラスが多数あります。各ウィジェットは、ボタンと他のユーザー入力の間のシグナルを管理します。コードを再利用して、メソッド関数の開始時にウィジェット シグナルをブロックし、最後にシグナルを解放する必要があることに気付きました。これを行うために、一般的なデコレータを作成してみることにしました。

私はSOを検索し、デコレータを使用した経験がほとんどない状態でこれを可能な限り実装しようとしたため、私のソリューションには満足していません.

私の質問は、明確な形式に従うそのクラス内のメソッドにアクセスして実行できる一般的なデコレータを作成する最良の方法は何ですか? とにかく私の方法は良い方法ですか?

わかりやすくするために、繰り返しコードを使用したコードは次のようになります (簡潔にするために一部を削除しました)。

class WidgetController(...):

    def __init__(...):
       self.widget.myWidget.currentIndexChanged.connect(reactToChange)

    def reactToChange(...):
        self.widget.myWidget.blockSignals(True) # Repetetive line...
        ...
        self.widget.myWidget.blockSignals(False)

    def anotherFunction(...):
        self.widget.anotherWidget.blockSignals(True)
        ...
        self.widget.anotherWidget.blockSignals(False)

次のようなものが欲しいです:

class WidgetController(...):

   @blockSignals(myWidget)
   def reactToChange(...):
      ...

   @blockSignals(anotherWidget, alsoBlockThisWidget)
   def anotherFunction(...):
      ...

私はデコレータを開発しました ( herehere、およびhereの助けを借りて) が、ひどくぎこちなく感じるので、それを示すのをためらっています。selfネストされた関数と同様に理解できない場所を使用し、execウィジェット名を文字列として渡す必要がありますが、機能しているようです。ここにあります:

class BlockSignals(object):

    def __init__(self, *toBeBlocked):
        self.toBeBlocked = toBeBlocked

    def __call__(self, f):
        toBeBlocked = self.toBeBlocked
        def wrapped_f(self, *args):
            for b in toBeBlocked:
                exec 'self.widget.' + b + '.blockSignals(False)' in locals()
            f(self, *args)
            for b in toBeBlocked:
                exec 'self.widget.' + b + '.blockSignals(False)' in locals()
        return wrapped_f

使用法:

class WidgetController(...):

   @BlockSignals("myWidget")
   def reactToChange(...):
      ...

   @BlockSignals("anotherWidget", "alsoBlockThisWidget")
   def anotherFunction(...):

ご覧のとおり、きれいではありません。文字列の解析を取り除き、 s を取り除きexec、紛らわしい s を整理しself、実際のウィジェット オブジェクトを渡すことで実装できるようにしたいと考えています@BlockSignals(self.widget.myWidget)。残念ながら、私は私の能力の限界に達しました。誰か助けてもらえますか?

4

1 に答える 1

2

getattrを探しています:

import functools

def blockSignals(*widgetnames):
    def decorator(func):
        @functool.wraps(func)
        def method(self, *args, **kwargs):
            widgets = [getattr(self.widget, name) for name in widgetnames]
            for widget in widgets:
                widget.blockSignals(True) 
            result = func(self, *args, **kwargs)
            for widget in widgets:
                widget.blockSignals(False)
            return result
        return method
    return decorator

class WidgetController(...):

    def __init__(...):
       self.widget.myWidget.currentIndexChanged.connect(reactToChange)

    @blockSignals('myWidget')
    def reactToChange(...):
        ...

    @blockSignals('anotherWidget', 'alsoBlockThisWidget')
    def anotherFunction(...):
        ...

インスタンスがインスタンス化されるときではなく、クラスが定義されるときにメソッドが定義されるため、ウィジェット自体ではなく、ウィジェットの名前を渡す必要があります。インスタンスと実際のウィジェットは、クラス定義時には存在しません。selfself.widget

functools.wrapsデコレーターは、元の関数の名前とその docstring を装飾された関数にコピーします

于 2013-06-17T11:52:10.577 に答える