PyQt5:检查鼠标在enter-event中是否按下

4

我的实际应用比这个复杂得多,但以下示例总结了我问题的大部分。我有多个QLabel,我对它们进行了子类化以使它们可点击。标签显示16x16图像,需要通过Pillow加载图像,将它们转换为ImageQt对象,然后设置标签的像素映射。在该示例中,我有3个可点击的QLabel,每次单击时都会运行print_something函数。我的目标是能够按住鼠标,并在悬停在每个标签上时调用该功能。任何指针都将是很好的帮助。

from PyQt5 import QtCore, QtWidgets, QtGui
from PIL import Image
from PIL.ImageQt import ImageQt
import sys


class ClickableLabel(QtWidgets.QLabel):

    def __init__(self):
        super().__init__()

    clicked = QtCore.pyqtSignal()

    def mousePressEvent(self, ev):
        if app.mouseButtons() & QtCore.Qt.LeftButton:
            self.clicked.emit()


class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        super().__init__()
        central_widget = QtWidgets.QWidget()

        self.setFixedSize(300, 300)
        image = Image.open("16x16image.png")
        image_imageqt = ImageQt(image)

        hbox = QtWidgets.QHBoxLayout()
        hbox.setSpacing(0)
        hbox.addStretch()

        label01 = ClickableLabel()
        label01.setPixmap(QtGui.QPixmap.fromImage(image_imageqt))
        label01.clicked.connect(self.print_something)
        hbox.addWidget(label01)

        label02 = ClickableLabel()
        label02.setPixmap(QtGui.QPixmap.fromImage(image_imageqt))
        label02.clicked.connect(self.print_something)
        hbox.addWidget(label02)

        label03 = ClickableLabel()
        label03.setPixmap(QtGui.QPixmap.fromImage(image_imageqt))
        label03.clicked.connect(self.print_something)
        hbox.addWidget(label03)

        hbox.addStretch()

        central_widget.setLayout(hbox)

        self.setCentralWidget(central_widget)

    def print_something(self):
        print("Printing something..")


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    sys.exit(app.exec_())

我尝试了检查鼠标按钮和enterEvent的组合,但当鼠标按下时,它似乎会保持所有其他事件,直到按钮被释放。 - huntrvro
1个回答

4
问题的原因在 QMouseEvent 的文档中已经说明:

当鼠标按钮在小部件内被按下时,Qt 会自动抓取鼠标;小部件将继续接收鼠标事件,直到最后一个鼠标按钮被释放。

看起来似乎没有简单的方法可以解决这个问题,因此需要一些 hackish(笨拙的)方法。其中一个想法是启动一个虚拟拖动,然后使用 dragEnterEvent 而不是 enterEvent。像这样做应该可以工作:

class ClickableLabel(QtWidgets.QLabel):
    clicked = QtCore.pyqtSignal()

    def __init__(self):
        super().__init__()
        self.setAcceptDrops(True)
        self.dragstart = None

    def mousePressEvent(self, event):
        if event.buttons() & QtCore.Qt.LeftButton:
            self.dragstart = event.pos()
            self.clicked.emit()

    def mouseReleaseEvent(self, event):
        self.dragstart = None

    def mouseMoveEvent(self, event):
        if (self.dragstart is not None and
            event.buttons() & QtCore.Qt.LeftButton and
            (event.pos() - self.dragstart).manhattanLength() >
             QtWidgets.qApp.startDragDistance()):
            self.dragstart = None
            drag = QtGui.QDrag(self)
            drag.setMimeData(QtCore.QMimeData())
            drag.exec_(QtCore.Qt.LinkAction)

    def dragEnterEvent(self, event):
        event.acceptProposedAction()
        if event.source() is not self:
            self.clicked.emit()

这对我想要实现的功能有效,但现在我需要找出如何防止鼠标光标在拖放过程中改变。 - huntrvro
1
@huntrvro。我曾经使用Qt.LinkAction来完成这个任务,它在Linux上可以正常工作,但显然在其他平台上不行。你可以尝试使用QDrag.setDragCursor。系统光标的像素图可以使用QCursor创建。 - ekhumoro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接