【问题标题】:How to access the position offsets of movable QGraphicsItems?如何访问可移动 QGraphicsItem 的位置偏移量?
【发布时间】:2021-08-03 05:50:30
【问题描述】:

我最近开始使用 Python Qt,我正在尝试制作一个单击并拖动地图编辑器,该编辑器可以读取和写入 .json 文件。到目前为止,我的进展是让 QGraphicsView 用矩形准确地动态显示整个房间布局。但是现在我不知道如何访问每个矩形的 x 和 y 偏移,因为它们都可以使用 setFlag(QGraphicsItem.ItemIsMovable) 属性单独移动。

这是我的代码的简短版本:

import json
import sys
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *

TILEWIDTH = 25
TILEHEIGHT = 15
OUTLINE = 3

class Room:
    def __init__(self, name, width, height, offset_x, offset_z):
        self.name = name
        self.width = width
        self.height = height
        self.offset_x = offset_x
        self.offset_z = offset_z

class Main(QMainWindow):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        #Setting up viewport
        self.scene = QGraphicsScene(self)
        self.view = QGraphicsView(self.scene, self)
        
        self.view.scale(1, -1)
        self.view.setStyleSheet("background:transparent; border: 0px")
        self.setCentralWidget(self.view)
        
        self.setGeometry(360, 190, 1200, 700)
        self.showMaximized()
        
        #Reading json and converting entries to rooms
        self.room_list = []
        with open("Data\Content\PB_DT_RoomMaster.json", "r") as file_reader:
            self.content = json.load(file_reader)
        for i in self.content:
            self.room_list.append(self.convert_json_to_room(i))
        self.draw_map()
    
    def convert_json_to_room(self, json):
        name = json["Key"]
        width = json["Value"]["AreaWidthSize"] * TILEWIDTH
        height = json["Value"]["AreaHeightSize"] * TILEHEIGHT
        offset_x = round(json["Value"]["OffsetX"]/12.6) * TILEWIDTH
        offset_z = round(json["Value"]["OffsetZ"]/7.2) * TILEHEIGHT 
        
        room = Room(name, width, height, offset_x, offset_z)
        return room
  
    def draw_map(self):
        for i in self.room_list:
            fill = QColor("#000000")
            outline = QPen("#ffffff")
            outline.setWidth(OUTLINE)
            outline.setJoinStyle(Qt.MiterJoin)
            #Drawing rooms
            rect = self.scene.addRect(i.offset_x, i.offset_z, i.width, i.height, outline, fill)
            rect.setFlag(QGraphicsItem.ItemIsMovable)

def main():
    app = QApplication(sys.argv)
    main = Main()
    main.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

这是json:

