1

この質問は、このトピックの質問に似ていますドラッグアンドドロップでQStandardItemサブクラスを保持しますが、適切な解決策が見つからないという問題があります。そのトピックは部分的に役立ちますが、より複雑なタスクでは失敗します。

QTreeView でアイテムを作成すると、そのアイテムが配列に配置されますが、ドラッグ アンド ドロップを使用するとアイテムが削除され、アクセスできなくなります。ドラッグ アンド ドロップは項目を移動せずにコピーするため、setData を使用する必要があることはわかっています。オブジェクトがコピーされ、それへの参照が失われるため、setDataをオブジェクトにすることはできません。

ここに例があります

itemsArray = self.addNewRow
def addNewRow(self)
    '''some code with more items'''
    itemHolder = QStandardItem("ProgressBarItem")
    widget = QProgressBar()
    itemHolder.setData(widget)

    inx = self.model.rowCount()
    self.model.setItem(inx, 0, itemIcon)
    self.model.setItem(inx, 1, itemName)
    self.model.setItem(inx, 2, itemHolder)
    ix = self.model.index(inx,2,QModelIndex())
    self.treeView.setIndexWidget(ix, widget)
    return [itemHolder, itemA, itemB, itemC]

#Simplified functionality
data = [xxx,xxx,xxx]
for items in itemsArray:
     items[0].data().setPercentage(data[0])
     items[1].data().setText(data[1])
     items[2].data().setChecked(data[2])

上記のコードは、ウィジェットを移動しない場合に機能します。2 回目にドラッグ アンド ドロップすると参照が失われ、すべてのアイテムの更新が失われ、クラッシュします。

RuntimeError: wrapped C/C++ object of type QProgressBar has been deleted

この問題を解決する方法として考えられるのは、ツリービュー全体を各行/子および名前一致の更新項目で再帰的にループすることです.... -各15アイテム。意味...非常に高速/効率的ではないと思います...0.5秒ごとに5000アイテムをループしたい場合...

この問題を解決する方法を誰かが提案できますか? おそらく、ドロップイベントを編集して、アイテムをコピー/貼り付けするのではなく、アイテムを移動することができます....このようにして、配列内のオブジェクトを失うことはありません

4

1 に答える 1

1

Qt は に格納できるオブジェクトのみをシリアル化できるQVariantため、これがQWidget. しかし、ウィジェットをシリアル化できたとしても、インデックスウィジェットはモデルではなくビューに属しているため、まだ機能しないと思います。

とにかく、ウィジェットへの参照を個別に保持し、モデル項目に単純なキーのみを保存する必要があると思います。次に、アイテムがドロップされたら、ウィジェットを取得してビューでリセットできます。

動作するデモ スクリプトを次に示します。

from PyQt4 import QtCore, QtGui

class TreeView(QtGui.QTreeView):
    def __init__(self, *args, **kwargs):
        super(TreeView, self).__init__(*args, **kwargs)
        self.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
        self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.setAllColumnsShowFocus(True)
        self.setModel(QtGui.QStandardItemModel(self))
        self._widgets = {}
        self._dropping = False
        self._droprange = range(0)

    def dropEvent(self, event):
        self._dropping = True
        super(TreeView, self).dropEvent(event)
        for row in self._droprange:
            item = self.model().item(row, 2)
            self.setIndexWidget(item.index(), self._widgets[item.data()])
            self._droprange = range(0)
        self._dropping = False

    def rowsInserted(self, parent, start, end):
        super(TreeView, self).rowsInserted(parent, start, end)
        if self._dropping:
            self._droprange = range(start, end + 1)

    def addNewRow(self, name):
        model = self.model()
        itemIcon = QtGui.QStandardItem()
        pixmap = QtGui.QPixmap(16, 16)
        pixmap.fill(QtGui.QColor(name))
        itemIcon.setIcon(QtGui.QIcon(pixmap))
        itemName = QtGui.QStandardItem(name.title())
        itemHolder = QtGui.QStandardItem('ProgressBarItem')
        widget = QtGui.QProgressBar()
        widget.setValue(5 * (model.rowCount() + 1))
        key = id(widget)
        self._widgets[key] = widget
        itemHolder.setData(key)
        model.appendRow([itemIcon, itemName, itemHolder])
        self.setIndexWidget(model.indexFromItem(itemHolder), widget)

class Window(QtGui.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.treeView = TreeView()
        for name in 'red yellow green purple blue orange'.split():
            self.treeView.addNewRow(name)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.treeView)

if __name__ == '__main__':

    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 150, 600, 400)
    window.show()
    sys.exit(app.exec_())
于 2016-11-06T20:27:34.027 に答える