826220679@qq.com
10 天以前 176cfa1a137d2050d4e8a105dfdbdc8f1b32afb2
修改
已修改2个文件
已重命名1个文件
564 ■■■■■ 文件已修改
src/dell_system/MessageViewPanel.java 552 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell_system/SerialCommPanel.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell_system/SerialPacketParser.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/dell_system/MessageViewPanel.java
@@ -16,50 +16,46 @@
import udptcp.UDPPortBReceiver;
public class MessageViewPanel extends JPanel {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    private ResourceBundle messages;   // å›½é™…化消息资源包
    // UI组件声明
    private JButton btnStart, btnPause, btnClear, btnSend; // æŽ§åˆ¶æŒ‰é’®ï¼šå¼€å§‹ã€æš‚停、清除、发送
    private static JComboBox<String> cbDataType; // ä¸‹æ‹‰æ¡†ï¼šæ•°æ®ç±»åž‹ã€åè®®ã€è®¾å¤‡ID
    private ResourceBundle messages;
    private JButton btnStart, btnPause, btnClear, btnSend;
    private static JComboBox<String> cbDataType;
    private static JComboBox<String> cbProtocol;
    private static JComboBox<String> cbDeviceId;
    private static JComboBox<String> cbRemoteDevice; // è¿œç¨‹è®¾å¤‡ä¸‹æ‹‰æ¡†
    private static JCheckBox chkAutoSave; // å¤é€‰æ¡†ï¼šè‡ªåŠ¨ä¿å­˜ã€æ˜¾ç¤ºæ¥æºã€åå…­è¿›åˆ¶æ˜¾ç¤ºã€ASCII显示
    private static JComboBox<String> cbRemoteDevice;
    private static JCheckBox chkAutoSave;
    private static JCheckBox chkShowSource;
    private static JCheckBox chkHexDisplay;
    private static JCheckBox chkAsciiDisplay;
    private static JTextArea txtDataView; // æ•°æ®æ˜¾ç¤ºåŒºåŸŸ
    private JScrollPane scrollPane; // å¸¦æ»šåŠ¨æ¡çš„é¢æ¿
    private JTextField txtSendData; // å‘送数据文本框
    private JRadioButton rdoSendHex; // HEX发送单选按钮
    private JRadioButton rdoSendAscii; // ASCII发送单选按钮
    private JCheckBox chkAppendNewline; // å›žè½¦æ¢è¡Œå¤é€‰æ¡†
    // æ·»åŠ é™æ€å˜é‡è·Ÿè¸ªçª—å£å¯è§çŠ¶æ€
    private static JTextArea txtDataView;
    private JScrollPane scrollPane;
    private JTextField txtSendData;
    private JRadioButton rdoSendHex;
    private JRadioButton rdoSendAscii;
    private JCheckBox chkAppendNewline;
    private static final ThreadLocal<StringBuilder> SB =
            ThreadLocal.withInitial(() -> new StringBuilder(256));
    private static final char[] DIGITS = "0123456789".toCharArray();
    private static final String COLON = ":";
    private static final String PREFIX = "[";
    private static final String SUFFIX = "]";
    public static volatile boolean isWindowVisible = false;
    // çŠ¶æ€å˜é‡
    private static boolean isCapturing = false; // æ˜¯å¦æ­£åœ¨æ•获数据的标志
    private static boolean isCapturing = false;
    private static boolean isStarted = false; // æ–°å¢žï¼šè·Ÿè¸ªå¼€å§‹æŒ‰é’®çŠ¶æ€
    // ä¿®æ”¹ä¸ºMap存储设备及其本地端口
    private static Map<String, Integer> remoteDeviceLocalPortMap = new HashMap<>();
    // æž„造函数
    public MessageViewPanel(ResourceBundle messages) {       
        this.messages = messages; // åˆå§‹åŒ–消息资源包
        initializeUI(); // åˆå§‹åŒ–用户界面
        this.messages = messages;
        initializeUI();
    }
    public void addNotify() {
        super.addNotify();
        Window window = SwingUtilities.getWindowAncestor(this);
        if (window != null) {
            isWindowVisible = true; // é¢æ¿å·²æ·»åŠ åˆ°å¯è§çª—å£
            isWindowVisible = true;
            window.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
@@ -74,154 +70,129 @@
        }
    }
    // åˆå§‹åŒ–UI组件
    private void initializeUI() {
        setLayout(new GridBagLayout()); // ä½¿ç”¨ç½‘格袋布局
        GridBagConstraints gbc = new GridBagConstraints(); // å¸ƒå±€çº¦æŸå¯¹è±¡
        gbc.insets = new Insets(5, 10, 5, 10); // è®¾ç½®ç»„件间距(上、左、下、右)
        gbc.anchor = GridBagConstraints.WEST; // ç»„件靠左对齐
        gbc.fill = GridBagConstraints.HORIZONTAL; // æ°´å¹³å¡«å……
        setBackground(new Color(240, 245, 249)); // è®¾ç½®èƒŒæ™¯è‰²
        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5, 10, 5, 10);
        gbc.anchor = GridBagConstraints.WEST;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        setBackground(new Color(240, 245, 249));
        // ä¸‹æ‹‰æ¡†åŒºåŸŸ
        gbc.gridx = 0; // èµ·å§‹åˆ—
        gbc.gridy = 0; // èµ·å§‹è¡Œ
        gbc.gridwidth = 1; // å ç”¨1列宽度
        gbc.weightx = 0.25; // æ°´å¹³æƒé‡
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 1;
        gbc.weightx = 0.25;
        // æ•°æ®ç±»åž‹ä¸‹æ‹‰æ¡†é¢æ¿
        JPanel dataTypePanel = new JPanel(new BorderLayout(5, 0)); // ä½¿ç”¨è¾¹ç•Œå¸ƒå±€
        dataTypePanel.setBackground(new Color(240, 245, 249)); // è®¾ç½®èƒŒæ™¯è‰²
        dataTypePanel.add(createLabel(messages.getString("MESSAGE_VIEW_DATA_TYPE")), BorderLayout.WEST); // æ·»åŠ æ ‡ç­¾
        cbDataType = new JComboBox<>(); // åˆ›å»ºä¸‹æ‹‰æ¡†
        loadtyps();// æ·»åŠ "所有类型"选项
        dataTypePanel.add(cbDataType, BorderLayout.CENTER); // å°†ä¸‹æ‹‰æ¡†æ·»åŠ åˆ°é¢æ¿ä¸­å¤®
        add(dataTypePanel, gbc); // å°†é¢æ¿æ·»åŠ åˆ°ä¸»é¢æ¿
        JPanel dataTypePanel = new JPanel(new BorderLayout(5, 0));
        dataTypePanel.setBackground(new Color(240, 245, 249));
        dataTypePanel.add(createLabel(messages.getString("MESSAGE_VIEW_DATA_TYPE")), BorderLayout.WEST);
        cbDataType = new JComboBox<>();
        loadtyps();
        dataTypePanel.add(cbDataType, BorderLayout.CENTER);
        add(dataTypePanel, gbc);
        // åè®®ä¸‹æ‹‰æ¡†
        gbc.gridx++; // ç§»åŠ¨åˆ°ä¸‹ä¸€åˆ—
        JPanel protocolPanel = new JPanel(new BorderLayout(5, 0)); // åè®®é€‰æ‹©é¢æ¿
        protocolPanel.setBackground(new Color(240, 245, 249)); // è®¾ç½®èƒŒæ™¯è‰²
        protocolPanel.add(createLabel(messages.getString("MESSAGE_VIEW_PROTOCOL")), BorderLayout.WEST); // æ·»åŠ åè®®æ ‡ç­¾
        cbProtocol = new JComboBox<>(new String[]{ // åˆ›å»ºåè®®ä¸‹æ‹‰æ¡†å¹¶åˆå§‹åŒ–选项
                messages.getString("MESSAGE_VIEW_ALL_PROTOCOLS"), // æ‰€æœ‰åè®®
                "UDP", // UDP协议
                "TCP", // TCP协议
                "MQTT", // MQTT协议
                "HTTP" // HTTP协议
        gbc.gridx++;
        JPanel protocolPanel = new JPanel(new BorderLayout(5, 0));
        protocolPanel.setBackground(new Color(240, 245, 249));
        protocolPanel.add(createLabel(messages.getString("MESSAGE_VIEW_PROTOCOL")), BorderLayout.WEST);
        cbProtocol = new JComboBox<>(new String[]{
                "ALL",
                "55AA01", "55AA02", "55AA03", "55AA05", "55AA07",
                "55AA0A", "55AA0C", "55AA12", "55AA14", "55AA20",
                "GNGGA", "XTB"
        });
        protocolPanel.add(cbProtocol, BorderLayout.CENTER); // å°†ä¸‹æ‹‰æ¡†æ·»åŠ åˆ°é¢æ¿ä¸­å¤®
        add(protocolPanel, gbc); // å°†é¢æ¿æ·»åŠ åˆ°ä¸»é¢æ¿
        protocolPanel.add(cbProtocol, BorderLayout.CENTER);
        add(protocolPanel, gbc);
        // è®¾å¤‡ID下拉框
        gbc.gridx++; // ç§»åŠ¨åˆ°ä¸‹ä¸€åˆ—
        JPanel devicePanel = new JPanel(new BorderLayout(5, 0)); // è®¾å¤‡ID选择面板
        devicePanel.setBackground(new Color(240, 245, 249)); // è®¾ç½®èƒŒæ™¯è‰²
        devicePanel.add(createLabel(messages.getString("MESSAGE_VIEW_DEVICE_ID")), BorderLayout.WEST); // æ·»åŠ è®¾å¤‡ID标签
        cbDeviceId = new JComboBox<>(); // åˆ›å»ºè®¾å¤‡ID下拉框
        cbDeviceId.setEditable(true); // è®¾ç½®ä¸ºå¯ç¼–辑,允许手动输入设备ID
        cbDeviceId.addItem(messages.getString("MESSAGE_VIEW_ALL_DEVICES")); // æ·»åŠ "所有设备"选项
        loadDeviceIds(); // åŠ è½½è®¾å¤‡ID列表
        devicePanel.add(cbDeviceId, BorderLayout.CENTER); // å°†ä¸‹æ‹‰æ¡†æ·»åŠ åˆ°é¢æ¿ä¸­å¤®
        add(devicePanel, gbc); // å°†é¢æ¿æ·»åŠ åˆ°ä¸»é¢æ¿
        gbc.gridx++;
        JPanel devicePanel = new JPanel(new BorderLayout(5, 0));
        devicePanel.setBackground(new Color(240, 245, 249));
        devicePanel.add(createLabel(messages.getString("MESSAGE_VIEW_DEVICE_ID")), BorderLayout.WEST);
        cbDeviceId = new JComboBox<>();
        cbDeviceId.setEditable(true);
        cbDeviceId.addItem("ALL");
        loadDeviceIds();
        devicePanel.add(cbDeviceId, BorderLayout.CENTER);
        add(devicePanel, gbc);
        // è¿œç¨‹è®¾å¤‡ä¸‹æ‹‰æ¡†
        gbc.gridx++; // ç§»åŠ¨åˆ°ä¸‹ä¸€åˆ—
        JPanel remoteDevicePanel = new JPanel(new BorderLayout(5, 0)); // è¿œç¨‹è®¾å¤‡é€‰æ‹©é¢æ¿
        remoteDevicePanel.setBackground(new Color(240, 245, 249)); // è®¾ç½®èƒŒæ™¯è‰²
        remoteDevicePanel.add(createLabel(messages.getString("MESSAGE_VIEW_REMOTE_DEVICE")), BorderLayout.WEST); // æ·»åŠ è¿œç¨‹è®¾å¤‡æ ‡ç­¾
        cbRemoteDevice = new JComboBox<>(); // åˆ›å»ºè¿œç¨‹è®¾å¤‡ä¸‹æ‹‰æ¡†
        cbRemoteDevice.setEditable(true); // è®¾ç½®ä¸ºå¯ç¼–辑
        cbRemoteDevice.addItem(messages.getString("MESSAGE_VIEW_ALL_DEVICES")); // æ·»åŠ "所有设备"选项
        remoteDevicePanel.add(cbRemoteDevice, BorderLayout.CENTER); // å°†ä¸‹æ‹‰æ¡†æ·»åŠ åˆ°é¢æ¿ä¸­å¤®
        add(remoteDevicePanel, gbc); // å°†é¢æ¿æ·»åŠ åˆ°ä¸»é¢æ¿
        gbc.gridx++;
        JPanel remoteDevicePanel = new JPanel(new BorderLayout(5, 0));
        remoteDevicePanel.setBackground(new Color(240, 245, 249));
        remoteDevicePanel.add(createLabel(messages.getString("MESSAGE_VIEW_REMOTE_DEVICE")), BorderLayout.WEST);
        cbRemoteDevice = new JComboBox<>();
        cbRemoteDevice.setEditable(true);
        cbRemoteDevice.addItem(messages.getString("MESSAGE_VIEW_ALL_DEVICES"));
        remoteDevicePanel.add(cbRemoteDevice, BorderLayout.CENTER);
        add(remoteDevicePanel, gbc);
        // å¤é€‰æ¡†åŒºåŸŸ
        gbc.gridx = 0; // é‡ç½®åˆ—位置
        gbc.gridy++; // ç§»åŠ¨åˆ°ä¸‹ä¸€è¡Œ
        gbc.gridwidth = 4; // æ¨ªè·¨4列
        gbc.weightx = 1.0; // æ°´å¹³æƒé‡
        // å¤é€‰æ¡†åŒºåŸŸ - ç®€åŒ–为两个复选框
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 4;
        gbc.weightx = 1.0;
        JPanel checkboxPanel = new JPanel(new GridLayout(1, 4, 6, 0)); // åˆ›å»ºç½‘格布局面板(1行4列)
        checkboxPanel.setBackground(new Color(240, 245, 249)); // è®¾ç½®èƒŒæ™¯è‰²
        chkAutoSave = createStyledCheckbox(messages.getString("MESSAGE_VIEW_AUTO_SAVE")); // åˆ›å»ºè‡ªåŠ¨ä¿å­˜å¤é€‰æ¡†
        chkShowSource = createStyledCheckbox(messages.getString("MESSAGE_VIEW_SHOW_SOURCE")); // åˆ›å»ºæ˜¾ç¤ºæ¥æºå¤é€‰æ¡†
        chkHexDisplay = createStyledCheckbox(messages.getString("MESSAGE_VIEW_HEX_DISPLAY")); // åˆ›å»ºåå…­è¿›åˆ¶æ˜¾ç¤ºå¤é€‰æ¡†
        chkAsciiDisplay = createStyledCheckbox(messages.getString("MESSAGE_VIEW_ASCII_DISPLAY")); // åˆ›å»ºASCII显示复选框
        JPanel checkboxPanel = new JPanel(new GridLayout(1, 2, 6, 0)); // ä¿®æ”¹ä¸º2列
        checkboxPanel.setBackground(new Color(240, 245, 249));
        chkAutoSave = createStyledCheckbox(messages.getString("MESSAGE_VIEW_AUTO_SAVE"));
        chkShowSource = createStyledCheckbox(messages.getString("MESSAGE_VIEW_SHOW_SOURCE"));
        // å°†å¤é€‰æ¡†æ·»åŠ åˆ°é¢æ¿
        // ç§»é™¤äº†åå…­è¿›åˆ¶å’ŒASCII显示复选框
        checkboxPanel.add(chkAutoSave);
        checkboxPanel.add(chkShowSource);
        checkboxPanel.add(chkHexDisplay);
        checkboxPanel.add(chkAsciiDisplay);
        add(checkboxPanel, gbc); // å°†å¤é€‰æ¡†é¢æ¿æ·»åŠ åˆ°ä¸»é¢æ¿
        add(checkboxPanel, gbc);
        // æ•°æ®æ˜¾ç¤ºåŒºåŸŸ
        gbc.gridy++; // ç§»åŠ¨åˆ°ä¸‹ä¸€è¡Œ
        gbc.weighty = 1.0; // åž‚直权重
        gbc.fill = GridBagConstraints.BOTH; // åŒå‘å¡«å……
        gbc.gridy++;
        gbc.weighty = 1.0;
        gbc.fill = GridBagConstraints.BOTH;
        txtDataView = new JTextArea(); // åˆ›å»ºæ–‡æœ¬åŒºåŸŸ
        txtDataView.setFont(new Font("Monospaced", Font.PLAIN, 14)); // è®¾ç½®ç­‰å®½å­—体
        txtDataView.setEditable(false); // è®¾ç½®ä¸ºä¸å¯ç¼–辑
        scrollPane = new JScrollPane(txtDataView); // åˆ›å»ºå¸¦æ»šåŠ¨æ¡çš„é¢æ¿
        txtDataView = new JTextArea();
        txtDataView.setFont(new Font("Monospaced", Font.PLAIN, 14));
        txtDataView.setEditable(false);
        scrollPane = new JScrollPane(txtDataView);
        scrollPane.setPreferredSize(new Dimension(800, 400));
        scrollPane.setBorder(BorderFactory.createTitledBorder( // è®¾ç½®å¸¦æ ‡é¢˜çš„边框
                BorderFactory.createLineBorder(new Color(180, 180, 220)), // è¾¹æ¡†é¢œè‰²
                messages.getString("MESSAGE_VIEW_DATA_PANEL"), // æ ‡é¢˜æ–‡æœ¬
                TitledBorder.LEFT, // æ ‡é¢˜ä½ç½®
                TitledBorder.TOP, // æ ‡é¢˜ä½ç½®
                new Font("微软雅黑", Font.BOLD, 12), // æ ‡é¢˜å­—体
                new Color(70, 130, 180) // æ ‡é¢˜é¢œè‰²
        scrollPane.setBorder(BorderFactory.createTitledBorder(
                BorderFactory.createLineBorder(new Color(180, 180, 220)),
                messages.getString("MESSAGE_VIEW_DATA_PANEL"),
                TitledBorder.LEFT,
                TitledBorder.TOP,
                new Font("微软雅黑", Font.BOLD, 12),
                new Color(70, 130, 180)
                ));
        add(scrollPane, gbc); // å°†æ»šåŠ¨é¢æ¿æ·»åŠ åˆ°ä¸»é¢æ¿
        add(scrollPane, gbc);
        // æŒ‰é’®é¢æ¿åŒºåŸŸ
        gbc.gridy++; // ç§»åŠ¨åˆ°ä¸‹ä¸€è¡Œ
        gbc.weighty = 0; // é‡ç½®åž‚直权重
        gbc.fill = GridBagConstraints.HORIZONTAL; // æ°´å¹³å¡«å……
        gbc.gridy++;
        gbc.weighty = 0;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        // æŒ‰é’®é¢æ¿
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5)); // ä½¿ç”¨æµå¼å¸ƒå±€ï¼ˆå·¦å¯¹é½ï¼‰
        buttonPanel.setBackground(new Color(240, 245, 249)); // è®¾ç½®èƒŒæ™¯è‰²
        btnStart = createStyledButton(messages.getString("MESSAGE_VIEW_START"), new Color(70, 130, 180)); // åˆ›å»ºå¼€å§‹æŒ‰é’®ï¼ˆè“è‰²ï¼‰
        btnPause = createStyledButton(messages.getString("MESSAGE_VIEW_PAUSE"), new Color(218, 165, 32)); // åˆ›å»ºæš‚停按钮(金色)
        btnClear = createStyledButton(messages.getString("MESSAGE_VIEW_CLEAR"), new Color(205, 92, 92)); // åˆ›å»ºæ¸…除按钮(红色)
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5));
        buttonPanel.setBackground(new Color(240, 245, 249));
        btnStart = createStyledButton(messages.getString("MESSAGE_VIEW_START"), new Color(70, 130, 180));
        btnPause = createStyledButton(messages.getString("MESSAGE_VIEW_PAUSE"), new Color(218, 165, 32));
        btnClear = createStyledButton(messages.getString("MESSAGE_VIEW_CLEAR"), new Color(205, 92, 92));
        // å‘送相关控件
        txtSendData = new JTextField(30); // å‘送数据文本框
        txtSendData.setFont(new Font("微软雅黑", Font.PLAIN, 12)); // è®¾ç½®å­—体
        btnSend = createStyledButton(messages.getString("MESSAGE_VIEW_SEND"), new Color(60, 179, 113)); // åˆ›å»ºå‘送按钮(绿色)
        txtSendData = new JTextField(30);
        txtSendData.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        btnSend = createStyledButton(messages.getString("MESSAGE_VIEW_SEND"), new Color(60, 179, 113));
        // åˆ›å»ºå‘送选项面板
        JPanel sendOptionsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 0));
        sendOptionsPanel.setBackground(new Color(240, 245, 249));
        // åˆ›å»ºå•选按钮组
        ButtonGroup sendFormatGroup = new ButtonGroup();
        // åˆ›å»ºHEX发送单选按钮
        rdoSendHex = createStyledRadioButton(messages.getString("MESSAGE_VIEW_SEND_HEX"));
        // åˆ›å»ºASCII发送单选按钮
        rdoSendAscii = createStyledRadioButton(messages.getString("MESSAGE_VIEW_SEND_ASCII"));
        // å°†å•选按钮添加到按钮组
        sendFormatGroup.add(rdoSendHex);
        sendFormatGroup.add(rdoSendAscii);
        // é»˜è®¤é€‰ä¸­ASCII发送
        rdoSendAscii.setSelected(true);
        // å›žè½¦æ¢è¡Œå¤é€‰æ¡†
        chkAppendNewline = createStyledCheckbox(messages.getString("MESSAGE_VIEW_APPEND_NEWLINE"));
        sendOptionsPanel.add(rdoSendHex);
        sendOptionsPanel.add(rdoSendAscii);
        sendOptionsPanel.add(chkAppendNewline);
        // å°†æŒ‰é’®æ·»åŠ åˆ°æŒ‰é’®é¢æ¿
        buttonPanel.add(btnStart);
        buttonPanel.add(btnPause);
        buttonPanel.add(btnClear);
