826220679@qq.com
2 天以前 48ee74129bb09a817a0bbbabe860c4007b74c66b
src/set/Sets.java
@@ -1,35 +1,42 @@
package set;
import baseStation.BaseStation;
import gecaoji.Device;
import gecaoji.MowerSafetyDistanceCalculator;
import publicway.buttonset;
import zhuye.MapRenderer;
import zhuye.Shouye;
import zhuye.celiangmoshi;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
 * 设置对话框 - 参考Shouye.java样式
 */
public class Sets extends JDialog {
    private static final long serialVersionUID = 1L;
    private static final int ROW_HEIGHT = 40;
    private static final int ROW_SPACING = 25;
    private static final int ROW_HEIGHT = 50;  // 增加行高以适应分割线
    private static final int ITEM_PADDING = 16;  // 列表项内边距
    
    // 主题颜色
    private final Color THEME_COLOR;
    private final Color BACKGROUND_COLOR = new Color(250, 250, 250);
    private final Color PANEL_BACKGROUND = new Color(255, 255, 255);
    private final Color BORDER_COLOR = new Color(220, 220, 220);
    private final Color BACKGROUND_COLOR = new Color(245, 247, 250);  // 更柔和的浅灰色背景
    private final Color PANEL_BACKGROUND = new Color(255, 255, 255);  // 白色面板
    private final Color BORDER_COLOR = new Color(233, 236, 239);  // 浅边框色
    private final Color DIVIDER_COLOR = new Color(233, 236, 239);  // 分割线颜色
    
    // 设置项组件
    private JLabel mowerIdLabel;
    private JLabel mowerSizeLabel;
    private JLabel mowingSafetyDistanceLabel;
    private JLabel baseStationIdLabel;
    private JLabel handheldMarkerLabel;
    private JLabel simCardNumberLabel;
@@ -37,12 +44,16 @@
    private JLabel firmwareVersionLabel;
    private JLabel appVersionLabel;
    private JLabel idleTrailDurationLabel;
    private JLabel boundaryLengthVisibleLabel;
    private JLabel measurementModeEnabledLabel;
    private JLabel manualBoundaryDrawingModeLabel;
    
    private JButton mowerIdEditBtn;
    private JButton mowerSizeEditBtn;
    private JButton mowingSafetyDistanceEditBtn;
    private JButton baseStationIdEditBtn;
    private JButton handheldEditBtn;
    private JButton checkUpdateBtn;
    private JButton systemDebugButton;
    private JButton feedbackButton;
    private JButton idleTrailEditBtn;
    
@@ -77,30 +88,42 @@
        setLocationRelativeTo(getParent());
        setResizable(false);
        
        // 创建主内容面板
        // 创建主内容面板(使用更柔和的浅灰色背景)
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
        mainPanel.setLayout(new BorderLayout());
        mainPanel.setBackground(BACKGROUND_COLOR);
        mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        
        // 创建设置项面板
        // 创建设置项面板(圆角白色面板)
        JPanel settingsPanel = createSettingsPanel();
        
        // 添加组件到主面板
        mainPanel.add(settingsPanel);
        mainPanel.add(Box.createVerticalGlue());
        mainPanel.add(settingsPanel, BorderLayout.CENTER);
        
