在PyQt5中,如何使用拖放功能正确移动QTableView中的行

问题描述 投票:0回答:2

我(简单地)希望能够使用QTableView的拖放机制来移动现有行。我发现了很多资料(例如hereherehere),它们描述了[[some拖放,插入,插入等方面,但我仍在努力使其适用于我的情况。] >这是我正在寻找的解决方案应具备的能力:

    研究“无Qt”数据结构,例如元组列表。
  • 对数据结构进行操作。即当物品的顺序在视图中修改它应该在数据结构中修改
  • 标准拖放列表的外观:
    • 选择/移动整行
  • 显示整行的放置指示器
  • 仍然必须进行进一步的操作,例如删除/编辑单元格即不会被拖放方法触摸]
  • This tutorial显示的解决方案非常接近[[非常,但我使用的是QStandardItemModel而不是QAbstractTableModel,它对我来说似乎是半最佳的,因为我必须对'镜像'数据进行操作QStandardItem所需的基于QStandardItemModel的结构(对吗?)

    下面是代表我当前进度的代码。

    目前,我看到两种可能的方法:

    方法1

    :针对QAbstractTableModel实施并实施所有必需的事件/插槽以修改基础数据结构:*专家:最通用的方法*专业人士:无冗余数据*缺点:我不知道如何了解完成的拖放操作操作以及什么索引移到了哪里

    在我添加的代码中,我跟踪了我所知道的所有相关方法,并输出了所有参数。这是将第2行拖到第3行时得到的结果

    dropMimeData(data: ['application/x-qabstractitemmodeldatalist'], action: 2, row: -1, col: -1, parent: '(row: 2, column: 0, valid: True)') insertRows(row=-1, count=1, parent=(row: 2, column: 0, valid: True)) setData(index=(row: 0, column: 0, valid: True), value='^line1', role=0) setData(index=(row: 0, column: 1, valid: True), value=1, role=0) removeRows(row=1, count=1, parent=(row: -1, column: -1, valid: False))

    此输出为我提出以下问题:

    为什么不调用moveRow / moveRows?什么时候会被称为?

      为什么不叫insertRow / removeRow而是只叫insertRows / removeRows
  • -1的行索引是什么意思?
  • 我该如何处理dropMimeData中提供的哑剧数据?我以后是否应该使用它来复制数据?
  • 方法2:使用QStandardItemModel并与QStandardItemModel管理的数据并行地修改您的数据。*专家:有working example*相反:您管理的冗余数据结构必须一致与另一个内部管理的数据结构。*相反:完全没有找到如何执行此操作]

    这是我目前使用QAbstractTableModel的方法:

    from PyQt5 import QtWidgets, QtCore, QtGui class MyModel(QtCore.QAbstractTableModel): def __init__(self, data, parent=None, *args): super().__init__(parent, *args) self._data = data def columnCount(self, parent): return 2 def rowCount(self, parent): return len(self._data) def headerData(self, column: int, orientation, role: QtCore.Qt.ItemDataRole): return (('Regex', 'Category')[column] if role == QtCore.Qt.DisplayRole and orientation == QtCore.Qt.Horizontal else None) def data(self, index, role: QtCore.Qt.ItemDataRole): if role not in {QtCore.Qt.DisplayRole, QtCore.Qt.EditRole}: return None print("data(index=%s, role=%r)" % (self._index2str(index), self._role2str(role))) return (self._data[index.row()][index.column()] if index.isValid() and role in {QtCore.Qt.DisplayRole, QtCore.Qt.EditRole} and index.row() < len(self._data) else None) def setData(self, index: QtCore.QModelIndex, value, role: QtCore.Qt.ItemDataRole): print("setData(index=%s, value=%r, role=%r)" % (self._index2str(index), value, role)) return super().setData(index, value, role) def flags(self, index): return ( super().flags(index) | QtCore.Qt.ItemIsDropEnabled | (QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsDragEnabled) if index.isValid() else QtCore.Qt.NoItemFlags) def dropMimeData(self, data, action, row, col, parent: QtCore.QModelIndex): """Always move the entire row, and don't allow column 'shifting'""" print("dropMimeData(data: %r, action: %r, row: %r, col: %r, parent: %r)" % ( data.formats(), action, row, col, self._index2str(parent))) assert action == QtCore.Qt.MoveAction return super().dropMimeData(data, action, row, 0, parent) def supportedDragActions(self): return QtCore.Qt.MoveAction def supportedDropActions(self): return QtCore.Qt.MoveAction | QtCore.Qt.CopyAction def removeRow(self, row: int, parent=None): print("removeRow(row=%r):" % (row)) return super().removeRow(row, parent) def removeRows(self, row: int, count: int, parent=None): print("removeRows(row=%r, count=%r, parent=%s)" % (row, count, self._index2str(parent))) return super().removeRows(row, count, parent) def insertRow(self, index, parent=None): print("insertRow(row=%r, count=%r):" % (row, count)) return super().insertRow(row, count, parent) def insertRows(self, row: int, count: int, parent: QtCore.QModelIndex = None): print("insertRows(row=%r, count=%r, parent=%s)" % (row, count, self._index2str(parent))) return super().insertRows(row, count, parent) @staticmethod def _index2str(index): return "(row: %d, column: %d, valid: %r)" % (index.row(), index.column(), index.isValid()) @staticmethod def _role2str(role: QtCore.Qt.ItemDataRole) -> str: return "%s (%d)" % ({ QtCore.Qt.DisplayRole: "DisplayRole", QtCore.Qt.DecorationRole: "DecorationRole", QtCore.Qt.EditRole: "EditRole", QtCore.Qt.ToolTipRole: "ToolTipRole", QtCore.Qt.StatusTipRole: "StatusTipRole", QtCore.Qt.WhatsThisRole: "WhatsThisRole", QtCore.Qt.SizeHintRole: "SizeHintRole", QtCore.Qt.FontRole: "FontRole", QtCore.Qt.TextAlignmentRole: "TextAlignmentRole", QtCore.Qt.BackgroundRole: "BackgroundRole", #QtCore.Qt.BackgroundColorRole: QtCore.Qt.ForegroundRole: "ForegroundRole", #QtCore.Qt.TextColorRole QtCore.Qt.CheckStateRole: "CheckStateRole", QtCore.Qt.InitialSortOrderRole: "InitialSortOrderRole", }[role], role) class MyTableView(QtWidgets.QTableView): class DropmarkerStyle(QtWidgets.QProxyStyle): def drawPrimitive(self, element, option, painter, widget=None): """Draw a line across the entire row rather than just the column we're hovering over. This may not always work depending on global style - for instance I think it won't work on OSX.""" if element == self.PE_IndicatorItemViewItemDrop and not option.rect.isNull(): option_new = QtWidgets.QStyleOption(option) option_new.rect.setLeft(0) if widget: option_new.rect.setRight(widget.width()) option = option_new super().drawPrimitive(element, option, painter, widget) def __init__(self): super().__init__() self.setStyle(self.DropmarkerStyle()) # only allow rows to be selected self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) # disallow multiple rows to be selected self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) self.setDragEnabled(True) self.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove) self.setDropIndicatorShown(True) # default self.setAcceptDrops(False) # ? self.viewport().setAcceptDrops(True) # ? self.setDragDropOverwriteMode(False) class HelloWindow(QtWidgets.QMainWindow): def __init__(self) -> None: super().__init__() model = MyModel([("^line0", 0), ("^line1", 1), ("^line2", 2), ("^line3", 3)]) table_view = MyTableView() table_view.setModel(model) table_view.verticalHeader().hide() table_view.setShowGrid(False) self.setCentralWidget(table_view) def main(): app = QtWidgets.QApplication([]) window = HelloWindow() window.show() app.exec_() if __name__ == "__main__": main()

    我(简单地)希望能够使用QTableViews拖放机制来移动现有行。我发现了很多来源(例如,此处,此处或此处),这些资源描述了拖放,...

  • python-3.x pyqt drag-and-drop qtableview
    2个回答
    0
    投票

    0
    投票
    © www.soinside.com 2019 - 2024. All rights reserved.