From 32c98d4855b6178554c787103dc956d161e152b3 Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期五, 19 十二月 2025 19:45:30 +0800
Subject: [PATCH] 增加了异形分析逻辑

---
 src/yaokong/RemoteControlDialog.java |  628 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 587 insertions(+), 41 deletions(-)

diff --git a/src/yaokong/RemoteControlDialog.java b/src/yaokong/RemoteControlDialog.java
index af45f17..ca29763 100644
--- a/src/yaokong/RemoteControlDialog.java
+++ b/src/yaokong/RemoteControlDialog.java
@@ -20,6 +20,17 @@
     private JLabel moveJoystickValueLabel;
     private JLabel turnJoystickValueLabel;
     private Timer speedUpdateTimer;  // 閫熷害鏇存柊瀹氭椂鍣�
+    // 鎽囨潌鎺у埗瀹氭椂鍣細鎸佺画鍙戦�佹帶鍒舵寚浠�
+    private Timer forwardControlTimer;  // 鍓嶈繘/鍚庨��鎺у埗瀹氭椂鍣�
+    private Timer steeringControlTimer;  // 杞悜鎺у埗瀹氭椂鍣�
+    private int targetForwardSpeed = 0;  // 鐩爣鍓嶈繘/鍚庨��閫熷害
+    private int targetSteeringSpeed = 0;  // 鐩爣杞悜閫熷害
+    // 鐙珛璺熻釜姣忎釜鎽囨潌鐨勫綋鍓嶉�熷害锛岄伩鍏嶇浉浜掑奖鍝�
+    private int independentForwardSpeed = 0;  // 鐙珛鐨勫墠杩涢�熷害锛堜笉鍙楄浆鍚戞憞鏉嗗奖鍝嶏級
+    private int independentSteeringSpeed = 0;  // 鐙珛鐨勮浆鍚戦�熷害锛堜笉鍙楀墠杩涙憞鏉嗗奖鍝嶏級
+    private List<JButton> bladeButtons = new ArrayList<>();  // 瀛樺偍鍒�鐩樻帶鍒舵寜閽紝鐢ㄤ簬娓呯悊瀹氭椂鍣�
+    private String bladeUpDefaultText = "鍒�鐩樺崌";  // 鍒�鐩樺崌鎸夐挳榛樿鏂囧瓧
+    private String bladeDownDefaultText = "鍒�鐩橀檷";  // 鍒�鐩橀檷鎸夐挳榛樿鏂囧瓧
     
     public RemoteControlDialog(Component parent, Color themeColor, JLabel speedLabel) {
         super(parent != null ? (JFrame) SwingUtilities.getWindowAncestor(parent) : null,
@@ -31,7 +42,7 @@
         Control03.resetSpeeds();
         Control03.sendNeutralCommandIfDebugSerialOpen();
         int dialogWidth = UIConfig.DIALOG_WIDTH;  // 涓庨椤靛搴︿竴鑷�
-        int dialogHeight = (int) (UIConfig.DIALOG_HEIGHT / 3.0 * 0.7) + 50 + 40;  // 澧炲姞40鍍忕礌
+        int dialogHeight = (int) (UIConfig.DIALOG_HEIGHT / 3.0 * 0.7) +150;  // 澧炲姞90鍍忕礌锛堝師40+鏂板40+鍐嶅10锛�
         initializeDialog(dialogWidth, dialogHeight);
         initializeRemoteContent();
         startSpeedUpdateTimer();  // 鍚姩閫熷害鏇存柊瀹氭椂鍣�
@@ -54,13 +65,69 @@
         setSize(width, height);
         setLocationRelativeTo(getOwner());
         setResizable(false);
-        getContentPane().setBackground(new Color(26, 26, 46)); // 娣辫壊鑳屾櫙
+        Container contentPane = getContentPane();
+        if (contentPane instanceof JComponent) {
+            JComponent jContentPane = (JComponent) contentPane;
+            jContentPane.setBackground(new Color(0, 0, 0, 0)); // 閫忔槑鑳屾櫙
+            jContentPane.setOpaque(false);
+        }
     }
     
     private void initializeRemoteContent() {
         JPanel contentPanel = new JPanel(new BorderLayout());
         contentPanel.setBorder(BorderFactory.createEmptyBorder(16, 16, 16, 16));
-        contentPanel.setBackground(Color.WHITE);
+        contentPanel.setOpaque(false); // 璁剧疆涓洪�忔槑
+
+        // 鍒涘缓椤堕儴闈㈡澘锛屽寘鍚寜閽拰鏁板�兼樉绀�
+        JPanel topPanel = new JPanel(new BorderLayout());
+        topPanel.setOpaque(false);
+        
+        // 鍒涘缓鎸夐挳闈㈡澘锛�4涓寜閽紝闂撮殧30鍍忕礌锛�
+        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 30, 0));
+        buttonPanel.setOpaque(false);
+        buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 8, 0)); // 搴曢儴闂磋窛8鍍忕礌
+        
+        // 鎸夐挳1锛歰ff.png <-> starton.png锛屾枃瀛楋細鍚姩 <-> 鐔勭伀
+        JLabel label1 = new JLabel("鍚姩", SwingConstants.CENTER);
+        label1.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 12));
+        label1.setForeground(new Color(40, 40, 40));
+        JButton button1 = createIconButtonWithLabel("image/off.png", "image/starton.png", 27, 27, 
+                                                     label1, "鍚姩", "鐔勭伀", "POWER");
+        JPanel panel1 = createButtonWithLabel(button1, label1);
+        buttonPanel.add(panel1);
+        
+        // 鎸夐挳2锛歞engoff.png <-> dengon.png锛屾枃瀛楋細寮�鐏� <-> 鍏崇伅
+        JLabel label2 = new JLabel("寮�鐏�", SwingConstants.CENTER);
+        label2.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 12));
+        label2.setForeground(new Color(40, 40, 40));
+        JButton button2 = createIconButtonWithLabel("image/dengoff.png", "image/dengon.png", 30, 30,
+                                                     label2, "寮�鐏�", "鍏崇伅", "LIGHT");
+        JPanel panel2 = createButtonWithLabel(button2, label2);
+        buttonPanel.add(panel2);
+        
+        // 鎸夐挳3锛歺ia1.png锛堝浐瀹氬浘鏍囷級锛屾枃瀛楋細鍒�鐩樺崌
+        JButton button3 = createBladeControlButton("image/xia1.png", "image/xia20.png", 30, 30, true);
+        JLabel label3 = new JLabel("鍒�鐩樺崌", SwingConstants.CENTER);
+        label3.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 12));
+        label3.setForeground(new Color(40, 40, 40));
+        button3.putClientProperty("label", label3);
+        button3.putClientProperty("defaultText", bladeUpDefaultText);
+        bladeButtons.add(button3);  // 娣诲姞鍒板垪琛ㄤ互渚挎竻鐞�
+        JPanel panel3 = createButtonWithLabel(button3, label3);
+        buttonPanel.add(panel3);
+        
+        // 鎸夐挳4锛歺ia2.png锛堝浐瀹氬浘鏍囷級锛屾枃瀛楋細鍒�鐩橀檷
+        JButton button4 = createBladeControlButton("image/xia2.png", "image/xia10.png", 30, 30, false);
+        JLabel label4 = new JLabel("鍒�鐩橀檷", SwingConstants.CENTER);
+        label4.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 12));
+        label4.setForeground(new Color(40, 40, 40));
+        button4.putClientProperty("label", label4);
+        button4.putClientProperty("defaultText", bladeDownDefaultText);
+        bladeButtons.add(button4);  // 娣诲姞鍒板垪琛ㄤ互渚挎竻鐞�
+        JPanel panel4 = createButtonWithLabel(button4, label4);
+        buttonPanel.add(panel4);
+        
+        topPanel.add(buttonPanel, BorderLayout.NORTH);
 
         // 鍦ㄦ瘡涓憞鏉嗕笂鏂瑰垎鍒樉绀哄叾鐘舵��/鏁板�硷紙鍒嗕袱鍒楋級
         JPanel valuesPanel = new JPanel(new GridLayout(1, 2, 20, 0));
