gpt4 book ai didi

python - 更改事件键上的光标形状

转载 作者:行者123 更新时间:2023-12-04 10:46:24 26 4
gpt4 key购买 nike

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

  • 当我按“C”时,我想显示一个 LineCursor,
  • 当我按“S”时,我想显示一个十字光标,和
  • 当我按“N”时,我想显示标准的箭头光标。

  • 光标只有在离开 Canvas 并返回 Canvas 时才会改变,
    但如果光标停留在 Canvas 上,则不会。
    Canvas 上的 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_())

    最佳答案

    这似乎是一个从 Unresolved 老错误:setCursor on QGraphicsView don't work when add QWidget on the QGraphicsScene

    有一种可能的解决方法,但它远非完美。
    首先,您必须考虑,在处理鼠标事件和小部件代理时,处理 QGraphicsScene 及其 View [s] 并不容易,主要是因为事件的多个嵌套级别以及实际 View (及其parent,直到顶层窗口)和代理本身,它是您添加到场景中的小部件的抽象。虽然 Qt 开发人员做了大量工作以使其尽可能透明,但在某些时候,您可能会面临一些通常难以修复或解决的意外或不受欢迎的行为,这也是因为图形场景可能在不止一个 View 。

    除了前面提到的错误,您还必须考虑到图形 View 使用 QWidget.setCursor每当它的任何项目调用 setCursor 时在内部因为 View 是一个非常复杂的小部件,在某些时候它甚至可能会尝试“恢复”光标,如果它认为它应该(即使它不应该)。
    最后,一些与焦点有关的事件可能会成为这一切的障碍。

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

    不幸的是,由于上面写的事件处理,这可能会变得有点困惑,因为一些事件甚至在主 Qt 事件循环中至少延迟了一个周期;结果是,虽然第一次设置光标可能会起作用,但再次设置它可能不会,即使这样,光标也可能在鼠标移动至少一个像素之前不会被应用。
    作为第二种解决方法,我们需要一个事件过滤器来绕过所有这些,并在鼠标在视口(viewport)边缘内移动时检查光标。

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

    关于python - 更改事件键上的光标形状,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59683838/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com