首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PyQt:当信元进入QCalendarWidget时发出信号

PyQt:当信元进入QCalendarWidget时发出信号
EN

Stack Overflow用户
提问于 2017-02-04 19:36:06
回答 2查看 978关注 0票数 1

在我的Qt应用程序中,我使用的是QCalendarWidget,当鼠标进入日历的一个新单元时,我希望得到通知。我知道QCalendarWidget在内部使用QTableView,这是从QAbstractItemView继承的,它有一个entered信号:

当鼠标光标进入索引指定的项时,将发出此信号。此功能需要启用鼠标跟踪才能工作。

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

代码语言:javascript
复制
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()

但我的回调函数从未被调用过。你知道为什么吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-02-04 21:17:17

QCalendarWidget类使用一个自定义表视图,它绕过普通的鼠标事件处理程序,因此enetered信号永远不会被发出。然而,可以通过使用事件筛选器来发出自定义信号来解决这一问题。

下面是一个实现该功能的演示脚本:

代码语言:javascript
复制
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_())
票数 3
EN

Stack Overflow用户

发布于 2017-02-04 21:14:23

我已经调查过了,我想我知道为什么会发生这种情况。

QCalendarWidget创建一个名为QCalendarView的私有QTableView子类,并将其实例化为自己的子类。(此实例称为qt_calendar_calendarview。)

如果您查看代码(Qt 5),您将看到以下内容:

代码语言:javascript
复制
void QCalendarView::mouseMoveEvent(QMouseEvent *event)
{
    [...]
    if (!calendarModel) {
        QTableView::mouseMoveEvent(event);
        return;
    }
    [...]
}

这意味着只有在没有calendarModel的情况下,超类mouseMoveEvent才会被调用,它负责发射entered信号。所有这些都是“`QCalendarWidget”的实现细节,所以最好还是不要依赖这些。

因此,为了解决这个问题,我不知道最好的方法是什么。你必须在事件到达谈判桌前抓住它。这可以使用QObject.installEventFilter()或重新实现QWidget.mouseMoveEvent()来完成,但是您不能直接获得模型索引。为此,您可能需要使用QAbstractItemView.indexAt()

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42044738

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档