Python 如何将QRAPHICSTEM的位置保存并加载到qraphicscene或(正确的drow项)
原则上,这不是一项困难的任务,但事实证明一切都不像看上去那么容易。很难理解坐标。因为它们有三对:模型、项目和视图。我保留x和y位置以及类的其他属性。然后我尝试使用当前位置将它们添加回。这就是魔法的开始。元素采取的立场显然是以前不存在的。这显然也与move items功能的实现有关。但是,它不是我的,我不知道如何正确设置坐标,无论是在开始还是结束时。还有一个功能,放大和缩小的场景,这是可能的,它也会影响后续加载,但我已经没有想法 装货前 后装 我的MRE工具Python 如何将QRAPHICSTEM的位置保存并加载到qraphicscene或(正确的drow项),python,pyqt,pyqt5,pyside2,Python,Pyqt,Pyqt5,Pyside2,原则上,这不是一项困难的任务,但事实证明一切都不像看上去那么容易。很难理解坐标。因为它们有三对:模型、项目和视图。我保留x和y位置以及类的其他属性。然后我尝试使用当前位置将它们添加回。这就是魔法的开始。元素采取的立场显然是以前不存在的。这显然也与move items功能的实现有关。但是,它不是我的,我不知道如何正确设置坐标,无论是在开始还是结束时。还有一个功能,放大和缩小的场景,这是可能的,它也会影响后续加载,但我已经没有想法 装货前 后装 我的MRE工具 import sys from P
import sys
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from math import pi
import os
from pickle import load,dump
class MyQGraphicsView(QGraphicsView):
def __init__ (self, parent=None):
super(MyQGraphicsView, self).__init__ (parent)
def wheelEvent(self, event):
if QApplication.keyboardModifiers() == Qt.ControlModifier:
print('Control+Click')
# Zoom Factor
zoomInFactor = 1.25
zoomOutFactor = 1 / zoomInFactor
# Set Anchors
self.setTransformationAnchor(QGraphicsView.NoAnchor)
self.setResizeAnchor(QGraphicsView.NoAnchor)
# Save the scene pos
oldPos = self.mapToScene(event.pos())
# Zoom
if event.delta() > 0:
zoomFactor = zoomInFactor
else:
zoomFactor = zoomOutFactor
self.scale(zoomFactor, zoomFactor)
# Get the new position
newPos = self.mapToScene(event.pos())
# Move scene to old position
delta = newPos - oldPos
self.translate(delta.x(), delta.y())
class Communicate(QObject):
closeApp = Signal()
add_delete_row = Signal(QModelIndex, str)
class Drow_equipent(QGraphicsItem):
def __init__(self, x, y, w, h,name,brush=Qt.blue,type='эллипс'):
super().__init__()
self.setPos(x, y)
self.penWidth = 1
self.name=name
self.x,self.y,self.h,self.w=x,y,h,w
self.setAcceptHoverEvents(True)
self.signal=Communicate()
self.setFlags(QGraphicsItem.ItemSendsGeometryChanges|QGraphicsItem.ItemIsSelectable)
self.rotation_=False
self._brush=QBrush(brush)
self.pen_color=Qt.black
self.type_obj=type
self.types = {'эллипс': lambda x: x.drawEllipse(self.x, self.y, self.w, self.h),'прямоугольник':lambda x: x.drawRect(self.x, self.y, self.w, self.h)}
# x.drawLine(QPoint(self.x+self.x*2,self.y+self.y*2),QPoint(self.w_eq-self.w_eq/8,self.h_eq-self.h_eq/8)),
# x.drawLine(QPoint(self.x+self.x*8,self.y+self.y*8),QPoint(self.x+self.x*4,self.y+self.y*4+self.h_eq/8)),
# x.drawLine(QPoint(self.x, self.y), QPoint(5, self.y)),
# x.drawLine(QPoint(self.w_eq,self.h_eq), QPoint(self.w_eq, self.h_eq-5)),
# x.drawLine(QPoint(self.w_eq, self.h_eq), QPoint(self.w_eq-5, self.h_eq)),
def get_file_settings(self):
c=self.scenePos()
return {'x':c.x(),'y':c.y(),'h':self.h,'w':self.w,'name':self.name,'rotation':self.rotation(),
'brush_color':self._brush.color().toTuple(),'type_obj':self.type_obj}
def createDefaultContextMenu(self):
menu = QMenu()
menu.addAction('Повернуть').triggered.connect(lambda: self.setMode('scale'))
return menu
def hoverEnterEvent(self, event):
QApplication.instance().setOverrideCursor(Qt.OpenHandCursor)
def hoverLeaveEvent(self, event):
QApplication.instance().restoreOverrideCursor()
def mouseMoveEvent(self, event):
if self.rotation_:
self.my_rotation(self.rotation()+1)
return True
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))
def createDefaultContextMenu(self):
menu = QMenu()
menu.addAction('Повернуть').triggered.connect(lambda: self.setMode(True))
return menu
def contextMenuEvent(self, event):
menu = self.createDefaultContextMenu()
menu.exec_(event.screenPos())
def setMode(self, mode):
self.rotation_ = mode
def mouseReleaseEvent(self, event):
print('x: {0}, y: {1}'.format(self.pos().x(), self.pos().y()))
if self.rotation_:
self.rotation_=False
def my_rotation(self,angle):
# self.prepareGeometryChange()
c=self.mapToScene(self.boundingRect().center())
self.setRotation(angle)
cNew = self.mapToScene(self.boundingRect().center())
offset = c - cNew
self.moveBy(offset.x(), offset.y())
def mousePressEvent(self, event):
print(event.pos())
def boundingRect(self):
# return QRectF(-10 - penWidth / 2, -10 - penWidth / 2,
# 20 + penWidth, 20 + penWidth)
return QRectF(self.x,self.y,self.w,self.h)
# return QRectF(self.x,self.y,self.w_eq,self.h_eq)
def paint(self, painter, option, widget, PySide2_QtWidgets_QWidget=None, *args, **kwargs):
# painter.drawRoundedRect(-10, -10, 20, 20, 5, 5)
# painter.setBrush()
painter.setRenderHints(QPainter.Antialiasing|QPainter.TextAntialiasing,True)
painter.setPen(self.pen_color)
painter.setBrush(self._brush)
self.types[self.type_obj](painter)
self._brush = painter.brush()
def setBrush(self,brush):
self._brush.setColor(brush)
def get_square(self):
type={'эллипс': round ((((pi*self.w*self.h)/4)/10000),4),
'прямоугольник':(self.h*self.w)/10000}
return type[self.type_obj]
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.centralwidget = QWidget(self)
self.centralwidget.setGeometry(0, 0, 600, 700)
self.centralwidget.setObjectName(u"centralwidget")
self.gridLayout = QGridLayout(self.centralwidget)
self.gridLayout.setObjectName(u"gridLayout")
self.verticalLayout = QVBoxLayout()
self.verticalLayout.setObjectName(u"verticalLayout")
self.graphicsView = MyQGraphicsView(self.centralwidget)
self.graphicsView.setObjectName(u"graphicsView")
self.scene = QGraphicsScene(self.graphicsView)
self.scene.setObjectName('scene')
self.scene.setSceneRect(0, 0, 500, 500)
self.graphicsView.setScene(self.scene)
self.graphicsView.setMouseTracking(True)
self.verticalLayout.addWidget(self.graphicsView)
self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.add_item = QPushButton(self.centralwidget)
self.add_item.setObjectName(u"add_item")
self.horizontalLayout.addWidget(self.add_item)
self.save_items = QPushButton(self.centralwidget)
self.save_items.setObjectName(u"save_items")
self.horizontalLayout.addWidget(self.save_items)
self.load_items = QPushButton(self.centralwidget)
self.load_items.setObjectName(u"load_items")
self.horizontalLayout.addWidget(self.load_items)
self.verticalLayout.addLayout(self.horizontalLayout)
self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
self.setGeometry(0, 0, 600, 700)
self.add_item.pressed.connect(self.add_equipment)
self.save_items.pressed.connect(self.save_items_)
self.load_items.pressed.connect(self.load_items_)
self.retranslateUi()
# setupUi
def retranslateUi(self):
self.add_item.setText(QCoreApplication.translate("MainWindow", u"add item", None))
self.save_items.setText(QCoreApplication.translate("MainWindow", u"save items", None))
self.load_items.setText(QCoreApplication.translate("MainWindow", u"load items", None))
# retranslateUi
def add_equipment(self):
self.eq_obj = Drow_equipent(30, 40, 20,
20, 'block', Qt.blue,'прямоугольник')
self.scene.addItem(self.eq_obj)
self.last_selected_item = self.eq_obj
def load_items_(self):
with open(os.path.join(os.getcwd(), 'config.ini'), 'rb') as f:
settings = load(f)
print(settings)
items_keys = [key for key in settings.keys() if key != 'grid']
print(items_keys)
for item in items_keys:
self.eq_obj = Drow_equipent(settings[item]['x'], settings[item]['y'],
settings[item]['w'], settings[item]['h'],
settings[item]['name'],
QBrush(QColor().fromRgb(*settings[item]['brush_color'])),
settings[item]['type_obj'])
self.scene.addItem(self.eq_obj)
def save_items_(self):
settings = {}
number_item = 0
for item in self.scene.items():
settings[f'item_№:{number_item}'] = item.get_file_settings()
number_item += 1
with open(os.path.join(os.getcwd(), 'config.ini'), 'wb') as f:
dump(settings, f)
if __name__ == '__main__':
app = QApplication(sys.argv)
translator = QTranslator()
if len(sys.argv) > 1:
locale = sys.argv[1]
else:
locale = QLocale.system().name()
translator.load('qt_%s' % locale,
QLibraryInfo.location(QLibraryInfo.TranslationsPath))
app.installTranslator(translator)
window = MainWindow()
window.show()
app.exec_()
一个非常重要的事情总是要考虑的是QLogiStIm的位置不一定要符合它的内容。
考虑两个矩形项:
rect1 = self.scene.addRect(5, 10, 20, 10)
rect2 = self.scene.addRect(0, 0, 20, 10)
rect2.setPos(5, 10)
虽然它们都显示在同一位置,但它们不是相同的。这些参数实际上将成为这些项的boundingRect
,但第一个参数的pos
仍在(0,0),第二个参数已被移动,这是因为图形项始终的起始位置在坐标(0,0)处,而boundingRect始终在项坐标中
创建新项目时,通常最好将其边界矩形设置为(0,0),除非需要特殊要求(例如,项目始终以其位置为中心显示)
在展示如何更正代码之前,还有一些其他问题需要解决
- 如果需要允许移动项目,通常不需要自己实现移动,因为QGraphicsItem标志
就足够了;如果需要对鼠标事件进行特殊控制,只需确保在需要移动时调用默认实现李>ItemIsMovable
- 这也意味着必须调用
super()李>
ex()
是所有QGraphics站点的现有函数,尽管您仍然可以通过y()
和self.pos().x()
访问它们,但覆盖这些属性确实没有任何好处李>self.pos().y()
- 鼠标事件不应返回
李>bool
还要注意的是,虽然不是运行所必需的,但始终建议使用良好的代码固定;逗号后面应该有空格,等号周围应该有空格,否则阅读会更不舒服,因为能够立即区分物体是非常重要的:看到
self.x,self.y=x,y
(这是不好的)与self.x,self.y=x,y
(这是好的). 阅读有关官方的更多信息。请在等待MRE时提供一段时间,从我所看到的情况来看,显然存在一个问题:给定的x
和y
坐标用于位置,但也用于绘图;结果是,如果X是5,Y是10,绘图将发生在10x20,因为绘图总是相对于项目的位置,所以我将从这个问题开始。然后,x
和y
都是QGraphicsItem的属性,因此它们永远不应该被其他数据覆盖。@musicamante感谢您的关注和评论@musicamante仍不清楚错误在哪里is@Valvea如第一条评论所述,您需要向我们提供MRE。请仔细阅读该链接并遵循其建议。您必须提供最少的代码,以便我们重现您的问题(这意味着我们应该能够轻松地复制、粘贴和运行您的代码),并且应该删除与此问题无关的任何代码部分。这个答案非常好!非常感谢您的时间和解释。没有你的帮助,我就不能再行动了。我真的很怀念代码的整洁。由于您的回答,进一步的实施将基于正确的概念。
class Drow_equipent(QGraphicsItem):
def __init__(self, x, y, w, h, name, brush=Qt.blue, type='эллипс'):
super().__init__()
self.setPos(x, y)
self.penWidth = 1
self.name = name
self.h, self.w = h, w
self.setAcceptHoverEvents(True)
self.signal = Communicate()
self.setFlags(
QGraphicsItem.ItemSendsGeometryChanges|
QGraphicsItem.ItemIsSelectable|
QGraphicsItem.ItemIsMovable)
# ...
self.types = {
'эллипс': lambda x: x.drawEllipse(0, 0, self.w, self.h),
'прямоугольник':lambda x: x.drawRect(0, 0, self.w, self.h)
}
# ...
def mouseMoveEvent(self, event):
if self.rotation_:
self.my_rotation(self.rotation() + 1)
else:
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
if self.rotation_:
self.rotation_ = False
super().mouseReleaseEvent(event)
def mousePressEvent(self, event):
print(event.pos())
super().mousePressEvent(event)
def boundingRect(self):
return QRectF(0, 0, self.w, self.h)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.centralwidget = QWidget(self)
self.setCentralWidget(self.centralwidget)