        add(mainPanel, BorderLayout.CENTER);
    }
    
    private JPanel createSettingsPanel() {
        // 创建圆角白色面板容器
        JPanel container = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setColor(PANEL_BACKGROUND);
                // 绘制圆角矩形背景
                g2d.fillRoundRect(0, 0, getWidth(), getHeight(), 16, 16);
                g2d.dispose();
            }
        };
        container.setLayout(new BorderLayout());
        container.setOpaque(false);
        // 内容面板
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        panel.setBackground(PANEL_BACKGROUND);
        panel.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(BORDER_COLOR),
            BorderFactory.createEmptyBorder(20, 20, 20, 20)
        ));
        panel.setOpaque(false);
        panel.setBorder(BorderFactory.createEmptyBorder(8, 0, 8, 0));
        
        // 割草机编号
        JPanel mowerIdPanel = createSettingItemPanel("割草机编号", 
@@ -108,6 +131,18 @@
        mowerIdLabel = (JLabel) mowerIdPanel.getClientProperty("valueLabel");
        mowerIdEditBtn = (JButton) mowerIdPanel.getClientProperty("editButton");
        // 割草机长宽
        JPanel mowerSizePanel = createSettingItemPanel("割草机长宽",
            formatMowerSize(), true);
        mowerSizeLabel = (JLabel) mowerSizePanel.getClientProperty("valueLabel");
        mowerSizeEditBtn = (JButton) mowerSizePanel.getClientProperty("editButton");
        // 割草安全距离
        JPanel mowingSafetyDistancePanel = createSettingItemPanel("割草安全距离",
            formatMowingSafetyDistance(), true);
        mowingSafetyDistanceLabel = (JLabel) mowingSafetyDistancePanel.getClientProperty("valueLabel");
        mowingSafetyDistanceEditBtn = (JButton) mowingSafetyDistancePanel.getClientProperty("editButton");
        JPanel baseStationIdPanel = createSettingItemPanel("差分基准站编号",
            resolveBaseStationId(), true);
        baseStationIdLabel = (JLabel) baseStationIdPanel.getClientProperty("valueLabel");
@@ -136,24 +171,57 @@
            formatIdleTrailDurationValue(), true);
        idleTrailDurationLabel = (JLabel) idleTrailPanel.getClientProperty("valueLabel");
        idleTrailEditBtn = (JButton) idleTrailPanel.getClientProperty("editButton");
        // 显示边界距离设置项
        JPanel boundaryLengthPanel = createBoundaryLengthPanel();
        boundaryLengthVisibleLabel = (JLabel) boundaryLengthPanel.getClientProperty("valueLabel");
        // 开启测量模式设置项
        JPanel measurementModePanel = createMeasurementModePanel();
        measurementModeEnabledLabel = (JLabel) measurementModePanel.getClientProperty("valueLabel");
        // 手动绘制边界模式设置项
        JPanel manualBoundaryDrawingPanel = createManualBoundaryDrawingPanel();
        manualBoundaryDrawingModeLabel = (JLabel) manualBoundaryDrawingPanel.getClientProperty("valueLabel");
        JPanel feedbackPanel = createFeedbackPanel();
        
        // APP版本
        JPanel appVersionPanel = createAppVersionPanel();
        
    addRowWithSpacing(panel, mowerIdPanel);
    addRowWithSpacing(panel, baseStationIdPanel);
        addRowWithSpacing(panel, handheldPanel);
    addRowWithSpacing(panel, simCardPanel);
    addRowWithSpacing(panel, baseStationSimPanel);
    addRowWithSpacing(panel, firmwarePanel);
    addRowWithSpacing(panel, idleTrailPanel);
    addRowWithSpacing(panel, feedbackPanel);
    addRowWithSpacing(panel, appVersionPanel);
    panel.add(createDebugPanel());
        // 添加设置项,使用分割线分隔
        addSettingItem(panel, mowerIdPanel, true);
        addSettingItem(panel, mowerSizePanel, true);
        addSettingItem(panel, mowingSafetyDistancePanel, true);
        addSettingItem(panel, baseStationIdPanel, true);
        addSettingItem(panel, handheldPanel, true);
        addSettingItem(panel, simCardPanel, true);
        addSettingItem(panel, baseStationSimPanel, true);
        addSettingItem(panel, firmwarePanel, true);
        addSettingItem(panel, idleTrailPanel, true);
        addSettingItem(panel, boundaryLengthPanel, true);
        addSettingItem(panel, measurementModePanel, true);
        addSettingItem(panel, manualBoundaryDrawingPanel, true);
        addSettingItem(panel, feedbackPanel, true);
        addSettingItem(panel, appVersionPanel, false);  // 最后一项不加分割线
        
        return panel;
        container.add(panel, BorderLayout.CENTER);
        return container;
    }
    /**
     * 添加设置项(带分割线)
     */
    private void addSettingItem(JPanel container, JPanel itemPanel, boolean showDivider) {
        container.add(itemPanel);
        if (showDivider) {
            // 添加分割线
            JSeparator divider = new JSeparator();
            divider.setForeground(DIVIDER_COLOR);
            divider.setMaximumSize(new Dimension(Integer.MAX_VALUE, 1));
            divider.setAlignmentX(Component.LEFT_ALIGNMENT);
            container.add(divider);
        }
    }
    private String formatIdleTrailDurationValue() {
@@ -164,18 +232,76 @@
        return seconds + "秒";
    }
    private void addRowWithSpacing(JPanel container, JPanel row) {
        container.add(row);
        container.add(Box.createRigidArea(new Dimension(0, ROW_SPACING)));
    /**
     * 将字符串值转换为米(兼容旧数据,如果值大于100认为是厘米,需要除以100)
     */
    private double convertToMeters(String value) {
        if (value == null || value.trim().isEmpty() || "-1".equals(value.trim())) {
            return -1;
        }
        try {
            double val = Double.parseDouble(value.trim());
            // 如果值大于100,认为是厘米,需要转换为米
            if (val > 100) {
                return val / 100.0;
            }
            return val;
        } catch (NumberFormatException e) {
            return -1;
        }
    }
    /**
     * 格式化数值为米,保留2位小数
     */
    private String formatMeters(double value) {
        if (value < 0) {
            return "未设置";
        }
        return String.format("%.2f", value) + "m";
    }
    private String formatMowerSize() {
        Device device = Device.getActiveDevice();
        if (device == null) {
            return "未设置";
        }
        String width = device.getMowerWidth();
        String length = device.getMowerLength();
        double widthMeters = convertToMeters(width);
        double lengthMeters = convertToMeters(length);
        if (widthMeters < 0 && lengthMeters < 0) {
            return "未设置";
        }
        String widthStr = widthMeters >= 0 ? formatMeters(widthMeters) : "未设置";
        String lengthStr = lengthMeters >= 0 ? formatMeters(lengthMeters) : "未设置";
        return lengthStr + " × " + widthStr;
    }
    private String formatMowingSafetyDistance() {
        Device device = Device.getActiveDevice();
        if (device == null) {
            return "未设置";
        }
        String distance = device.getMowingSafetyDistance();
        double distanceMeters = convertToMeters(distance);
        if (distanceMeters < 0) {
            return "未设置";
        }
        return formatMeters(distanceMeters);
    }
    
    private JPanel createSettingItemPanel(String title, String value, boolean editable) {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBackground(PANEL_BACKGROUND);
        panel.setOpaque(false);  // 透明背景,由容器绘制
        panel.setAlignmentX(Component.LEFT_ALIGNMENT);
        panel.setMaximumSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setPreferredSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setMinimumSize(new Dimension(0, ROW_HEIGHT));
        panel.setBorder(BorderFactory.createEmptyBorder(ITEM_PADDING, ITEM_PADDING, ITEM_PADDING, ITEM_PADDING));
        GridBagConstraints gbc = new GridBagConstraints();
@@ -221,11 +347,12 @@
    
    private JPanel createAppVersionPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBackground(PANEL_BACKGROUND);
        panel.setOpaque(false);  // 透明背景
        panel.setAlignmentX(Component.LEFT_ALIGNMENT);
        panel.setMaximumSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setPreferredSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setMinimumSize(new Dimension(0, ROW_HEIGHT));
        panel.setBorder(BorderFactory.createEmptyBorder(ITEM_PADDING, ITEM_PADDING, ITEM_PADDING, ITEM_PADDING));
        GridBagConstraints gbc = new GridBagConstraints();
@@ -250,28 +377,8 @@
        gbc.anchor = GridBagConstraints.EAST;
        panel.add(appVersionLabel, gbc);
    checkUpdateBtn = new JButton("检查更新");
    checkUpdateBtn.setFont(new Font("微软雅黑", Font.PLAIN, 12));
    checkUpdateBtn.setBackground(THEME_COLOR);
    checkUpdateBtn.setForeground(Color.WHITE);
    checkUpdateBtn.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 20));
    checkUpdateBtn.setPreferredSize(new Dimension(100, 28));
    checkUpdateBtn.setMinimumSize(new Dimension(100, 28));
    checkUpdateBtn.setMaximumSize(new Dimension(100, 28));
        checkUpdateBtn.setFocusPainted(false);
        checkUpdateBtn.addMouseListener(new MouseAdapter() {
            public void mouseEntered(MouseEvent e) {
                checkUpdateBtn.setBackground(new Color(
                    Math.max(THEME_COLOR.getRed() - 20, 0),
                    Math.max(THEME_COLOR.getGreen() - 20, 0),
                    Math.max(THEME_COLOR.getBlue() - 20, 0)
                ));
            }
            public void mouseExited(MouseEvent e) {
                checkUpdateBtn.setBackground(THEME_COLOR);
            }
        });
        checkUpdateBtn = buttonset.createStyledButton("检查更新", THEME_COLOR);
        checkUpdateBtn.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        gbc = new GridBagConstraints();
        gbc.gridx = 2;
