항목을 이동할 때 QStandardItem이 올바르게 복제되지 않습니다.

팀 카르 나 한

다음 코드에서 알 수 있듯이 항목 ( 메서드 QStandardItem사용하여 하위 클래스로 분류 됨)을 끌어서 놓으면 하위 클래스가 아닌 a가 표시됩니다. 더욱이-클래스 또는 setData의 일부로 저장된 데이터가 손실됩니다. 나는 이것이 데이터를 '직렬화'할 수 없기 때문이라고 생각합니다. 그러나 나는 데이터 또는 메타를 '저장'하는 방법을 알지 못합니다. 어떻게 보존 할 수 있습니까? 다음 코드는 잘 작동하지만 분기 노드를 이동하면 분기와 분기의 모든 노드가 's'가되며 데이터가 손실됩니다 (있는 경우).clone()QStandardItemQObjectQStandardItemmyItem

# -*- coding: utf-8 -*-
"""
Created on Mon Nov  4 09:10:16 2019

Test of Tree view with subclassed QStandardItem and Drag and Drop
enabled.  When you move a parent the parent looses the subclass and thus
the meta - however, it also looses the data:  This is likely because
the data cannot be serialized.  How to fix?

@author: tcarnaha
"""
import sys
from PyQt5 import QtGui, QtWidgets, QtCore


class myData():
    def __init__(self, title):
        self._title = title
        self._stuff = dict()
        self._obj = QtCore.QObject()

    @property
    def obj(self):
        return self._obj

    @obj.setter
    def obj(self, value):
        self._obj = value

    @property
    def title(self):
        return self._title

    @title.setter
    def title(self, value):
        self._title = value


class myItem(QtGui.QStandardItem):
    def __init__(self, parent=None):
        super(myItem, self).__init__(parent)
        self._meta = None

    @property
    def meta(self):
        return self._meta

    @meta.setter
    def meta(self, value):
        self._meta = value

    def clone(self):
        print "My cloning"
        old_data = self.data()
        print "Old data [{}]".format(old_data)
        old_meta = self.meta
        obj = myItem()
        obj.setData(old_data)
        print "New data [{}]".format(obj.data())
        obj.meta = old_meta
        print "Clone is a ", obj.__class__
        return obj

class mainWidget(QtWidgets.QMainWindow):
    def __init__(self):
        super(mainWidget, self).__init__()
        self.model = QtGui.QStandardItemModel()
        self.model.setItemPrototype(myItem())
        self.view = QtWidgets.QTreeView()
        self.view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.view.customContextMenuRequested.connect(self.list_click)
        self.view.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
        self.view.setDefaultDropAction(QtCore.Qt.MoveAction)
        self.view.setDragDropOverwriteMode(False)
        self.view.setAcceptDrops(True)
        self.view.setDropIndicatorShown(True)
        self.view.setDragEnabled(True)
        self.view.setModel(self.model)
        dataA = myData('A thing')
        parentA = myItem()
        parentA.setText('A')
        parentA.setDragEnabled(True)
        parentA.setDropEnabled(True)
        parentA.setData(dataA)
        parentA.meta = QtCore.QObject()
        childa = myItem()
        childa.setText('a')
        childb = myItem()
        childb.setText('b')
        childc = myItem()
        childc.setText('c')
        parentA.appendRows([childa, childb, childc])
        dataB = myData('B thing')
        parentB = myItem()
        parentB.setText('B')
        parentB.setDragEnabled(True)
        parentB.setDropEnabled(True)
        parentB.setData(dataB)
        parentB.meta = QtCore.QObject()
        childd = myItem()
        childd.setText('d')
        childe = myItem()
        childe.setText('e')
        childf = myItem()
        childf.setText('f')
        parentB.appendRows([childd, childe, childf])
        self.model.appendRow(parentA)
        self.model.appendRow(parentB)

        classAct = QtWidgets.QAction('Class', self)
        classAct.triggered.connect(self.classIs)
        dataAct = QtWidgets.QAction('Data', self)
        dataAct.triggered.connect(self.dataIs)
        metaAct = QtWidgets.QAction('Meta', self)
        metaAct.triggered.connect(self.metaIs)
        self.menu = QtWidgets.QMenu("Item info")
        self.menu.addAction(classAct)
        self.menu.addAction(dataAct)
        self.menu.addAction(metaAct)

        self.setCentralWidget(self.view)

    @QtCore.pyqtSlot(QtCore.QPoint)
    def list_click(self, position):
        self.menu.popup(self.view.viewport().mapToGlobal(position))

    def classIs(self):
        selected_indexes = self.view.selectedIndexes()
        for index in selected_indexes:
            item = self.model.itemFromIndex(index)
            print "Item {} Class {} ".format(item.text(), item.__class__())

    def dataIs(self):
        selected_indexes = self.view.selectedIndexes()
        for index in selected_indexes:
            item = self.model.itemFromIndex(index)
            try:
                print "Item {} data {} Object {}".format(item.text(),
                                                         item.data().title,
                                                         item.data().obj)
            except Exception as exc:
                print "Data exception ", exc

    def metaIs(self):
        selected_indexes = self.view.selectedIndexes()
        for index in selected_indexes:
            item = self.model.itemFromIndex(index)
            try:
                print "Item {} meta {} ".format(item.text(), item.meta)
            except Exception as exc:
                print "Meta exception ", exc


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    main = mainWidget()
    main.show()
    app.exec_()
