установка курсора в виджете метки PyQt5

Я делаю программу получения изображений с помощью веб-камеры в PyQt. Всякий раз, когда я нажимаю на изображение, которое находится внутри виджета метки, мне нужно поместить дополнительный фиксированный курсор в эту позицию (например, чтобы иметь точку отсчета). Я создал объект курсора, задал форму и положение (полученное из положения щелчка). но я не вижу, чтобы дополнительный курсор создавался в месте щелчка, т.е. Qpoint

ниже фрагмент кода:

 def eventFilter(self, source, event):
     if  event.type()==QtCore.QEvent.MouseButtonPress:
         self.new_cursor=QtGui.QCursor()               # the additional cursori want to place
         self.new_cursor.setShape(self,Qt.PointingHandCursor) # setting shape

         self.cursor_clicked=event.pos()           # getting position from the click

         self.cursor_clicked=self.label.mapFromParent(event.pos()) #mapping to widget coords.

         self.cursor_x=self.cursor_clicked.x()
         self.cursor_y=self.cursor_clicked.y()
         self.new_cursor.setPos(self.cursor_x,self.cursor_y)
         self.setCursor(self.new_cursor)


     return QtWidgets.QWidget.eventFilter(self,source,event)   

person krishna saraswathula    schedule 15.11.2019    source источник


Ответы (1)


QCursor — это не «статическое изображение», а «абстрактный» объект, связанный с курсором мыши, поэтому для ваших целей он бесполезен.

Вам нужно рисовать на существующем изображении или виджете, который его показывает.
Поскольку вы, вероятно, хотите оставить изображение без изменений, вам нужен второй вариант.

Идея состоит в том, что вы вызываете реализацию базового класса метода paintEvent, а затем рисуете поверх его.
Нарисовать перекрестие вручную не так сложно, используя простые линии, но вам нужно будет нарисовать дополнительная рамка вокруг креста с использованием другого цвета, чтобы обеспечить его видимость даже на светлом или темном фоне, что делает его ненужным длинным; в этом примере я использую изображение курсора, которое Qt использует в CursorShape enum документации, но вы можете использовать любое изображение, если его центр находится точно в центре его (подсказка: используйте квадратное изображение с нечетным размером ширины/высоты).

from PyQt5 import QtCore, QtGui, QtWidgets

class Window(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        layout = QtWidgets.QGridLayout(self)

        self.label = QtWidgets.QLabel()
        layout.addWidget(self.label)
        self.label.setPixmap(QtGui.QPixmap('myimage.png'))
        self.label.installEventFilter(self)

        self.cursorPos = None
        # I'm using the crosshair cursor as shown at
        # https://doc.qt.io/qt-5/qt.html#CursorShape-enum
        self.cursorPixmap = QtGui.QPixmap('cursor-cross.png')

    def eventFilter(self, source, event):
        if event.type() == QtCore.QEvent.MouseButtonPress:
            # set the current position and schedule a repaint of the label
            self.cursorPos = event.pos()
            self.label.update()
        elif event.type() == QtCore.QEvent.Paint:
            # intercept the paintEvent of the label and call the base
            # implementation to actually draw its contents
            self.label.paintEvent(event)
            if self.cursorPos is not None:
                # if the cursor position has been set, draw it
                qp = QtGui.QPainter(self.label)
                # translate the painter at the cursor position
                qp.translate(self.cursorPos)
                # paint the pixmap at an offset based on its center
                qp.drawPixmap(-self.cursorPixmap.rect().center(), self.cursorPixmap)
            return True
        return super().eventFilter(source, event)


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

Кроме того, другой подход заключается в использовании Graphics View Framework, добавлении растрового изображения на сцену и добавить/переместить другое растровое изображение для курсора, когда пользователь нажимает на изображение. Работа с QGraphicsViews, QGraphicsScenes и их элементами немного сложнее, но если вам нужен более продвинутый уровень взаимодействия с изображением, обычно это лучший путь.

from PyQt5 import QtCore, QtGui, QtWidgets

class Window(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        layout = QtWidgets.QGridLayout(self)

        self.view = QtWidgets.QGraphicsView()
        layout.addWidget(self.view)
        # remove any border around the view
        self.view.setFrameShape(0)
        self.scene = QtWidgets.QGraphicsScene()
        self.view.setScene(self.scene)

        pixmap = QtGui.QPixmap('myimage.png')
        # adapt the view's size to that of the pixmap
        self.view.setFixedSize(pixmap.size())

        # add a pixmap to a scene, which returns a QGraphicsPixmapItem
        self.pixmapItem = self.scene.addPixmap(pixmap)

        self.crossHairItem = None

        self.view.installEventFilter(self)

    def eventFilter(self, source, event):
        if event.type() == QtCore.QEvent.MouseButtonPress:
            if not self.crossHairItem:
                # as above, get a QGraphicsPixmapItem for the crosshair cursor
                pixmap = QtGui.QPixmap('cursor-cross.png')
                self.crossHairItem = self.scene.addPixmap(pixmap)
                # set an offset of the item, so that its position is always
                # based on the center of the pixmap
                self.crossHairItem.setOffset(-pixmap.rect().center())
            self.crossHairItem.setPos(self.view.mapToScene(event.pos()))
        return super().eventFilter(source, event)


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

Оба метода ведут себя одинаково для пользователя и, как видите, выглядят совершенно одинаково.

сравнение изображений двух методов

person musicamante    schedule 16.11.2019