将子窗口添加到主窗口
Adding a subwindow into the Mainwindow
我在主 window 中添加了一个可拖动的红色圆圈。红圈可以移动到主window上你想要的任何地方。但我想设置一个允许移动红色圆圈的边界。可能应该用 sub window 来完成?任何人都知道如何做到这一点?我走到这一步:
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_())
首先,不需要重新实现鼠标事件来允许使用鼠标移动 QGraphicsItem,因为设置 ItemIsMovable
标志就足够了。
设置标志后,需要的是过滤几何变化并对它们做出反应。
这是通过设置ItemSendsGeometryChanges
标志并重新实现itemChange()
函数来实现的。使用 ItemPositionChange
更改,您可以在应用之前接收“future”位置并最终更改(和 return)接收到的值; returned 值是将在移动过程中应用的实际最终位置。
剩下的就是给个参考查一下
在下面的示例中,我将 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)
<b>self.setFlag(self.ItemIsMovable, True)
self.setFlag(self.ItemSendsGeometryChanges, True)
self.margins = None</b>
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)
<b>self.scene.setSceneRect(0, 0, 120, 120)</b>
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())
请注意,图形视图框架非常强大,但真的 很难了解和理解。鉴于你问的问题(“可能应该用 sub window 来完成?”)很明显你仍然需要了解它是如何工作的,因为使用 sub windows 是完全不同的事情.
我强烈建议您仔细阅读它的 documentation and everything (functions and properties) related to the QGraphicsItem,它是 所有 图形项目的基础 class。
现有属性应该永远不会被覆盖; scene()
是 QGraphicsView 的基本 属性,因此您要么选择另一个名称作为实例属性(self.myScene = QGraphicsScene()
),要么只使用局部变量(scene = QGraphicsScene()
)并且总是在 __init__
.
之外使用 self.scene()
我在主 window 中添加了一个可拖动的红色圆圈。红圈可以移动到主window上你想要的任何地方。但我想设置一个允许移动红色圆圈的边界。可能应该用 sub window 来完成?任何人都知道如何做到这一点?我走到这一步:
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_())
首先,不需要重新实现鼠标事件来允许使用鼠标移动 QGraphicsItem,因为设置 ItemIsMovable
标志就足够了。
设置标志后,需要的是过滤几何变化并对它们做出反应。
这是通过设置ItemSendsGeometryChanges
标志并重新实现itemChange()
函数来实现的。使用 ItemPositionChange
更改,您可以在应用之前接收“future”位置并最终更改(和 return)接收到的值; returned 值是将在移动过程中应用的实际最终位置。
剩下的就是给个参考查一下
在下面的示例中,我将 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)
<b>self.setFlag(self.ItemIsMovable, True)
self.setFlag(self.ItemSendsGeometryChanges, True)
self.margins = None</b>
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)
<b>self.scene.setSceneRect(0, 0, 120, 120)</b>
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())
请注意,图形视图框架非常强大,但真的 很难了解和理解。鉴于你问的问题(“可能应该用 sub window 来完成?”)很明显你仍然需要了解它是如何工作的,因为使用 sub windows 是完全不同的事情.
我强烈建议您仔细阅读它的 documentation and everything (functions and properties) related to the QGraphicsItem,它是 所有 图形项目的基础 class。
现有属性应该永远不会被覆盖; scene()
是 QGraphicsView 的基本 属性,因此您要么选择另一个名称作为实例属性(self.myScene = QGraphicsScene()
),要么只使用局部变量(scene = QGraphicsScene()
)并且总是在 __init__
.
self.scene()