@@ -229,55 +200,46 @@
        buttonPanel.add(btnSend);
        buttonPanel.add(sendOptionsPanel);
        add(buttonPanel, gbc); // å°†æŒ‰é’®é¢æ¿æ·»åŠ åˆ°ä¸»é¢æ¿
        add(buttonPanel, gbc);
        // è®¾ç½®æŒ‰é’®åŠ¨ä½œ
        setupActions();
    }
    // åˆ›å»ºå¸¦æ ·å¼çš„æ ‡ç­¾
    private JLabel createLabel(String text) {
        JLabel label = new JLabel(text); // åˆ›å»ºæ ‡ç­¾
        label.setFont(new Font("微软雅黑", Font.BOLD, 12)); // è®¾ç½®å­—体
        label.setForeground(new Color(70, 70, 70)); // è®¾ç½®å‰æ™¯è‰²
        JLabel label = new JLabel(text);
        label.setFont(new Font("微软雅黑", Font.BOLD, 12));
        label.setForeground(new Color(70, 70, 70));
        return label;
    }
    // åˆ›å»ºå¸¦æ ·å¼çš„æŒ‰é’®
    private JButton createStyledButton(String text, Color bgColor) {
        JButton button = new JButton(text); // åˆ›å»ºæŒ‰é’®
        button.setFont(new Font("微软雅黑", Font.BOLD, 12)); // è®¾ç½®å­—体
        button.setBackground(bgColor); // è®¾ç½®èƒŒæ™¯è‰²
        button.setForeground(Color.WHITE); // è®¾ç½®å‰æ™¯è‰²ï¼ˆç™½è‰²ï¼‰
        button.setFocusPainted(false); // ç¦ç”¨ç„¦ç‚¹è¾¹æ¡†
        button.setBorder(BorderFactory.createCompoundBorder( // è®¾ç½®å¤åˆè¾¹æ¡†
                BorderFactory.createLineBorder(bgColor.darker(), 1), // å¤–部边框(深色)
                BorderFactory.createEmptyBorder(5, 15, 5, 15) // å†…部边距
        JButton button = new JButton(text);
        button.setFont(new Font("微软雅黑", Font.BOLD, 12));
        button.setBackground(bgColor);
        button.setForeground(Color.WHITE);
        button.setFocusPainted(false);
        button.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createLineBorder(bgColor.darker(), 1),
                BorderFactory.createEmptyBorder(5, 15, 5, 15)
                ));
        return button;
    }
    // åˆ›å»ºå¸¦æ ·å¼çš„复选框
    private JCheckBox createStyledCheckbox(String text) {
        JCheckBox checkBox = new JCheckBox(text); // åˆ›å»ºå¤é€‰æ¡†
        checkBox.setFont(new Font("微软雅黑", Font.PLAIN, 12)); // è®¾ç½®å­—体
        checkBox.setBackground(new Color(240, 245, 249)); // è®¾ç½®èƒŒæ™¯è‰²
        checkBox.setForeground(new Color(70, 70, 70)); // è®¾ç½®å‰æ™¯è‰²
        JCheckBox checkBox = new JCheckBox(text);
        checkBox.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        checkBox.setBackground(new Color(240, 245, 249));
        checkBox.setForeground(new Color(70, 70, 70));
        return checkBox;
    }
    // åˆ›å»ºå¸¦æ ·å¼çš„单选按钮
    private JRadioButton createStyledRadioButton(String text) {
        JRadioButton radioButton = new JRadioButton(text); // åˆ›å»ºå•选按钮
        radioButton.setFont(new Font("微软雅黑", Font.PLAIN, 12)); // è®¾ç½®å­—体
        radioButton.setBackground(new Color(240, 245, 249)); // è®¾ç½®èƒŒæ™¯è‰²
        radioButton.setForeground(new Color(70, 70, 70)); // è®¾ç½®å‰æ™¯è‰²
        // ç¾ŽåŒ–选中效果
        JRadioButton radioButton = new JRadioButton(text);
        radioButton.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        radioButton.setBackground(new Color(240, 245, 249));
        radioButton.setForeground(new Color(70, 70, 70));
        radioButton.setIcon(new RadioButtonIcon(false));
        radioButton.setSelectedIcon(new RadioButtonIcon(true));
        // æ·»åŠ é¼ æ ‡æ‚¬åœæ•ˆæžœ
        radioButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseEntered(java.awt.event.MouseEvent evt) {
                radioButton.setForeground(new Color(30, 144, 255));
@@ -286,11 +248,9 @@
                radioButton.setForeground(new Color(70, 70, 70));
            }
        });
        return radioButton;
    }
    // è‡ªå®šä¹‰å•选按钮图标
    private static class RadioButtonIcon implements Icon {
        private static final int SIZE = 14;
        private final boolean selected;
@@ -305,19 +265,14 @@
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            if (selected) {
                // é€‰ä¸­çŠ¶æ€ - è“è‰²å¡«å……
                g2d.setColor(new Color(70, 130, 180));
                g2d.fillOval(x, y, SIZE, SIZE);
                // å†…圆 - ç™½è‰²
                g2d.setColor(Color.WHITE);
                g2d.fillOval(x + SIZE/4, y + SIZE/4, SIZE/2, SIZE/2);
            } else {
                // æœªé€‰ä¸­çŠ¶æ€ - ç°è‰²è¾¹æ¡†
                g2d.setColor(new Color(150, 150, 150));
                g2d.drawOval(x, y, SIZE-1, SIZE-1);
            }
            g2d.dispose();
        }
