更改事件键上的光标形状

我正在尝试在按键事件上更改光标形状:

  • 当我按'C'时,我想显示一个LineCursor,
  • 当我按'S'时,我想显示一个CrossCursor,并且
  • 当我按'N'时,我要显示标准的ArrowCursor。

光标仅在离开画布并返回画布时才会更改,但如果光标停留在画布中则不会更改。画布上的self.update()不起作用

这里的代码重现了这个问题:

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setObjectName("MainWindow")
        self.resize(942, 935)
        self.centralwidget = QWidget(self)
        self.centralwidget.setObjectName("centralwidget")
        self.horizontalLayout = QHBoxLayout(self.centralwidget)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.MainView = QGraphicsView(self.centralwidget)
        self.MainView.setObjectName("MainView")
        self.horizontalLayout.addWidget(self.MainView)
        self.setCentralWidget(self.centralwidget)
        self.setWindowTitle("MainWindow")

        self.scene = QGraphicsScene( 0.,0., 1240., 1780. )
        self.canvas = Canvas()

        self.widget = QWidget()
        box_layout = QVBoxLayout()
        self.widget.setLayout(box_layout)
        box_layout.addWidget(self.canvas)
        self.scene.addWidget(self.widget)
        self.MainView.setScene(self.scene)
        self.MainView.setRenderHints(QPainter.Antialiasing)
        self.MainView.fitInView(0, 0, 45, 55, Qt.KeepAspectRatio)

        self.show()

        empty = QPixmap(1240, 1748)
        empty.fill(QColor(Qt.white))
        self.canvas.newPixmap(empty)

    def keyPressEvent(self, e):
        key = e.key()
        if key == Qt.Key_C:
            self.canvas.setCutCursor()
        elif key == Qt.Key_N:
            self.canvas.setNormalCursor()
        elif key == Qt.Key_S:
            self.canvas.setSelectionCursor()


class Canvas(QLabel):
    def __init__(self):
        super().__init__()
        sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.setSizePolicy(sizePolicy)
        self.setAlignment(Qt.AlignLeft)
        self.setAlignment(Qt.AlignTop)

    def newPixmap(self, pixmap):
        self.setPixmap(pixmap)

    def setCutCursor(self):
        newCursor = QPixmap(500,3)
        newCursor.fill(QColor("#000000"))
        self.setCursor(QCursor(newCursor))

    def setSelectionCursor(self):
        self.setCursor(Qt.CrossCursor)

    def setNormalCursor(self):
        self.setCursor(QCursor(Qt.ArrowCursor))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    mainWindow = MainWindow()
    sys.exit(app.exec_())
音乐家

这似乎是一个从未解决的老错误:在QGraphicsScene上添加QWidget时,QGraphicsView上的setCursor不起作用

有可能的解决方法,但这远非完美。
首先,您必须考虑到,在处理QGraphicsScene及其视图时,处理鼠标事件和窗口小部件代理并不容易,这主要是因为事件的多个嵌套级别以及实际视图(及其视图之间的交互)父级,直到顶级窗口)和代理本身,这是您添加到场景中的小部件的抽象。虽然Qt开发人员做了很多工作以使其尽可能透明,但在某些时候您可能会遇到一些意料之外的或不希望有的行为,这些行为通常很难修复或解决,这也是因为图形场景可以在不仅仅是一个视图。

除了上述错误外,您还必须考虑到图形视图QWidget.setCursor在任何项目调用setCursor到自己时都会在内部使用,并且由于该视图是一个非常复杂的小部件,因此在某个时候它甚至可能会尝试“恢复”光标(如果认为)它应该(即使不应该)。
最后,一些与焦点有关的事件可能会成为所有事情的方式。

第一种解决方法是将光标设置到视图本身(或者更好的是,视图的视口,它是显示场景内容的实际窗口小部件)。为了确保这一点,我们显然需要检查光标是否在画布内。

