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(...):
...
私はデコレータを開発しました ( here、here、および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)
。残念ながら、私は私の能力の限界に達しました。誰か助けてもらえますか?