@@ -283,69 +390,14 @@
        return panel;
    }
    private JPanel createDebugPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBackground(PANEL_BACKGROUND);
        panel.setAlignmentX(Component.LEFT_ALIGNMENT);
        panel.setMaximumSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setPreferredSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setMinimumSize(new Dimension(0, ROW_HEIGHT));
        GridBagConstraints gbc = new GridBagConstraints();
        JLabel titleLabel = new JLabel("系统调试");
        titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 14));
        titleLabel.setForeground(Color.BLACK);
        titleLabel.setHorizontalAlignment(SwingConstants.RIGHT);
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.weightx = 0;
        gbc.anchor = GridBagConstraints.EAST;
        gbc.insets = new Insets(0, 0, 0, 12);
        panel.add(titleLabel, gbc);
        systemDebugButton = new JButton("系统调试");
        systemDebugButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        systemDebugButton.setBackground(new Color(
            Math.max(THEME_COLOR.getRed() - 20, 0),
            Math.max(THEME_COLOR.getGreen() - 20, 0),
            Math.max(THEME_COLOR.getBlue() - 20, 0)));
        systemDebugButton.setForeground(Color.WHITE);
        systemDebugButton.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 20));
        systemDebugButton.setPreferredSize(new Dimension(100, 28));
        systemDebugButton.setMinimumSize(new Dimension(100, 28));
        systemDebugButton.setMaximumSize(new Dimension(100, 28));
        systemDebugButton.setFocusPainted(false);
        systemDebugButton.addMouseListener(new MouseAdapter() {
            public void mouseEntered(MouseEvent e) {
                systemDebugButton.setBackground(THEME_COLOR);
            }
            public void mouseExited(MouseEvent e) {
                systemDebugButton.setBackground(new Color(
                    Math.max(THEME_COLOR.getRed() - 20, 0),
                    Math.max(THEME_COLOR.getGreen() - 20, 0),
                    Math.max(THEME_COLOR.getBlue() - 20, 0)));
            }
        });
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.weightx = 1.0;
        gbc.anchor = GridBagConstraints.EAST;
        panel.add(systemDebugButton, gbc);
        return panel;
    }
    private JPanel createFeedbackPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBackground(PANEL_BACKGROUND);
        panel.setOpaque(false);  // 透明背景
        panel.setAlignmentX(Component.LEFT_ALIGNMENT);
        panel.setMaximumSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setPreferredSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setMinimumSize(new Dimension(0, ROW_HEIGHT));
        panel.setBorder(BorderFactory.createEmptyBorder(ITEM_PADDING, ITEM_PADDING, ITEM_PADDING, ITEM_PADDING));
        GridBagConstraints gbc = new GridBagConstraints();
