1

関数の引数として、シグナルを呼び出すオブジェクトを渡し、その関数でそのオブジェクトを操作できるようにします。そのオブジェクトはQLineEditウィジェットです。次に例を示します。

self.fieldList = []

for i in range(10):
        self.valueField = QtGui.QLineEdit()
        self.fieldList.append(self.valueField)
        self.fieldList[i].cursorPositionChanged.connect(lambda: (self.checkState(self.fieldList[i], palette1, palette2)))

def checkState(self, line, palette1, palette2):
        if len(line.text()) > 3:
            line.setPalette(palette1)
        else:
            line.setPalette(palette2)

ご覧のとおり、checkState()関数の名前行を使用してリスト要素self.fieldList[i]を引数として渡そうとしています。checkState()関数でfieldList要素(つまり、 self.fieldList [0])を明示的に定義すると、コードは完全に機能しますが、引数として渡すことはできません。私は何が間違っているのですか?

ところで。プログラムを実行しようとしても、コンパイラーはエラーメッセージを表示しませんが、想定どおりの動作をしません(3文字を超える文字を書き込んだ場合はQLineEditの色を変更してください)。

編集:

@ dex19dt

はい、これは一例ですが、あなたは正しいです!最後のQLineEditのみが正常に機能します。

問題は、ウィジェットの数が選択したレイヤーによって異なるため、これらすべてのウィジェットに名前を付けることができないことです。つまり、ウィジェットが5つある場合もあれば、11または75の場合もあります。

これらのウィジェットに簡単に名前を付けて、次のようにテキストを設定できます。

 self.fieldList[i].setObjectName(_fromUtf8("attributeValueField_{0}".format(i)))
 self.fieldList[i].setText(_fromUtf8("{0}".format(value.toString())))

これはすべてのウィジェットで問題なく機能しますが、信号を定義する方法がわかりませんか?アイデアはありますか?


編集:

@ dex19dt

OK、それで私はインデックスが関数呼び出しに「固執」しないというこの問題について尋ねました、そしてこれがちょうどpythonが機能する方法であることがわかりました、そしてこの問題を修正するために私はこの行を置き換える必要がありました:

self.fieldList[i].cursorPositionChanged.connect(lambda: (self.checkState(self.fieldList[i], palette1, palette2)))

これで:

self.fieldList[i].cursorPositionChanged.connect(lambda old, new, i=i: (self.checkState(self.fieldList[i], palette1, palette2)))

したがって、このようにして、現在のインデックスがシグナルインデックスにコピーされます。なぜあるのかよくわかりませんがold, new。ラムダ関数を参照しているのでしょうか、それとも単に左iを古い変数として、右iを新しい変数として定義しているのでしょうか...グーグルで試しましたが、成功しませんでした。

4

1 に答える 1

1

さて、あなたの質問のコードは例であり、実際のコードではないと思います。なぜなら、追加のパラメーターを使用せずにループでウィジェットを作成しているため、結果としてウィンドウ内のすべてのオブジェクトがオーバーラップすることになります。ご覧のとおり、すべてのlineEditは同じ場所にあります(デフォルトでは、ウィンドウの左上部分)。その場合、lineEditのどのインスタンスが信号を送信しているかを知るだけの問題であるように見えるので、問題がどこにあるのかを判断するのは非常に困難です。

したがって、上記のコードを機能させる方法を説明します。そうでない場合は、いつでも返信できます。

信号の接続方法がすべてです。コードを見ると、同じ名前(self.valueField)ですべてのlineEditを作成していることになります。オブジェクトはすべて作成され、メモリ内で独自の位置にありますが、接続での参照は常に最後の接続によって上書きされます。あなたもテストを行うことができます。この行をcheckState関数に追加すると、次のようになります。

print self.fieldList.index(line)

シグナルは常にリストの最後のアイテムに対して呼び出され、これは接続された最後のシグナルでもあることがわかります。

すべてのlineEditを別の名前で1つずつ設定するだけです。また、リストを作成し、その中にすべての名前を入力します。このように、forループはlineEditsのみを接続し、それらを作成しなくなります。

編集:

Ok。これを機能させる1つの方法は、SignalMapperを使用することです。こちらのドキュメントをご覧ください。

上記の例では、次のようなことができます。

他のウィジェットを宣言するのと同じ方法で、最初にマッパーを宣言します。

self.myMapper = QtCore.QSignalMapper()

最初のforループの後。リストを繰り返し処理します。

for item in self.fieldList:
     self.myMapper.setMapping(item, self.fieldList.index(item))
     item.textEdited.connect(self.myMapper.map)
self.myMapper.mapped[int].connect(checkState)

つまり、これにより、リスト内のすべてのオブジェクトが、リスト上の対応するインデックス(int)にマップされます。したがって、シグナルが発行されると、マッパーはそのインデックス値を引数としてcheckState関数を呼び出します。このようにして、リストを再度使用してオブジェクトに到達できます。

def checkState(i):
    print (self.fieldList[i].objectName())
    self.fieldList[i].setText("It works!")

ご覧のとおり、マッパーは引数としてインデックスのみを送信します。したがって、追加の引数を使用して関数を適応させる必要があると思いますpalette1, palette2。または、フィルターのようなpreliminar関数を使用して、その中で適切なcheckState関数を呼び出すこともできます。

def myfilter(i):
    checkState(self.fieldList[i], palette1, palette2)

私はこれを機能させるための他のアプローチが存在することをかなり確信していますが、これは仕事をしますが、より良い解決策は現れません。

于 2012-06-20T13:05:13.127 に答える