# 光舞燈效編輯器 ‑ `editor.py` 詳解筆記 ## 開頭:用 Qt Designer 設計介面 UI → 轉換成 `ui.py` > 下面這段是我實際操作的流程,給還沒用過 Qt Designer 的同學參考。 1. **開啟 Qt Designer** * Windows 在 Start Menu 找 *Qt Designer*;macOS 用 `Qt Creator` 內建的 Designer;Linux 直接執行 `designer` 指令。 2. **建立或載入 `.ui` 檔** * 我通常選 *Main Window* 模板。 * 拖拉元件(`QPushButton`、`QComboBox`、`QWebEngineView`…)到視窗,並調整 `objectName`,這名字就是未來在 Python 裡呼叫的屬性名。 3. **設定版面配置(Layouts)** * 使用水平、垂直、網格布局,確保視窗放大縮小時元件不會跑位。 4. **存檔** * 存成 `UI.ui`(或你自訂檔名),並把檔案一併放進 Git 版本控制。 5. **命令列執行 `pyuic6` 轉 Python** ```bash pyuic6 UI.ui -o UI.py ``` * `pyuic6` 會解析 `.ui` 的 XML,輸出一支純 Python 檔案(大約數百行)。 6. **在主程式匯入 `Ui_MainWindow`** ```python from UI import Ui_MainWindow class MainWindow_controller(QMainWindow): def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) ``` 7. **串接事件與邏輯** * 之後就能寫 `self.ui.pushButton.clicked.connect(self.do_something)` 來綁定功能。 8. **反覆迭代** * UI 改版 → 回 Designer 編輯 → 重新 `pyuic6` → 覆蓋 `UI.py` → Git commit。 > **小提醒**:請避免手動修改 `UI.py`,因為下次重新產生會被覆蓋。若要擴充 UI 行為,應在 Controller 類別中操作,而非直接動 `UI.py`。 --- ## 1 程式的大鋼 1. **PyQt6 主框架** ‑ 產生整體視窗,並匯入 Qt Designer 匯出的 `UI.py`。 2. **`QWebEngineView` 嵌網頁** ‑ 中央區塊載入 `index.html`,裡面跑時間軸、WaveSurfer 音波、Canvas 動畫。 3. **前後端橋梁 – `QtWebChannel`** ‑ 透過 `CallHandler` 暴露 Python API,讓 JavaScript 能呼叫(例如:更新顏色、設定關鍵幀)。 4. **JSON 資料倉庫** ‑ `setting.json`(舞者設定)、`data.json`(顏色幀)、`pos.json`(走位幀)。 5. **UDP 即時同步** ‑ 每當跳到新幀,就把幀號用 UDP 廣播出去,實體 LED 服裝即時跟隨。 掌握這 5 點後,再深入細節就不會迷路。 --- ## 2 檔案開頭:常數與工具函式 ### 2‑1 路徑常數與 UDP socket ```python # editor.py 行25–44 settingjson_path = r"data/setting.json" ... sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) ``` * 我把所有 JSON 路徑集中在檔頭,未來搬資料夾只改這裡。 * `UDP()`(行45–51)把幀號打包成 4 bytes,廣播到 `255.255.255.255:12345`。 ### 2‑2 `loadjson()` / `savejson()` ```python # editor.py 行53–78 def loadjson(path): ... def savejson(path, data): ... ``` * `loadjson()`:若檔案不存在就自動產生預設結構,避免程式直接崩潰。 * `savejson()`:除了寫檔,還把資料同步到 Firebase(行68 之後),多台電腦協作靠它。 --- ## 3 `ColorDelegate`(行86–92) 這個自訂 `QStyledItemDelegate` 讓 `QComboBox` 的每個選項直接顯示背景色,用肉眼挑色最直觀。 --- ## 4 `CallHandler`(行94–113) 前端透過 `QtWebChannel` 呼叫的插槽集中在這裡,例如: | 函式 | 作用 | | ------------------- | ------------------------------------- | | `receiveTime(sec)` | 前端每 1/60 秒回報時間,Python 端據此更新 UI 與 UDP。 | | `updateframe(obj)` | 拖移時間軸的顏色幀標記後呼叫,重排陣列並寫檔。 | | `updatepos(obj)` | 拖舞者位置時即時更新 `pos.json`。 | | `selectdancer(idx)` | 前端點人物縮圖 → 切換下方 ComboBox 顏色區。 | --- ## 5 `MainWindow_controller` 核心(行115–683) 我把它拆成七段說明。 ### 5‑1 建構子 `__init__`(行116–149) 1. `Ui_MainWindow()` 初始化版面。 2. 建立 `QWebEngineView` → 指向 `simulator/index.html`。 3. 啟動 Firebase 監聽,檔案一變就 `async_reload()`。 4. 呼叫 `setup_control()` 把按鈕、快捷鍵、ComboBox 通通綁好。 ### 5‑2 `setup_control()`(行150–214) * 註冊 `CallHandler` → 前端能呼叫 Python。 * 初始化全域狀態:`self.time`、`self.nowframe`、`self.nowPos`、`self.partcolors`… * 預設選到第一位舞者:`dancerselected()`。 ### 5‑3 UI 事件綁定 * `setup_btn()`(行215–242)— 把所有 `QPushButton` 對應到函式。 * `setup_shortcuts()`(行243–272)— 快捷鍵一覽:`1` 存顏色、`G` 播放/暫停、`Z` 新增走位幀…。 > **小技巧**:元件超過十顆就用 dict + 迴圈批次綁定,程式乾淨很多。 ### 5‑4 時間軸互動核心 | 函式 | 行數 | 職責 | 備註 | | --------------------------- | ------- | ----------------------------------- | --------------------------- | | `receivetime` | 304–339 | 前端回報時間,計算 `nowframe/nowPos` 並廣播 UDP | 用 `get_time_index()` 二分搜尋定位 | | `set_frame_start_bynowtime` | 515–533 | 把目前時間標記為「此幀開始」 | 須檢查與前一幀衝突 | | `set_frame_end_bynowtime` | 534–550 | 把目前時間標記為「此幀結束」 | 同理檢查下一幀 | ### 5‑5 顏色編輯流程 1. **載入顏色表** – `setcomboboxcolor()`(361–392) 2. **顯示當前顏色** – `loadcolor()`(394–400) 3. **使用者改色** – `colorchanged()`(420–427)→ 寫回 `data.json` → 前端自動刷新。 ### 5‑6 走位 (`pos.json`) 流程 * `newpos()` / `delpos()`:插入或刪除走位關鍵幀。 * `updatepos()`:拖曳人物時即時寫座標。 * 完成後呼叫 `reloadDataAndRedraw()` 讓網頁重新繪製。 ### 5‑7 除錯 & UDP 小工具 * `debug_btn()` + `debug()`:0.5 秒來回第一、最後一幀,現場排線超好用。 * `UDP_now()`:手動重送幀號,裝置斷訊時救援。 --- ## 6 輔助函式速查表 | 函式 | 行數 | 一句話說明 | | ---------------------------- | ------- | -------------------------------- | | `get_time_index` | 78–93 | 二分搜尋:給定時間 → 回傳它屬於哪段 `time` array | | `settime` | 272–279 | 把文字框秒數塞回前端 `setTime()` | | `zoomin` / `zoomout` | 668–672 | 呼叫前端縮放 WaveSurfer 顯示 | | `scrollleft` / `scrollright` | 673–677 | 時間軸橫向捲動 10 px | 更多細節請自行翻 `editor.py`,函式名稱都很直白。 --- ## 7 技術關鍵 1. **PyQt × Web 混搭** ‑ 用桌面程式包裹 Web 互動,得兩邊優勢。 2. **資料 ↔ UI ↔ 存檔 三向同步** ‑ 保證多端一致性。 3. **快捷功能** ‑ UDP 重廣播、快捷鍵、Debug 閃爍… 緊急狀況救場。 --- ## 8 動手試試看 1. 把 `setting.json` 的舞者名字改掉,再跑程式,看左下角是否跟著變。 2. 在時間軸新增顏色幀,改幾個部位顏色,按 `1` 儲存,重開程式驗證。 3. 換另一首歌路徑,重新載入,WaveSurfer 波形若正常顯示,即設定成功。 完成三步,就能正式使用這套編輯器! --- > 若有任何段落不清楚,歡迎問我或直接用除錯器一步步跑最有效!