package home; import javax.swing.*; import javax.swing.border.Border; import javax.swing.border.TitledBorder; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import java.awt.*; import java.awt.event.*; import java.util.*; import java.io.InputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.io.File; import java.io.FileInputStream; import java.util.PropertyResourceBundle; import com.fazecast.jSerialComm.SerialPort; import home.Dell55AA01Parser.ParseResult; public class AOAFollowSystem extends JFrame { private static final long serialVersionUID = 1L; private CardLayout cardLayout; private JPanel mainPanel; private HomePanel homePanel; private ConfigPanel configPanel; private ResourceBundle messages; private Locale currentLocale; private JButton homeBtn; private JButton configBtn; private JComboBox languageCombo; private JLabel languageLabel; private SerialPortService serialService; public AOAFollowSystem() { this.currentLocale = Locale.SIMPLIFIED_CHINESE; this.messages = loadResourceBundle(currentLocale); this.serialService = new SerialPortService(); initializeUI(); } private ResourceBundle loadResourceBundle(Locale locale) { String fileName = locale.equals(Locale.ENGLISH) ? "Messages_en.properties" : "Messages_zh.properties"; File langFile = new File("systemfile/" + fileName); if (!langFile.exists()) { System.err.println("默认资源文件未找到: " + langFile.getAbsolutePath()); return ResourceBundle.getBundle("systemfile.Messages"); } try (InputStream inputStream = new FileInputStream(langFile)) { return new PropertyResourceBundle(inputStream); } catch (IOException e) { System.err.println("无法加载资源文件: " + e.getMessage()); return ResourceBundle.getBundle("systemfile.Messages"); } } public String getString(String key) { if (messages != null && messages.containsKey(key)) { return messages.getString(key); } // 默认文本(中文) switch (key) { case "home": return "首页"; case "config": return "配置"; case "device_id": return "设备编号"; case "group": return "通信小组"; case "frequency": return "通信频率"; case "read_config": return "读取配置"; case "save_config": return "保存配置"; case "serial_port": return "串口"; case "baud_rate": return "波特率"; case "open_serial": return "打开串口"; case "close_serial": return "关闭串口"; case "start": return "开始"; case "pause": return "暂停"; case "clear": return "清空"; case "send": return "发送"; case "device_id_table": return "设备编号"; case "distance_table": return "实时距离"; case "angle_table": return "实时角度"; case "signal_table": return "信号质量"; case "power_table": return "电量"; case "button_table": return "按钮"; case "time_table": return "时间"; case "LANGUAGE": return "语言"; case "log": return "日志"; case "send_data": return "发送数据"; case "select_serial_port": return "请选择串口"; case "error": return "错误"; case "open_serial_first": return "请先打开串口"; case "input_data_to_send": return "请输入要发送的数据"; case "send_failed": return "发送失败"; case "receive": return "接收"; case "visualization": return "可视化"; case "config_read_success": return "配置读取成功"; case "info": return "信息"; case "input_valid_number": return "请输入有效的数字"; case "config_save_success": return "配置保存成功"; case "select_file": return "选择文件"; case "upgrade": return "升级"; case "upgrade_progress": return "升级进度"; case "select_bin_file": return "请选择bin文件"; case "upgrade_success": return "升级成功"; case "upgrade_failed": return "升级失败"; case "hex": return "HEX"; case "ascii": return "ASCII"; case "hex_send": return "HEX发送"; case "display_format": return "显示格式"; case "pair_tooltip": return currentLocale.equals(Locale.SIMPLIFIED_CHINESE) ? "点击发送后进入20秒配对模式" : "Enter 20-second pairing mode after clicking send"; case "scale": return currentLocale.equals(Locale.SIMPLIFIED_CHINESE) ? "缩放" : "Scale"; default: return key; } } private void initializeUI() { setTitle("HXZK_AOA"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(1000, 700); setLocationRelativeTo(null); // 创建顶部导航 JPanel navPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); homeBtn = createNavButton(getString("home"), new Color(70, 130, 180)); configBtn = createNavButton(getString("config"), new Color(70, 130, 180)); languageCombo = new JComboBox<>(new String[]{"中文", "English"}); languageCombo.setSelectedIndex(0); languageCombo.addActionListener(e -> { Locale newLocale = languageCombo.getSelectedIndex() == 0 ? Locale.SIMPLIFIED_CHINESE : Locale.ENGLISH; switchLanguage(newLocale); }); navPanel.add(homeBtn); navPanel.add(configBtn); navPanel.add(Box.createHorizontalStrut(20)); languageLabel = new JLabel(getString("LANGUAGE") + ":"); navPanel.add(languageLabel); navPanel.add(languageCombo); // 创建主面板(卡片布局) cardLayout = new CardLayout(); mainPanel = new JPanel(cardLayout); homePanel = new HomePanel(serialService, this); configPanel = new ConfigPanel(serialService, this); mainPanel.add(homePanel, "home"); mainPanel.add(configPanel, "config"); // 添加导航按钮事件 homeBtn.addActionListener(e -> cardLayout.show(mainPanel, "home")); configBtn.addActionListener(e -> cardLayout.show(mainPanel, "config")); // 设置布局 setLayout(new BorderLayout()); add(navPanel, BorderLayout.NORTH); add(mainPanel, BorderLayout.CENTER); // 设置默认显示首页 cardLayout.show(mainPanel, "home"); } private void switchLanguage(Locale newLocale) { this.currentLocale = newLocale; this.messages = loadResourceBundle(currentLocale); // 更新界面文本 updateUILanguage(); // 更新语言选择框 languageCombo.setSelectedIndex(newLocale.equals(Locale.SIMPLIFIED_CHINESE) ? 0 : 1); revalidate(); repaint(); } private void updateUILanguage() { // 更新导航按钮文本 homeBtn.setText(getString("home")); configBtn.setText(getString("config")); // 更新语言标签 languageLabel.setText(getString("LANGUAGE") + ":"); // 更新各面板文本 homePanel.updateLanguage(); configPanel.updateLanguage(); // 更新配对复选框的提示信息 homePanel.updatePairCheckboxTooltip(); } private JButton createNavButton(String text, Color color) { JButton button = new JButton(text); button.setBackground(color); button.setForeground(Color.WHITE); button.setFocusPainted(false); button.setBorder(BorderFactory.createEmptyBorder(5, 15, 5, 15)); button.addMouseListener(new MouseAdapter() { @Override public void mouseEntered(MouseEvent e) { button.setBackground(color.darker()); } @Override public void mouseExited(MouseEvent e) { button.setBackground(color); } }); return button; } // 首页面板 class HomePanel extends JPanel { /** * */ private static final long serialVersionUID = 1L; private VisualizationPanel visualizationPanel; private JTable dataTable; private JTextArea logArea; private JComboBox serialPortCombo; private JComboBox baudRateCombo; private JButton openSerialBtn; private JButton startPauseBtn; private JButton clearBtn; private JButton sendBtn; private JTextField sendField; private JLabel displayFormatLabel; // 新增:显示格式标签 private JLabel serialPortLabel; // 新增:串口标签 private JLabel baudRateLabel; // 新增:波特率标签 private SerialPortService serialService; private AOAFollowSystem parentFrame; private boolean serialOpened = false; private boolean isRunning = false; // 新增:显示格式单选按钮 private JRadioButton hexRadio; private JRadioButton asciiRadio; private JCheckBox hexSendCheckBox; private JCheckBox pairCheckBox; // 表格模型 - 只有1行 private Object[][] tableData = new Object[1][7]; private String[] columnNames = { getString("device_id_table"), getString("distance_table"), getString("angle_table"), getString("signal_table"), getString("power_table"), getString("button_table"), getString("time_table") }; // 优化:重用对象减少内存分配 private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); private StringBuilder hexBuilder = new StringBuilder(); private StringBuilder displayBuilder = new StringBuilder(); public HomePanel(SerialPortService serialService, AOAFollowSystem parentFrame) { this.serialService = serialService; this.parentFrame = parentFrame; setLayout(new BorderLayout(10, 10)); setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); // 创建左侧面板(可视化区域和表格) JPanel leftPanel = new JPanel(new BorderLayout(10, 10)); // 可视化面板 visualizationPanel = new VisualizationPanel(parentFrame); leftPanel.add(visualizationPanel, BorderLayout.CENTER); // 数据表格 JPanel tablePanel = new JPanel(new BorderLayout()); tablePanel.setBorder(BorderFactory.createTitledBorder(getString("device_id_table"))); dataTable = new JTable(tableData, columnNames); JScrollPane tableScroll = new JScrollPane(dataTable); tableScroll.setPreferredSize(new Dimension(0, 80)); tablePanel.add(tableScroll, BorderLayout.CENTER); leftPanel.add(tablePanel, BorderLayout.SOUTH); // 创建右侧面板(日志和控制) JPanel rightPanel = new JPanel(new BorderLayout(10, 10)); // 日志区域 JPanel logPanel = new JPanel(new BorderLayout()); logPanel.setBorder(BorderFactory.createTitledBorder(getString("log"))); logArea = new JTextArea(); logArea.setEditable(false); JScrollPane logScroll = new JScrollPane(logArea); logScroll.setPreferredSize(new Dimension(400, 0)); logPanel.add(logScroll, BorderLayout.CENTER); // 新增:显示格式选择面板 JPanel formatPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); formatPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); displayFormatLabel = new JLabel(getString("display_format") + ":"); // 使用getString获取文本 formatPanel.add(displayFormatLabel); ButtonGroup formatGroup = new ButtonGroup(); asciiRadio = new JRadioButton(getString("ascii"), true); // 默认选中ASCI asciiRadio.addItemListener(e -> { if (asciiRadio.isSelected()) { asciiRadio.setForeground(Color.RED); } else { asciiRadio.setForeground(null); // 恢复默认颜色 } }); hexRadio = new JRadioButton(getString("hex"), false); // 默认不选中HEX hexRadio.addItemListener(e -> { if (hexRadio.isSelected()) { hexRadio.setForeground(Color.RED); } else { hexRadio.setForeground(null); // 恢复默认颜色 } }); pairCheckBox = new JCheckBox(getString("pair"), false); // 默认不勾选 // 为配对复选框添加提示信息 pairCheckBox.setToolTipText(getString("pair_tooltip")); pairCheckBox.addItemListener(e -> { if (pairCheckBox.isSelected()) { sendField.setText("55AA030304F5FF"); } else { sendField.setText(""); } }); formatGroup.add(hexRadio); formatGroup.add(asciiRadio); formatPanel.add(hexRadio); formatPanel.add(asciiRadio); formatPanel.add(pairCheckBox); // 将格式选择面板添加到日志面板的底部 logPanel.add(formatPanel, BorderLayout.SOUTH); rightPanel.add(logPanel, BorderLayout.CENTER); // 控制面板 JPanel controlPanel = new JPanel(new GridBagLayout()); controlPanel.setBorder(BorderFactory.createTitledBorder(getString("serial_port"))); GridBagConstraints gbc = new GridBagConstraints(); gbc.insets = new Insets(5, 2, 5, 5); gbc.fill = GridBagConstraints.HORIZONTAL; // 串口选择 gbc.gridx = 0; gbc.gridy = 0; gbc.weightx = 0; serialPortLabel = new JLabel(getString("serial_port") + ":"); // 使用getString获取文本 controlPanel.add(serialPortLabel, gbc); gbc.gridx = 1; gbc.weightx = 1; serialPortCombo = new JComboBox<>(); // 添加弹出菜单监听器,点击时刷新串口列表 serialPortCombo.addPopupMenuListener(new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { refreshSerialPorts(); } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {} @Override public void popupMenuCanceled(PopupMenuEvent e) {} }); refreshSerialPorts(); controlPanel.add(serialPortCombo, gbc); // 波特率选择 gbc.gridx = 0; gbc.gridy = 1; gbc.weightx = 0; baudRateLabel = new JLabel(getString("baud_rate") + ":"); // 使用getString获取文本 controlPanel.add(baudRateLabel, gbc); gbc.gridx = 1; gbc.weightx = 1; baudRateCombo = new JComboBox<>(new String[]{"115200", "921600","9600", "19200", "38400", "57600"}); baudRateCombo.setSelectedIndex(0); controlPanel.add(baudRateCombo, gbc); // 串口控制按钮 gbc.gridx = 0; gbc.gridy = 2; gbc.gridwidth = 1; // 修改:只占一列 gbc.weightx = 0.5; // 修改:设置权重 openSerialBtn = createColoredButton(getString("open_serial"), new Color(70, 130, 180)); openSerialBtn.setPreferredSize(new Dimension(100, 30)); // 修改:设置与开始按钮相同尺寸 openSerialBtn.addActionListener(e -> toggleSerialPort()); controlPanel.add(openSerialBtn, gbc); openSerialBtn.setBackground(Color.GRAY); // 启动/暂停按钮(合并为一个) gbc.gridx = 1; // 修改:放在第二列 gbc.gridy = 2; JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 0)); startPauseBtn = createColoredButton(getString("start"), new Color(50, 205, 50)); startPauseBtn.setPreferredSize(new Dimension(100, 30)); startPauseBtn.addActionListener(e -> toggleCapture()); buttonPanel.add(startPauseBtn); clearBtn = createColoredButton(getString("clear"), new Color(192, 192, 192)); clearBtn.setPreferredSize(new Dimension(100, 30)); clearBtn.addActionListener(e -> clearLog()); buttonPanel.add(clearBtn); controlPanel.add(buttonPanel, gbc); rightPanel.add(controlPanel, BorderLayout.SOUTH); // 发送数据面板 - 移到表格下方 JPanel sendDataPanel = new JPanel(new BorderLayout(5, 5)); sendDataPanel.setBorder(BorderFactory.createTitledBorder(getString("send_data"))); JPanel sendControlPanel = new JPanel(new BorderLayout(5, 0)); sendField = new JTextField(); sendBtn = createColoredButton(getString("send"), new Color(70, 130, 180)); sendBtn.setPreferredSize(new Dimension(100, 30)); sendBtn.addActionListener(e -> sendData()); // 新增:HEX发送复选框 hexSendCheckBox = new JCheckBox(getString("hex_send"), false); // 默认勾选 sendControlPanel.add(hexSendCheckBox, BorderLayout.WEST); sendControlPanel.add(sendBtn, BorderLayout.EAST); sendDataPanel.add(sendField, BorderLayout.CENTER); sendDataPanel.add(sendControlPanel, BorderLayout.EAST); // 添加发送数据面板到左侧面板的最底部 leftPanel.add(sendDataPanel, BorderLayout.SOUTH); // 添加左右面板 add(leftPanel, BorderLayout.CENTER); add(rightPanel, BorderLayout.EAST); } // 在HomePanel类中添加更新配对复选框提示信息的方法 public void updatePairCheckboxTooltip() { pairCheckBox.setToolTipText(getString("pair_tooltip")); } private JButton createColoredButton(String text, Color color) { JButton button = new JButton(text); button.setBackground(color); button.setForeground(Color.WHITE); button.setFocusPainted(false); button.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10)); button.addMouseListener(new MouseAdapter() { @Override public void mouseEntered(MouseEvent e) { button.setBackground(color.darker()); } @Override public void mouseExited(MouseEvent e) { button.setBackground(color); } }); return button; } private void refreshSerialPorts() { String selectedPort = (String) serialPortCombo.getSelectedItem(); serialPortCombo.removeAllItems(); SerialPort[] ports = SerialPort.getCommPorts(); for (SerialPort port : ports) { serialPortCombo.addItem(port.getSystemPortName()); } // 尝试恢复之前的选择 if (selectedPort != null) { serialPortCombo.setSelectedItem(selectedPort); } else if (ports.length > 0) { serialPortCombo.setSelectedIndex(0); } } private void toggleSerialPort() { if (serialOpened) { closeSerialPort(); openSerialBtn.setText(getString("open_serial")); openSerialBtn.setBackground(Color.GRAY); // 关闭时灰色 serialOpened = false; // 关闭串口时停止捕获 if (isRunning) { toggleCapture(); } } else { if (openSerialPort()) { openSerialBtn.setText(getString("close_serial")); openSerialBtn.setBackground(Color.GREEN); serialOpened = true; } } } private boolean openSerialPort() { String portName = (String) serialPortCombo.getSelectedItem(); if (portName == null) { JOptionPane.showMessageDialog(this, getString("select_serial_port"), getString("error"), JOptionPane.ERROR_MESSAGE); return false; } int baudRate = Integer.parseInt((String) baudRateCombo.getSelectedItem()); return serialService.open(portName, baudRate); } private void closeSerialPort() { serialService.close(); } private void toggleCapture() { if (!serialOpened) { JOptionPane.showMessageDialog(this, getString("open_serial_first"), getString("error"), JOptionPane.ERROR_MESSAGE); return; } isRunning = !isRunning; serialService.setPaused(!isRunning); if (isRunning) { startPauseBtn.setText(getString("pause")); startPauseBtn.setBackground(new Color(255, 165, 0)); // 启动数据捕获 serialService.startCapture(this::processReceivedData); } else { startPauseBtn.setText(getString("start")); startPauseBtn.setBackground(new Color(50, 205, 50)); } } private void clearLog() { logArea.setText(""); } private void sendData() { if (!serialOpened) { JOptionPane.showMessageDialog(this, getString("open_serial_first"), getString("error"), JOptionPane.ERROR_MESSAGE); return; } String data = sendField.getText(); if (data.isEmpty()) { JOptionPane.showMessageDialog(this, getString("input_data_to_send"), getString("error"), JOptionPane.ERROR_MESSAGE); return; } byte[] sendBytes; if (hexSendCheckBox.isSelected()) { // HEX发送模式 try { sendBytes = hexStringToByteArray(data.replaceAll("\\s+", "")); if (sendBytes == null) { JOptionPane.showMessageDialog(this, "无效的HEX格式", getString("error"), JOptionPane.ERROR_MESSAGE); return; } } catch (Exception e) { JOptionPane.showMessageDialog(this, "HEX转换错误: " + e.getMessage(), getString("error"), JOptionPane.ERROR_MESSAGE); return; } } else { // ASCII发送模式 sendBytes = data.getBytes(); } boolean success = serialService.send(sendBytes); if (success) { appendLog(getString("send") + ": " + (hexSendCheckBox.isSelected() ? bytesToHex(sendBytes) : data)); } else { appendLog(getString("send_failed") + ": " + data); } sendField.setText(""); } private void processReceivedData(byte[] data) { // 优化:重用StringBuilder对象 hexBuilder.setLength(0); for (byte b : data) { hexBuilder.append(String.format("%02X", b)); } String displayText = hexBuilder.toString(); String displayText1 = new String(data).replaceAll("\\s+", ""); // 先检查数据长度是否足够进行解析 if (displayText.length() < 30) { // 至少需要30个字符(15字节)才能解析基本字段 appendLog("数据长度不足: " + displayText); return; } if (displayText.startsWith("55AA1F")) { Dell55AA1FParser.ParseResult result = Dell55AA1FParser.parse(displayText, "127.0.0.1", 0); if (result != null) { updateTable(result); visualizationPanel.updatePosition(result.distance, result.angle, result.signalQuality); visualizationPanel.setTagId(result.tagId); } else { appendLog("55AA1F协议解析失败: " + displayText); } } else if(displayText.startsWith("55AA01")) { ParseResult result = Dell55AA01Parser.parse(displayText, "127.0.0.1", 0); if (result != null) { visualizationPanel.updatePosition(result.distance, 270, 0); visualizationPanel.setTagId(result.tagId); } else { appendLog("55AA01协议解析失败: " + displayText); } } else if(displayText.startsWith("55AA51")) { Dell55AA51Parser.ParseResult result = Dell55AA51Parser.parse(displayText, "127.0.0.1", 0); if (result != null) { visualizationPanel.updatePosition(result.distance, result.horizontalAngle, result.signalStrength); visualizationPanel.setTagId(result.tagId); } else { appendLog("55AA51协议解析失败: " + displayText); } } else { // 如果不是已知协议,直接记录原始数据 appendLog("未知协议: " + displayText); } if (hexRadio.isSelected()) { appendLog(displayText); } else { if (displayText.startsWith("55AA1F")) { Dell55AA1FParser.ParseResult result = Dell55AA1FParser.parse(displayText, "127.0.0.1", 0); if (result != null) { // 优化:重用StringBuilder对象 displayBuilder.setLength(0); displayBuilder.append(result.tagId) .append(",Dis:") .append(result.distance) .append("cm,Angle:") .append(result.angle) .append("°,Signal:") .append(result.signalQuality) .append(",Button:") .append(result.buttonPressed) .append(",Power:") .append(result.power); appendLog(displayBuilder.toString()); } } else if(displayText.startsWith("55AA01")) { ParseResult result = Dell55AA01Parser.parse(displayText, "127.0.0.1", 0); if (result != null) { // 优化:重用StringBuilder对象 displayBuilder.setLength(0); displayBuilder.append("55AA01 Seq:") .append(result.sequenceNum) .append(",Tagid:") .append(result.tagId) .append(",Anchorid:") .append(result.anchorId) .append(",Distance:") .append(result.distance) .append(",Power:") .append(result.power) .append(",Button:") .append(result.buttonPressed); appendLog(displayBuilder.toString()); } } else if(displayText.startsWith("55AA51")) { Dell55AA51Parser.ParseResult result = Dell55AA51Parser.parse(displayText, "127.0.0.1", 0); if (result != null) { displayBuilder.setLength(0); displayBuilder.append(result.tagId) .append(",Dis:") .append(result.distance) .append("cm,HAngle:") .append(result.horizontalAngle) .append("°,VAngle:") .append(result.verticalAngle) .append("°,Signal:") .append(result.signalStrength) .append("°,ASignal:") .append(result.angleConfidence) .append(",Power:") .append(result.tagBattery) .append("%,Status:") .append(result.deviceStatus); appendLog(displayBuilder.toString()); } } else { appendLog(displayText1); } } } private void appendLog(String message) { SwingUtilities.invokeLater(() -> { // 优化:限制日志长度,防止内存无限增长 if (logArea.getLineCount() > 1000) { try { int end = logArea.getDocument().getLength(); int start = logArea.getDocument().getText(0, end).indexOf("\n") + 1; logArea.getDocument().remove(0, start); } catch (Exception e) { logArea.setText(""); // 如果出错则清空日志 } } String time = sdf.format(new Date()); logArea.append("[" + time + "] " + message + "\n"); // 自动滚动到最后 logArea.setCaretPosition(logArea.getDocument().getLength()); }); } private void updateTable(Dell55AA1FParser.ParseResult result) { SwingUtilities.invokeLater(() -> { // 只有1行数据,直接更新 String time = sdf.format(new Date()); tableData[0] = new Object[]{ result.tagId, result.distance + "cm", result.angle + "°", result.signalQuality, result.power + "%", result.buttonPressed, time }; // 刷新表格 dataTable.repaint(); }); } // 辅助方法:将字节数组转换为HEX字符串 private String bytesToHex(byte[] bytes) { // 优化:重用StringBuilder对象 hexBuilder.setLength(0); for (byte b : bytes) { hexBuilder.append(String.format("%02X ", b)); } return hexBuilder.toString().trim(); } // 辅助方法:将HEX字符串转换为字节数组 private byte[] hexStringToByteArray(String s) { int len = s.length(); if (len % 2 != 0) { return null; } byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { try { data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16)); } catch (Exception e) { return null; } } return data; } public void updateLanguage() { // 更新界面文本 openSerialBtn.setText(serialOpened ? getString("close_serial") : getString("open_serial")); startPauseBtn.setText(isRunning ? getString("pause") : getString("start")); clearBtn.setText(getString("clear")); sendBtn.setText(getString("send")); // 更新标签文本 displayFormatLabel.setText(getString("display_format") + ":"); serialPortLabel.setText(getString("serial_port") + ":"); baudRateLabel.setText(getString("baud_rate") + ":"); // 更新列名 columnNames[0] = getString("device_id_table"); columnNames[1] = getString("distance_table"); columnNames[2] = getString("angle_table"); columnNames[3] = getString("signal_table"); columnNames[4] = getString("power_table"); columnNames[5] = getString("button_table"); columnNames[6] = getString("time_table"); // 更新显示格式单选按钮 hexRadio.setText(getString("hex")); asciiRadio.setText(getString("ascii")); hexSendCheckBox.setText(getString("hex_send")); pairCheckBox.setText(getString("pair")); // 更新配对复选框的提示信息 updatePairCheckboxTooltip(); // 更新边框标题 updateBorderTitles(this); dataTable.repaint(); } private void updateBorderTitles(Container container) { for (Component comp : container.getComponents()) { if (comp instanceof JPanel) { JPanel panel = (JPanel) comp; Border border = panel.getBorder(); if (border instanceof TitledBorder) { TitledBorder titledBorder = (TitledBorder) border; String title = titledBorder.getTitle(); if (title.equals("日志") || title.equals("Log")) { titledBorder.setTitle(getString("log")); } else if (title.equals(getString("device_id_table")) || title.equals("Device ID")) { titledBorder.setTitle(getString("device_id_table")); } else if (title.equals(getString("serial_port")) || title.equals("Serial Port")) { titledBorder.setTitle(getString("serial_port")); } else if (title.equals("发送数据") || title.equals("Send Data")) { titledBorder.setTitle(getString("send_data")); } else if (title.equals("可视化") || title.equals("Visualization")) { titledBorder.setTitle(getString("visualization")); } panel.repaint(); } // 递归更新子组件 updateBorderTitles(panel); } } } private String getString(String key) { if (parentFrame != null) { return parentFrame.getString(key); } else { // 返回默认文本(中文)或 key 本身作为备用 switch (key) { case "home": return "首页"; case "config": return "配置"; case "display_format": return "显示格式"; case "serial_port": return "串口"; case "baud_rate": return "波特率"; case "close_serial": return "关闭串口"; // 其他 key 的默认值... default: return key; } } } } }