에쿠 모로

Qt 및 PyQt에 의해 객체가 직렬화되는 방법과 관련된 몇 가지 문제가 있습니다. 첫째,를 복제 할 때 QStandardItem플래그와 데이터 만 복사되고 나머지는 모두 무시됩니다 (동적 파이썬 속성 포함). 둘째, QObject. 이것은 QVariant(Qt가 직렬화에 사용 하는) 캐스트 할 수없고 피클 (PyQt가 직렬화에 사용하는) 할 수 없기 때문입니다.

두 번째 문제를 해결하려면 모든 QObject인스턴스에 대한 별도의 참조를 유지 한 다음 간접 키를 사용하여 나중에 다시 액세스해야합니다. 이를 달성하는 방법에는 여러 가지가있을 수 있지만 기본 아이디어를 보여주는 매우 간단한 접근 방식이 있습니다.

objects = {}

class MyObject(QtCore.QObject):
    def __init__(self, parent=None):
        super(MyObject, self).__init__(parent)
        self.setProperty('key', max(objects.keys() or [0]) + 1)
        objects[self.property('key')] = self

따라서 자동으로 각 인스턴스를 전역 캐시에 추가하고 나중에 쉽게 찾을 수 있도록 고유 한 조회 키를 제공합니다. 이 상태에서 myData이제 클래스를 사용하여 피클 링이 올바르게 처리MyObject 되도록 클래스를 조정해야 합니다 .

class myData():
    def __init__(self, title):
        self._title = title
        self._stuff = dict()
        self._obj = MyObject()

    def __setstate__(self, state):
        self._obj = objects.get(state['obj'])
        self._stuff = state['stuff']
        self._title = state['title']

    def __getstate__(self):
        return {
            'obj': self._obj and self._obj.property('key'),
            'title': self._title,
            'stuff': self._stuff,
            }

첫 번째 문제를 해결하는 것은 훨씬 간단합니다. 동적 Python 속성이 사용자 지정 데이터 역할을 사용하여 항목의 데이터에 기본 값을 저장하는지 확인하기 만하면됩니다. 이 특별한 경우, 값은 MyObject드래그 앤 드롭 작업 후에 검색 할 수 있도록 항목 인스턴스 의 키 여야합니다 .

