【问题标题】:Adding a subwindow into the Mainwindow在主窗口中添加子窗口
【发布时间】:2021-04-06 05:41:39
【问题描述】:

我在主窗口中添加了一个可拖动的红色圆圈。红色圆圈可以移动到主窗口上您想要的任何位置。但我想设置一个允许红色圆圈移动的边界。可能应该用子窗口来完成?任何人都知道如何做到这一点?我走了这么远:

import sys

from PyQt5.QtWidgets import QApplication, QGraphicsView, QWidget, QGraphicsEllipseItem, QMainWindow, QGroupBox, QGraphicsScene, QHBoxLayout
from PyQt5.QtCore import Qt, QPointF, QRect


class MovingObject(QGraphicsEllipseItem):
    def __init__(self, x, y, r):
        #de meegegeven waardes gebruiken om beginpositie en grootte ellips te bepalen
        super().__init__(0, 0, r, r)
        self.setPos(x, y)
        self.setBrush(Qt.red)

    ##mousePressEvent checkt of er wel of niet wordt geklikt
    def mousePressEvent(self, event):
        pass

    ##mouseMoveEvent is om de item te kunnen draggen
    def mouseMoveEvent(self, event):
        orig_cursor_position = event.lastScenePos()
        updated_cursor_position = event.scenePos()

        orig_position = self.scenePos()

        updated_cursor_x = updated_cursor_position.x() - orig_cursor_position.x() + orig_position.x()
        updated_cursor_y = updated_cursor_position.y() - orig_cursor_position.y() + orig_position.y()
        self.setPos(QPointF(updated_cursor_x, updated_cursor_y))


class GraphicView(QGraphicsView):
    def __init__(self):
        super().__init__()

        self.scene = QGraphicsScene()
        self.setScene(self.scene)
        self.setSceneRect(0, 0, 60, 60)


        #waardes x, y, r waarvan x en y beginpositie van ellips is en r is straal van ellips
        self.scene.addItem(MovingObject(0, 0, 40))

class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setGeometry(800, 500, 400, 400)
        self.setWindowTitle("MainWindow")

        #set GraphicView in Window
        self.graphicView = GraphicView()
        self.setCentralWidget(self.graphicView)


app = QApplication(sys.argv)

GUI = Window()
GUI.show()

sys.exit(app.exec_())

【问题讨论】:

    标签: python drag-and-drop pyqt5 qgraphicsview qgraphicsscene


    【解决方案1】:

    首先,不需要重新实现鼠标事件以允许使用鼠标移动 QGraphicsItem,因为设置 ItemIsMovable 标志就足够了。

    设置标志后,需要过滤几何变化并对其做出反应。

    这是通过设置ItemSendsGeometryChanges 标志并重新实现itemChange() 函数来实现的。使用ItemPositionChange 更改,您可以在应用之前接收“future”位置,并最终更改(并返回)接收到的值;返回值是在移动过程中应用的实际最终位置。

    剩下的就是提供一个参考来检查它。
    在以下示例中,我将 scene 矩形(而不是您所做的 view 矩形)设置为更大的边距,并为项目设置这些边距;你显然可以为此设置任何QRectF

    我还实现了drawBackground() 函数,以显示用作限制的场景矩形。

    class MovingObject(QGraphicsEllipseItem):
        def __init__(self, x, y, r):
            super().__init__(0, 0, r, r)
            self.setPos(x, y)
            self.setBrush(Qt.red)
            self.setFlag(self.ItemIsMovable, True)
            self.setFlag(self.ItemSendsGeometryChanges, True)
            self.margins = None
    
        def setMargins(self, margins):
            self.margins = margins
    
        def itemChange(self, change, value):
            if change == self.ItemPositionChange and self.margins:
                newRect = self.boundingRect().translated(value)
                if newRect.x() < self.margins.x():
                    # beyond left margin, reset
                    value.setX(self.margins.x())
                elif newRect.right() > self.margins.right():
                    # beyond right margin
                    value.setX(self.margins.right() - newRect.width())
                if newRect.y() < self.margins.y():
                    # beyond top margin
                    value.setY(self.margins.y())
                elif newRect.bottom() > self.margins.bottom():
                    # beyond bottom margin
                    value.setY(self.margins.bottom() - newRect.height())
            return super().itemChange(change, value)
    
    
    class GraphicView(QGraphicsView):
        def __init__(self):
            super().__init__()
    
            self.scene = QGraphicsScene()
            self.setScene(self.scene)
            self.scene.setSceneRect(0, 0, 120, 120)
    
            self.movingObject = MovingObject(0, 0, 40)
            self.scene.addItem(self.movingObject)
            self.movingObject.setMargins(self.scene.sceneRect())
    
        def drawBackground(self, painter, rect):
            painter.drawRect(self.sceneRect())
    

    请注意,图形视图框架功能强大,但很难真正了解和理解。鉴于您提出的问题(“可能应该使用子窗口来完成?”),很明显您仍然需要了解它是如何工作的,因为使用子窗口是完全不同的事情。
    我强烈建议您仔细检查与QGraphicsItem 相关的documentationeverything(函数和属性),QGraphicsItemall 图形项的基类。 p>

    不应永远覆盖现有属性; scene() 是 QGraphicsView 的基本属性,因此您要么选择另一个名称作为实例属性 (self.myScene = QGraphicsScene()),要么只使用局部变量 (scene = QGraphicsScene()) 并始终在 __init__ 之外使用 self.scene()

    【讨论】:

      猜你喜欢
      • 2011-04-24
      • 2023-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多