add:增加倒车功能
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"carousel_interval": 4,
|
"carousel_interval": 4,
|
||||||
"brightness": 50,
|
"brightness": 50,
|
||||||
"radar_unit": 0,
|
"radar_unit": 1,
|
||||||
"show_radar": 0,
|
"show_radar": 1,
|
||||||
"radar_alarm_dist": 70,
|
"radar_alarm_dist": 5,
|
||||||
"display_mode": 0
|
"display_mode": 0
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@ from tkinter import ttk, scrolledtext
|
|||||||
# ==========================================================
|
# ==========================================================
|
||||||
# 串口配置
|
# 串口配置
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
SERIAL_PORT = "/dev/ttyS3"
|
SERIAL_PORT = "/dev/ttyS0"
|
||||||
BAUD_RATE = 115200
|
BAUD_RATE = 115200
|
||||||
TIMEOUT = 1
|
TIMEOUT = 1
|
||||||
|
|
||||||
|
|||||||
135
web.py
135
web.py
@@ -224,26 +224,30 @@ class SerialWorker(threading.Thread):
|
|||||||
|
|
||||||
def get_state(self):
|
def get_state(self):
|
||||||
with self._rx_lock:
|
with self._rx_lock:
|
||||||
return list(self._active_dirs), self._radar_dist, self._stopped
|
return list(self._active_dirs), self._radar_dist, self._stopped, self._reverse #add 返回倒车状态
|
||||||
|
|
||||||
|
|
||||||
def _parse_rx_frame(self, frame):
|
def _parse_rx_frame(self, frame):
|
||||||
if len(frame) != 9 or frame[0] != 0x55 or frame[8] != 0xAA:
|
# print("[串口1 RX] " + " ".join("{:02X}".format(b) for b in frame))
|
||||||
|
if len(frame) != 10 or frame[0] != 0x55 or frame[9] != 0xAA:
|
||||||
return
|
return
|
||||||
front = frame[1]; left = frame[2]
|
front = frame[1]; left = frame[2]
|
||||||
back = frame[3]; right = frame[4]
|
back = frame[3]; right = frame[4]
|
||||||
radar = frame[5]; stop = frame[6]
|
radar = frame[5]; stop = frame[6]
|
||||||
reverse = frame[7]
|
reverse = frame[7] # 倒车信号 00=正常 01=倒车
|
||||||
|
|
||||||
active = []
|
active = []
|
||||||
for name, val in [("front", front), ("left", left),
|
for name, val in [("front", front), ("left", left),
|
||||||
("back", back), ("right", right)]:
|
("back", back), ("right", right)]:
|
||||||
if val != 0x00:
|
if val != 0x00:
|
||||||
active.append(name)
|
active.append(name)
|
||||||
|
|
||||||
with self._rx_lock:
|
with self._rx_lock:
|
||||||
self._active_dirs = active
|
self._active_dirs = active
|
||||||
self._radar_dist = radar
|
self._radar_dist = radar
|
||||||
self._stopped = (stop != 0x00)
|
self._stopped = (stop != 0x00)
|
||||||
# self._reverse = (reverse != 0x00)
|
self._reverse = (reverse == 0x01) # add 倒车信号
|
||||||
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
try:
|
||||||
@@ -288,10 +292,10 @@ class SerialWorker(threading.Thread):
|
|||||||
buf.append(b)
|
buf.append(b)
|
||||||
continue
|
continue
|
||||||
buf.append(b)
|
buf.append(b)
|
||||||
if len(buf) == 9:
|
if len(buf) == 10:
|
||||||
self._parse_rx_frame(bytes(buf))
|
self._parse_rx_frame(bytes(buf))
|
||||||
buf.clear()
|
buf.clear()
|
||||||
elif len(buf) > 9:
|
elif len(buf) > 10:
|
||||||
buf.clear()
|
buf.clear()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if self.running:
|
if self.running:
|
||||||
@@ -777,19 +781,81 @@ class RenderWorker(threading.Thread):
|
|||||||
sw = self.sw
|
sw = self.sw
|
||||||
sh = self.sh
|
sh = self.sh
|
||||||
|
|
||||||
# 获取状态
|
# 获取状态 add 修改解包状态
|
||||||
active_dirs, radar_dist, is_stopped = \
|
active_dirs, radar_dist, is_stopped, is_reverse = \
|
||||||
self.serial_worker.get_state()
|
self.serial_worker.get_state()
|
||||||
display_dir, remaining = self.carousel.update(active_dirs)
|
display_dir, remaining = self.carousel.update(active_dirs)
|
||||||
|
|
||||||
# 决定显示模式
|
# 决定显示模式
|
||||||
# 当有人时(active_dirs非空)进入全屏轮播模式
|
# 当有人时(active_dirs非空)进入全屏轮播模式
|
||||||
self._fullscreen_mode = len(active_dirs) > 0
|
# 决定显示模式(倒车优先级最高)
|
||||||
|
if is_reverse:
|
||||||
|
display_mode = "reverse"
|
||||||
|
elif len(active_dirs) > 0:
|
||||||
|
display_mode = "fullscreen"
|
||||||
|
else:
|
||||||
|
display_mode = "normal"
|
||||||
|
|
||||||
|
# self._fullscreen_mode = (display_mode == "fullscreen")
|
||||||
|
|
||||||
|
|
||||||
cfg = self.cfg_ref
|
cfg = self.cfg_ref
|
||||||
brightness = cfg.get("brightness", 50)
|
brightness = cfg.get("brightness", 50)
|
||||||
|
if display_mode == "reverse":
|
||||||
|
# ==========================================
|
||||||
|
# 倒车模式:左侧鸟瞰 + 右侧后视摄像头
|
||||||
|
# ==========================================
|
||||||
|
bw = sw // 3
|
||||||
|
fw = sw - bw
|
||||||
|
|
||||||
if self._fullscreen_mode:
|
back_frame = self.raw_worker.get_frame("back")
|
||||||
|
crop_ratio = self.CROP_RATIO.get("back", 0)
|
||||||
|
if back_frame is not None and crop_ratio > 0:
|
||||||
|
back_frame = self.crop_image(back_frame, crop_ratio)
|
||||||
|
|
||||||
|
bird_part = cv2.resize(self._last_bird, (bw, sh),
|
||||||
|
interpolation=cv2.INTER_LINEAR)
|
||||||
|
|
||||||
|
if back_frame is not None:
|
||||||
|
back_part = cv2.resize(back_frame, (fw, sh),
|
||||||
|
interpolation=cv2.INTER_LINEAR)
|
||||||
|
else:
|
||||||
|
back_part = np.zeros((sh, fw, 3), dtype=np.uint8)
|
||||||
|
|
||||||
|
if brightness != 50:
|
||||||
|
alpha_v = brightness / 50.0
|
||||||
|
back_part = cv2.convertScaleAbs(back_part, alpha=alpha_v, beta=0)
|
||||||
|
|
||||||
|
display = np.hstack((bird_part, back_part))
|
||||||
|
rgb = cv2.cvtColor(display, cv2.COLOR_BGR2RGB)
|
||||||
|
pil_img = Image.fromarray(rgb)
|
||||||
|
|
||||||
|
texts = []
|
||||||
|
|
||||||
|
# 倒车标题
|
||||||
|
texts.append((bw + 10, 10, "倒车模式 ◀ 后视", (255, 180, 0), 32))
|
||||||
|
|
||||||
|
# 雷达信息
|
||||||
|
if cfg.get("show_radar", 1):
|
||||||
|
unit_str = "厘米" if cfg.get("radar_unit", 0) else "分米"
|
||||||
|
dist_val = (radar_dist * 10 if cfg.get("radar_unit", 0)
|
||||||
|
else radar_dist)
|
||||||
|
alarm_d = cfg.get("radar_alarm_dist", 50)
|
||||||
|
rc = ((255, 80, 80) if dist_val <= alarm_d else (180, 220, 255))
|
||||||
|
texts.append((bw + 10, sh - 80,
|
||||||
|
f"雷达: {dist_val} {unit_str} 报警值: {alarm_d}{unit_str}",
|
||||||
|
rc, 22))
|
||||||
|
|
||||||
|
# 停机状态
|
||||||
|
stop_text = "已停机" if is_stopped else "运行中"
|
||||||
|
stop_color = ((255, 100, 100) if is_stopped else (100, 255, 100))
|
||||||
|
texts.append((bw + 10, sh - 52, f"状态: {stop_text}", stop_color, 22))
|
||||||
|
|
||||||
|
# 时间戳
|
||||||
|
texts.append((bw + 10, sh - 26,
|
||||||
|
time.strftime("%Y-%m-%d %H:%M:%S"), (160, 160, 160), 20))
|
||||||
|
|
||||||
|
elif display_mode == "fullscreen":
|
||||||
# ==========================================
|
# ==========================================
|
||||||
# 全屏轮播模式:显示有人方向的画面
|
# 全屏轮播模式:显示有人方向的画面
|
||||||
# ==========================================
|
# ==========================================
|
||||||
@@ -806,7 +872,7 @@ class RenderWorker(threading.Thread):
|
|||||||
frame = self.raw_worker.get_frame("front")
|
frame = self.raw_worker.get_frame("front")
|
||||||
|
|
||||||
if frame is not None:
|
if frame is not None:
|
||||||
# ★ 应用左右裁切
|
# 应用左右裁切
|
||||||
crop_ratio = self.CROP_RATIO.get(display_dir or active_dirs[0] if active_dirs else "front", 0)
|
crop_ratio = self.CROP_RATIO.get(display_dir or active_dirs[0] if active_dirs else "front", 0)
|
||||||
if crop_ratio > 0:
|
if crop_ratio > 0:
|
||||||
frame = self.crop_image(frame, crop_ratio)
|
frame = self.crop_image(frame, crop_ratio)
|
||||||
@@ -887,7 +953,7 @@ class RenderWorker(threading.Thread):
|
|||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# ★ 对右侧画面应用裁切
|
# 对右侧画面应用裁切
|
||||||
crop_ratio = self.CROP_RATIO.get(display_dir or "front", 0)
|
crop_ratio = self.CROP_RATIO.get(display_dir or "front", 0)
|
||||||
if crop_ratio > 0:
|
if crop_ratio > 0:
|
||||||
right_frame = self.crop_image(right_frame, crop_ratio)
|
right_frame = self.crop_image(right_frame, crop_ratio)
|
||||||
@@ -960,7 +1026,10 @@ class RenderWorker(threading.Thread):
|
|||||||
# 记录状态用于调试
|
# 记录状态用于调试
|
||||||
if self._last_active_dirs != active_dirs:
|
if self._last_active_dirs != active_dirs:
|
||||||
self._last_active_dirs = active_dirs.copy()
|
self._last_active_dirs = active_dirs.copy()
|
||||||
print(f"[RENDER] 模式切换: {'全屏轮播' if self._fullscreen_mode else '正常模式'}, 检测到: {active_dirs}")
|
mode_str = {"reverse": "倒车模式", "fullscreen": "全屏轮播",
|
||||||
|
"normal": "正常模式"}.get(display_mode, display_mode)
|
||||||
|
print(f"[RENDER] 模式切换: {mode_str}, 检测到: {active_dirs}, 倒车: {is_reverse}")
|
||||||
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("[RENDER ERROR] {}".format(e))
|
print("[RENDER ERROR] {}".format(e))
|
||||||
@@ -1049,7 +1118,7 @@ class QuadRenderWorker(threading.Thread):
|
|||||||
for (name, label_cn) in self.ORDER:
|
for (name, label_cn) in self.ORDER:
|
||||||
f = self.raw_worker.get_frame(name)
|
f = self.raw_worker.get_frame(name)
|
||||||
if f is not None:
|
if f is not None:
|
||||||
# ★ 先裁切,再拉伸
|
# 先裁切,再拉伸
|
||||||
crop_ratio = self.CROP_RATIO.get(name, 0)
|
crop_ratio = self.CROP_RATIO.get(name, 0)
|
||||||
if crop_ratio > 0:
|
if crop_ratio > 0:
|
||||||
f = self.crop_image(f, crop_ratio)
|
f = self.crop_image(f, crop_ratio)
|
||||||
@@ -1116,8 +1185,8 @@ class QuadRenderWorker(threading.Thread):
|
|||||||
|
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
# 12. 回放面板
|
# 12. 回放面板
|
||||||
# ★ 视频充满右侧区域:强制拉伸到 label 尺寸(不保持宽高比)
|
# 视频充满右侧区域:强制拉伸到 label 尺寸(不保持宽高比)
|
||||||
# ★ 字体放大
|
# 字体放大
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
class PlaybackPanel(QWidget):
|
class PlaybackPanel(QWidget):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
@@ -1151,7 +1220,7 @@ class PlaybackPanel(QWidget):
|
|||||||
|
|
||||||
self._list_widget = QListWidget()
|
self._list_widget = QListWidget()
|
||||||
self._list_widget.setFocusPolicy(Qt.NoFocus)
|
self._list_widget.setFocusPolicy(Qt.NoFocus)
|
||||||
# ★ 行高增大,字体加大
|
# 行高增大,字体加大
|
||||||
self._list_widget.setStyleSheet("""
|
self._list_widget.setStyleSheet("""
|
||||||
QListWidget {
|
QListWidget {
|
||||||
background:#0d1117; border:1px solid #0f3460;
|
background:#0d1117; border:1px solid #0f3460;
|
||||||
@@ -1199,7 +1268,7 @@ class PlaybackPanel(QWidget):
|
|||||||
"font-size:18px; color:#e94560; font-weight:bold;")
|
"font-size:18px; color:#e94560; font-weight:bold;")
|
||||||
rl.addWidget(play_title)
|
rl.addWidget(play_title)
|
||||||
|
|
||||||
# ★ label 充满右侧:Expanding + setScaledContents(True)
|
# label 充满右侧:Expanding + setScaledContents(True)
|
||||||
# setScaledContents(True) 让 pixmap 自动随 label 尺寸拉伸
|
# setScaledContents(True) 让 pixmap 自动随 label 尺寸拉伸
|
||||||
self._play_label = QLabel("选择左侧录像后按 OK 播放")
|
self._play_label = QLabel("选择左侧录像后按 OK 播放")
|
||||||
self._play_label.setAlignment(Qt.AlignCenter)
|
self._play_label.setAlignment(Qt.AlignCenter)
|
||||||
@@ -1208,7 +1277,7 @@ class PlaybackPanel(QWidget):
|
|||||||
" border:1px solid #0f3460;")
|
" border:1px solid #0f3460;")
|
||||||
self._play_label.setSizePolicy(
|
self._play_label.setSizePolicy(
|
||||||
QSizePolicy.Expanding, QSizePolicy.Expanding)
|
QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||||
self._play_label.setScaledContents(True) # ★ 自动拉伸填满
|
self._play_label.setScaledContents(True) # 自动拉伸填满
|
||||||
rl.addWidget(self._play_label, stretch=1)
|
rl.addWidget(self._play_label, stretch=1)
|
||||||
|
|
||||||
self._status_label = QLabel("")
|
self._status_label = QLabel("")
|
||||||
@@ -1273,7 +1342,7 @@ class PlaybackPanel(QWidget):
|
|||||||
self._play_fps = self._play_cap.get(cv2.CAP_PROP_FPS) or RECORD_FPS
|
self._play_fps = self._play_cap.get(cv2.CAP_PROP_FPS) or RECORD_FPS
|
||||||
self._play_paused = False
|
self._play_paused = False
|
||||||
|
|
||||||
# ★ 开始播放时启用 ScaledContents 填满 label
|
# 开始播放时启用 ScaledContents 填满 label
|
||||||
self._play_label.setScaledContents(True)
|
self._play_label.setScaledContents(True)
|
||||||
self._play_label.setText("")
|
self._play_label.setText("")
|
||||||
|
|
||||||
@@ -1293,7 +1362,7 @@ class PlaybackPanel(QWidget):
|
|||||||
self._status_label.setText("✅ 播放完毕")
|
self._status_label.setText("✅ 播放完毕")
|
||||||
return
|
return
|
||||||
|
|
||||||
# ★ 直接设置 pixmap,label.setScaledContents(True) 自动填满
|
# 直接设置 pixmap,label.setScaledContents(True) 自动填满
|
||||||
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||||
h, w = rgb.shape[:2]
|
h, w = rgb.shape[:2]
|
||||||
qimg = QImage(rgb.tobytes(), w, h, w * 3, QImage.Format_RGB888)
|
qimg = QImage(rgb.tobytes(), w, h, w * 3, QImage.Format_RGB888)
|
||||||
@@ -1339,7 +1408,7 @@ class PlaybackPanel(QWidget):
|
|||||||
|
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
# 13. 设置面板
|
# 13. 设置面板
|
||||||
# ★ 字体全面放大(列表 20px、标题 26px、值标签 36px)
|
# 字体全面放大(列表 20px、标题 26px、值标签 36px)
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
class SettingsPanel(QWidget):
|
class SettingsPanel(QWidget):
|
||||||
SUB_MAIN = 0
|
SUB_MAIN = 0
|
||||||
@@ -1363,7 +1432,7 @@ class SettingsPanel(QWidget):
|
|||||||
{"name":"画面亮度", "type":"range",
|
{"name":"画面亮度", "type":"range",
|
||||||
"key":"brightness", "min":0, "max":100, "step":5},
|
"key":"brightness", "min":0, "max":100, "step":5},
|
||||||
{"name":"雷达报警距离", "type":"range",
|
{"name":"雷达报警距离", "type":"range",
|
||||||
"key":"radar_alarm_dist", "min":10, "max":200, "step":10},
|
"key":"radar_alarm_dist", "min":5, "max":50, "step":5},
|
||||||
{"name":"雷达距离单位", "type":"toggle",
|
{"name":"雷达距离单位", "type":"toggle",
|
||||||
"key":"radar_unit",
|
"key":"radar_unit",
|
||||||
"values":[0, 1], "labels":["分米", "厘米"]},
|
"values":[0, 1], "labels":["分米", "厘米"]},
|
||||||
@@ -1375,7 +1444,7 @@ class SettingsPanel(QWidget):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def _build_ui(self):
|
def _build_ui(self):
|
||||||
# ★ 全面放大字号
|
# 全面放大字号
|
||||||
self.setStyleSheet("""
|
self.setStyleSheet("""
|
||||||
QWidget {
|
QWidget {
|
||||||
background:#1a1a2e;
|
background:#1a1a2e;
|
||||||
@@ -1427,7 +1496,7 @@ class SettingsPanel(QWidget):
|
|||||||
self._list_widget.setFocusPolicy(Qt.NoFocus)
|
self._list_widget.setFocusPolicy(Qt.NoFocus)
|
||||||
ml.addWidget(self._list_widget, stretch=1)
|
ml.addWidget(self._list_widget, stretch=1)
|
||||||
|
|
||||||
# ★ 当前值标签放大
|
# 当前值标签放大
|
||||||
self._val_label = QLabel("")
|
self._val_label = QLabel("")
|
||||||
self._val_label.setAlignment(Qt.AlignCenter)
|
self._val_label.setAlignment(Qt.AlignCenter)
|
||||||
self._val_label.setFixedHeight(52)
|
self._val_label.setFixedHeight(52)
|
||||||
@@ -1546,7 +1615,7 @@ class SettingsPanel(QWidget):
|
|||||||
|
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
# 14. 主窗口
|
# 14. 主窗口
|
||||||
# ★ 真全屏:showFullScreen() + image_label 用 setScaledContents(True)
|
# 真全屏:showFullScreen() + image_label 用 setScaledContents(True)
|
||||||
# 渲染线程按真实屏幕尺寸生成图像,label 自动填满无黑边
|
# 渲染线程按真实屏幕尺寸生成图像,label 自动填满无黑边
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
class SurroundViewWindow(QMainWindow):
|
class SurroundViewWindow(QMainWindow):
|
||||||
@@ -1562,7 +1631,7 @@ class SurroundViewWindow(QMainWindow):
|
|||||||
self.carousel = CarouselScheduler()
|
self.carousel = CarouselScheduler()
|
||||||
|
|
||||||
self.setWindowTitle("环视系统")
|
self.setWindowTitle("环视系统")
|
||||||
# ★ 先全屏,再取实际尺寸传给渲染线程
|
# 先全屏,再取实际尺寸传给渲染线程
|
||||||
self.showFullScreen()
|
self.showFullScreen()
|
||||||
self.sw = 1024
|
self.sw = 1024
|
||||||
self.sh = 600
|
self.sh = 600
|
||||||
@@ -1578,13 +1647,13 @@ class SurroundViewWindow(QMainWindow):
|
|||||||
ml.setContentsMargins(0, 0, 0, 0)
|
ml.setContentsMargins(0, 0, 0, 0)
|
||||||
ml.setSpacing(0)
|
ml.setSpacing(0)
|
||||||
|
|
||||||
# ★ setScaledContents(True) 让 pixmap 自动充满 label,无黑边
|
# setScaledContents(True) 让 pixmap 自动充满 label,无黑边
|
||||||
self.image_label = QLabel()
|
self.image_label = QLabel()
|
||||||
self.image_label.setAlignment(Qt.AlignCenter)
|
self.image_label.setAlignment(Qt.AlignCenter)
|
||||||
self.image_label.setStyleSheet("background:black;")
|
self.image_label.setStyleSheet("background:black;")
|
||||||
self.image_label.setSizePolicy(
|
self.image_label.setSizePolicy(
|
||||||
QSizePolicy.Expanding, QSizePolicy.Expanding)
|
QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||||
self.image_label.setScaledContents(True) # ★ 关键
|
self.image_label.setScaledContents(True) # 关键
|
||||||
ml.addWidget(self.image_label)
|
ml.addWidget(self.image_label)
|
||||||
self.stack.addWidget(main_page)
|
self.stack.addWidget(main_page)
|
||||||
|
|
||||||
@@ -1602,7 +1671,7 @@ class SurroundViewWindow(QMainWindow):
|
|||||||
multi_cam.birdview, framestep=2)
|
multi_cam.birdview, framestep=2)
|
||||||
self.bird_worker.start()
|
self.bird_worker.start()
|
||||||
|
|
||||||
# ★ 渲染线程用实际屏幕尺寸
|
# 渲染线程用实际屏幕尺寸
|
||||||
self.render_360 = RenderWorker(
|
self.render_360 = RenderWorker(
|
||||||
self.bird_worker, self.raw_worker,
|
self.bird_worker, self.raw_worker,
|
||||||
serial_worker, self.carousel, cfg,
|
serial_worker, self.carousel, cfg,
|
||||||
@@ -1642,7 +1711,7 @@ class SurroundViewWindow(QMainWindow):
|
|||||||
else self.render_360.get_qimage())
|
else self.render_360.get_qimage())
|
||||||
if qimg is None:
|
if qimg is None:
|
||||||
return
|
return
|
||||||
# ★ 直接 setPixmap,setScaledContents(True) 自动填满,无黑边
|
# 直接 setPixmap,setScaledContents(True) 自动填满,无黑边
|
||||||
self.image_label.setPixmap(QPixmap.fromImage(qimg))
|
self.image_label.setPixmap(QPixmap.fromImage(qimg))
|
||||||
|
|
||||||
def _on_key(self, code):
|
def _on_key(self, code):
|
||||||
@@ -1719,7 +1788,7 @@ def main():
|
|||||||
|
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
|
|
||||||
# ★ 禁用系统缩放干扰,确保全屏像素对齐
|
# 禁用系统缩放干扰,确保全屏像素对齐
|
||||||
app.setAttribute(Qt.AA_DisableHighDpiScaling, True)
|
app.setAttribute(Qt.AA_DisableHighDpiScaling, True)
|
||||||
|
|
||||||
win = SurroundViewWindow(
|
win = SurroundViewWindow(
|
||||||
|
|||||||
Reference in New Issue
Block a user