class myItem(QtGui.QStandardItem):
    MetaRole = QtCore.Qt.UserRole + 1000

    @property
    def meta(self):
        return objects.get(self.data(myItem.MetaRole))

    @meta.setter
    def meta(self, value):
        self.setData(value.property('key'), myItem.MetaRole)

    def clone(self):
        print "My cloning"
        obj = myItem(self)
        print "Clone is a ", obj.__class__
        return obj

아래는 위의 모든 사항을 구현하는 원본 스크립트의 작동 버전입니다. 그러나 실제 코드에서 제대로 작동하려면 거의 확실하게이를 조정해야합니다. 이것은 위에서 설명한 두 가지 문제를 처리하는 방법을 보여주는 작동하는 개념 증명입니다.

# -*- coding: utf-8 -*-
import sys
from PyQt5 import QtGui, QtWidgets, QtCore

objects = {}

class MyObject(QtCore.QObject):
    def __init__(self, parent=None):
        super(MyObject, self).__init__(parent)
        self.setProperty('key', max(objects.keys() or [0]) + 1)
        objects[self.property('key')] = self

class myData():
    def __init__(self, title):
        self._title = title
        self._stuff = dict()
        self._obj = MyObject()

    def __setstate__(self, state):
        self._obj = objects.get(state['obj'])
        self._stuff = state['stuff']
        self._title = state['title']

    def __getstate__(self):
        return {
            'obj': self._obj.property('key'),
            'title': self._title,
            'stuff': self._stuff,
            }

    @property
    def obj(self):
        return self._obj

    @obj.setter
    def obj(self, value):
        self._obj = value

    @property
    def title(self):
        return self._title

    @title.setter
    def title(self, value):
        self._title = value

class myItem(QtGui.QStandardItem):
    MetaRole = QtCore.Qt.UserRole + 1000

    @property
    def meta(self):
        return objects.get(self.data(myItem.MetaRole))

    @meta.setter
    def meta(self, value):
        self.setData(value.property('key'), myItem.MetaRole)

    def clone(self):
        print "My cloning"
        obj = myItem(self)
        print "Clone is a ", obj.__class__
        return obj

class mainWidget(QtWidgets.QMainWindow):
    def __init__(self):
        super(mainWidget, self).__init__()
        self.model = QtGui.QStandardItemModel()
        self.model.setItemPrototype(myItem())
        self.view = QtWidgets.QTreeView()
        self.view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.view.customContextMenuRequested.connect(self.list_click)
        self.view.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
        self.view.setDefaultDropAction(QtCore.Qt.MoveAction)
        self.view.setDragDropOverwriteMode(False)
        self.view.setAcceptDrops(True)
        self.view.setDropIndicatorShown(True)
        self.view.setDragEnabled(True)
        self.view.setModel(self.model)
        dataA = myData('A thing')
        parentA = myItem()
        parentA.setText('A')
        parentA.setDragEnabled(True)
        parentA.setDropEnabled(True)
        parentA.setData(dataA)
        parentA.meta = MyObject()
        childa = myItem()
        childa.setText('a')
        childb = myItem()
        childb.setText('b')
        childc = myItem()
        childc.setText('c')
        parentA.appendRows([childa, childb, childc])
        dataB = myData('B thing')
        parentB = myItem()
        parentB.setText('B')
        parentB.setDragEnabled(True)
        parentB.setDropEnabled(True)
        parentB.setData(dataB)
        parentB.meta = MyObject()
        childd = myItem()
        childd.setText('d')
        childe = myItem()
        childe.setText('e')
        childf = myItem()
        childf.setText('f')
        parentB.appendRows([childd, childe, childf])
        self.model.appendRow(parentA)
        self.model.appendRow(parentB)

        classAct = QtWidgets.QAction('Class', self)
        classAct.triggered.connect(self.classIs)
        dataAct = QtWidgets.QAction('Data', self)
        dataAct.triggered.connect(self.dataIs)
        metaAct = QtWidgets.QAction('Meta', self)
        metaAct.triggered.connect(self.metaIs)
        self.menu = QtWidgets.QMenu("Item info")
        self.menu.addAction(classAct)
        self.menu.addAction(dataAct)
        self.menu.addAction(metaAct)

        self.setCentralWidget(self.view)

    @QtCore.pyqtSlot(QtCore.QPoint)
    def list_click(self, position):
        self.menu.popup(self.view.viewport().mapToGlobal(position))

    def classIs(self):
        selected_indexes = self.view.selectedIndexes()
        for index in selected_indexes:
            item = self.model.itemFromIndex(index)
            print "Item {} Class {} ".format(item.text(), item.__class__())

    def dataIs(self):
        selected_indexes = self.view.selectedIndexes()
        for index in selected_indexes:
            item = self.model.itemFromIndex(index)
            try:
                print "Item {} data {} Object {}".format(item.text(),
                                                         item.data().title,
                                                         item.data().obj)
            except Exception as exc:
                print "Data exception ", exc

    def metaIs(self):
        selected_indexes = self.view.selectedIndexes()
        for index in selected_indexes:
            item = self.model.itemFromIndex(index)
            try:
                print "Item {} meta {} ".format(item.text(), item.meta)
            except Exception as exc:
                print "Meta exception ", exc


