qlistwidget을 사용하여 내부 드래그 앤 드롭 작업에 어떻게 응답합니까?
문제
QT4 응용 프로그램 (PYQT 바인딩 사용)이 포함되어 있습니다. QListWidget
, 그렇게 초기화 :
class MyList(QtGui.QListWidget):
def __init__(self):
QtGui.QListWidget.__init__(self)
self.setDragDropMode(self.InternalMove)
항목을 추가 할 수있어서 목록을 다시 주문하기 위해 드래그 앤 드롭 할 수 있습니다. 그러나 사용자가 목록을 재정렬 할 때 알림을 얻으려면 어떻게해야합니까? 나는 추가를 시도했다 dropMimeData(self, index, data, action)
수업에 대한 방법이지만 결코 호출되지 않습니다.
해결책
나는 단지 이것을 다루어야했고 그것은 엉덩이의 고통이지만 여기에해야 할 일이 있습니다.
당신은 설치해야합니다 eventFilter
너의 ListWidget
서브 클래스를 지켜보고 ChildRemoved
이벤트. 이 이벤트는 이동뿐만 아니라 제거를 다루므로 목록 내부에 드래그 앤 드롭이있는 항목을 다시 조절하는 데 작동해야합니다.
QT를 C ++로 작성하지만 여기에는 파이터 화 버전이 있습니다.
class MyList(QtGui.QListWidget):
def __init__(self):
QtGui.QListWidget.__init__(self)
self.setDragDropMode(self.InternalMove)
self.installEventFilter(self)
def eventFilter(self, sender, event):
if (event.type() == QEvent.ChildRemoved):
self.on_order_changed()
return False # don't actually interrupt anything
def on_order_changed(self):
# do magic things with our new-found knowledge
이 목록이 포함 된 다른 클래스가있는 경우 이벤트 필터 메소드를 이동할 수 있습니다. 이것이 도움이되기를 바랍니다. 나는 이것을 알아 내기 전에 하루 동안 이것과 싸워야한다는 것을 알고 있습니다.
다른 팁
더 쉬운 방법이 있습니다. :)
실제로 ListWidget의 내부 모델에 액세스 할 수 있습니다. myList->model()
- 그리고 거기에서 많은 신호가 있습니다.
드래그 앤 드롭에 관심이 있다면 layoutChanged
. 이동 버튼이있는 경우 (일반적으로 제거+추가로 구현 됨) 연결 rowsInserted
도.
무슨 일이 있었는지 알고 싶다면 rowsMoved
보다 낫다 layoutChanged
.
나는 찾았다 Trey Stout의 답변 그러나 일을했지만 목록 순서가 실제로 변경되지 않았을 때 분명히 이벤트를 받고있었습니다. 나는 돌렸다 Chani의 대답 필요에 따라 작동하지만 코드가 없으면 Python에서 구현하는 데 약간의 작업이 필요했습니다.
미래의 방문객을 돕기 위해 코드 스 니펫을 공유 할 것이라고 생각했습니다.
class MyList(QListWidget):
def __init__(self):
QListWidget.__init__(self)
self.setDragDropMode(self.InternalMove)
list_model = self.model()
list_model.layoutChanged.connect(self.on_layout_changed)
def on_layout_changed(self):
print "Layout Changed"
이것은 파이 사이드에서 테스트되지만 PYQT에서는 작동하지 않을 이유가 없습니다.
해결책이 아니라 일부 아이디어 :
supportedDropactions 메소드로 반환 된 내용을 확인해야 할 것입니다. qt :: moveaction 또는 qt :: 복사를 포함시키기 위해 해당 메소드를 덮어 쓰야 할 수도 있습니다.
qlistView :: IndexSmoved Signal이 있지만 QlistWidget을 사용하는 경우 방출되는지 확실하지 않습니다. 확인하는 가치가 있습니다.
나는 이것이 오래된 것을 알고 있지만 Trey의 답변을 사용하여 코드를 작동시킬 수 있었고 파이썬 솔루션을 공유하고 싶었습니다. 이것은 a입니다 QListWidget
내부 a QDialog
, 하위 클래스가 아닌 것은 아닙니다.
class NotesDialog(QtGui.QDialog):
def __init__(self, notes_list, notes_dir):
QtGui.QDialog.__init__(self)
self.ui=Ui_NotesDialog()
# the notesList QListWidget is created here (from Qt Designer)
self.ui.setupUi(self)
# install an event filter to catch internal QListWidget drop events
self.ui.notesList.installEventFilter(self)
def eventFilter(self, sender, event):
# this is the function that processes internal drop in notesList
if event.type() == QtCore.QEvent.ChildRemoved:
self.update_views() # do something
return False # don't actually interrupt anything
그만큼 QListWidget.model()
접근 방식은 제안 된 솔루션 중 가장 우아한 것처럼 보였지만 PYQT5에서는 저에게 효과가 없었습니다. 왜 그런지 모르겠지만 아마도 QT5로 이동할 때 무언가가 바뀌었을 것입니다. 그만큼 eventFilter
접근 방식은 효과가 있었지만 고려해야 할 또 다른 대안이 있습니다. PYQT5를 확인하기 위해 코딩 된 모든 제안 된 솔루션이있는 MVCE의 아래 코드를 참조하십시오.
import sys
from PyQt5 import QtGui, QtWidgets, QtCore
class MyList(QtWidgets.QListWidget):
itemMoved = QtCore.pyqtSignal()
def __init__(self):
super(MyList, self).__init__()
self.setDragDropMode(self.InternalMove)
list_model = self.model()
# list_model.layoutChanged.connect(self.onLayoutChanged) # doesn't work
# self.installEventFilter(self) # works
self.itemMoved.connect(self.onLayoutChanged) # works
def onLayoutChanged(self):
print("Layout Changed")
def eventFilter(self, sender, event):
"""
Parameters
----------
sender : object
event : QtCore.QEvent
"""
if event.type() == QtCore.QEvent.ChildRemoved:
self.onLayoutChanged()
return False
def dropEvent(self, QDropEvent):
"""
Parameters
----------
QDropEvent : QtGui.QDropEvent
"""
mime = QDropEvent.mimeData() # type: QtCore.QMimeData
source = QDropEvent.source()
if source is self:
super(MyList, self).dropEvent(QDropEvent)
self.itemMoved.emit()
app = QtWidgets.QApplication([])
form = MyList()
for text in ("one", "two", "three"):
item = QtWidgets.QListWidgetItem(text)
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
item.setCheckState(QtCore.Qt.Checked)
form.addItem(item)
form.show()
sys.exit(app.exec_())