在父窗口小部件和子窗口小部件上处理鼠标事件(按钮不使用事件?)

2024-06-25 23:03:01 发布

您现在位置:Python中文网/ 问答频道 /正文

以下是我的设置:

enter image description here

我的QTableWidget上有一个eventFilter来处理mousePressmouseRelease事件

我还有一个自定义类,用于QPushButton处理mousePressmouseRelease事件

但是,当我通过单击并按住按钮来触发mousePress事件时,QTableWidget没有看到该事件

以防万一,这里是自定义QPushButton类和QTableWidget{}的代码

class Button(QPushButton):
    key = None

    def __init__(self, title, parent):
        super().__init__(title, parent)

    def mousePressEvent(self, e):

        super().mousePressEvent(e)

        if e.button() == Qt.LeftButton:
            print('press')


class TableWidget(QTableWidget):

    def __init__(self, rows, columns, parent=None):
        QTableWidget.__init__(self, rows, columns, parent)
        self._last_index = QPersistentModelIndex()
        self.viewport().installEventFilter(self)

    def eventFilter(self, source, event):
        if event.type() == QEvent.MouseButtonRelease:
            print("mouse release")
        return QTableWidget.eventFilter(self, source, event)

我希望看到的是,当我按下自定义按钮,然后释放鼠标时,它会在控制台中打印“鼠标释放”

这不会发生

但当我单击表中除按钮以外的任何位置时,它都会成功打印

如果您希望我添加任何额外信息,请在评论中告诉我


Tags: selfnoneeventtitleinitdef事件按钮
1条回答
网友
1楼 · 发布于 2024-06-25 23:03:01

说明:

正如我在this post:中已经指出的,小部件之间的鼠标事件处理从子部件到父部件,也就是说,如果子部件不接受事件(它不使用事件),那么它将把事件传递给父部件。可使用以下示例进行验证:

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
    QApplication,
    QLabel,
    QPushButton,
    QTableWidget,
    QTableWidgetItem,
    QVBoxLayout,
    QWidget,
)


class TableWidget(QTableWidget):
    def mouseReleaseEvent(self, event):
        super().mouseReleaseEvent(event)
        print("released")


class Widget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.tablewidget = TableWidget(4, 4)

        container = QWidget()
        lay = QVBoxLayout(container)
        lay.addWidget(QLabel("QLabel", alignment=Qt.AlignCenter))
        lay.addWidget(QPushButton("QPushButton"))
        container.setFixedSize(container.sizeHint())

        item = QTableWidgetItem()
        self.tablewidget.setItem(0, 0, item)
        item.setSizeHint(container.sizeHint())
        self.tablewidget.setCellWidget(0, 0, container)
        self.tablewidget.resizeRowsToContents()
        self.tablewidget.resizeColumnsToContents()

        lay = QVBoxLayout(self)
        lay.addWidget(self.tablewidget)


def main():
    import sys

    app = QApplication(sys.argv)

    widget = Widget()
    widget.resize(640, 480)
    widget.show()

    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

如果按下QPushButton,则不会调用QTableWidget的mouseReleaseEvent方法,因为QPushButton会使用它,这与按下QLabel时不同,因为它不会使用它,而QTableWidget会使用它

解决方案:

正如我在另一篇文章中指出的,一个可能的解决方案是对QWindow使用eventfilter,并通过验证是否在单元格上单击来进行过滤

from PyQt5.QtCore import (
    pyqtSignal,
    QEvent,
    QObject,
    QPoint,
    Qt,
)
from PyQt5.QtWidgets import (
    QApplication,
    QLabel,
    QPushButton,
    QTableWidget,
    QTableWidgetItem,
    QVBoxLayout,
    QWidget,
)


class MouseObserver(QObject):
    pressed = pyqtSignal(QPoint, QPoint)
    released = pyqtSignal(QPoint, QPoint)
    moved = pyqtSignal(QPoint, QPoint)

    def __init__(self, window):
        super().__init__(window)
        self._window = window

        self.window.installEventFilter(self)

    @property
    def window(self):
        return self._window

    def eventFilter(self, obj, event):
        if self.window is obj:
            if event.type() == QEvent.MouseButtonPress:
                self.pressed.emit(event.pos(), event.globalPos())
            elif event.type() == QEvent.MouseMove:
                self.moved.emit(event.pos(), event.globalPos())
            elif event.type() == QEvent.MouseButtonRelease:
                self.released.emit(event.pos(), event.globalPos())
        return super().eventFilter(obj, event)


class Widget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.tablewidget = QTableWidget(4, 4)

        container = QWidget()
        lay = QVBoxLayout(container)
        lay.addWidget(QLabel("QLabel", alignment=Qt.AlignCenter))
        lay.addWidget(QPushButton("QPushButton"))
        container.setFixedSize(container.sizeHint())

        item = QTableWidgetItem()
        self.tablewidget.setItem(0, 0, item)
        item.setSizeHint(container.sizeHint())
        self.tablewidget.setCellWidget(0, 0, container)
        self.tablewidget.resizeRowsToContents()
        self.tablewidget.resizeColumnsToContents()

        lay = QVBoxLayout(self)
        lay.addWidget(self.tablewidget)

    def handle_window_released(self, window_pos, global_pos):
        lp = self.tablewidget.viewport().mapFromGlobal(global_pos)
        ix = self.tablewidget.indexAt(lp)
        if ix.isValid():
            print(ix.row(), ix.column())


def main():
    import sys

    app = QApplication(sys.argv)

    widget = Widget()
    widget.resize(640, 480)
    widget.show()

    mouse_observer = MouseObserver(widget.windowHandle())
    mouse_observer.released.connect(widget.handle_window_released)

    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

相关问题 更多 >