简体   繁体   English

在 PyQt5 label 小部件中设置 cursor

[英]setting a cursor in PyQt5 label widget

I am making an image acquisition program using a webcam in PyQt.我正在使用 PyQt 中的网络摄像头制作图像采集程序。 Whenever I click on the image, which is inside a label widget, i need to put an additional fixed cursor at that position (to have a reference point for eg).每当我单击位于 label 小部件内的图像时,我需要在该 position 处放置一个额外的固定 cursor(以获取例如参考点)。 I created a cursor object, set a shape and position (obtained from the clicked position).我创建了一个 cursor object,设置一个形状和 position(从点击位置获得)。 yet I dont see an additional cursor being created at the clicked position ie Qpoint但是我没有看到在单击的 position 即 Qpoint 处创建了额外的 cursor

below is the code snippet:下面是代码片段:

 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)   

QCursor is not a "static image", but is an "abstract" object related to the mouse cursor , so there's no use of it for your purpose. QCursor 不是“静态图像”,而是与鼠标 cursor相关的“抽象” object ,因此您无法使用它。

What you're looking for is drawing on the existing image or the widget that shows it.您正在寻找的是在现有图像或显示它的小部件上绘图。
Since you probably want to leave the image unchanged, the second option is what you're looking for.由于您可能希望保持图像不变,因此您正在寻找第二个选项。

The idea is that you call the base class implementation of the paintEvent method and then draw over it.这个想法是你调用paintEvent方法的基本class实现,然后它上面绘制。
Painting a crosshair by hand is not that hard using simple lines, but you'll need to draw an extra border around the cross using a different color to ensure its visibility even on lighter or darker backgrounds, which makes it unnecessary long;使用简单的线条手工绘制十字准线并不难,但是您需要使用不同的颜色在十字周围画一个额外的边框,以确保即使在较浅或较深的背景上也能看到它,这使得它不需要太长; in this example I'm using the cursor image Qt uses in the CursorShape enum documentation, but you can use whatever image you want, as soon as its center is exactly at the center of it (hint: use a square image with odd sized width/height).在这个例子中,我使用的是 cursor 图像 ZE8801102A40AD89DDCFDCAEBF008D25Z 在CursorShape 枚举文档中使用,但是你可以使用任何你想要的图像,只要它的中心正好在它中心(提示:使用具有奇数宽度的方形图像/高度)。

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

Besides that, another approach is to use the Graphics View Framework , add the pixmap to the scene and add/move another pixmap for the cursor when the user clicks on the image.除此之外,另一种方法是使用图形视图框架,将像素图添加到场景中,并在用户单击图像时为 cursor 添加/移动另一个像素图。 Dealing with QGraphicsViews, QGraphicsScenes and their items is a bit more complex, but if you're going to need some more advanced level of interaction with an image, it usually is the better path to take.处理 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_())

Both methods behave in the same way for the user, and as you can see they look exactly identical.这两种方法对用户的行为方式相同,并且您可以看到它们看起来完全相同。

两种方法的图像比较

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM