Improve drag and drop targetting

This commit is contained in:
Keith Edmunds 2024-06-22 21:52:08 +01:00
parent 3831ebb01d
commit c139215603
2 changed files with 115 additions and 2 deletions

View File

@ -271,8 +271,20 @@ class PlaylistTab(QTableView):
from_rows = self.selected_model_row_numbers()
to_index = self.indexAt(event.position().toPoint())
to_model_row = self.proxy_model.mapToSource(to_index).row()
log.info(f"PlaylistTab.dropEvent(): {from_rows=}, {to_index=}, {to_model_row=}")
if (
self.dropIndicatorPosition()
== QAbstractItemView.DropIndicatorPosition.BelowItem
):
internal_id = to_index.internalId()
proxy_index = self.proxy_model.createIndex(
to_index.row() + 1, to_index.column(), internal_id
)
else:
proxy_index = to_index
to_model_row = self.proxy_model.mapToSource(proxy_index).row()
log.info(
f"PlaylistTab.dropEvent(): {from_rows=}, {proxy_index=}, {to_model_row=}"
)
if (
0 <= min(from_rows) <= self.source_model.rowCount()

101
archive/dragdrop.py Executable file
View File

@ -0,0 +1,101 @@
#!/usr/bin/env python3
# https://stackoverflow.com/questions/26227885/drag-and-drop-rows-within-qtablewidget
import sys
from PyQt6.QtWidgets import (
QTableWidget,
QAbstractItemView,
QTableWidgetItem,
QWidget,
QHBoxLayout,
QApplication,
)
from PyQt6.QtCore import Qt
class TableWidgetDragRows(QTableWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setDragEnabled(True)
self.setAcceptDrops(True)
self.viewport().setAcceptDrops(True)
self.setDragDropOverwriteMode(False)
self.setDropIndicatorShown(True)
self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
self.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove)
self.DropIndicatorPosition(QAbstractItemView.DropIndicatorPosition.BelowItem)
def dropEvent(self, event):
if event.source() == self:
rows = set([mi.row() for mi in self.selectedIndexes()])
targetRow = self.indexAt(event.position().toPoint()).row()
if self.dropIndicatorPosition() == QAbstractItemView.DropIndicatorPosition.BelowItem:
targetRow += 1
rows.discard(targetRow)
rows = sorted(rows)
if not rows:
return
if targetRow == -1:
targetRow = self.rowCount()
for _ in range(len(rows)):
self.insertRow(targetRow)
rowMapping = dict() # Src row to target row.
for idx, row in enumerate(rows):
if row < targetRow:
rowMapping[row] = targetRow + idx
else:
rowMapping[row + len(rows)] = targetRow + idx
colCount = self.columnCount()
for srcRow, tgtRow in sorted(rowMapping.items()):
for col in range(0, colCount):
self.setItem(tgtRow, col, self.takeItem(srcRow, col))
for row in reversed(sorted(rowMapping.keys())):
self.removeRow(row)
event.accept()
return
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
layout = QHBoxLayout()
self.setLayout(layout)
self.table_widget = TableWidgetDragRows()
layout.addWidget(self.table_widget)
# setup table widget
self.table_widget.setColumnCount(2)
self.table_widget.setHorizontalHeaderLabels(["Type", "Name"])
items = [
("Red", "Toyota"),
("Blue", "RV"),
("Green", "Beetle"),
("Silver", "Chevy"),
("Black", "BMW"),
]
self.table_widget.setRowCount(len(items))
for i, (color, model) in enumerate(items):
item_flags = Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsDragEnabled
colour_item = QTableWidgetItem(color)
colour_item.setFlags(item_flags)
model_item = QTableWidgetItem(model)
model_item.setFlags(item_flags)
self.table_widget.setItem(i, 0, QTableWidgetItem(color))
self.table_widget.setItem(i, 1, QTableWidgetItem(model))
self.resize(400, 400)
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
sys.exit(app.exec())