Search code examples
pythonpyqtpyqt5qtablewidget

How to highlight table cell during drag&drop event from another widget


There's two dockable widgets: one with icons(QLabel), another with table(QTableWidget).

I've been trying to implement tables' cell colours on mouse hovering during drag&drop event from the second widget. The problem is that they dont do this. The tables' class is simple with added event filter for hovering.

class TableEdit(QtWidgets.QTableWidget):
    def __init__(self, parent=None):
        super(TableEdit, self).__init__(parent=parent)

        # self.setMinimumSize(QtCore.QSize(self.width(), self.height()))

        self.current_hover = [0, 0]
        row = 3
        column = 3

        self.setColumnCount(column)
        self.setAlternatingRowColors(True)

        self.setRowCount(row)

        for row in range(0, 3):
            for column in range(0, 3):
                item = QtWidgets.QTableWidgetItem("This is cell {} {}".format(row + 1, column + 1))
                self.setItem(row, column, item)

        self.setHorizontalHeaderItem(0, QtWidgets.QTableWidgetItem("Col1"))
        self.horizontalHeader().setVisible(False)
        # self.setShowGrid(False)

        self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
        self.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)

        self.setAcceptDrops(True)
        self.setMouseTracking(True)
        self.cellEntered.connect(self.cellHover)

    def cellHover(self, row, column):
        item = self.item(row, column)
        old_item = self.item(self.current_hover[0], self.current_hover[1])
        if self.current_hover != [row, column]:
            old_item.setBackground(QtGui.QBrush(QtGui.QColor('white')))
            item.setBackground(QtGui.QBrush(QtGui.QColor('yellow')))
        self.current_hover = [row, column]

    def dragEnterEvent(self, event):
        event.accept()
        print("drag enter +")

    def dragMoveEvent(self, event):
        event.accept()

    def dropEvent(self, event):
        event.accept()
        print("drop +")

        mime = event.mimeData()
        if mime.hasFormat("application/x-fire"):
            print("Fire")

Here's a screenshot shows that nothing happens when you drag a QLabel into a cell.


Solution

  • You must implement the dragMoveEvent method and implement the logic of the colors, to obtain the item you must use the position of the QCursor:

    class TableEdit(QtWidgets.QTableWidget):
        def __init__(self, parent=None):
            super(TableEdit, self).__init__(parent)
            self.hover_item = None
    
            row, column = 3, 3
            self.setColumnCount(column)
            self.setAlternatingRowColors(True)
            self.setRowCount(row)
    
            for r in range(self.rowCount()):
                for c in range(self.columnCount()):
                    item = QtWidgets.QTableWidgetItem("This is cell {} {}".format(r + 1, c + 1))
                    self.setItem(r, c, item)
    
            self.setHorizontalHeaderItem(0, QtWidgets.QTableWidgetItem("Col1"))
            self.horizontalHeader().setVisible(False)
            # self.setShowGrid(False)
            self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
            self.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
    
            self.setAcceptDrops(True)
            self.setMouseTracking(True)
    
        def dragMoveEvent(self, event):
            p = self.viewport().mapFromGlobal(QtGui.QCursor().pos())
            it = self.itemAt(p)
            if self.hover_item != it:
                if self.hover_item is not None:
                    self.hover_item.setBackground(QtCore.Qt.white)
                self.hover_item = it
                if self.hover_item is not None:
                    self.hover_item.setBackground(QtCore.Qt.yellow)
            super(TableEdit, self).dragMoveEvent(event)
    
        # ...