如何访问可移动 QGraphicsItem 的位置偏移量?
How to access the position offsets of movable QGraphicsItems?
我最近开始使用 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 中每个房间在地图编辑器上移动后的偏移量。处理此问题的最佳方法是什么?
您没有将偏移设置为矩形的参数,因为稍后您将不得不进行转换,因为它位于项目的本地坐标中,而是使用场景坐标中的方法 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()
我最近开始使用 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 中每个房间在地图编辑器上移动后的偏移量。处理此问题的最佳方法是什么?
您没有将偏移设置为矩形的参数,因为稍后您将不得不进行转换,因为它位于项目的本地坐标中,而是使用场景坐标中的方法 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()