在PyQt5标签小部件中设置光标

时间:2019-11-15 15:06:08

标签: python pyqt pyqt5 python-3.6

我正在使用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)   

1 个答案:

答案 0 :(得分:1)

QCursor不是“静态图像”,而是与鼠标光标有关的“抽象”对象,因此没有出于您的目的使用它。

您要查找的是在现有图像或显示该图像的小部件上进行绘制。
由于您可能想保持图像不变,因此第二个选择就是您要寻找的东西。

这个想法是,您调用paintEvent方法的基类实现,然后在其上绘制

使用简单的线条手工绘制十字准线并不难,但是您需要使用不同的颜色在十字周围画一个额外的边框,以确保即使在较亮或较暗的背景下,它的可见性也是如此。在此示例中,我使用的是CursorShape enum文档中Qt使用的光标图像,但是只要其中心正好位于它的 the 中心,您就可以使用所需的任何图像(提示:请使用宽度/高度为奇数的正方形图像。

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_())

这两种方法对用户的行为都相同,如您所见,它们看起来完全相同。

image comparison of the two methods