if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    main = mainWidget()
    main.show()
    app.exec_()

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

UIButton의 제목 속성이 올바르게 기록되지만 버튼을 하위보기로 추가 할 때 표시되지 않습니다.

분류에서Dev

react canvas.scale이 설정되었을 때 올바르게 작동하지 않는 것 같습니다.

분류에서Dev

목록 항목이 올바르게 삽입되지 않았습니다.

분류에서Dev

github 페이지에 배포했을 때 React 앱이 올바르게 렌더링되지 않았습니다.

분류에서Dev

301 리디렉션이 올바르게 코딩되었다고 생각할 때 작동하지 않습니다.

분류에서Dev

파이썬이 목록을 올바르게 반복하지 않습니다.

분류에서Dev

다시 열 때 Matplotlib 그림이 올바르게 표시되지 않습니다.

분류에서Dev

스크롤 할 때 recycleview 항목의 데이터가 올바르지 않습니다.

분류에서Dev

반복이 올바르게 계산되지 않습니다.

분류에서Dev

내 양식이 올바르게 반복되지 않습니다.

분류에서Dev

목록 항목이 올바르게 표시되지 않음

분류에서Dev

DropDownList가 데이터베이스에 바인딩되어 수동으로 항목을 추가 할 때 제대로 작동하지 않습니다.

분류에서Dev

규칙 ([asd]-> [cpp])에서 제품 (CodeGenerator)을 사용할 때 종속성이 올바르게 해결되지 않음

분류에서Dev

ListBox는 바인딩을 사용할 때 항목을 자동으로 업데이트하지 않습니다.

분류에서Dev

마지막 행이 삭제되었을 때 QTableWidget의 셀 위젯이 올바르게 표시되지 않음

분류에서Dev

SQL Server에서 이동 평균을 계산할 때 올바르게 그룹화하지 않는 이유

분류에서Dev

UTC 월을 가져올 때 월이 올바르지 않습니다.

분류에서Dev

jQuery Masonry-항목이 올바르게 구성되지 않음

분류에서Dev

jQuery Masonry-항목이 올바르게 구성되지 않음

분류에서Dev

지침에 넣을 때 모달이 올바르게 표시되지 않음

분류에서Dev

Swift : 장치가 회전 할 때 AutoLayout 제약 조건이 올바르게 작동하지 않습니까?

분류에서Dev

소프트웨어 업데이트 후 새 커널을 설치할 때 2 개의 DKMS 드라이버가 올바르게 빌드되지 않습니다.

분류에서Dev