[
  {
    "Key": "m01SIP_000",
    "Value": {
      "LevelName": "m01SIP_000",
      "EnemyPatternSuffix": "",
      "AreaID": "EAreaID::m01SIP",
      "SameRoom": "None",
      "AdjacentRoomName": [
        "m01SIP_001",
        "m01SIP_024",
        "m01SIP_023"
      ],
      "OutOfMap": false,
      "EventFlagNameForShowEventIfNotSeen": "None",
      "EventFlagNameForMarkEventAsSeen": "None",
      "WarpPositionX": 0.0,
      "WarpPositionY": 0.0,
      "WarpPositionZ": 0.0,
      "RoomType": "ERoomType::Normal",
      "RoomPath": "ERoomPath::Both",
      "ConsiderLeft": true,
      "ConsiderRight": true,
      "ConsiderTop": true,
      "ConsiderBottom": true,
      "AreaWidthSize": 2,
      "AreaHeightSize": 1,
      "OffsetX": 25.2,
      "OffsetZ": 0.0,
      "DoorFlag": [
        2,
        32
      ],
      "HiddenFlag": [],
      "RoomCollisionFromSplineOnly": false,
      "RoomCollisionFromGimmick": false,
      "NoRoomOutBlinder": false,
      "Collision2DProjectionDistance": -1.0,
      "FlyMaterialDistance": 10.0,
      "NoTraverse": [],
      "MagCameraFovScale": 0.0,
      "MagCameraVolumeScale": 1.5,
      "DemagCameraFovScale": 0.77,
      "DemagCameraVolumeScale": 0.0,
      "BgmID": "BGM_m01SIP",
      "BgmType": "ERoomBgmType::PlayNormal",
      "Amb1": "AMB_01SIP_Ship_Roll01",
      "AmbVol1": 70,
      "Amb2": "",
      "AmbVol2": 0,
      "Amb3": "",
      "AmbVol3": 0,
      "Amb4": "",
      "AmbVol4": 0,
      "Decay_Near": 1260.0,
      "Decay_Far": 2520.0,
      "Decay_Far_Volume": 0.5,
      "UseLava": false,
      "FrameType": "EFramePlateType::FPT_Full",
      "PerfLevel": 1
    }
  },
  {
    "Key": "m01SIP_001",
    "Value": {
      "LevelName": "m01SIP_001",
      "EnemyPatternSuffix": "",
      "AreaID": "EAreaID::m01SIP",
      "SameRoom": "None",
      "AdjacentRoomName": [
        "m01SIP_000",
        "m01SIP_023",
        "m01SIP_002"
      ],
      "OutOfMap": false,
      "EventFlagNameForShowEventIfNotSeen": "None",
      "EventFlagNameForMarkEventAsSeen": "None",
      "WarpPositionX": 0.0,
      "WarpPositionY": 0.0,
      "WarpPositionZ": 0.0,
      "RoomType": "ERoomType::Normal",
      "RoomPath": "ERoomPath::Both",
      "ConsiderLeft": true,
      "ConsiderRight": true,
      "ConsiderTop": true,
      "ConsiderBottom": true,
      "AreaWidthSize": 3,
      "AreaHeightSize": 1,
      "OffsetX": 50.4,
      "OffsetZ": 0.0,
      "DoorFlag": [
        1,
        24,
        3,
        8
      ],
      "HiddenFlag": [],
      "RoomCollisionFromSplineOnly": false,
      "RoomCollisionFromGimmick": false,
      "NoRoomOutBlinder": false,
      "Collision2DProjectionDistance": -1.0,
      "FlyMaterialDistance": 10.0,
      "NoTraverse": [],
      "MagCameraFovScale": 0.0,
      "MagCameraVolumeScale": 1.5,
      "DemagCameraFovScale": 0.77,
      "DemagCameraVolumeScale": 0.0,
      "BgmID": "BGM_m01SIP",
      "BgmType": "ERoomBgmType::PlayNormal",
      "Amb1": "AMB_01SIP_Ship_Roll01",
      "AmbVol1": 70,
      "Amb2": "AMB_01SIP_Wind02_LP",
      "AmbVol2": 70,
      "Amb3": "",
      "AmbVol3": 0,
      "Amb4": "",
      "AmbVol4": 0,
      "Decay_Near": 1260.0,
      "Decay_Far": 2520.0,
      "Decay_Far_Volume": 0.5,
      "UseLava": false,
      "FrameType": "EFramePlateType::FPT_Full",
      "PerfLevel": 1
    }
  },
...

基本上我需要在 json 中每个房间在地图编辑器上移动后更新它的偏移量。解决这个问题的最佳方法是什么?

【问题讨论】:

    标签: python offset qgraphicsitem pyside6 movable


    【解决方案1】:

    您没有将偏移设置为矩形的参数,因为稍后您必须进行转换,因为它位于项目的本地坐标中,而是使用场景坐标中的方法 pos():

    rect = self.scene.addRect(0, 0, i.width, i.height, outline, fill)
    rect.setPos(i.offset_x, i.offset_z)
    rect.setFlag(QGraphicsItem.ItemIsMovable)
    

    那么做完就可以拿到位置了:

    i.offset_x = rect.pos().x()
    i.offset_z = rect.pos().y()
    

    我认为没有必要将信息分开,因为您可以创建一个存储信息的项目,以便以后检索。

    import json
    import sys
    from functools import cached_property
    
    from PySide6.QtCore import Qt
    from PySide6.QtGui import QColor, QPen
    from PySide6.QtWidgets import (
        QApplication,
        QGraphicsRectItem,
        QGraphicsScene,
        QGraphicsView,
        QMainWindow,
        QGraphicsItem,
    )
    
    TILEWIDTH = 25
    TILEHEIGHT = 15
    OUTLINE = 3
    
    KEY_METADATA = 1
    
    
    class RoomItem(QGraphicsRectItem):
        def __init__(self, x, y, width, height, metadata=None, parent=None):
            super().__init__(0, 0, width, height, parent)
            self.setPos(x, y)
            self.setFlag(QGraphicsItem.ItemIsMovable)
            self.setData(KEY_METADATA, metadata)
    
            fill = QColor("#000000")
            outline = QPen("#ffffff")
            outline.setWidth(OUTLINE)
            outline.setJoinStyle(Qt.MiterJoin)
            self.setPen(outline)
            self.setBrush(fill)
    
        @classmethod
        def from_json(cls, d):
            x = d["Value"]["OffsetX"] / 12.6 * TILEWIDTH
            y = d["Value"]["OffsetZ"] / 7.2 * TILEHEIGHT
            width = d["Value"]["AreaWidthSize"] * TILEWIDTH
            height = d["Value"]["AreaHeightSize"] * TILEHEIGHT
            return cls(x, y, width, height, d)
    
        def to_json(self):
            d = self.data(KEY_METADATA) or dict()
            d["Value"] = dict(
                OffsetX=self.pos().x() * 12.6 / TILEWIDTH,
                OffsetZ=self.pos().y() * 7.2 / TILEHEIGHT,
                AreaWidthSize=self.rect().width() / TILEWIDTH,
                AreaHeightSize=self.rect().height() / TILEHEIGHT,
            )
            return d
    
    
    class Main(QMainWindow):
        def __init__(self):
            super().__init__()
            self.initUI()
    
        @cached_property
        def items(self):
            return list()
    
        def initUI(self):
            # Setting up viewport
            self.scene = QGraphicsScene(self)
            self.view = QGraphicsView(self.scene, self)
    
            self.view.scale(1, -1)
            self.view.setStyleSheet("background:transparent; border: 0px")
            self.setCentralWidget(self.view)
    
            self.setGeometry(360, 190, 1200, 700)
            self.showMaximized()
    
        def load_from_json(self, filename):
            with open(filename, "r") as f:
                for e in json.load(f):
                    item = RoomItem.from_json(e)
                    self.scene.addItem(item)
                    self.items.append(item)
    
        def save_to_json(self, filename):
            with open(filename, "w") as f:
                l = []
                for item in self.items:
                    l.append(item.to_json())
                json.dump(l, f)
    
    
    def main():
        app = QApplication(sys.argv)
        main = Main()
        main.show()
        main.load_from_json("data.json")
        ret = app.exec_()
    
        main.save_to_json("data.json")
    
        sys.exit(ret)
    
    
    if __name__ == "__main__":
        main()
    

    【讨论】:

    • 好吧,我明白了,但是我如何访问特定的“矩形”,因为我是从循环中生成所有这些的。如何访问用户选择和移动的特定矩形?
    • @Lakifume 您的问题并不清楚,但现在我最大的问题是:您想什么时候访问?
    • 好吧,假设我想在用户点击保存按钮的最后访问它们。我想访问每个矩形的位置并将其传递给 json 列表中的每个相应条目。因此,例如,如果第一个矩形被移动到某个地方,我希望获得那个新位置并将其修补到“m01SIP_000”条目中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-20
    • 2014-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多