1

PyQt 5.5 では次のコードが機能しましたが、PyQt 5.7 では機能しませんでした (リストには「新しい例」ではなく「例」が表示され、実際にデバッグするとスロットがヒットしないことが示されます)。誰がそれの何が悪いのか知っていますか:

from PyQt5.QtWidgets import QListWidgetItem, QListWidget, QApplication
from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal, Qt


class MyListItemData(QObject):
    def __init__(self, list_widget_item, obj):
        super().__init__()
        self.list_widget_item = list_widget_item
        obj.sig_name_changed.connect(self.__on_list_item_name_changed)

    # @pyqtSlot(str)
    def __on_list_item_name_changed(self, new_name: str):
        self.list_widget_item.setText(new_name)


class Data(QObject):
    sig_name_changed = pyqtSignal(str)


class SearchPanel2(QListWidget):
    def __init__(self, parent=None):
        QListWidget.__init__(self, parent)
        obj = Data()
        hit_item = QListWidgetItem('example')
        hit_item.setData(Qt.UserRole, MyListItemData(hit_item, obj))
        self.addItem(hit_item)
        obj.sig_name_changed.emit('new_example')


app = QApplication([])
search = SearchPanel2()
search.show()
app.exec

おそらくこれが行われるはずの方法ではありませんが、PyQt 5.5 では、PyQt 5.5 のバグ (QListWidgetItem から単純に派生させることができず、アイテムをシグナルに直接接続できなかった) の許容できる回避策でした。

回答後の編集

Ekhumoro が回答した後、私は厳しい現実に直面しました。これにより、投稿されたサンプル コードは修正されましたが、私のアプリでは修正されませんでした。そこで再訪しました。実際のアプリでは、アイテムは後で作成され、名前変更のシグナルは後で発行されます。したがって、私の問題を再現するためのより良い最小限の例は次のとおりです。

class SearchPanel2(QListWidget):
    def __init__(self, obj, parent=None):
        QListWidget.__init__(self, parent)

        hit_item = QListWidgetItem('example')
        data = MyListItemData(hit_item, obj)
        hit_item.setData(Qt.UserRole, data)  # slot not called

        self.addItem(hit_item)
        # self.data = data

    def emit(self):
        obj.sig_name_changed.emit('new_example')


app = QApplication([])
obj = Data()
search = SearchPanel2(obj)
search.show()
QTimer.singleShot(2000, search.emit)
app.exec()

assert search.item(0).text() == 'new_example'

これはアサーションに失敗します。データが強い参照によって保持されている場合、アサーションはパスします (init の最後の行のコメントを外します)。そのため、setData() は 2 番目の引数への弱い参照のみを保持する可能性が高く、データがどこかに保存されていない限り、init の最後にデータが削除されます。

4

1 に答える 1

1

ある種のガベージコレクションの問題があるようです。代わりにこれを試してください:

    hit_item = QListWidgetItem('example')
    data = MyListItemData(hit_item, obj)
    hit_item.setData(Qt.UserRole, data)
于 2016-09-02T17:50:26.167 に答える