细节优化
parent
a0417d080c
commit
44c582487e
|
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"canvas": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"w": 1920.0,
|
||||
"h": 1080.0
|
||||
},
|
||||
"widgets": [
|
||||
{
|
||||
"widget_type": "label",
|
||||
"x": 173.0,
|
||||
"y": 210.0,
|
||||
"w": 162.0,
|
||||
"h": 62.0,
|
||||
"z": 1.0,
|
||||
"config": {
|
||||
"fieldName": "主轴承#3",
|
||||
"prefix": "主轴承温度",
|
||||
"suffix": " ℃",
|
||||
"fontSize": 16,
|
||||
"color": "#FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widget_type": "label",
|
||||
"x": 46.0,
|
||||
"y": 378.0,
|
||||
"w": 162.0,
|
||||
"h": 62.0,
|
||||
"z": 1.0,
|
||||
"config": {
|
||||
"fieldName": "减速箱小轴承2",
|
||||
"prefix": "减速箱小轴承温度",
|
||||
"suffix": "℃",
|
||||
"fontSize": 16,
|
||||
"color": "#FFFFFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widget_type": "image",
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"w": 650.0,
|
||||
"h": 865.0,
|
||||
"z": 0.0,
|
||||
"config": {
|
||||
"imagePath": "D:/1-2.JPG"
|
||||
}
|
||||
},
|
||||
{
|
||||
"widget_type": "web",
|
||||
"x": 648.5,
|
||||
"y": 0.0,
|
||||
"w": 887.0,
|
||||
"h": 863.0,
|
||||
"z": 0.0,
|
||||
"config": {
|
||||
"url": "http://127.0.0.1:8086/orgs/b2542eeb72a3e614/dashboards/0f8ab8a328fe9000?lower=now%28%29+-+1h",
|
||||
"locked": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -4,5 +4,5 @@
|
|||
"org": "MEASCON",
|
||||
"bucket": "PCM",
|
||||
"interval_ms": 1000,
|
||||
"query": "from(bucket: \"PCM\")\n |> range(start: -3h)\n |> filter(fn: (r) => r._measurement == \"PCM_Measurement\")\n |> filter(fn: (r) => r.data_type == \"LSDAQ\")\n |> keep(columns: [\"_time\", \"_field\", \"_value\"])\n |> last()"
|
||||
"query": "from(bucket: \"PCM\")\n |> range(start: -24h)\n |> filter(fn: (r) => r._measurement == \"PCM_Measurement\")\n |> filter(fn: (r) => r.data_type == \"LSDAQ\")\n |> keep(columns: [\"_time\", \"_field\", \"_value\"])\n |> last()"
|
||||
}
|
||||
129
main.py
129
main.py
|
|
@ -201,6 +201,25 @@ class DashboardItem(QGraphicsRectItem):
|
|||
super().paint(painter, option, widget)
|
||||
|
||||
def to_state(self) -> WidgetState:
|
||||
"""将组件状态转换为 WidgetState,使用精确的 pos() 和 rect(),而不是 sceneBoundingRect()"""
|
||||
pos = self.pos()
|
||||
r = self.rect()
|
||||
return WidgetState(
|
||||
widget_type=self._get_widget_type(),
|
||||
x=float(pos.x()),
|
||||
y=float(pos.y()),
|
||||
w=float(r.width()),
|
||||
h=float(r.height()),
|
||||
z=float(self.zValue()),
|
||||
config=self._get_config(),
|
||||
)
|
||||
|
||||
def _get_widget_type(self) -> str:
|
||||
"""子类需要重写,返回组件类型"""
|
||||
raise NotImplementedError
|
||||
|
||||
def _get_config(self) -> Dict[str, Any]:
|
||||
"""子类需要重写,返回配置字典"""
|
||||
raise NotImplementedError
|
||||
|
||||
def apply_state(self, state: WidgetState):
|
||||
|
|
@ -387,17 +406,11 @@ class ImageItem(DashboardItem):
|
|||
)
|
||||
self._pixmap_item.setScale(scale)
|
||||
|
||||
def to_state(self) -> WidgetState:
|
||||
r = self.sceneBoundingRect()
|
||||
return WidgetState(
|
||||
widget_type="image",
|
||||
x=r.x(),
|
||||
y=r.y(),
|
||||
w=r.width(),
|
||||
h=r.height(),
|
||||
z=float(self.zValue()),
|
||||
config={"imagePath": self._image_path},
|
||||
)
|
||||
def _get_widget_type(self) -> str:
|
||||
return "image"
|
||||
|
||||
def _get_config(self) -> Dict[str, Any]:
|
||||
return {"imagePath": self._image_path}
|
||||
|
||||
def apply_state(self, state: WidgetState):
|
||||
super().apply_state(state)
|
||||
|
|
@ -484,17 +497,11 @@ class LabelItem(DashboardItem):
|
|||
if self._field_name and self._field_name in data:
|
||||
self._update_preview_text(data[self._field_name])
|
||||
|
||||
def to_state(self) -> WidgetState:
|
||||
r = self.sceneBoundingRect()
|
||||
return WidgetState(
|
||||
widget_type="label",
|
||||
x=r.x(),
|
||||
y=r.y(),
|
||||
w=r.width(),
|
||||
h=r.height(),
|
||||
z=float(self.zValue()),
|
||||
config=self.label_config(),
|
||||
)
|
||||
def _get_widget_type(self) -> str:
|
||||
return "label"
|
||||
|
||||
def _get_config(self) -> Dict[str, Any]:
|
||||
return self.label_config()
|
||||
|
||||
def apply_state(self, state: WidgetState):
|
||||
super().apply_state(state)
|
||||
|
|
@ -558,20 +565,14 @@ class WebItem(DashboardItem):
|
|||
def is_locked(self) -> bool:
|
||||
return self._locked
|
||||
|
||||
def to_state(self) -> WidgetState:
|
||||
r = self.sceneBoundingRect()
|
||||
return WidgetState(
|
||||
widget_type="web",
|
||||
x=r.x(),
|
||||
y=r.y(),
|
||||
w=r.width(),
|
||||
h=r.height(),
|
||||
z=float(self.zValue()),
|
||||
config={
|
||||
"url": self._url,
|
||||
"locked": self._locked,
|
||||
},
|
||||
)
|
||||
def _get_widget_type(self) -> str:
|
||||
return "web"
|
||||
|
||||
def _get_config(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"url": self._url,
|
||||
"locked": self._locked,
|
||||
}
|
||||
|
||||
def apply_state(self, state: WidgetState):
|
||||
super().apply_state(state)
|
||||
|
|
@ -715,9 +716,35 @@ class DashboardView(QGraphicsView):
|
|||
# 布局持久化
|
||||
def save_layout(self, path: str):
|
||||
states = []
|
||||
canvas_bounds = self._scene.canvas_rect()
|
||||
canvas_pos = self._scene.canvas_item.pos()
|
||||
canvas_left = canvas_pos.x()
|
||||
canvas_top = canvas_pos.y()
|
||||
canvas_right = canvas_left + canvas_bounds.width()
|
||||
canvas_bottom = canvas_top + canvas_bounds.height()
|
||||
|
||||
for it in self._scene.items():
|
||||
if isinstance(it, DashboardItem):
|
||||
states.append(asdict(it.to_state()))
|
||||
# 获取组件状态
|
||||
state = it.to_state()
|
||||
state_dict = asdict(state)
|
||||
|
||||
# 修正超出边界的位置数据(直接修改字典,不移动组件)
|
||||
item_left = state_dict["x"]
|
||||
item_top = state_dict["y"]
|
||||
item_w = state_dict["w"]
|
||||
item_h = state_dict["h"]
|
||||
|
||||
# 修正超出边界的位置数据
|
||||
final_x = max(canvas_left, min(item_left, canvas_right - item_w))
|
||||
final_y = max(canvas_top, min(item_top, canvas_bottom - item_h))
|
||||
|
||||
# 更新状态数据
|
||||
state_dict["x"] = final_x
|
||||
state_dict["y"] = final_y
|
||||
|
||||
states.append(state_dict)
|
||||
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
payload = {
|
||||
"canvas": self._scene.canvas_state(),
|
||||
|
|
@ -769,6 +796,28 @@ class DashboardView(QGraphicsView):
|
|||
else:
|
||||
continue
|
||||
it.apply_state(ws)
|
||||
|
||||
# 加载后也应用边界限制,确保组件不超出画布
|
||||
canvas_bounds = self._scene.canvas_rect()
|
||||
canvas_pos = self._scene.canvas_item.pos()
|
||||
canvas_left = canvas_pos.x()
|
||||
canvas_top = canvas_pos.y()
|
||||
canvas_right = canvas_left + canvas_bounds.width()
|
||||
canvas_bottom = canvas_top + canvas_bounds.height()
|
||||
|
||||
pos = it.pos()
|
||||
r = it.rect()
|
||||
item_left = pos.x()
|
||||
item_top = pos.y()
|
||||
item_right = item_left + r.width()
|
||||
item_bottom = item_top + r.height()
|
||||
|
||||
# 修正超出边界的位置
|
||||
final_x = max(canvas_left, min(item_left, canvas_right - r.width()))
|
||||
final_y = max(canvas_top, min(item_top, canvas_bottom - r.height()))
|
||||
|
||||
if final_x != item_left or final_y != item_top:
|
||||
it.setPos(final_x, final_y)
|
||||
|
||||
|
||||
# -----------------------------
|
||||
|
|
@ -1106,6 +1155,8 @@ class MainWindow(QMainWindow):
|
|||
super().__init__()
|
||||
self.setWindowTitle("PCM Viewer - Widgets Dashboard")
|
||||
self.resize(1400, 840)
|
||||
# 设置焦点策略,确保能够接收键盘事件(特别是 ESC 键)
|
||||
self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
|
||||
self._edit_mode = True
|
||||
# 全屏编辑标志(展示模式本身也会全屏)
|
||||
self._fullscreen_edit = False
|
||||
|
|
@ -1219,12 +1270,16 @@ class MainWindow(QMainWindow):
|
|||
if want_full:
|
||||
# 真全屏:使用 Qt 的 showFullScreen,退出时用 showMaximized 恢复普通 Windows 窗口
|
||||
self.showFullScreen()
|
||||
# 全屏后确保窗口获得焦点,以便接收键盘事件(ESC 键)
|
||||
self.setFocus()
|
||||
# 全屏时关闭滚动条,避免 1920x1080 屏幕上还出现滚动条
|
||||
self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||
self.view.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||
else:
|
||||
# 恢复为标准的最大化窗口(带边框/任务栏)
|
||||
self.showMaximized()
|
||||
# 恢复焦点,确保能够接收键盘事件
|
||||
self.setFocus()
|
||||
self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
||||
self.view.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue