2016-11-06 1 views
1

이 질문은이 항목의 내용과 비슷합니다. Preserve QStandardItem subclasses in drag and drop 그러나 좋은 해결책을 찾을 수 없다는 문제가 있습니다. 이 주제는 부분적으로 도움이되지만 더 복잡한 작업에는 실패합니다.QT, Python, QTreeView, 사용자 정의 위젯, setData - 드래그 앤 드롭 후 참조를 잃습니다.

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]) 

입니다. 두 번째 드래그/드롭 내가 참조를 잃게 내 모든 항목에 대한 업데이 트를 잃고 나는 충돌을 얻을.

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

나는이 문제를 해결의 생각할 수있는 방법은 재귀 적으로 각 행/자녀 이상 이름과 일치 업데이트 항목 전체 트 리뷰를 통해 루프입니다 .... 문제는 내가 매 0.5 초 상쾌 트 리뷰가 될 것입니다 5 ~ 15 개의 항목이있는 500 개 이상의 행이 있습니다. 의미 ... 나는 그것이 매우 빠르고 효율적일 것이라고 생각하지 않습니다 ... 5 초마다 5 000 개의 항목을 반복하고 싶다면 ...

이 문제를 어떻게 풀 수 있을지 제안 할 수 있습니까? 아마도 dropEvent를 편집하여 항목을 복사/붙여 넣기하지 않고 항목을 옮길 수 있습니다. 배열에서 객체를 잃지 않을 것입니다.

답변

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_()) 
+0

나는 사전 및 ID와 작품에서 비슷한했다,하지만 내가 배운대로 내가/드롭을 드래그 할 때 setIndexWidget는 트 리뷰 할 때 QT에 배열에있는 개체를두고 있기 때문에 Copy/past는 또한 항목을 제거했습니다. 다른 실수를 저 지르지 않으면 오류가 발생합니다. 어쨌든 내가하려는 것은'dropEvent() super (treeView, self) .dropEvent (event) self.treeView.reInitializeView()'이후에 각 위젯을 반복적으로 반복하고 그들에게 새로운 진행 바. 그것은 문제의 90 %에 대해 작동하지만 그 또한 항목을 복제하는 것입니다 : - (드롭 이벤트의 마지막 기능은 무엇입니까? – Dariusz

+0

@Dariusz. 다 잘 됐어요. 완전한 데모 스크립트를 추가했습니다. 내 대답. – ekhumoro

+0

세미 작동, 일단 0 항목을 다른 0 항목으로 드래그하면 하위 항목은 진행 대신 ProgressBarItem 텍스트를 가지게됩니다. 진행률 표시 줄에 데이터 배열의 특정 위치를 찾는 함수를 지정했습니다. 그것은 항상 배열의 데이터 위치의 ID를 유지하기 때문에 항목을 이동하는 등의 작업을 수행합니다. 항상 이러한 진행 막대를 다시 첨부하기 위해 dragEvent에 update 함수를 호출합니다. 항목 1-2 -3 (0 이외) 다른 항목 위에 항목 행이 사라집니다. 아마도 그 제한 방법을 알고있을 것입니다. https://youtu.be/L6qLuC2dmhE 예 – Dariusz

관련 문제