PyQt:在QCalendarWidget中输入单元格时发出信号

时间:2017-02-04 19:36:07

标签: python qt pyqt signals-slots qcalendarwidget

在我的Qt应用程序中,我使用QCalendarWidget,我希望在鼠标进入日历的新单元格时收到通知。我知道QCalendarWidget内部使用了QTableView,它继承自QAbstractItemView并且有一个entered信号:

  

当鼠标光标进入指定的项目时会发出此信号   按索引。需要启用鼠标跟踪才能使此功能正常工作。

我尝试使用以下代码接收信号:

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class MyCalendar:

    def __init__(self):
        app = QApplication(sys.argv)

        window = QMainWindow()
        cal = QCalendarWidget(window)

        window.resize(320, 240)
        cal.resize(320, 240)

        table = cal.findChild(QTableView)
        table.setMouseTracking(True)
        table.entered.connect(self.onCellEntered)

        window.show()
        sys.exit(app.exec_())

    def onCellEntered(self, index):
        print("CellEntered")

if __name__ == "__main__":
    window = MyCalendar()

但我的回调函数从未被调用过。你有什么想法吗?

2 个答案:

答案 0 :(得分:2)

我已经调查了一下,我想我知道为什么会这样。

QCalendarWidget创建一个名为QTableView的{​​{1}}私有子类,并将其实例化为自身的子级。 (此实例称为QCalendarView。)

如果你看QCalendarView's code (Qt 5),你就会看到:

qt_calendar_calendarview

这意味着只有在没有void QCalendarView::mouseMoveEvent(QMouseEvent *event) { [...] if (!calendarModel) { QTableView::mouseMoveEvent(event); return; } [...] } 的情况下,才会调用超类calendarModel,它负责发出mouseMoveEvent信号。所有这些都是`QCalendarWidget的实现细节,所以最好不要依赖任何一个。

因此,为了解决这个问题,我不确定最佳方法是什么。您必须在之前抓住事件才能到达表格。这可以使用entered或重新实施QObject.installEventFilter()来完成,但是您不能直接获得模型索引。您可以将QWidget.mouseMoveEvent()用于此目的。

答案 1 :(得分:2)

QCalendarWidget类使用自定义表视图绕过正常的鼠标事件处理程序 - 因此enetered信号永远不会被发出。但是,通过使用事件过滤器来发出执行相同操作的自定义信号,可以解决这个问题。

这是一个实现它的演示脚本:

import sys
from PyQt4 import QtCore, QtGui

class Window(QtGui.QWidget):
    cellEntered = QtCore.pyqtSignal(object)

    def __init__(self):
        super(Window, self).__init__()
        self.calendar = QtGui.QCalendarWidget(self)
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.calendar)
        self._table = self.calendar.findChild(QtGui.QTableView)
        self._table.setMouseTracking(True)
        self._table.installEventFilter(self)
        self._index = None
        self.cellEntered.connect(self.handleCellEntered)

    def eventFilter(self, source, event):
        if source is self._table:
            if event.type() == QtCore.QEvent.MouseMove:
                index = QtCore.QPersistentModelIndex(
                    source.indexAt(event.pos()))
                if index != self._index:
                    self._index = index
                    self.cellEntered.emit(QtCore.QModelIndex(index))
            elif event.type() == QtCore.QEvent.Leave:
                self._index = None
        return super(Window, self).eventFilter(source, event)

    def handleCellEntered(self, index):
        print(index.row(), index.column())

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.setGeometry(600, 100, 300, 200)
    window.show()
    sys.exit(app.exec_())