【问题标题】:How to catch mouse over event of QTableWidget item in pyqt?如何在pyqt中捕获鼠标悬停在QTableWidget项的事件上?
【发布时间】:2019-05-13 06:29:10
【问题描述】:

当我将鼠标悬停在 QTableWidget 的项目上时,我想做的是更改 QTableWidget 项目的颜色。

【问题讨论】:

    标签: python pyqt qtablewidget mousehover qtablewidgetitem


    【解决方案1】:

    首先,表格小部件需要打开mouse-tracking 才能获取悬停事件。

    其次,我们需要找到一些信号,告诉我们鼠标何时进入和离开表格单元格,以便可以在正确的时间更改背景颜色。

    QTableWidget 类有cellEntered / itemEntered 信号,但是当鼠标离开单元格时没有任何东西。因此,我们需要创建一些自定义信号来做到这一点。

    下面的演示脚本中的TableWidget 类设置了必要的cellExited / itemExited 信号,然后显示了如何在鼠标悬停时连接所有内容以更改项目背景:

    from PyQt4 import QtGui, QtCore
    
    class TableWidget(QtGui.QTableWidget):
        cellExited = QtCore.pyqtSignal(int, int)
        itemExited = QtCore.pyqtSignal(QtGui.QTableWidgetItem)
    
        def __init__(self, rows, columns, parent=None):
            QtGui.QTableWidget.__init__(self, rows, columns, parent)
            self._last_index = QtCore.QPersistentModelIndex()
            self.viewport().installEventFilter(self)
    
        def eventFilter(self, widget, event):
            if widget is self.viewport():
                index = self._last_index
                if event.type() == QtCore.QEvent.MouseMove:
                    index = self.indexAt(event.pos())
                elif event.type() == QtCore.QEvent.Leave:
                    index = QtCore.QModelIndex()
                if index != self._last_index:
                    row = self._last_index.row()
                    column = self._last_index.column()
                    item = self.item(row, column)
                    if item is not None:
                        self.itemExited.emit(item)
                    self.cellExited.emit(row, column)
                    self._last_index = QtCore.QPersistentModelIndex(index)
            return QtGui.QTableWidget.eventFilter(self, widget, event)
    
    class Window(QtGui.QWidget):
        def __init__(self, rows, columns):
            QtGui.QWidget.__init__(self)
            self.table = TableWidget(rows, columns, self)
            for column in range(columns):
                for row in range(rows):
                    item = QtGui.QTableWidgetItem('Text%d' % row)
                    self.table.setItem(row, column, item)
            layout = QtGui.QVBoxLayout(self)
            layout.addWidget(self.table)
            self.table.setMouseTracking(True)
            self.table.itemEntered.connect(self.handleItemEntered)
            self.table.itemExited.connect(self.handleItemExited)
    
        def handleItemEntered(self, item):
            item.setBackground(QtGui.QColor('moccasin'))
    
        def handleItemExited(self, item):
            item.setBackground(QtGui.QTableWidgetItem().background())
    
    if __name__ == '__main__':
    
        import sys
        app = QtGui.QApplication(sys.argv)
        window = Window(6, 3)
        window.setGeometry(500, 300, 350, 250)
        window.show()
        sys.exit(app.exec_())
    

    【讨论】:

    • 为什么我们需要创建信号来处理鼠标离开细胞?使用变量跟踪当前悬停的单元格的方法有什么问题?
    • @Vicent。我的目标是更通用的解决方案。我认为 cellExited/itemExited 信号本身很有用,并且对 Qt 没有提供它们感到有点惊讶(但也许我遗漏了一些东西)。尝试跟踪当前单元格的问题是离开视口时没有通知(因为没有新的单元格可以进入)。因此,当离开表格的视口时,最后一个单元格将保持突出显示(这可能不是预期/想要的)。
    • @ekhumoro 我问了同样的问题,但写的是QTreeView of QStandardItemModel:stackoverflow.com/questions/28802763/…。我的预感是它可以轻松修改您的代码,但认为最好将其作为一个单独的问题。
    【解决方案2】:

    您可以使用正确的信号轻松实现您的目标,如下简单代码所示:

    from PyQt4.QtGui import *
    from PyQt4.QtCore import *
    
    class TableViewer(QMainWindow):
        def __init__(self, parent=None):
            super(TableViewer, self).__init__(parent)
            self.table = QTableWidget(3, 3)
            for row in range (0,3):
                for column in range(0,3):
                    item = QTableWidgetItem("This is cell {} {}".format(row+1, column+1))
                    self.table.setItem(row, column, item)
            self.setCentralWidget(self.table)
    
            self.table.setMouseTracking(True)
    
            self.current_hover = [0, 0]
            self.table.cellEntered.connect(self.cellHover)
    
        def cellHover(self, row, column):
            item = self.table.item(row, column)
            old_item = self.table.item(self.current_hover[0], self.current_hover[1])
            if self.current_hover != [row,column]:
                old_item.setBackground(QBrush(QColor('white')))
                item.setBackground(QBrush(QColor('yellow')))
            self.current_hover = [row, column]
    
    
    if __name__ == '__main__':
        import sys
        app = QApplication(sys.argv)
        tv = TableViewer()
        tv.show()
        sys.exit(app.exec_())
    

    您可能也对其他信号感兴趣,尤其是itemEntered。但是,如果您想完全控制项目的编辑和显示,则强烈建议使用委托(通过QTableWidget.setItemDelegate 方法)。

    更新

    抱歉,我忘记了问题的第二部分,即鼠标退出单元格时会发生什么。即使这样,问题也可以在不使用事件的情况下轻松解决。请查看更新后的代码。

    【讨论】:

    • +1 用于修复第二部分,但如果在离开表格的视口时恢复最后一个单元格的背景会更好。
    • 如何实现QTableView? QTableView 没有 setMouseTracking 方法。
    • @san setMouseTrackingQWidget 类的方法。 QTableView 继承 QWidget,因此您也可以将该方法与您的 QTableView 小部件一起使用。
    【解决方案3】:

    没有基于 QTableWidgetItem 的事件,但你可以这样做:

    • 重新实现QTableWidget的mouseMoveEvent(),可以获取鼠标位置;
    • 使用itemAt()方法获取鼠标光标下的项目;
    • 自定义您的项目;

    这可能会满足您的需求。

    【讨论】:

    • 我希望我使用 QImage 的单元格中的图片可以放大到一定程度,当我取出鼠标时它应该恢复到设置的大小。
    • @san 因为光标下只能有一个项目,所以可以将项目保留为私有成员 current_hovered_item 以指示当前悬停的项目,并在 mouseMoveEvent 的开头检查是否当前悬停的项目是存储在current_hovered_item 中的项目,如果不是,您可能希望使用旧项目缩小图像。
    【解决方案4】:

    我知道这是旧的,但我想更新它的几个部分,因为我遇到了这个页面来寻找类似的解决方案。这有几个部分,一个类似于上面的部分,但如果单元格为空,则会避免 NoneType 错误。此外,它将更改突出显示的单元格的颜色,但还会更新单元格的工具提示,以在工具提示中显示单元格的内容。很好,如果你有径流 123 的细胞......

    当然可以稍微清理一下,但适用于 PyQt5。干杯!

    def cellHover(self, row, column):
        item = self.My_Table1.item(row, column)
        old_item = self.My_Table1.item(self.current_hover[0], self.current_hover[1])
        if item is not None:
            if self.current_hover != [row,column]:
                text = item.text()
                if text is not None:
                    self.My_Table1.setToolTip(text)
                    item.setBackground(QBrush(QColor('#bbd9f7')))
                    old_item.setBackground(QBrush(QColor('white')))
                self.current_hover = [row, column]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-21
      • 2015-02-14
      • 2020-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-07
      • 2011-04-20
      相关资源
      最近更新 更多