@@ -360,30 +412,8 @@
        gbc.insets = new Insets(0, 0, 0, 12);
        panel.add(titleLabel, gbc);
        feedbackButton = new JButton("反馈");
        feedbackButton = buttonset.createStyledButton("反馈", THEME_COLOR);
        feedbackButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        feedbackButton.setBackground(THEME_COLOR);
        feedbackButton.setForeground(Color.WHITE);
        feedbackButton.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 20));
        feedbackButton.setPreferredSize(new Dimension(100, 28));
        feedbackButton.setMinimumSize(new Dimension(100, 28));
        feedbackButton.setMaximumSize(new Dimension(100, 28));
        feedbackButton.setFocusPainted(false);
        feedbackButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                feedbackButton.setBackground(new Color(
                        Math.max(THEME_COLOR.getRed() - 20, 0),
                        Math.max(THEME_COLOR.getGreen() - 20, 0),
                        Math.max(THEME_COLOR.getBlue() - 20, 0)));
            }
            @Override
            public void mouseExited(MouseEvent e) {
                feedbackButton.setBackground(THEME_COLOR);
            }
        });
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
@@ -395,6 +425,424 @@
        return panel;
    }
    
    /**
     * 创建显示边界距离设置面板
     */
    private JPanel createBoundaryLengthPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setOpaque(false);  // 透明背景
        panel.setAlignmentX(Component.LEFT_ALIGNMENT);
        panel.setMaximumSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setPreferredSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setMinimumSize(new Dimension(0, ROW_HEIGHT));
        panel.setBorder(BorderFactory.createEmptyBorder(ITEM_PADDING, ITEM_PADDING, ITEM_PADDING, ITEM_PADDING));
        GridBagConstraints gbc = new GridBagConstraints();
        JLabel titleLabel = new JLabel("显示边界距离");
        titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 14));
        titleLabel.setForeground(Color.BLACK);
        titleLabel.setHorizontalAlignment(SwingConstants.RIGHT);
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.weightx = 0;
        gbc.anchor = GridBagConstraints.EAST;
        gbc.insets = new Insets(0, 0, 0, 12);
        panel.add(titleLabel, gbc);
        boundaryLengthVisibleLabel = new JLabel(setData.isBoundaryLengthVisible() ? "已开启" : "已关闭");
        boundaryLengthVisibleLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        boundaryLengthVisibleLabel.setForeground(Color.DARK_GRAY);
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.weightx = 1.0;
        gbc.anchor = GridBagConstraints.EAST;
        panel.add(boundaryLengthVisibleLabel, gbc);
        panel.putClientProperty("valueLabel", boundaryLengthVisibleLabel);
        // 创建切换按钮(使用图标)
        JButton toggleBtn = createBoundaryLengthToggleButton();
        gbc = new GridBagConstraints();
        gbc.gridx = 2;
        gbc.gridy = 0;
        gbc.weightx = 0;
        gbc.anchor = GridBagConstraints.EAST;
        panel.add(toggleBtn, gbc);
        panel.putClientProperty("toggleButton", toggleBtn);
        return panel;
    }
    /**
     * 创建手动绘制边界模式设置面板
     */
    private JPanel createManualBoundaryDrawingPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setOpaque(false);  // 透明背景
        panel.setAlignmentX(Component.LEFT_ALIGNMENT);
        panel.setMaximumSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setPreferredSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setMinimumSize(new Dimension(0, ROW_HEIGHT));
        panel.setBorder(BorderFactory.createEmptyBorder(ITEM_PADDING, ITEM_PADDING, ITEM_PADDING, ITEM_PADDING));
        GridBagConstraints gbc = new GridBagConstraints();
        JLabel titleLabel = new JLabel("手动绘制边界模式");
        titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 14));
        titleLabel.setForeground(Color.BLACK);
        titleLabel.setHorizontalAlignment(SwingConstants.RIGHT);
        titleLabel.setCursor(new Cursor(Cursor.HAND_CURSOR));
        // 添加点击事件,显示坐标对话框
        titleLabel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                showManualBoundaryCoordinatesDialog();
            }
            @Override
            public void mouseEntered(MouseEvent e) {
                titleLabel.setForeground(THEME_COLOR);
            }
            @Override
            public void mouseExited(MouseEvent e) {
                titleLabel.setForeground(Color.BLACK);
            }
        });
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.weightx = 0;
        gbc.anchor = GridBagConstraints.EAST;
        gbc.insets = new Insets(0, 0, 0, 12);
        panel.add(titleLabel, gbc);
        manualBoundaryDrawingModeLabel = new JLabel(setData.isManualBoundaryDrawingMode() ? "已开启" : "已关闭");
        manualBoundaryDrawingModeLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        manualBoundaryDrawingModeLabel.setForeground(Color.DARK_GRAY);
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.weightx = 1.0;
        gbc.anchor = GridBagConstraints.EAST;
        panel.add(manualBoundaryDrawingModeLabel, gbc);
        panel.putClientProperty("valueLabel", manualBoundaryDrawingModeLabel);
        // 创建切换按钮(使用图标)
        JButton toggleBtn = createManualBoundaryDrawingToggleButton();
        gbc = new GridBagConstraints();
        gbc.gridx = 2;
        gbc.gridy = 0;
        gbc.weightx = 0;
        gbc.anchor = GridBagConstraints.EAST;
        panel.add(toggleBtn, gbc);
        panel.putClientProperty("toggleButton", toggleBtn);
        return panel;
    }
    /**
     * 创建手动绘制边界模式切换按钮
     */
    private JButton createManualBoundaryDrawingToggleButton() {
        JButton button = new JButton();
        button.setContentAreaFilled(false);
        button.setBorder(null);
        button.setFocusPainted(false);
        button.setCursor(new Cursor(Cursor.HAND_CURSOR));
        button.setPreferredSize(new Dimension(32, 32));
        button.setMinimumSize(new Dimension(32, 32));
        button.setMaximumSize(new Dimension(32, 32));
        updateManualBoundaryDrawingToggleButton(button);
        button.addActionListener(e -> toggleManualBoundaryDrawingMode(button));
        return button;
    }
    /**
     * 更新手动绘制边界模式切换按钮图标
     */
    private void updateManualBoundaryDrawingToggleButton(JButton button) {
        boolean isEnabled = setData.isManualBoundaryDrawingMode();
        try {
            String iconPath = isEnabled ? "image/open.png" : "image/close.png";
            ImageIcon icon = new ImageIcon(iconPath);
            if (icon.getIconWidth() > 0) {
                Image scaledImage = icon.getImage().getScaledInstance(32, 32, Image.SCALE_SMOOTH);
                button.setIcon(new ImageIcon(scaledImage));
                button.setText(null);
            } else {
                button.setIcon(null);
                button.setText(isEnabled ? "开" : "关");
            }
        } catch (Exception e) {
            button.setIcon(null);
            button.setText(isEnabled ? "开" : "关");
            System.err.println("无法加载手动绘制边界模式图标: " + e.getMessage());
        }
    }
    /**
     * 切换手动绘制边界模式状态
     */
    private void toggleManualBoundaryDrawingMode(JButton button) {
        boolean newValue = !setData.isManualBoundaryDrawingMode();
        setData.setManualBoundaryDrawingMode(newValue);
        // 保存到配置文件
        setData.updateProperty("manualBoundaryDrawingMode", String.valueOf(newValue));
        // 更新UI
        if (manualBoundaryDrawingModeLabel != null) {
            manualBoundaryDrawingModeLabel.setText(newValue ? "已开启" : "已关闭");
        }
        updateManualBoundaryDrawingToggleButton(button);
        // 通知MapRenderer更新手动绘制边界模式状态
        Shouye shouye = Shouye.getInstance();
        if (shouye != null) {
            MapRenderer renderer = shouye.getMapRenderer();
            if (renderer != null) {
                renderer.setManualBoundaryDrawingMode(newValue);
                if (!newValue) {
                    // 如果关闭模式,清空已绘制的点
                    renderer.clearManualBoundaryPoints();
                }
            }
            // 通知首页更新悬浮返回按钮显示状态
            shouye.updateSettingsReturnButtonVisibility();
        }
        // 如果开启,关闭系统设置页面并返回首页
        if (newValue) {
            SwingUtilities.invokeLater(() -> {
                setVisible(false);
                dispose();
            });
        }
    }
    /**
     * 创建开启测量模式设置面板
     */
    private JPanel createMeasurementModePanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setOpaque(false);  // 透明背景
        panel.setAlignmentX(Component.LEFT_ALIGNMENT);
        panel.setMaximumSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setPreferredSize(new Dimension(Integer.MAX_VALUE, ROW_HEIGHT));
        panel.setMinimumSize(new Dimension(0, ROW_HEIGHT));
        panel.setBorder(BorderFactory.createEmptyBorder(ITEM_PADDING, ITEM_PADDING, ITEM_PADDING, ITEM_PADDING));
        GridBagConstraints gbc = new GridBagConstraints();
        JLabel titleLabel = new JLabel("开启测量模式");
        titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 14));
        titleLabel.setForeground(Color.BLACK);
        titleLabel.setHorizontalAlignment(SwingConstants.RIGHT);
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.weightx = 0;
        gbc.anchor = GridBagConstraints.EAST;
        gbc.insets = new Insets(0, 0, 0, 12);
        panel.add(titleLabel, gbc);
        measurementModeEnabledLabel = new JLabel(setData.isMeasurementModeEnabled() ? "已开启" : "已关闭");
        measurementModeEnabledLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        measurementModeEnabledLabel.setForeground(Color.DARK_GRAY);
        gbc = new GridBagConstraints();
        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.weightx = 1.0;
        gbc.anchor = GridBagConstraints.EAST;
        panel.add(measurementModeEnabledLabel, gbc);
        panel.putClientProperty("valueLabel", measurementModeEnabledLabel);
        // 创建切换按钮(使用图标)
        JButton toggleBtn = createMeasurementModeToggleButton();
        gbc = new GridBagConstraints();
        gbc.gridx = 2;
        gbc.gridy = 0;
        gbc.weightx = 0;
        gbc.anchor = GridBagConstraints.EAST;
        panel.add(toggleBtn, gbc);
        panel.putClientProperty("toggleButton", toggleBtn);
        return panel;
    }
    /**
     * 创建测量模式切换按钮
     */
    private JButton createMeasurementModeToggleButton() {
        JButton button = new JButton();
        button.setContentAreaFilled(false);
        button.setBorder(null);
        button.setFocusPainted(false);
        button.setCursor(new Cursor(Cursor.HAND_CURSOR));
        button.setPreferredSize(new Dimension(32, 32));
        button.setMinimumSize(new Dimension(32, 32));
        button.setMaximumSize(new Dimension(32, 32));
        updateMeasurementModeToggleButton(button);
        button.addActionListener(e -> toggleMeasurementMode(button));
        return button;
    }
    /**
     * 更新测量模式切换按钮图标
     */
    private void updateMeasurementModeToggleButton(JButton button) {
        boolean isEnabled = setData.isMeasurementModeEnabled();
        try {
            String iconPath = isEnabled ? "image/open.png" : "image/close.png";
            ImageIcon icon = new ImageIcon(iconPath);
            if (icon.getIconWidth() > 0) {
                Image scaledImage = icon.getImage().getScaledInstance(32, 32, Image.SCALE_SMOOTH);
                button.setIcon(new ImageIcon(scaledImage));
                button.setText(null);
            } else {
                button.setIcon(null);
                button.setText(isEnabled ? "开" : "关");
            }
        } catch (Exception e) {
            button.setIcon(null);
            button.setText(isEnabled ? "开" : "关");
            System.err.println("无法加载测量模式图标: " + e.getMessage());
        }
    }
    /**
     * 切换测量模式状态
     */
    private void toggleMeasurementMode(JButton button) {
        boolean newValue = !setData.isMeasurementModeEnabled();
        setData.setMeasurementModeEnabled(newValue);
        // 保存到配置文件
        setData.updateProperty("measurementModeEnabled", String.valueOf(newValue));
        // 更新UI
        if (measurementModeEnabledLabel != null) {
            measurementModeEnabledLabel.setText(newValue ? "已开启" : "已关闭");
        }
        updateMeasurementModeToggleButton(button);
        // 通知MapRenderer更新
        Shouye shouye = Shouye.getInstance();
        if (shouye != null) {
            MapRenderer renderer = shouye.getMapRenderer();
            if (renderer != null) {
                renderer.setMeasurementMode(newValue);
            }
            if (newValue) {
                celiangmoshi.start();
            } else {
                celiangmoshi.stop();
            }
            // 刷新地图显示(通过MapRenderer触发重绘)
            if (renderer != null) {
                renderer.repaint();
            }
            // 通知首页更新悬浮返回按钮显示状态
            shouye.updateSettingsReturnButtonVisibility();
        }
        // 如果开启,关闭系统设置页面并返回首页
        if (newValue) {
            SwingUtilities.invokeLater(() -> {
                setVisible(false);
                dispose();
            });
        }
    }
    /**
     * 创建边界距离显示切换按钮
     */
    private JButton createBoundaryLengthToggleButton() {
        JButton button = new JButton();
        button.setContentAreaFilled(false);
        button.setBorder(null);
        button.setFocusPainted(false);
        button.setCursor(new Cursor(Cursor.HAND_CURSOR));
        button.setPreferredSize(new Dimension(32, 32));
        button.setMinimumSize(new Dimension(32, 32));
        button.setMaximumSize(new Dimension(32, 32));
        updateBoundaryLengthToggleButton(button);
        button.addActionListener(e -> toggleBoundaryLengthVisible(button));
        return button;
    }
    /**
     * 更新边界距离切换按钮图标
     */
    private void updateBoundaryLengthToggleButton(JButton button) {
        boolean isVisible = setData.isBoundaryLengthVisible();
        try {
            String iconPath = isVisible ? "image/open.png" : "image/close.png";
            ImageIcon icon = new ImageIcon(iconPath);
            if (icon.getIconWidth() > 0) {
                Image scaledImage = icon.getImage().getScaledInstance(32, 32, Image.SCALE_SMOOTH);
                button.setIcon(new ImageIcon(scaledImage));
                button.setText(null);
            } else {
                button.setIcon(null);
                button.setText(isVisible ? "开" : "关");
            }
        } catch (Exception e) {
            button.setIcon(null);
            button.setText(isVisible ? "开" : "关");
            System.err.println("无法加载边界距离图标: " + e.getMessage());
        }
    }
    /**
     * 切换边界距离显示状态
     */
    private void toggleBoundaryLengthVisible(JButton button) {
        boolean newValue = !setData.isBoundaryLengthVisible();
        setData.setBoundaryLengthVisible(newValue);
        // 保存到配置文件
        setData.updateProperty("boundaryLengthVisible", String.valueOf(newValue));
        // 更新UI
        if (boundaryLengthVisibleLabel != null) {
            boundaryLengthVisibleLabel.setText(newValue ? "已开启" : "已关闭");
        }
        updateBoundaryLengthToggleButton(button);
        // 通知MapRenderer更新
        Shouye shouye = Shouye.getInstance();
        if (shouye != null) {
            MapRenderer renderer = shouye.getMapRenderer();
            if (renderer != null) {
                renderer.setBoundaryLengthVisible(newValue);
            }
            // 通知首页更新悬浮返回按钮显示状态
            shouye.updateSettingsReturnButtonVisibility();
        }
        // 如果开启,关闭系统设置页面并返回首页
        if (newValue) {
            SwingUtilities.invokeLater(() -> {
                setVisible(false);
                dispose();
            });
        }
    }
    private JButton createEditButton() {
        JButton button = new JButton();
        try {
@@ -431,7 +879,54 @@
        // 从Setsys类加载数据
        setData.initializeFromProperties();
        baseStation.load();
        // 从device.properties加载设备数据
        Device device = Device.getActiveDevice();
        if (device != null) {
            device.initFromProperties();
        }
        updateDisplay();
        // 加载并应用上次保存的视图中心坐标
        loadViewCenterFromProperties();
    }
    /**
     * 从配置文件加载视图中心坐标并应用到MapRenderer
     */
    private void loadViewCenterFromProperties() {
        Shouye shouye = Shouye.getInstance();
        if (shouye == null) {
            return;
        }
        MapRenderer renderer = shouye.getMapRenderer();
        if (renderer == null) {
            return;
        }
        // 从配置文件读取视图中心坐标
        String viewCenterXValue = Setsys.getPropertyValue("viewCenterX");
        String viewCenterYValue = Setsys.getPropertyValue("viewCenterY");
        double savedTranslateX = 0.0;
        double savedTranslateY = 0.0;
        if (viewCenterXValue != null && !viewCenterXValue.trim().isEmpty()) {
            try {
                savedTranslateX = Double.parseDouble(viewCenterXValue.trim());
            } catch (NumberFormatException e) {
                savedTranslateX = 0.0;
            }
        }
        if (viewCenterYValue != null && !viewCenterYValue.trim().isEmpty()) {
            try {
                savedTranslateY = Double.parseDouble(viewCenterYValue.trim());
            } catch (NumberFormatException e) {
                savedTranslateY = 0.0;
            }
        }
        // 应用视图中心坐标(保持当前缩放比例)
        double currentScale = renderer.getScale();
        renderer.setViewTransform(currentScale, savedTranslateX, savedTranslateY);
    }
    
    private void updateDisplay() {
@@ -440,6 +935,16 @@
            mowerIdLabel.setText(setData.getMowerId() != null ? setData.getMowerId() : "未设置");
        }
        // 更新割草机长宽显示
        if (mowerSizeLabel != null) {
            mowerSizeLabel.setText(formatMowerSize());
        }
        // 更新割草安全距离显示
        if (mowingSafetyDistanceLabel != null) {
            mowingSafetyDistanceLabel.setText(formatMowingSafetyDistance());
        }
        if (baseStationIdLabel != null) {
            baseStationIdLabel.setText(resolveBaseStationId());
        }
@@ -468,6 +973,45 @@
            idleTrailDurationLabel.setText(formatIdleTrailDurationValue());
        }
        
        // 更新显示边界距离状态
        if (boundaryLengthVisibleLabel != null) {
            boundaryLengthVisibleLabel.setText(setData.isBoundaryLengthVisible() ? "已开启" : "已关闭");
        }
        // 更新切换按钮图标
        JPanel boundaryLengthPanel = (JPanel) boundaryLengthVisibleLabel.getParent();
        if (boundaryLengthPanel != null) {
            JButton toggleBtn = (JButton) boundaryLengthPanel.getClientProperty("toggleButton");
            if (toggleBtn != null) {
                updateBoundaryLengthToggleButton(toggleBtn);
            }
        }
        // 更新测量模式状态
        if (measurementModeEnabledLabel != null) {
            measurementModeEnabledLabel.setText(setData.isMeasurementModeEnabled() ? "已开启" : "已关闭");
        }
        // 更新测量模式切换按钮图标
        JPanel measurementModePanel = (JPanel) measurementModeEnabledLabel.getParent();
        if (measurementModePanel != null) {
            JButton toggleBtn = (JButton) measurementModePanel.getClientProperty("toggleButton");
            if (toggleBtn != null) {
                updateMeasurementModeToggleButton(toggleBtn);
            }
        }
        // 更新手动绘制边界模式状态
        if (manualBoundaryDrawingModeLabel != null) {
            manualBoundaryDrawingModeLabel.setText(setData.isManualBoundaryDrawingMode() ? "已开启" : "已关闭");
        }
        // 更新手动绘制边界模式切换按钮图标
        JPanel manualBoundaryDrawingPanel = (JPanel) manualBoundaryDrawingModeLabel.getParent();
        if (manualBoundaryDrawingPanel != null) {
            JButton toggleBtn = (JButton) manualBoundaryDrawingPanel.getClientProperty("toggleButton");
            if (toggleBtn != null) {
                updateManualBoundaryDrawingToggleButton(toggleBtn);
            }
        }
        // 更新APP版本显示
        if (appVersionLabel != null) {
            appVersionLabel.setText(setData.getAppVersion() != null ? 
@@ -511,6 +1055,16 @@
            mowerIdEditBtn.addActionListener(e -> editMowerId());
        }
        // 割草机长宽编辑按钮事件
        if (mowerSizeEditBtn != null) {
            mowerSizeEditBtn.addActionListener(e -> editMowerSize());
        }
        // 割草安全距离编辑按钮事件
        if (mowingSafetyDistanceEditBtn != null) {
            mowingSafetyDistanceEditBtn.addActionListener(e -> editMowingSafetyDistance());
        }
        if (baseStationIdEditBtn != null) {
            baseStationIdEditBtn.addActionListener(e -> editBaseStationId());
        }
@@ -528,10 +1082,6 @@
            feedbackButton.addActionListener(e -> showFeedbackDialog());
        }
        if (systemDebugButton != null) {
            systemDebugButton.addActionListener(e -> openSystemDebugDialog());
        }
        if (idleTrailEditBtn != null) {
            idleTrailEditBtn.addActionListener(e -> editIdleTrailDuration());
        }
