PyQt5: проверьте, удерживается ли мышь в enter-event

Мое реальное заявление намного сложнее, чем это, но пример ниже подводит итог большей части моей проблемы. У меня есть несколько QLabels, которые я разделил, чтобы сделать их кликабельными. На этикетках отображаются изображения 16x16, для чего требуется загрузка изображений с помощью Pillow, преобразование их в объекты ImageQt, а затем настройка растрового изображения на этикетке. В этом примере у меня есть 3 кликабельных QLabels, которые запускают функцию 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_())

1 ответ

Решение

Причина проблемы указана в документации для QMouseEvent:

Qt автоматически захватывает мышь при нажатии кнопки мыши внутри виджета; виджет будет продолжать получать события мыши, пока не будет отпущена последняя кнопка мыши.

Не похоже, что есть простой способ обойти это, поэтому потребуется что-то хакерское. Одна идея состоит в том, чтобы начать поддельное перетаскивание, а затем использовать 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()
Другие вопросы по тегам