@@ -332,51 +287,41 @@
        }
    }
    // åŠ è½½æ•°æ®ç±»åž‹
    private void loadtyps() {
        cbDataType.removeAllItems();
        // æ·»åŠ å›½é™…åŒ–é€‰é¡¹
        cbDataType.addItem(messages.getString("MESSAGE_VIEW_ALL_TYPES"));
        cbDataType.addItem(messages.getString("MESSAGE_VIEW_UDP_PORT_A"));
        cbDataType.addItem(messages.getString("MESSAGE_VIEW_UDP_PORT_B"));
        cbDataType.addItem(messages.getString("MESSAGE_VIEW_TCP_PORT"));
        cbDataType.addItem(messages.getString("MESSAGE_VIEW_MQTT_PORT"));
        cbDataType.addItem("UDPA");
        cbDataType.addItem("UDPB");
        cbDataType.addItem("TCP");
    }
    // è®¾ç½®æŒ‰é’®åŠ¨ä½œ
    private void setupActions() {
        btnStart.addActionListener(e -> startCapture()); // å¼€å§‹æŒ‰é’®ç»‘定开始捕获方法
        btnPause.addActionListener(e -> pauseCapture()); // æš‚停按钮绑定暂停捕获方法
        btnClear.addActionListener(e -> clearDisplay()); // æ¸…除按钮绑定清除显示方法
        btnSend.addActionListener(e -> sendData()); // å‘送按钮绑定发送方法
        btnStart.addActionListener(e -> startCapture());
        btnPause.addActionListener(e -> pauseCapture());
        btnClear.addActionListener(e -> clearDisplay());
        btnSend.addActionListener(e -> sendData());
    }
    // å¼€å§‹æ•获数据
    private void startCapture() {
        if (!isCapturing) { // å¦‚果当前未在捕获状态
            isCapturing = true; // è®¾ç½®æ•获状态为true
            btnStart.setEnabled(false); // ç¦ç”¨å¼€å§‹æŒ‰é’®
            btnPause.setEnabled(true); // å¯ç”¨æš‚停按钮
            // å¯åŠ¨æ•°æ®æ•èŽ·çº¿ç¨‹
        if (!isCapturing) {
            isStarted = true; // è®¾ç½®å¼€å§‹æ ‡å¿—
            isCapturing = true;
            btnStart.setEnabled(false);
            btnPause.setEnabled(true);
        }
    }
    // æš‚停捕获数据
    private void pauseCapture() {
        isCapturing = false; // è®¾ç½®æ•获状态为false
        btnStart.setEnabled(true); // å¯ç”¨å¼€å§‹æŒ‰é’®
        btnPause.setEnabled(false); // ç¦ç”¨æš‚停按钮
        isStarted = false; // æ¸…除开始标志
        isCapturing = false;
        btnStart.setEnabled(true);
        btnPause.setEnabled(false);
    }
    // æ¸…除数据显示
    private void clearDisplay() {
        txtDataView.setText(""); // æ¸…空文本区域
        txtDataView.setText("");
    }
    // å‘送数据到远程设备
    private void sendData() {
        // ä½¿ç”¨æ–°æ–¹æ³•获取当前资源包
        ResourceBundle currentMessages = Languages.getCurrentMessages();        
        String selectedDevice = (String) cbRemoteDevice.getSelectedItem();
        if (selectedDevice == null || selectedDevice.equals(currentMessages.getString("MESSAGE_VIEW_ALL_DEVICES"))) {
@@ -387,7 +332,6 @@
            return;
        }
        // èŽ·å–æœ¬åœ°ç«¯å£
        Integer localPort = remoteDeviceLocalPortMap.get(selectedDevice);
        if (localPort == null) {
            JOptionPane.showMessageDialog(this, 
@@ -397,7 +341,6 @@
            return;
        }
        // è§£æžIP和端口
        String[] parts = selectedDevice.split(":");
        if (parts.length != 2) {
            JOptionPane.showMessageDialog(this, 
@@ -428,12 +371,10 @@
            return;
        }
        // æ·»åŠ å›žè½¦æ¢è¡Œ
        if (chkAppendNewline.isSelected()) {
            dataToSend += "\r\n";
        }
        // è®°å½•发送数据到界面
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String timestamp = sdf.format(new Date());
@@ -441,21 +382,15 @@
        displayData.append("[SEND][").append(timestamp).append("][").append(ip).append(":").append(port).append("] ");
        if (rdoSendHex.isSelected()) {
            // HEX格式发送
            String hexData = toHexString(dataToSend);
            displayData.append(hexData);
            if (localPort == UDPPortAReceiver.PORT) {
                // ä¼ å…¥æ˜¯å¦HEX发送的标志
                UDPPortAReceiver.sendData(ip, port, dataToSend, true);
            } else if (localPort == UDPPortBReceiver.PORT) {
                // ä¼ å…¥æ˜¯å¦HEX发送的标志
                UDPPortBReceiver.sendData(ip, port, dataToSend, true);
            }
        } else {
            // ASCII格式发送
            displayData.append(dataToSend);
            // å®žé™…发送ASCII数据(这里需要调用UDP发送方法)
            if (localPort == UDPPortAReceiver.PORT) {
                UDPPortAReceiver.sendData(ip, port, dataToSend, false);
            } else if (localPort == UDPPortBReceiver.PORT) {
@@ -463,22 +398,17 @@
            }
        }
        // åœ¨EDT线程中更新UI
        SwingUtilities.invokeLater(() -> {
            txtDataView.append(displayData.toString() + "\n");
            // è‡ªåŠ¨æ»šåŠ¨åˆ°åº•éƒ¨
            txtDataView.setCaretPosition(txtDataView.getDocument().getLength());
        });
    }
    // ä¿®æ”¹æ·»åŠ è¿œç¨‹è®¾å¤‡æ–¹æ³•
    // åœ¨MessageViewPanel类中修改addRemoteDevice方法
    public static void addRemoteDevice(String ip, int port, int localPort) {
        String device = ip + ":" + port;
        if (!remoteDeviceLocalPortMap.containsKey(device)) {
            remoteDeviceLocalPortMap.put(device, localPort);
            SwingUtilities.invokeLater(() -> {
                // æ£€æŸ¥ä¸‹æ‹‰æ¡†ä¸­æ˜¯å¦å·²å­˜åœ¨è¯¥è®¾å¤‡
                boolean exists = false;
                ComboBoxModel<String> model = cbRemoteDevice.getModel();
                for (int i = 0; i < model.getSize(); i++) {
@@ -495,120 +425,56 @@
        }
    }
    // æ•获数据的核心方法
    // ä¿®æ”¹é€šç”¨æ•°æ®æ˜¾ç¤ºæ–¹æ³•
    public static void showData(String rawData, String ip, int port, int localPort, String deviceId) {
        if (!isWindowVisible) {
    public static void showData(String rawData, String ip, int port, int localPort,
                               String DataType, String Protocol, String Id) {
        // åŒé‡æ£€æŸ¥ï¼šçª—口可见且已点击开始按钮
        if (!isWindowVisible || !isStarted) {
            return;
        }
        // èŽ·å–å½“å‰é€‰æ‹©
        if (cbDataType == null || cbProtocol == null || cbDeviceId == null) {
            return;
        }
        String selectedDataType = (String) cbDataType.getSelectedItem();
        String selectedProtocol = (String) cbProtocol.getSelectedItem();
        String selectedDeviceId = (String) cbDeviceId.getSelectedItem();
        // ä½¿ç”¨æ–°æ–¹æ³•获取当前资源包
        ResourceBundle messages = Languages.getCurrentMessages();
        boolean DataTypeboolean = "ALL".equals(selectedDataType) || selectedDataType.equals(DataType);
        boolean Protocolboolean = "ALL".equals(selectedProtocol) || selectedProtocol.equals(Protocol);
        boolean DeviceIdboolean = "ALL".equals(selectedDeviceId) || selectedDeviceId.equals(Id);
        
        String allTypes = messages.getString("MESSAGE_VIEW_ALL_TYPES");
        String allProtocols = messages.getString("MESSAGE_VIEW_ALL_PROTOCOLS");
        String allDevices = messages.getString("MESSAGE_VIEW_ALL_DEVICES");
        String udpPortA = messages.getString("MESSAGE_VIEW_UDP_PORT_A");
        String udpPortB = messages.getString("MESSAGE_VIEW_UDP_PORT_B");
        String udpProtocol = "UDP"; // ç›´æŽ¥ä½¿ç”¨åè®®åç§°
        if (DataTypeboolean && Protocolboolean && DeviceIdboolean) {
            StringBuilder sb = SB.get();
            sb.setLength(0);
        // æ£€æŸ¥æ•°æ®ç±»åž‹è¿‡æ»¤
        boolean dataTypeMatch = selectedDataType.equals(allTypes) ||
                (localPort == UDPPortAReceiver.PORT && selectedDataType.equals(udpPortA)) ||
                (localPort == UDPPortBReceiver.PORT && selectedDataType.equals(udpPortB));
        // æ£€æŸ¥åè®®è¿‡æ»¤
        boolean protocolMatch = selectedProtocol.equals(allProtocols) ||
                (localPort == UDPPortAReceiver.PORT && selectedProtocol.equals(udpProtocol)) ||
                (localPort == UDPPortBReceiver.PORT && selectedProtocol.equals(udpProtocol));
        // æ£€æŸ¥è®¾å¤‡ID过滤
        boolean deviceIdMatch=false;
        if("1".equals(deviceId)) {
            deviceIdMatch=true;
        }else {
            deviceIdMatch = selectedDeviceId.equals(allDevices) ||
                    (deviceId != null && deviceId.equals(selectedDeviceId));
            if (chkShowSource.isSelected()) {
                sb.append(PREFIX);
                formatTime(sb);
                sb.append(',').append(ip).append(COLON).append(port).append(SUFFIX);
        }
            sb.append(rawData);
        // åªæœ‰å½“所有条件都匹配时才显示
        if (!(dataTypeMatch && protocolMatch && deviceIdMatch)) {
            return;
        }
        // ç”Ÿæˆæ¯«ç§’级时间戳
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
        String timestamp = sdf.format(new Date());
        String formattedData = formatData(rawData, ip, port, timestamp);
        if (isCapturing) {
            // æ·»åŠ è¿œç¨‹è®¾å¤‡åˆ°ä¸‹æ‹‰æ¡†
            addRemoteDevice(ip, port, localPort);
            // åœ¨EDT线程中更新UI
            final String finalText = sb.toString();
            SwingUtilities.invokeLater(() -> {
                txtDataView.append(formattedData + "\n");
                txtDataView.append(finalText);
                txtDataView.append("\n");
                txtDataView.setCaretPosition(txtDataView.getDocument().getLength());
            });
            if (isCapturing && localPort != 0) {
                addRemoteDevice(ip, port, localPort);
        }
        // å¦‚果启用了自动保存,则保存到文件
        if (chkAutoSave.isSelected()) {
            saveToFile(formattedData);
                saveToFile(finalText);
            }
        }
    }
    // æ ¼å¼åŒ–数据显示
    // ä¿®æ”¹æ ¼å¼æ˜¾ç¤ºæ–¹æ³•,支持混合格式
    private static String formatData(String rawData, String ip, int port, String timestamp) {
        StringBuilder formatted = new StringBuilder();
        // ä½¿ç”¨æ–°æ–¹æ³•获取当前资源包
        ResourceBundle messages = Languages.getCurrentMessages();
        // æ˜¾ç¤ºæ¥æºä¿¡æ¯
        if (chkShowSource.isSelected()) {
            formatted.append("[")
            .append(timestamp)
            .append("][")
            .append(ip)
            .append(":")
            .append(port)
            .append("] ");
        }
        // æ ¹æ®æ˜¾ç¤ºé€‰é¡¹æ ¼å¼åŒ–数据
        if (chkHexDisplay.isSelected() && chkAsciiDisplay.isSelected()) {
            formatted.append(formatHexString(rawData))
            .append(" | ")
            .append(hexToAscii(rawData))
            .append(" [")
            .append(messages.getString("MESSAGE_VIEW_MIXED_FORMAT"))
            .append("]");
        } else if (chkHexDisplay.isSelected()) {
            formatted.append(formatHexString(rawData))
            .append(" [")
            .append(messages.getString("MESSAGE_VIEW_HEX_FORMAT"))
            .append("]");
        } else if (chkAsciiDisplay.isSelected()) {
            formatted.append(hexToAscii(rawData))
            .append(" [")
            .append(messages.getString("MESSAGE_VIEW_ASCII_FORMAT"))
            .append("]");
        } else {
            formatted.append(hexToAscii(rawData));
        }
        return formatted.toString();
    }
    // ä¿®æ”¹è®¾å¤‡ID加载方法
    private void loadDeviceIds() {
        cbDeviceId.removeAllItems();
        cbDeviceId.addItem(messages.getString("MESSAGE_VIEW_ALL_DEVICES"));
        cbDeviceId.addItem("ALL");
        List<String> tags = Dell_tag.getAlldeviceIds();
        for (String tag : tags) {
@@ -616,42 +482,54 @@
        }
    }
    // å°†å­—符串转换为十六进制表示
    private static String toHexString(String input) {
        StringBuilder hex = new StringBuilder(); // ä½¿ç”¨StringBuilder构建十六进制字符串
        for (char c : input.toCharArray()) { // éåŽ†æ¯ä¸ªå­—ç¬¦
            hex.append(String.format("%02X ", (int) c)); // æ ¼å¼åŒ–为两位十六进制
        StringBuilder hex = new StringBuilder();
        for (char c : input.toCharArray()) {
            hex.append(String.format("%02X ", (int) c));
        }
        return hex.toString().trim(); // è¿”回并去除末尾空格
    }
    // æ ¼å¼åŒ–十六进制字符串(每两个字符加空格)
    private static String formatHexString(String hex) {
        StringBuilder formatted = new StringBuilder();
        for (int i = 0; i < hex.length(); i += 2) {
            if (i > 0) formatted.append(" ");
            formatted.append(hex.substring(i, Math.min(i + 2, hex.length())));
        }
        return formatted.toString();
        return hex.toString().trim();
    }
    // å°†åå…­è¿›åˆ¶å­—符串转换为ASCII
    private static String hexToAscii(String hexStr) {
        StringBuilder output = new StringBuilder();
        for (int i = 0; i < hexStr.length(); i += 2) {
            String str = hexStr.substring(i, i + 2);
            output.append((char) Integer.parseInt(str, 16));
        }
        return output.toString();
    }
    // ä¿å­˜æ•°æ®åˆ°æ–‡ä»¶
    private static void saveToFile(String data) {
        SimpleDateFormat fileFormat = new SimpleDateFormat("yyyyMMdd"); // æ–‡ä»¶æ—¥æœŸæ ¼å¼
        String fileName = "systemfile/baowen/messages_" + fileFormat.format(new Date()) + ".txt"; // æ–‡ä»¶ååŒ…含日期
        SimpleDateFormat fileFormat = new SimpleDateFormat("yyyyMMdd");
        String fileName = "systemfile/baowen/messages_" + fileFormat.format(new Date()) + ".txt";
        try (java.io.FileWriter writer = new java.io.FileWriter(fileName, true)) { // ä½¿ç”¨è¿½åŠ æ¨¡å¼
            writer.write(data + "\n"); // å†™å…¥æ•°æ®å¹¶æ¢è¡Œ
        try (java.io.FileWriter writer = new java.io.FileWriter(fileName, true)) {
            writer.write(data + "\n");
        } catch (java.io.IOException ex) {
            ex.printStackTrace(); // æ‰“印IO异常
            ex.printStackTrace();
        }
    }
    public static String getSelectedDataType() {
        return cbDataType == null ? "" : String.valueOf(cbDataType.getSelectedItem());
    }
    public static String getSelectedProtocol() {
        return cbProtocol == null ? "" : String.valueOf(cbProtocol.getSelectedItem());
    }
    public static String getSelectedDeviceId() {
        return cbDeviceId == null ? "" : String.valueOf(cbDeviceId.getSelectedItem());
    }
    private static void formatTime(StringBuilder sb) {
        long now = System.currentTimeMillis();
        long sec  = (now / 1000) % 86400;
        int  ms   = (int) (now % 1000);
        int h = (int) (sec / 3600);
        int m = (int) ((sec % 3600) / 60);
        int s = (int) (sec % 60);
        sb.append((char) ('0' + (h / 10)))
          .append((char) ('0' + (h % 10))).append(':');
        sb.append((char) ('0' + (m / 10)))
          .append((char) ('0' + (m % 10))).append(':');
        sb.append((char) ('0' + (s / 10)))
          .append((char) ('0' + (s % 10))).append('.');
        sb.append(DIGITS[ms / 100])
          .append(DIGITS[(ms / 10) % 10])
          .append(DIGITS[ms % 10]);
    }
}
src/dell_system/SerialCommPanel.java
@@ -1,6 +1,6 @@
package dell_system;
import com.fazecast.jSerialComm.SerialPort;
import dell55AAData.PacketParser;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.event.PopupMenuEvent;
@@ -332,7 +332,7 @@
            lblPacketCount.setText(String.format(messages.getString("packet.count.format"), packetCounter));
            try {
                String parsed = PacketParser.parse(data, messages, chkTimestamp.isSelected());
                String parsed = SerialPacketParser.parse(data, messages, chkTimestamp.isSelected());
                txtParsedData.append(parsed);
                txtParsedData.setCaretPosition(txtParsedData.getDocument().getLength());
                lblParseStatus.setText(
src/dell_system/SerialPacketParser.java
ÎļþÃû´Ó src/dell55AAData/PacketParser.java ÐÞ¸Ä
@@ -1,4 +1,4 @@
package dell55AAData;
package dell_system;
import dell55AAData.Dell55AA12HighPerf;
import dell55AAData.Dell55AA12HighPerf.ParseResult;
import dell55AAData.Dell55AA01Parser;
@@ -10,11 +10,11 @@
 * å…¬å…±è§£æžå™¨ï¼šæ ¹æ®åŒ…头统一解析 55AA01 / 55AA12 / æœªçŸ¥åè®®
 * å¯è¢«ä»»ä½• UI æˆ–业务类直接调用
 */
public final class PacketParser {
public final class SerialPacketParser {
    private static final SimpleDateFormat SDF = new SimpleDateFormat("HH:mm:ss.SSS");
    private PacketParser() { /* å·¥å…·ç±»ï¼Œç¦æ­¢å®žä¾‹åŒ– */ }
    private SerialPacketParser() { /* å·¥å…·ç±»ï¼Œç¦æ­¢å®žä¾‹åŒ– */ }
    /**
     * è§£æžå…¥å£
@@ -32,7 +32,7 @@
        }
        if (hex.startsWith("55AA01")) {
            Dell55AA01Parser.ParseResult r = Dell55AA01Parser.parse(hex);
            Dell55AA01Parser.ParseResult r = Dell55AA01Parser.parse(hex,"127.0.0.1", 0);
            if (r == null) {
                sb.append(bundle.getString("parser.invalid")).append(" 55AA01");
                return sb.toString();