@@ -563,6 +1113,181 @@
        }
    }
    private void editMowerSize() {
        Device device = Device.getActiveDevice();
        if (device == null) {
            JOptionPane.showMessageDialog(this, "设备未初始化", "错误", JOptionPane.ERROR_MESSAGE);
            return;
        }
        // 获取当前值并转换为米(兼容旧数据)
        double currentLengthMeters = convertToMeters(device.getMowerLength());
        double currentWidthMeters = convertToMeters(device.getMowerWidth());
        String currentLengthStr = currentLengthMeters >= 0 ? String.format("%.2f", currentLengthMeters) : "";
        String currentWidthStr = currentWidthMeters >= 0 ? String.format("%.2f", currentWidthMeters) : "";
        // 创建输入对话框
        JPanel inputPanel = new JPanel(new GridLayout(2, 2, 5, 5));
        inputPanel.add(new JLabel("长度(m):"));
        JTextField lengthField = new JTextField(currentLengthStr);
        inputPanel.add(lengthField);
        inputPanel.add(new JLabel("宽度(m):"));
        JTextField widthField = new JTextField(currentWidthStr);
        inputPanel.add(widthField);
        int result = JOptionPane.showConfirmDialog(this,
            inputPanel,
            "修改割草机长宽",
            JOptionPane.OK_CANCEL_OPTION,
            JOptionPane.QUESTION_MESSAGE);
        if (result == JOptionPane.OK_OPTION) {
            String newLength = lengthField.getText().trim();
            String newWidth = widthField.getText().trim();
            // 验证输入
            if (newLength.isEmpty() && newWidth.isEmpty()) {
                JOptionPane.showMessageDialog(this, "长度和宽度不能同时为空", "提示", JOptionPane.WARNING_MESSAGE);
                return;
            }
            double lengthValue = -1;
            double widthValue = -1;
            if (!newLength.isEmpty()) {
                try {
                    lengthValue = Double.parseDouble(newLength);
                    if (lengthValue < 0) {
                        JOptionPane.showMessageDialog(this, "长度必须大于等于0", "提示", JOptionPane.WARNING_MESSAGE);
                        return;
                    }
                } catch (NumberFormatException e) {
                    JOptionPane.showMessageDialog(this, "长度必须是有效的数字", "提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }
            }
            if (!newWidth.isEmpty()) {
                try {
                    widthValue = Double.parseDouble(newWidth);
                    if (widthValue < 0) {
                        JOptionPane.showMessageDialog(this, "宽度必须大于等于0", "提示", JOptionPane.WARNING_MESSAGE);
                        return;
                    }
                } catch (NumberFormatException e) {
                    JOptionPane.showMessageDialog(this, "宽度必须是有效的数字", "提示", JOptionPane.WARNING_MESSAGE);
                    return;
                }
            }
            // 更新设备属性(保存为米,保留2位小数)
            if (lengthValue >= 0) {
                String lengthStr = String.format("%.2f", lengthValue);
                device.setMowerLength(lengthStr);
                device.updateField("mowerLength", lengthStr);
            } else {
                device.setMowerLength("-1");
                device.updateField("mowerLength", "-1");
            }
            if (widthValue >= 0) {
                String widthStr = String.format("%.2f", widthValue);
                device.setMowerWidth(widthStr);
                device.updateField("mowerWidth", widthStr);
            } else {
                device.setMowerWidth("-1");
                device.updateField("mowerWidth", "-1");
            }
            // 如果长度和宽度都有效,自动计算安全距离
            if (lengthValue > 0 && widthValue > 0) {
                try {
                    double safetyDistance = MowerSafetyDistanceCalculator.calculateSafetyDistance(lengthValue, widthValue);
                    String safetyDistanceStr = String.format("%.2f", safetyDistance);
                    device.setMowingSafetyDistance(safetyDistanceStr);
                    device.updateField("mowingSafetyDistance", safetyDistanceStr);
                    // 更新安全距离显示
                    if (mowingSafetyDistanceLabel != null) {
                        mowingSafetyDistanceLabel.setText(formatMowingSafetyDistance());
                    }
                } catch (IllegalArgumentException e) {
                    // 如果计算失败,不更新安全距离
                    System.err.println("计算安全距离失败: " + e.getMessage());
                }
            }
            // 保存到device.properties
            device.saveToProperties();
            // 更新显示
            if (mowerSizeLabel != null) {
                mowerSizeLabel.setText(formatMowerSize());
            }
            JOptionPane.showMessageDialog(this, "割草机长宽更新成功" +
                (lengthValue > 0 && widthValue > 0 ? ",安全距离已自动计算" : ""),
                "成功", JOptionPane.INFORMATION_MESSAGE);
        }
    }
    private void editMowingSafetyDistance() {
        Device device = Device.getActiveDevice();
        if (device == null) {
            JOptionPane.showMessageDialog(this, "设备未初始化", "错误", JOptionPane.ERROR_MESSAGE);
            return;
        }
        // 获取当前值并转换为米(兼容旧数据)
        double currentDistanceMeters = convertToMeters(device.getMowingSafetyDistance());
        String currentValueStr = currentDistanceMeters >= 0 ? String.format("%.2f", currentDistanceMeters) : "";
        String newValue = (String) JOptionPane.showInputDialog(this,
            "请输入割草安全距离(单位:m):",
            "修改割草安全距离",
            JOptionPane.QUESTION_MESSAGE,
            null,
            null,
            currentValueStr);
        if (newValue == null) {
            return; // 用户取消
        }
        newValue = newValue.trim();
        if (newValue.isEmpty()) {
            JOptionPane.showMessageDialog(this, "割草安全距离不能为空", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        // 验证输入
        double distanceValue;
        try {
            distanceValue = Double.parseDouble(newValue);
            if (distanceValue < 0) {
                JOptionPane.showMessageDialog(this, "割草安全距离必须大于等于0", "提示", JOptionPane.WARNING_MESSAGE);
                return;
            }
        } catch (NumberFormatException e) {
            JOptionPane.showMessageDialog(this, "割草安全距离必须是有效的数字", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        // 更新设备属性(保存为米,保留2位小数)
        String distanceStr = String.format("%.2f", distanceValue);
        device.setMowingSafetyDistance(distanceStr);
        device.updateField("mowingSafetyDistance", distanceStr);
        // 保存到device.properties
        device.saveToProperties();
        // 更新显示
        if (mowingSafetyDistanceLabel != null) {
            mowingSafetyDistanceLabel.setText(formatMowingSafetyDistance());
        }
        JOptionPane.showMessageDialog(this, "割草安全距离更新成功", "成功", JOptionPane.INFORMATION_MESSAGE);
    }
    private void editHandheldMarkerId() {
        String currentValue = setData.getHandheldMarkerId() != null ? setData.getHandheldMarkerId() : "";
        String newValue = (String) JOptionPane.showInputDialog(this,
@@ -715,9 +1440,8 @@
        photoControls.setAlignmentX(Component.LEFT_ALIGNMENT);
        JLabel photoLabel = new JLabel("选择照片(最多6张):");
        photoLabel.setFont(new Font("微软雅黑", Font.BOLD, 13));
        JButton selectPhotosButton = new JButton("选择照片");
        selectPhotosButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        selectPhotosButton.setFocusPainted(false);
    JButton selectPhotosButton = buttonset.createStyledButton("选择照片", THEME_COLOR);
    selectPhotosButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        photoControls.add(photoLabel);
        photoControls.add(selectPhotosButton);
    content.add(photoControls);
@@ -737,13 +1461,11 @@
        content.add(Box.createRigidArea(new Dimension(0, 20)));
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        JButton cancelButton = new JButton("放弃");
        JButton submitButton = new JButton("提交");
        submitButton.setBackground(THEME_COLOR);
        submitButton.setForeground(Color.WHITE);
        submitButton.setFocusPainted(false);
        cancelButton.setFocusPainted(false);
    JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
    JButton cancelButton = buttonset.createStyledButton("放弃", new Color(128, 128, 128));
    cancelButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
    JButton submitButton = buttonset.createStyledButton("提交", THEME_COLOR);
    submitButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        buttonPanel.add(cancelButton);
        buttonPanel.add(submitButton);
@@ -831,6 +1553,187 @@
        }
    }
    
    /**
     * 显示手动绘制边界坐标对话框
     */
    private void showManualBoundaryCoordinatesDialog() {
        // 从 shoudongbianjie.properties 文件读取坐标
        String coordinates = null;
        int pointCount = 0;
        try {
            java.util.Properties props = new java.util.Properties();
            java.io.File file = new java.io.File("shoudongbianjie.properties");
            if (file.exists()) {
                try (java.io.FileInputStream input = new java.io.FileInputStream(file)) {
                    props.load(input);
                    coordinates = props.getProperty("boundaryCoordinates");
                    String pointCountStr = props.getProperty("pointCount");
                    if (pointCountStr != null && !pointCountStr.trim().isEmpty()) {
                        try {
                            pointCount = Integer.parseInt(pointCountStr.trim());
                        } catch (NumberFormatException e) {
                            // 如果无法解析,从坐标字符串计算点数
                            if (coordinates != null && !coordinates.trim().isEmpty()) {
                                pointCount = coordinates.split(";").length;
                            }
                        }
                    } else if (coordinates != null && !coordinates.trim().isEmpty()) {
                        // 如果没有点数量,从坐标字符串计算
                        pointCount = coordinates.split(";").length;
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            JOptionPane.showMessageDialog(this,
                "读取坐标文件失败: " + ex.getMessage(),
                "错误",
                JOptionPane.ERROR_MESSAGE);
            return;
        }
        // 如果没有坐标数据,显示提示
        if (coordinates == null || coordinates.trim().isEmpty()) {
            JOptionPane.showMessageDialog(this,
                "当前没有保存的边界坐标",
                "提示",
                JOptionPane.INFORMATION_MESSAGE);
            return;
        }
        // 创建对话框 - 宽度和系统设置页面一样(400)
        JDialog dialog = new JDialog(this, "手动绘制边界坐标", true);
        dialog.setLayout(new BorderLayout(0, 12));
        dialog.setResizable(true);
        dialog.setPreferredSize(new Dimension(400, 400));
        dialog.setSize(new Dimension(400, 400));
        dialog.setMinimumSize(new Dimension(400, 300));
        JPanel content = new JPanel();
        content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
        content.setBorder(BorderFactory.createEmptyBorder(20, 24, 20, 24));
        dialog.add(content, BorderLayout.CENTER);
        // 标题
        String titleText = pointCount > 0
            ? "坐标点列表(共 " + pointCount + " 个点):"
            : "坐标点列表:";
        JLabel titleLabel = new JLabel(titleText);
        titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 14));
        titleLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
        content.add(titleLabel);
        content.add(Box.createRigidArea(new Dimension(0, 10)));
        // 坐标文本区域
        JTextArea coordinatesArea = new JTextArea(coordinates);
        coordinatesArea.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        coordinatesArea.setLineWrap(true);
        coordinatesArea.setWrapStyleWord(false);
        coordinatesArea.setEditable(false);
        coordinatesArea.setBackground(Color.WHITE);
        JScrollPane scrollPane = new JScrollPane(coordinatesArea);
        scrollPane.setAlignmentX(Component.LEFT_ALIGNMENT);
        scrollPane.setPreferredSize(new Dimension(0, 200));
        content.add(scrollPane);
        content.add(Box.createRigidArea(new Dimension(0, 16)));
        // 按钮面板
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 0));
        buttonPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
        // 创建复制按钮,使用图标
        JButton copyButton = new JButton();
        try {
            ImageIcon copyIcon = new ImageIcon("image/fuzhi.png");
            if (copyIcon.getIconWidth() > 0) {
                // 调整图标大小
                Image scaledImage = copyIcon.getImage().getScaledInstance(32, 32, Image.SCALE_SMOOTH);
                copyButton.setIcon(new ImageIcon(scaledImage));
            } else {
                copyButton.setText("复制坐标");
            }
        } catch (Exception ex) {
            copyButton.setText("复制坐标");
            System.err.println("无法加载复制图标: " + ex.getMessage());
        }
        copyButton.setContentAreaFilled(false);
        copyButton.setBorder(null);
        copyButton.setFocusPainted(false);
        copyButton.setCursor(new Cursor(Cursor.HAND_CURSOR));
        copyButton.setToolTipText("复制坐标");
        // 加载成功图标
        ImageIcon successIcon = null;
        try {
            ImageIcon originalSuccessIcon = new ImageIcon("image/fuzhisucc.png");
            if (originalSuccessIcon.getIconWidth() > 0) {
                Image scaledSuccessImage = originalSuccessIcon.getImage().getScaledInstance(32, 32, Image.SCALE_SMOOTH);
                successIcon = new ImageIcon(scaledSuccessImage);
            }
        } catch (Exception ex) {
            System.err.println("无法加载成功图标: " + ex.getMessage());
        }
        final ImageIcon finalSuccessIcon = successIcon;
        final ImageIcon originalCopyIcon = (ImageIcon) copyButton.getIcon();
        copyButton.addActionListener(e -> {
            String text = coordinatesArea.getText();
            if (text != null && !text.trim().isEmpty()) {
                java.awt.Toolkit.getDefaultToolkit().getSystemClipboard().setContents(
                    new java.awt.datatransfer.StringSelection(text), null);
                // 切换为成功图标
                if (finalSuccessIcon != null) {
                    copyButton.setIcon(finalSuccessIcon);
                }
                // 2秒后恢复为原始图标
                Timer restoreTimer = new Timer(2000, evt -> {
                    if (originalCopyIcon != null) {
                        copyButton.setIcon(originalCopyIcon);
                    }
                });
                restoreTimer.setRepeats(false);
                restoreTimer.start();
            }
        });
        // 创建关闭按钮,使用图标
        JButton closeButton = new JButton();
        try {
            ImageIcon closeIcon = new ImageIcon("image/closepage.png");
            if (closeIcon.getIconWidth() > 0) {
                // 调整图标大小
                Image scaledImage = closeIcon.getImage().getScaledInstance(32, 32, Image.SCALE_SMOOTH);
                closeButton.setIcon(new ImageIcon(scaledImage));
            } else {
                closeButton.setText("关闭");
            }
        } catch (Exception ex) {
            closeButton.setText("关闭");
            System.err.println("无法加载关闭图标: " + ex.getMessage());
        }
        closeButton.setContentAreaFilled(false);
        closeButton.setBorder(null);
        closeButton.setFocusPainted(false);
        closeButton.setCursor(new Cursor(Cursor.HAND_CURSOR));
        closeButton.setToolTipText("关闭");
        closeButton.addActionListener(e -> dialog.dispose());
        buttonPanel.add(copyButton);
        buttonPanel.add(closeButton);
        content.add(buttonPanel);
        dialog.pack();
        dialog.setLocationRelativeTo(this);
        dialog.setVisible(true);
    }
    private void checkForUpdates() {
        // 模拟检查更新过程
        checkUpdateBtn.setEnabled(false);
@@ -852,12 +1755,6 @@
        timer.setRepeats(false);
        timer.start();
    }
    private void openSystemDebugDialog() {
        debug dialog = new debug(this, THEME_COLOR);
        dialog.setLocationRelativeTo(this);
        dialog.setVisible(true);
    }
    
    @Override
    public void setVisible(boolean visible) {