I need to drag and drop (move) CellWidget in a QtableWidget.
I can move them, but if i drop a CellWidget on a cell occupied by an other one, i deleted the previous.
Example : (row, col)
B(0, 1) move to (1, 2)
C(0, 2) move to (0, 1)
B is deleted.
More : A cellWidget can't be put on an old position.
Here is my minimal code.
from PySide6.QtWidgets import QApplication, QHBoxLayout, QWidget, QPushButton, QTableWidget
from PySide6.QtCore import Qt, QMimeData
from PySide6.QtGui import QDrag
class DragButton(QPushButton):
def mouseMoveEvent(self, e):
if e.buttons() == Qt.LeftButton:
drag = QDrag(self)
mime = QMimeData()
drag.setMimeData(mime)
drag.exec(Qt.MoveAction)
class Window(QWidget):
def __init__(self):
super().__init__()
self.setAcceptDrops(True)
self.nb_col = 5
self.nb_row = 5
self.tbl = QTableWidget(self.nb_row, self.nb_col)
self.tbl.setHorizontalHeaderLabels([str(x) for x in range(self.nb_col)])
self.tbl.setVerticalHeaderLabels([str(x) for x in range(self.nb_row)])
self.layout = QHBoxLayout()
self.layout.addWidget(self.tbl)
nom = ['A', 'B', 'C', 'D']
for l in range(len(nom)):
new_btn = DragButton(nom[l])
new_btn2 = DragButton(nom[l] + 'j')
self.tbl.setCellWidget(0, l, new_btn)
self.tbl.setCellWidget(l, 1, new_btn2)
self.setLayout(self.layout)
def dragEnterEvent(self, e):
e.accept()
def dropEvent(self, e):
position = e.position()
widget = e.source()
row = self.tbl.rowAt(position.y() - self.tbl.horizontalHeader().height() - self.tbl.y())
column = self.tbl.columnAt(position.x() - self.tbl.x())
self.tbl.setCellWidget(row, column, widget)
e.accept()
if __name__ == "__main__":
app = QApplication([])
w = Window()
w.showMaximized()
app.exec()
Thanks for your help. Christophe
I might be a little late to the party ^^ but I just had the same problem on a QTableWidget, the trick is to create a temporary QWidget and QHBoxLayout in which you place your buttons or whatever. That way, those temporary widgets will get destroyed instead.
from PySide6.QtWidgets import QApplication, QHBoxLayout, QWidget, QPushButton, QTableWidget
from PySide6.QtCore import Qt, QMimeData
from PySide6.QtGui import QDrag
class DragButton(QPushButton):
def mouseMoveEvent(self, e):
if e.buttons() == Qt.LeftButton:
drag = QDrag(self)
mime = QMimeData()
drag.setMimeData(mime)
drag.exec(Qt.MoveAction)
class Window(QWidget):
def __init__(self):
super().__init__()
self.setAcceptDrops(True)
self.nb_col = 5
self.nb_row = 5
self.tbl = QTableWidget(self.nb_row, self.nb_col)
self.tbl.setHorizontalHeaderLabels([str(x) for x in range(self.nb_col)])
self.tbl.setVerticalHeaderLabels([str(x) for x in range(self.nb_row)])
self.layout = QHBoxLayout()
self.layout.addWidget(self.tbl)
nom = ['A', 'B', 'C', 'D']
for l in range(len(nom)):
new_btn = DragButton(nom[l])
new_btn2 = DragButton(nom[l] + 'j')
self.set_cell_widget(0, l, new_btn)
self.set_cell_widget(l, 1, new_btn2)
self.setLayout(self.layout)
def set_cell_widget(self, row, column, widget):
container_widget = QWidget()
container_layout = QHBoxLayout()
container_layout.setContentsMargins(0, 0, 0, 0)
container_layout.setSpacing(0)
container_widget.setLayout(container_layout)
container_layout.addWidget(widget)
self.tbl.setCellWidget(row, column, container_widget)
def dragEnterEvent(self, e):
e.accept()
def dropEvent(self, e):
position = e.position()
widget = e.source()
row = self.tbl.rowAt(position.y() - self.tbl.horizontalHeader().height() - self.tbl.y())
column = self.tbl.columnAt(position.x() - self.tbl.x())
self.set_cell_widget(row, column, widget)
e.accept()
if __name__ == "__main__":
app = QApplication([])
w = Window()
w.showMaximized()
app.exec()
Hope this helps!