不幸的是,由于上面编写了事件处理,这可能会变得有些混乱,因为某些事件甚至在主Qt事件循环内甚至延迟了至少一个周期。结果是,在第一次设置光标时可能会起作用,而再次设置它可能不会,即使这样做,也有可能直到鼠标至少移动一个像素才应用光标。
第二种解决方法是,我们需要一个事件过滤器来绕过所有过滤器,并在鼠标在视口边界内移动时检查光标。

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        # ...
        self.show()

        empty = QPixmap(1240, 1748)
        empty.fill(QColor(Qt.darkGray))
        self.canvas.newPixmap(empty)

        # install an event filter on the view's viewport;
        # this is very, *VERY* important: on the *VIEWPORT*!
        # if you install it on the view, it will *not* work
        self.MainView.viewport().installEventFilter(self)

    def insideCanvasRect(self, pos):
        canvasRect = self.canvas.rect()
        # translate the canvas rect to its top level window to get the actual
        # geometry according to the scene; we can't use canvas.geometry(), as
        # geometry() is based on the widget's parent coordinates, and that
        # parent could also have any number of parents in turn;
        canvasRect.translate(self.canvas.mapTo(self.canvas.window(), QPoint(0, 0)))
        # map the geometry to the view's transformation, which probably uses
        # some scaling, but also translation *and* shearing; the result is a
        # polygon, as with shearing you could transform a rectangle to an
        # irregular quadrilateral
        polygon = self.MainView.mapFromScene(QRectF(canvasRect))
        # tell if the point is within the resulting polygon
        return polygon.containsPoint(pos, Qt.WindingFill)

    def eventFilter(self, source, event):
        if source == self.MainView.viewport() and (
            (event.type() == QEvent.MouseMove and not event.buttons()) or
            (event.type() == QEvent.MouseButtonRelease)
            ):
                # process the event
                super(MainWindow, self).eventFilter(source, event)
                if self.insideCanvasRect(event.pos()):
                    source.setCursor(self.canvas.cursor())
                else:
                    source.unsetCursor()
                # usually a mouse move event within the view's viewport returns False,
                # but in that case the event would be propagated to the parents, up
                # to the top level window, which might reset the *previous* cursor
                # at some point, no matter if we try to avoid that; to prevent that
                # we return True to avoid propagation.
                # Note that this will prevent any upper-level filtering and *could*
                # also create some issues for the drag and drop framework
                if event.type() == QEvent.MouseMove:
                    return True
        return super(MainWindow, self).eventFilter(source, event)

    def keyPressEvent(self, e):
        # send the canvas a fake leave event
        QApplication.sendEvent(self.canvas, QEvent(QEvent.Leave))
        key = e.key()
        if key == Qt.Key_C:
            self.canvas.setCutCursor()
        elif key == Qt.Key_N:
            self.canvas.setNormalCursor()
        elif key == Qt.Key_S:
            self.canvas.setSelectionCursor()
        pos = self.canvas.rect().center()
        event = QEnterEvent(pos, self.canvas.mapTo(self.canvas.window(), pos), self.canvas.mapToGlobal(pos))
        # send a fake enter event (mapped to the center of the widget, just to be sure)
        QApplication.sendEvent(self.canvas, event)
        # if we're inside the widget, set the view's cursor, otherwise it will not
        # be set until the mouse is moved
        if self.insideCanvasRect(self.MainView.viewport().mapFromGlobal(QCursor.pos())):
            self.MainView.viewport().setCursor(self.canvas.cursor())

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在翻转事件上更改光标

来自分类Dev

如何在翻转事件上更改光标

来自分类Dev

Powershell || 无法更改光标形状

来自分类Dev

在 tkinter 条目上的单击事件中更改光标位置

来自分类Dev

形状上的双击事件

来自分类Dev

如何更改QPlainTextEdit(Pyqt,PySide)的光标形状

来自分类Dev

如何更改QPlainTextEdit(Pyqt,PySide)的光标形状

来自分类Dev

如何更改光标的形状和大小?

来自分类Dev

如何在具有上下文菜单事件处理程序的组件上更改鼠标光标?

来自分类Dev

KIneticJS上的多种形状上的事件

来自分类Dev

在Linux的Windows子系统中更改光标形状

来自分类Dev

如何更改返回键的事件?

来自分类Dev

在非活动NSWindow上更改鼠标光标

来自分类Dev

如何更改fullcalendar上的光标指针?

来自分类Dev

禁用点击后在图例上更改光标

来自分类Dev

在用户控件上更改光标

来自分类Dev

更改OSX Mavericks上的默认鼠标光标

来自分类Dev

在用户控件上更改光标

来自分类Dev

输入键上的输入更改事件在IE中不起作用

来自分类Dev

更改UISearchBar上的光标颜色而不更改tintColor

来自分类Dev

IntelliJ终端光标形状

来自分类Dev

在 WPF 中使用 QueryCursor 事件时隐藏图像上的光标

来自分类Dev

更改表单输入上的事件

来自分类Dev

jQuery Tokenize上的更改事件

来自分类Dev

形状上的mouseClicked事件不断在画布上重新绘制

来自分类Dev

在KeyDown事件上检测星号键

来自分类Dev

jQuery:Tab键上的触发事件

来自分类Dev

在KeyDown事件上检测星号键

来自分类Dev

检测 KeyDown 事件上的单引号键

Related 相关文章

热门标签

归档