제거 된 foreach 항목이 올바르게 계산되지 않음

분류에서Dev

제거 된 foreach 항목이 올바르게 계산되지 않음

분류에서Dev

Pycharm이 우분투 16.04에서 올바르게 설치되지 않고 닫을 때마다 사라집니다.

분류에서Dev

Rock-Paper-Scissors 유형 게임을 플레이 할 때 값이 올바르게 반환되지 않음

분류에서Dev

패널 제목이 올바르게 표시되지 않음

분류에서Dev

Ruby net / smtp에서 이메일 제목이 올바르게 지정되지 않았습니다.

분류에서Dev

목록 필터가 올바르게 작동하지 않는 이유를 파악할 수 없습니다.

Related 관련 기사

  1. 1

    UIButton의 제목 속성이 올바르게 기록되지만 버튼을 하위보기로 추가 할 때 표시되지 않습니다.

  2. 2

    react canvas.scale이 설정되었을 때 올바르게 작동하지 않는 것 같습니다.

  3. 3

    목록 항목이 올바르게 삽입되지 않았습니다.

  4. 4

    github 페이지에 배포했을 때 React 앱이 올바르게 렌더링되지 않았습니다.

  5. 5

    301 리디렉션이 올바르게 코딩되었다고 생각할 때 작동하지 않습니다.

  6. 6

    파이썬이 목록을 올바르게 반복하지 않습니다.

  7. 7

    다시 열 때 Matplotlib 그림이 올바르게 표시되지 않습니다.

  8. 8

    스크롤 할 때 recycleview 항목의 데이터가 올바르지 않습니다.

  9. 9

    반복이 올바르게 계산되지 않습니다.

  10. 10

    내 양식이 올바르게 반복되지 않습니다.

  11. 11

    목록 항목이 올바르게 표시되지 않음

  12. 12

    DropDownList가 데이터베이스에 바인딩되어 수동으로 항목을 추가 할 때 제대로 작동하지 않습니다.

  13. 13

    규칙 ([asd]-> [cpp])에서 제품 (CodeGenerator)을 사용할 때 종속성이 올바르게 해결되지 않음

  14. 14

    ListBox는 바인딩을 사용할 때 항목을 자동으로 업데이트하지 않습니다.

  15. 15

    마지막 행이 삭제되었을 때 QTableWidget의 셀 위젯이 올바르게 표시되지 않음

  16. 16

    SQL Server에서 이동 평균을 계산할 때 올바르게 그룹화하지 않는 이유

  17. 17

    UTC 월을 가져올 때 월이 올바르지 않습니다.

  18. 18

    jQuery Masonry-항목이 올바르게 구성되지 않음

  19. 19

    jQuery Masonry-항목이 올바르게 구성되지 않음

  20. 20

    지침에 넣을 때 모달이 올바르게 표시되지 않음

  21. 21

    Swift : 장치가 회전 할 때 AutoLayout 제약 조건이 올바르게 작동하지 않습니까?

  22. 22

    소프트웨어 업데이트 후 새 커널을 설치할 때 2 개의 DKMS 드라이버가 올바르게 빌드되지 않습니다.

  23. 23

    제거 된 foreach 항목이 올바르게 계산되지 않음

  24. 24

    제거 된 foreach 항목이 올바르게 계산되지 않음

  25. 25

    Pycharm이 우분투 16.04에서 올바르게 설치되지 않고 닫을 때마다 사라집니다.

  26. 26

    Rock-Paper-Scissors 유형 게임을 플레이 할 때 값이 올바르게 반환되지 않음

  27. 27

    패널 제목이 올바르게 표시되지 않음

  28. 28

    Ruby net / smtp에서 이메일 제목이 올바르게 지정되지 않았습니다.

  29. 29

    목록 필터가 올바르게 작동하지 않는 이유를 파악할 수 없습니다.

뜨겁다태그

보관