@@ -80,57 +147,91 @@
 
         valuesPanel.add(moveJoystickValueLabel);
         valuesPanel.add(turnJoystickValueLabel);
-        contentPanel.add(valuesPanel, BorderLayout.NORTH);
+        topPanel.add(valuesPanel, BorderLayout.CENTER);
+        
+        contentPanel.add(topPanel, BorderLayout.NORTH);
 
         // 鍒涘缓鎽囨潌闈㈡澘
         JPanel joystickPanel = new JPanel(new GridLayout(1, 2, 20, 0));
         joystickPanel.setOpaque(false);
 
         // 绉诲姩鎽囨潌锛堢豢鑹蹭富棰橈級
-        moveJoystick = new ModernJoystickComponent("鍓嶈繘/鍚庨��", 
+        moveJoystick = new ModernJoystickComponent(" ", 
             new Color(46, 204, 113), true);  // 缁胯壊涓婚
         moveJoystick.setJoystickListener(new JoystickListener() {
             @Override
             public void onJoystickMoved(double x, double y) {
-                // 鍙娇鐢╕杞存帶鍒跺墠杩涘悗閫�锛屽悜涓婏紙鍖楋級涓烘
-                // 璁$畻骞跺洓鑸嶄簲鍏ュ埌鏁存暟閫熷害鍊硷紝姝d负鍓嶈繘锛岃礋涓哄悗閫�
+                // 鍙娇鐢╕杞存帶鍒跺墠杩涘悗閫�
+                // y鍊艰寖鍥达細-1.0锛堝悜涓婏級鍒� 1.0锛堝悜涓嬶級
+                // 璁$畻閫熷害鍊硷細鍚戜笅锛坹>0锛変负鍚庨��锛堣礋鍊硷級锛屽悜涓婏紙y<0锛変负鍓嶈繘锛堟鍊硷級
+                // 鍚庨��鍊艰寖鍥达細0 鍒� -100锛屽墠杩涘�艰寖鍥达細0 鍒� 100
                 int forwardVal = (int) Math.round(-y * 100.0);
                 // 闄愬埗鍦� [-100, 100]
                 forwardVal = Math.max(-100, Math.min(100, forwardVal));
 
-                if (Math.abs(y) > 0.1) {
-                    applyForwardSpeed(forwardVal);
-                } else {
-                    // 鍓嶅悗
-                    stopForward();
+                // 姝诲尯澶勭悊锛氬鏋滈�熷害鍊煎湪-10鍒�10涔嬮棿锛岃涓�0锛堥伩鍏嶅井灏忔姈鍔級
+                if (Math.abs(forwardVal) <= 10) {
+                    forwardVal = 0;
                 }
 
-                // 鏇存柊椤堕儴鏄剧ず锛堢Щ鍔ㄦ樉绀哄綋鍓嶅墠杩�/鍚庨��閫熷害锛岃浆鍚戝彇褰撳墠杞悜閫熷害浣滀负鍙傝�冿級
-                int steeringVal = Control03.getCurrentSteeringSpeed();
-                updateJoystickValues(forwardVal, steeringVal);
+                // 鏇存柊鐩爣閫熷害鍜岀嫭绔嬮�熷害
+                targetForwardSpeed = forwardVal;
+                independentForwardSpeed = forwardVal;
+
+                if (forwardVal != 0) {
+                    // 鎽囨潌涓嶅湪姝诲尯锛屽惎鍔ㄦ寔缁彂閫佸畾鏃跺櫒
+                    // 鍚庨��鏃� forwardVal 涓鸿礋鍊硷紙-100鍒�-11锛夛紝鍓嶈繘鏃� forwardVal 涓烘鍊硷紙11鍒�100锛�
+                    startForwardControlTimer();
+                } else {
+                    // 鎽囨潌鍦ㄦ鍖烘垨涓績浣嶇疆锛屽仠姝㈠畾鏃跺櫒
+                    stopForwardControlTimer();
+                    // 灏嗙嫭绔嬬殑鍓嶈繘閫熷害璁剧疆涓�0
+                    independentForwardSpeed = 0;
+                    // 鍙戦�佸仠姝㈡寚浠わ紙淇濇寔杞悜閫熷害涓嶅彉锛�
+                    Control03.setAndSendSpeeds(independentSteeringSpeed, 0);
+                }
+
+                // 鏇存柊椤堕儴鏄剧ず锛堜娇鐢ㄧ嫭绔嬬殑閫熷害鍊硷級
+                updateJoystickValues(forwardVal, independentSteeringSpeed);
             }
         });
         // 杞悜鎽囨潌锛堣摑鑹蹭富棰橈級
-        turnJoystick = new ModernJoystickComponent("宸﹁浆/鍙宠浆", 
+        turnJoystick = new ModernJoystickComponent("", 
             new Color(52, 152, 219), false);  // 钃濊壊涓婚
         turnJoystick.setJoystickListener(new JoystickListener() {
             @Override
             public void onJoystickMoved(double x, double y) {
-                // 鍙娇鐢╔杞存帶鍒跺乏鍙宠浆鍚戯紝鍚戝彸涓烘
-                // 璁$畻骞跺洓鑸嶄簲鍏ュ埌鏁存暟杞悜鍊硷紝姝d负鍙宠浆锛岃礋涓哄乏杞�
+                // 鍙娇鐢╔杞存帶鍒跺乏鍙宠浆鍚�
+                // x鍊艰寖鍥达細-1.0锛堝悜宸︼級鍒� 1.0锛堝悜鍙筹級
+                // 璁$畻杞悜鍊硷細鍚戝乏锛坸<0锛変负宸﹁浆锛堣礋鍊硷級锛屽悜鍙筹紙x>0锛変负鍙宠浆锛堟鍊硷級
+                // 宸﹁浆鍊艰寖鍥达細0 鍒� -100锛屽彸杞�艰寖鍥达細0 鍒� 100
                 int steeringVal = (int) Math.round(x * 100.0);
                 steeringVal = Math.max(-100, Math.min(100, steeringVal));
 
-                if (Math.abs(x) > 0.1) {
-                    applySteeringSpeed(steeringVal);
-                } else {
-                    // 宸﹀彸
-                    stopSteering();
+                // 姝诲尯澶勭悊锛氬鏋滈�熷害鍊煎湪-10鍒�10涔嬮棿锛岃涓�0锛堥伩鍏嶅井灏忔姈鍔級
+                if (Math.abs(steeringVal) <= 10) {
+                    steeringVal = 0;
                 }
 
-                // 鏇存柊椤堕儴鏄剧ず锛堣浆鍚戞樉绀哄綋鍓嶈浆鍚戦�熷害锛岀Щ鍔ㄦ樉绀哄綋鍓嶅墠杩涢�熷害锛�
-                int forwardVal = Control03.getCurrentForwardSpeed();
-                updateJoystickValues(forwardVal, steeringVal);
+                // 鏇存柊鐩爣閫熷害鍜岀嫭绔嬮�熷害
+                targetSteeringSpeed = steeringVal;
+                independentSteeringSpeed = steeringVal;
+
+                if (steeringVal != 0) {
+                    // 鎽囨潌涓嶅湪姝诲尯锛屽惎鍔ㄦ寔缁彂閫佸畾鏃跺櫒
+                    // 宸﹁浆鏃� steeringVal 涓鸿礋鍊硷紙-100鍒�-11锛夛紝鍙宠浆鏃� steeringVal 涓烘鍊硷紙11鍒�100锛�
+                    startSteeringControlTimer();
+                } else {
+                    // 鎽囨潌鍦ㄦ鍖烘垨涓績浣嶇疆锛屽仠姝㈠畾鏃跺櫒
+                    stopSteeringControlTimer();
+                    // 灏嗙嫭绔嬬殑杞悜閫熷害璁剧疆涓�0
+                    independentSteeringSpeed = 0;
+                    // 鍙戦�佸仠姝㈡寚浠わ紙淇濇寔鍓嶈繘閫熷害涓嶅彉锛�
+                    Control03.setAndSendSpeeds(0, independentForwardSpeed);
+                }
+
+                // 鏇存柊椤堕儴鏄剧ず锛堜娇鐢ㄧ嫭绔嬬殑閫熷害鍊硷級
+                updateJoystickValues(independentForwardSpeed, steeringVal);
             }
         });
         joystickPanel.add(moveJoystick);
@@ -142,6 +243,360 @@
         getContentPane().add(contentPanel);
     }
 
+    /**
+     * 鍒涘缓甯︽爣绛剧殑鎸夐挳闈㈡澘锛堝瀭鐩村竷灞�锛氭寜閽湪涓婏紝鏍囩鍦ㄤ笅锛�
+     * @param button 鎸夐挳
+     * @param label 鏍囩
+     * @return 鍖呭惈鎸夐挳鍜屾爣绛剧殑闈㈡澘
+     */
+    private JPanel createButtonWithLabel(JButton button, JLabel label) {
+        JPanel panel = new JPanel(new BorderLayout());
+        panel.setOpaque(false);
+        panel.add(button, BorderLayout.CENTER);
+        panel.add(label, BorderLayout.SOUTH);
+        panel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+        return panel;
+    }
+
+    /**
+     * 鍒涘缓鍙垏鎹㈠浘鏍囩殑鎸夐挳锛堝甫鏍囩鏂囧瓧鍒囨崲锛�
+     * @param defaultIconPath 榛樿鍥炬爣璺緞
+     * @param clickedIconPath 鐐瑰嚮鍚庣殑鍥炬爣璺緞
+     * @param width 鍥炬爣瀹藉害
+     * @param height 鍥炬爣楂樺害
+     * @param label 鏍囩缁勪欢
+     * @param defaultText 榛樿鏂囧瓧
+     * @param clickedText 鐐瑰嚮鍚庣殑鏂囧瓧
+     * @param controlType 鎺у埗鎸囦护绫诲瀷锛�"POWER"琛ㄧず鍚姩/鐔勭伀锛�"LIGHT"琛ㄧず寮�鐏�/鍏崇伅锛宯ull琛ㄧず鏃犳帶鍒舵寚浠�
+     * @return 閰嶇疆濂界殑鎸夐挳
+     */
+    private JButton createIconButtonWithLabel(String defaultIconPath, String clickedIconPath, 
+                                               int width, int height, JLabel label, 
+                                               String defaultText, String clickedText, String controlType) {
+        JButton button = new JButton();
+        button.setPreferredSize(new Dimension(width, height));
+        button.setMinimumSize(new Dimension(width, height));
+        button.setMaximumSize(new Dimension(width, height));
+        button.setContentAreaFilled(false);
+        button.setBorderPainted(false);
+        button.setFocusPainted(false);
+        
+        // 鍔犺浇榛樿鍥炬爣鍜岀偣鍑诲浘鏍�
+        ImageIcon defaultIcon = loadIcon(defaultIconPath, width, height);
+        ImageIcon clickedIcon = loadIcon(clickedIconPath, width, height);
+        
+        if (defaultIcon != null) {
+            button.setIcon(defaultIcon);
+        }
+        
+        // 浣跨敤 clientProperty 鏉ヨ窡韪寜閽姸鎬侊紙false=榛樿鍥炬爣锛宼rue=鐐瑰嚮鍥炬爣锛�
+        button.putClientProperty("isClicked", false);
+        button.putClientProperty("defaultIcon", defaultIcon);
+        button.putClientProperty("clickedIcon", clickedIcon);
+        button.putClientProperty("label", label);
+        button.putClientProperty("defaultText", defaultText);
+        button.putClientProperty("clickedText", clickedText);
+        button.putClientProperty("controlType", controlType);
+        
+        // 娣诲姞鐐瑰嚮浜嬩欢锛屽垏鎹㈠浘鏍囧拰鏂囧瓧锛屽苟鍙戦�佹帶鍒舵寚浠�
+        button.addActionListener(e -> {
+            Boolean isClicked = (Boolean) button.getClientProperty("isClicked");
+            ImageIcon defaultIconRef = (ImageIcon) button.getClientProperty("defaultIcon");
+            ImageIcon clickedIconRef = (ImageIcon) button.getClientProperty("clickedIcon");
+            JLabel labelRef = (JLabel) button.getClientProperty("label");
+            String defaultTextRef = (String) button.getClientProperty("defaultText");
+            String clickedTextRef = (String) button.getClientProperty("clickedText");
+            String controlTypeRef = (String) button.getClientProperty("controlType");
+            
+            if (isClicked == null || !isClicked) {
+                // 褰撳墠鏄粯璁ゅ浘鏍囷紝鍒囨崲鍒扮偣鍑诲浘鏍�
+                if (clickedIconRef != null) {
+                    button.setIcon(clickedIconRef);
+                    button.putClientProperty("isClicked", true);
+                }
+                // 鏇存柊鏍囩鏂囧瓧
+                if (labelRef != null && clickedTextRef != null) {
+                    labelRef.setText(clickedTextRef);
+                }
+                // 鍙戦�佹帶鍒舵寚浠わ紙寮�鍚級
+                if ("POWER".equals(controlTypeRef)) {
+                    boolean success = Control05.sendPowerOnIfDebugSerialOpen();
+                    if (!success) {
+                        showSerialClosedWarning();
+                    }
+                } else if ("LIGHT".equals(controlTypeRef)) {
+                    boolean success = Control07.sendLightOnIfDebugSerialOpen();
+                    if (!success) {
+                        showSerialClosedWarning();
+                    }
+                }
+            } else {
+                // 褰撳墠鏄偣鍑诲浘鏍囷紝鍒囨崲鍥為粯璁ゅ浘鏍�
+                if (defaultIconRef != null) {
+                    button.setIcon(defaultIconRef);
+                    button.putClientProperty("isClicked", false);
+                }
+                // 鏇存柊鏍囩鏂囧瓧
+                if (labelRef != null && defaultTextRef != null) {
+                    labelRef.setText(defaultTextRef);
+                }
+                // 鍙戦�佹帶鍒舵寚浠わ紙鍏抽棴锛�
+                if ("POWER".equals(controlTypeRef)) {
+                    boolean success = Control05.sendPowerOffIfDebugSerialOpen();
+                    if (!success) {
+                        showSerialClosedWarning();
+                    }
+                } else if ("LIGHT".equals(controlTypeRef)) {
+                    boolean success = Control07.sendLightOffIfDebugSerialOpen();
+                    if (!success) {
+                        showSerialClosedWarning();
+                    }
+                }
+            }
+        });
+        
+        return button;
+    }
+
+    /**
+     * 鍒涘缓鍙垏鎹㈠浘鏍囩殑鎸夐挳
+     * @param defaultIconPath 榛樿鍥炬爣璺緞
+     * @param clickedIconPath 鐐瑰嚮鍚庣殑鍥炬爣璺緞
+     * @param width 鍥炬爣瀹藉害
+     * @param height 鍥炬爣楂樺害
+     * @return 閰嶇疆濂界殑鎸夐挳
+     */
+    private JButton createIconButton(String defaultIconPath, String clickedIconPath, int width, int height) {
+        JButton button = new JButton();
+        button.setPreferredSize(new Dimension(width, height));
+        button.setMinimumSize(new Dimension(width, height));
+        button.setMaximumSize(new Dimension(width, height));
+        button.setContentAreaFilled(false);
+        button.setBorderPainted(false);
+        button.setFocusPainted(false);
+        
+        // 鍔犺浇榛樿鍥炬爣鍜岀偣鍑诲浘鏍�
+        ImageIcon defaultIcon = loadIcon(defaultIconPath, width, height);
+        ImageIcon clickedIcon = loadIcon(clickedIconPath, width, height);
+        
+        if (defaultIcon != null) {
+            button.setIcon(defaultIcon);
+        }
+        
+        // 浣跨敤 clientProperty 鏉ヨ窡韪寜閽姸鎬侊紙false=榛樿鍥炬爣锛宼rue=鐐瑰嚮鍥炬爣锛�
+        button.putClientProperty("isClicked", false);
+        button.putClientProperty("defaultIcon", defaultIcon);
+        button.putClientProperty("clickedIcon", clickedIcon);
+        
+        // 娣诲姞鐐瑰嚮浜嬩欢锛屽垏鎹㈠浘鏍�
+        button.addActionListener(e -> {
+            Boolean isClicked = (Boolean) button.getClientProperty("isClicked");
+            ImageIcon defaultIconRef = (ImageIcon) button.getClientProperty("defaultIcon");
+            ImageIcon clickedIconRef = (ImageIcon) button.getClientProperty("clickedIcon");
+            
+            if (isClicked == null || !isClicked) {
+                // 褰撳墠鏄粯璁ゅ浘鏍囷紝鍒囨崲鍒扮偣鍑诲浘鏍�
+                if (clickedIconRef != null) {
+                    button.setIcon(clickedIconRef);
+                    button.putClientProperty("isClicked", true);
+                }
+            } else {
+                // 褰撳墠鏄偣鍑诲浘鏍囷紝鍒囨崲鍥為粯璁ゅ浘鏍�
+                if (defaultIconRef != null) {
+                    button.setIcon(defaultIconRef);
+                    button.putClientProperty("isClicked", false);
+                }
+            }
+        });
+        
+        return button;
+    }
+
+    /**
+     * 鍒涘缓鍥哄畾鍥炬爣鐨勬寜閽�
+     * @param iconPath 鍥炬爣璺緞
+     * @param width 鍥炬爣瀹藉害
+     * @param height 鍥炬爣楂樺害
+     * @return 閰嶇疆濂界殑鎸夐挳
+     */
+    private JButton createFixedIconButton(String iconPath, int width, int height) {
+        JButton button = new JButton();
+        button.setPreferredSize(new Dimension(width, height));
+        button.setMinimumSize(new Dimension(width, height));
+        button.setMaximumSize(new Dimension(width, height));
+        button.setContentAreaFilled(false);
+        button.setBorderPainted(false);
+        button.setFocusPainted(false);
+        
+        ImageIcon icon = loadIcon(iconPath, width, height);
+        if (icon != null) {
+            button.setIcon(icon);
+        }
+        
+        return button;
+    }
+
+    /**
+     * 鍒涘缓鍒�鐩樺崌闄嶆帶鍒舵寜閽紙鏀寔鐐瑰嚮鍜岄暱鎸夛級
+     * @param defaultIconPath 榛樿鍥炬爣璺緞
+     * @param clickedIconPath 鐐瑰嚮/闀挎寜鏃剁殑鍥炬爣璺緞
+     * @param width 鍥炬爣瀹藉害
+     * @param height 鍥炬爣楂樺害
+     * @param isUp true琛ㄧず鍒�鐩樺崌锛宖alse琛ㄧず鍒�鐩橀檷
+     * @return 閰嶇疆濂界殑鎸夐挳
+     */
+    private JButton createBladeControlButton(String defaultIconPath, String clickedIconPath, 
+                                             int width, int height, boolean isUp) {
+        JButton button = new JButton();
+        button.setPreferredSize(new Dimension(width, height));
+        button.setMinimumSize(new Dimension(width, height));
+        button.setMaximumSize(new Dimension(width, height));
+        button.setContentAreaFilled(false);
+        button.setBorderPainted(false);
+        button.setFocusPainted(false);
+        
+        // 鍔犺浇鍥炬爣
+        ImageIcon defaultIcon = loadIcon(defaultIconPath, width, height);
+        ImageIcon clickedIcon = loadIcon(clickedIconPath, width, height);
+        
+        if (defaultIcon != null) {
+            button.setIcon(defaultIcon);
+        }
+        
+        button.putClientProperty("defaultIcon", defaultIcon);
+        button.putClientProperty("clickedIcon", clickedIcon);
+        button.putClientProperty("isUp", isUp);
+        button.putClientProperty("isPressed", false);
+        
+        // 闀挎寜瀹氭椂鍣�
+        Timer longPressTimer = new Timer(100, e -> {  // 姣�100ms鎵ц涓�娆�
+            if (button.getClientProperty("isPressed") == Boolean.TRUE) {
+                boolean isUpButton = (Boolean) button.getClientProperty("isUp");
+                int currentHeight = Control06.getCurrentBladeHeight();
+                
+                // 浣跨敤Control06鐨勬柟娉曞彂閫佹寚浠�
+                boolean success;
+                if (isUpButton) {
+                    success = Control06.sendBladeUpIfDebugSerialOpen(1);
+                } else {
+                    success = Control06.sendBladeDownIfDebugSerialOpen(1);
+                }
+                
+                if (!success) {
+                    showSerialClosedWarning();
+                } else {
+                    // 鏇存柊鎸夐挳鏍囩鏄剧ず褰撳墠鏁板��
+                    updateBladeButtonLabel(button);
+                }
+            }
+        });
+        longPressTimer.setInitialDelay(500);  // 闀挎寜500ms鍚庡紑濮嬭繛缁彉鍖�
+        button.putClientProperty("longPressTimer", longPressTimer);  // 瀛樺偍瀹氭椂鍣ㄥ紩鐢�
+        
+        // 榧犳爣鎸変笅浜嬩欢
+        button.addMouseListener(new MouseAdapter() {
+            @Override
+            public void mousePressed(MouseEvent e) {
+                button.putClientProperty("isPressed", true);
+                
+                // 绔嬪嵆鍒囨崲鍥炬爣
+                ImageIcon clickedIconRef = (ImageIcon) button.getClientProperty("clickedIcon");
+                if (clickedIconRef != null) {
+                    button.setIcon(clickedIconRef);
+                }
+                
+                // 鐐瑰嚮鏃剁珛鍗冲鍔�/鍑忓皯10锛屼娇鐢–ontrol06鐨勬柟娉曞彂閫佹寚浠�
+                boolean isUpButton = (Boolean) button.getClientProperty("isUp");
+                boolean success;
+                if (isUpButton) {
+                    success = Control06.sendBladeUpIfDebugSerialOpen(10);
+                } else {
+                    success = Control06.sendBladeDownIfDebugSerialOpen(10);
+                }
+                
+                if (!success) {
+                    showSerialClosedWarning();
+                } else {
+                    // 鏇存柊鎸夐挳鏍囩鏄剧ず褰撳墠鏁板��
+                    updateBladeButtonLabel(button);
+                }
+                
+                // 鍚姩闀挎寜瀹氭椂鍣�
+                longPressTimer.start();
+            }
+            
+            @Override
+            public void mouseReleased(MouseEvent e) {
+                button.putClientProperty("isPressed", false);
+                
+                // 鍋滄闀挎寜瀹氭椂鍣�
+                longPressTimer.stop();
+                
+                // 鎭㈠榛樿鍥炬爣
+                ImageIcon defaultIconRef = (ImageIcon) button.getClientProperty("defaultIcon");
+                if (defaultIconRef != null) {
+                    button.setIcon(defaultIconRef);
+                }
+                
+                // 鎭㈠榛樿鏂囧瓧
+                JLabel labelRef = (JLabel) button.getClientProperty("label");
+                String defaultTextRef = (String) button.getClientProperty("defaultText");
+                if (labelRef != null && defaultTextRef != null) {
+                    labelRef.setText(defaultTextRef);
+                }
+            }
+        });
+        
+        return button;
+    }
+
+    /**
+     * 鏇存柊鍒�鐩樻寜閽爣绛炬樉绀哄綋鍓嶆暟鍊�
+     * @param button 鎸夐挳
+     */
+    private void updateBladeButtonLabel(JButton button) {
+        JLabel labelRef = (JLabel) button.getClientProperty("label");
+        if (labelRef != null) {
+            String defaultTextRef = (String) button.getClientProperty("defaultText");
+            int currentHeight = Control06.getCurrentBladeHeight();
+            String displayText = defaultTextRef + " " + currentHeight;
+            labelRef.setText(displayText);
+        }
+    }
+
+    /**
+     * 鍔犺浇骞剁缉鏀惧浘鏍�
+     * @param iconPath 鍥炬爣璺緞
+     * @param width 鐩爣瀹藉害
+     * @param height 鐩爣楂樺害
+     * @return 缂╂斁鍚庣殑鍥炬爣
+     */
+    private ImageIcon loadIcon(String iconPath, int width, int height) {
+        try {
+            java.net.URL imgURL = getClass().getClassLoader().getResource(iconPath);
+            if (imgURL == null) {
+                // 灏濊瘯浠庢枃浠剁郴缁熷姞杞�
+                java.io.File imgFile = new java.io.File(iconPath);
+                if (imgFile.exists()) {
+                    ImageIcon originalIcon = new ImageIcon(imgFile.getAbsolutePath());
+                    Image scaledImage = originalIcon.getImage().getScaledInstance(width, height, Image.SCALE_SMOOTH);
+                    ImageIcon scaledIcon = new ImageIcon(scaledImage);
+                    scaledIcon.setDescription(iconPath);
+                    return scaledIcon;
+                }
+            } else {
+                ImageIcon originalIcon = new ImageIcon(imgURL);
+                Image scaledImage = originalIcon.getImage().getScaledInstance(width, height, Image.SCALE_SMOOTH);
+                ImageIcon scaledIcon = new ImageIcon(scaledImage);
+                scaledIcon.setDescription(iconPath);
+                return scaledIcon;
+            }
+        } catch (Exception e) {
+            System.err.println("鏃犳硶鍔犺浇鍥炬爣: " + iconPath + " - " + e.getMessage());
+        }
+        return null;
+    }
+
     private JPanel createStatusPanel(String label, String value, Color color) {
         JPanel panel = new JPanel(new BorderLayout(0, 5));
         panel.setOpaque(false);
@@ -195,14 +650,9 @@
     }
 
     private void stopForward() {
-        if (Control03.getCurrentForwardSpeed() != 0) {
-            boolean success = Control03.approachForwardSpeedToZero(20);
-            if (!success) {
-                showSerialClosedWarning();
-                return;
-            }
-            serialWarningShown = false;
-        }
+        // 灏嗙嫭绔嬬殑鍓嶈繘閫熷害璁剧疆涓�0锛屼繚鎸佽浆鍚戦�熷害涓嶅彉
+        independentForwardSpeed = 0;
+        Control03.setAndSendSpeeds(independentSteeringSpeed, 0);
     }
 
     private void applySteeringSpeed(int speed) {
@@ -225,14 +675,93 @@
     }
 
     private void stopSteering() {
-        if (Control03.getCurrentSteeringSpeed() != 0) {
-            boolean success = Control03.approachSteeringSpeedToZero(25);
-            if (!success) {
-                showSerialClosedWarning();
-                return;
-            }
-            serialWarningShown = false;
+        // 灏嗙嫭绔嬬殑杞悜閫熷害璁剧疆涓�0锛屼繚鎸佸墠杩涢�熷害涓嶅彉
+        independentSteeringSpeed = 0;
+        Control03.setAndSendSpeeds(0, independentForwardSpeed);
+    }
+
+    /**
+     * 鍚姩鍓嶈繘/鍚庨��鎺у埗瀹氭椂鍣紝鎸佺画鍙戦�佹帶鍒舵寚浠�
+     */
+    private void startForwardControlTimer() {
+        // 濡傛灉瀹氭椂鍣ㄥ凡缁忓湪杩愯锛屽厛鍋滄瀹�
+        if (forwardControlTimer != null && forwardControlTimer.isRunning()) {
+            forwardControlTimer.stop();
         }
+        
+        // 鍒涘缓鏂扮殑瀹氭椂鍣紝姣�100ms鍙戦�佷竴娆℃寚浠�
+        forwardControlTimer = new Timer(100, new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                // 鎸佺画鍙戦�佺洰鏍囬�熷害鐨勬寚浠�
+                applyForwardSpeedContinuously(targetForwardSpeed);
+            }
+        });
+        forwardControlTimer.setInitialDelay(0);
+        forwardControlTimer.start();
+    }
+
+    /**
+     * 鍋滄鍓嶈繘/鍚庨��鎺у埗瀹氭椂鍣�
+     */
+    private void stopForwardControlTimer() {
+        if (forwardControlTimer != null && forwardControlTimer.isRunning()) {
+            forwardControlTimer.stop();
+        }
+    }
+
+    /**
+     * 鍚姩杞悜鎺у埗瀹氭椂鍣紝鎸佺画鍙戦�佹帶鍒舵寚浠�
+     */
+    private void startSteeringControlTimer() {
+        // 濡傛灉瀹氭椂鍣ㄥ凡缁忓湪杩愯锛屽厛鍋滄瀹�
+        if (steeringControlTimer != null && steeringControlTimer.isRunning()) {
+            steeringControlTimer.stop();
+        }
+        
+        // 鍒涘缓鏂扮殑瀹氭椂鍣紝姣�100ms鍙戦�佷竴娆℃寚浠�
+        steeringControlTimer = new Timer(100, new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                // 鎸佺画鍙戦�佺洰鏍囬�熷害鐨勬寚浠�
+                applySteeringSpeedContinuously(targetSteeringSpeed);
+            }
+        });
+        steeringControlTimer.setInitialDelay(0);
+        steeringControlTimer.start();
+    }
+
+    /**
+     * 鍋滄杞悜鎺у埗瀹氭椂鍣�
+     */
+    private void stopSteeringControlTimer() {
+        if (steeringControlTimer != null && steeringControlTimer.isRunning()) {
+            steeringControlTimer.stop();
+        }
+    }
+
+    /**
+     * 鎸佺画鍙戦�佸墠杩�/鍚庨��閫熷害鎸囦护
+     */
+    private void applyForwardSpeedContinuously(int targetSpeed) {
+        // 鏇存柊鐙珛鐨勫墠杩涢�熷害
+        independentForwardSpeed = targetSpeed;
+        
+        // 浣跨敤鐙珛鐨勮浆鍚戦�熷害锛堜笉鍙楀墠杩涙憞鏉嗗奖鍝嶏級锛屽彧鏇存柊鍓嶈繘閫熷害
+        // 杩欐牱鍓嶈繘鎽囨潌鐨勬搷浣滀笉浼氬奖鍝嶈浆鍚戦�熷害
+        Control03.setAndSendSpeeds(independentSteeringSpeed, independentForwardSpeed);
+    }
+
+    /**
+     * 鎸佺画鍙戦�佽浆鍚戦�熷害鎸囦护
+     */
+    private void applySteeringSpeedContinuously(int targetSpeed) {
+        // 鏇存柊鐙珛鐨勮浆鍚戦�熷害
+        independentSteeringSpeed = targetSpeed;
+        
+        // 浣跨敤鐙珛鐨勫墠杩涢�熷害锛堜笉鍙楄浆鍚戞憞鏉嗗奖鍝嶏級锛屽彧鏇存柊杞悜閫熷害
+        // 杩欐牱杞悜鎽囨潌鐨勬搷浣滀笉浼氬奖鍝嶅墠杩涢�熷害
+        Control03.setAndSendSpeeds(independentSteeringSpeed, independentForwardSpeed);
     }
 
     // 鏇存柊椤堕儴鏄剧ず鐨勬憞鏉嗘暟鍊硷紙鍦� EDT 涓婅皟鐢級锛屾枃瀛楁牴鎹暟鍊兼槧灏勪负鏂瑰悜鎻忚堪
@@ -330,6 +859,15 @@
 
     @Override
     public void dispose() {
+        // 鍋滄骞舵竻鐞嗘帶鍒跺畾鏃跺櫒
+        stopForwardControlTimer();
+        stopSteeringControlTimer();
+        if (forwardControlTimer != null) {
+            forwardControlTimer = null;
+        }
+        if (steeringControlTimer != null) {
+            steeringControlTimer = null;
+        }
         // 鍓嶅悗閫熷害鏇存柊瀹氭椂鍣�
         if (speedUpdateTimer != null) {
             speedUpdateTimer.stop();
@@ -349,6 +887,14 @@
         if (turnJoystick != null) {
             turnJoystick.dispose();
         }
+        // 鍋滄骞舵竻鐞嗗垁鐩樻寜閽殑瀹氭椂鍣�
+        for (JButton bladeButton : bladeButtons) {
+            Timer timer = (Timer) bladeButton.getClientProperty("longPressTimer");
+            if (timer != null && timer.isRunning()) {
+                timer.stop();
+            }
+        }
+        bladeButtons.clear();
         super.dispose();
     }
 

--
Gitblit v1.10.0