I'm trying to do a drag and drop between two items, but I'm having trouble getting the information out of the cell I click on in the table. I have a custom table that has a custom model.
class PyTableWidget(QTableView):
def __init__(self, *args):
super().__init__()
self.setDragEnabled(True)
self.set_stylesheet(*args)
def onLeftClick(self, index):
print('onClick index.row: %s, index.col: %s' % (index.row(), index.column()))
def mouseMoveEvent(self, event):
if event.buttons() == Qt.LeftButton:
drag = QDrag(self)
mime = QMimeData()
drag.setMimeData(mime)
drag.exec(Qt.MoveAction)
Here's the custom model for the table:
class CustomizedNumpyModel(QAbstractTableModel):
def __init__(self, data, parent=None):
QAbstractTableModel.__init__(self, parent)
self._data = np.array(data.values)
self._cols = data.columns
self.r, self.c = np.shape(self._data)
def data(self, index, role=Qt.DisplayRole):
if role == Qt.DisplayRole:
value = self._data[index.row(), index.column()]
if isinstance(value, float):
return "%.2f" % value
if isinstance(value, str):
return '%s' % value
return unicode(value)
def rowCount(self, parent=None):
return self.r
def columnCount(self, parent=None):
return self.c
def headerData(self, p_int, orientation, role):
if role == Qt.DisplayRole:
if orientation == Qt.Horizontal:
return str(self._cols[p_int])
if orientation == Qt.Vertical:
return p_int
return None
def flags(self, index):
return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
def setData(self, index, value, role=Qt.EditRole):
index_value = None
based_columns = [6, 8, 10, 12]
if role == Qt.EditRole:
row = index.row()
column = index.column()
tmp = str(value)
if tmp != '':
if column in based_columns:
if column == 6 and tmp in self._cols:
index_no = np.where(self._cols == tmp)[0][0]
self._data[row, column + 1] = self._data[row, index_no]
self._data[row, column] = tmp
elif column in [8, 10, 12]:
for x in range(97, 181):
if self._data[row, x] == int(tmp):
index_value = x
break
col_name = self._cols[index_value]
col_name = col_name.removesuffix('_rank')
self._data[row, column + 1] = col_name
self._data[row, column] = tmp
self.dataChanged.emit(index, index)
return True
else:
return False
And here the code in the other widget which accept the drop
class PyCustomButton(QPushButton):
def __init__(self, *args):
super().__init__()
self.setCursor(Qt.PointingHandCursor)
self.setAcceptsDrops(True)
self._lista = []
def dragEnterEvent(self, event):
if event.mimeData().hasText():
event.accept()
else:
event.ignore()
def dropEvent(self, event):
self._lista.append(event.mimeData().text())
print(self._lista)
The table has following aspect:
| Names |
|---|
| First |
| Second |
And I want plain text i.e. First or Second drag from table and drop in custom button.
The simple solution is to get the "selected" index using
indexAt(). Note that it's generally better to start a drag action when the user has moved the mouse by a certain amount of pixels, which defaults to the QApplicationstartDragDistance()property.Note that Qt item views already support drag and drop: to enable that support in custom models, you need to also add
Qt.ItemIsDragEnabledinflags()and ensure that the table supports drag either by usingsetDragEnabled(True)(as you did) or by setting thedragDropModeof the view at least toDragOnly.The only remaining "issue" is getting the data from outside the view from the drag mime data, which uses an internal format to serialize the content.
While this approach might seem more complex and difficult, it's also a better solution whenever you intend to support drag and drop between multiple item views, since that serialization format is common and standard to all Qt views.
Note that
setData()must always return a bool. Remove the lastelse:and push thereturn Falseback to the main indentation level of the function.