| | |
| | | private JLabel moveJoystickValueLabel; |
| | | private JLabel turnJoystickValueLabel; |
| | | private Timer speedUpdateTimer; // 速度更新定时器 |
| | | // 摇杆控制定时器:持续发送控制指令 |
| | | private Timer forwardControlTimer; // 前进/后退控制定时器 |
| | | private Timer steeringControlTimer; // 转向控制定时器 |
| | | private int targetForwardSpeed = 0; // 目标前进/后退速度 |
| | | private int targetSteeringSpeed = 0; // 目标转向速度 |
| | | private List<JButton> bladeButtons = new ArrayList<>(); // 存储刀盘控制按钮,用于清理定时器 |
| | | private String bladeUpDefaultText = "刀盘升"; // 刀盘升按钮默认文字 |
| | | private String bladeDownDefaultText = "刀盘降"; // 刀盘降按钮默认文字 |
| | | |
| | | public RemoteControlDialog(Component parent, Color themeColor, JLabel speedLabel) { |
| | | super(parent != null ? (JFrame) SwingUtilities.getWindowAncestor(parent) : null, |
| | |
| | | Control03.resetSpeeds(); |
| | | Control03.sendNeutralCommandIfDebugSerialOpen(); |
| | | int dialogWidth = UIConfig.DIALOG_WIDTH; // 与首页宽度一致 |
| | | int dialogHeight = (int) (UIConfig.DIALOG_HEIGHT / 3.0 * 0.7) + 50 + 40; // 增加40像素 |
| | | int dialogHeight = (int) (UIConfig.DIALOG_HEIGHT / 3.0 * 0.7) +150; // 增加90像素(原40+新增40+再增10) |
| | | initializeDialog(dialogWidth, dialogHeight); |
| | | initializeRemoteContent(); |
| | | startSpeedUpdateTimer(); // 启动速度更新定时器 |
| | |
| | | setSize(width, height); |
| | | setLocationRelativeTo(getOwner()); |
| | | setResizable(false); |
| | | getContentPane().setBackground(new Color(26, 26, 46)); // 深色背景 |
| | | Container contentPane = getContentPane(); |
| | | if (contentPane instanceof JComponent) { |
| | | JComponent jContentPane = (JComponent) contentPane; |
| | | jContentPane.setBackground(new Color(0, 0, 0, 0)); // 透明背景 |
| | | jContentPane.setOpaque(false); |
| | | } |
| | | } |
| | | |
| | | private void initializeRemoteContent() { |
| | | JPanel contentPanel = new JPanel(new BorderLayout()); |
| | | contentPanel.setBorder(BorderFactory.createEmptyBorder(16, 16, 16, 16)); |
| | | contentPanel.setBackground(Color.WHITE); |
| | | contentPanel.setOpaque(false); // 设置为透明 |
| | | |
| | | // 创建顶部面板,包含按钮和数值显示 |
| | | JPanel topPanel = new JPanel(new BorderLayout()); |
| | | topPanel.setOpaque(false); |
| | | |
| | | // 创建按钮面板(4个按钮,间隔30像素) |
| | | JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 30, 0)); |
| | | buttonPanel.setOpaque(false); |
| | | buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 8, 0)); // 底部间距8像素 |
| | | |
| | | // 按钮1:off.png <-> starton.png,文字:启动 <-> 熄火 |
| | | JLabel label1 = new JLabel("启动", SwingConstants.CENTER); |
| | | label1.setFont(new Font("微软雅黑", Font.PLAIN, 12)); |
| | | label1.setForeground(new Color(40, 40, 40)); |
| | | JButton button1 = createIconButtonWithLabel("image/off.png", "image/starton.png", 27, 27, |
| | | label1, "启动", "熄火", "POWER"); |
| | | JPanel panel1 = createButtonWithLabel(button1, label1); |
| | | buttonPanel.add(panel1); |
| | | |
| | | // 按钮2:dengoff.png <-> dengon.png,文字:开灯 <-> 关灯 |
| | | JLabel label2 = new JLabel("开灯", SwingConstants.CENTER); |
| | | label2.setFont(new Font("微软雅黑", Font.PLAIN, 12)); |
| | | label2.setForeground(new Color(40, 40, 40)); |
| | | JButton button2 = createIconButtonWithLabel("image/dengoff.png", "image/dengon.png", 30, 30, |
| | | label2, "开灯", "关灯", "LIGHT"); |
| | | JPanel panel2 = createButtonWithLabel(button2, label2); |
| | | buttonPanel.add(panel2); |
| | | |
| | | // 按钮3:xia1.png(固定图标),文字:刀盘升 |
| | | JButton button3 = createBladeControlButton("image/xia1.png", "image/xia20.png", 30, 30, true); |
| | | JLabel label3 = new JLabel("刀盘升", SwingConstants.CENTER); |
| | | label3.setFont(new Font("微软雅黑", Font.PLAIN, 12)); |
| | | label3.setForeground(new Color(40, 40, 40)); |
| | | button3.putClientProperty("label", label3); |
| | | button3.putClientProperty("defaultText", bladeUpDefaultText); |
| | | bladeButtons.add(button3); // 添加到列表以便清理 |
| | | JPanel panel3 = createButtonWithLabel(button3, label3); |
| | | buttonPanel.add(panel3); |
| | | |
| | | // 按钮4:xia2.png(固定图标),文字:刀盘降 |
| | | JButton button4 = createBladeControlButton("image/xia2.png", "image/xia10.png", 30, 30, false); |
| | | JLabel label4 = new JLabel("刀盘降", SwingConstants.CENTER); |
| | | label4.setFont(new Font("微软雅黑", Font.PLAIN, 12)); |
| | | label4.setForeground(new Color(40, 40, 40)); |
| | | button4.putClientProperty("label", label4); |
| | | button4.putClientProperty("defaultText", bladeDownDefaultText); |
| | | bladeButtons.add(button4); // 添加到列表以便清理 |
| | | JPanel panel4 = createButtonWithLabel(button4, label4); |
| | | buttonPanel.add(panel4); |
| | | |
| | | topPanel.add(buttonPanel, BorderLayout.NORTH); |
| | | |
| | | // 在每个摇杆上方分别显示其状态/数值(分两列) |
| | | JPanel valuesPanel = new JPanel(new GridLayout(1, 2, 20, 0)); |
| | |
| | | |
| | | valuesPanel.add(moveJoystickValueLabel); |
| | | valuesPanel.add(turnJoystickValueLabel); |
| | | contentPanel.add(valuesPanel, BorderLayout.NORTH); |
| | | topPanel.add(valuesPanel, BorderLayout.CENTER); |
| | | |
| | | contentPanel.add(topPanel, BorderLayout.NORTH); |
| | | |
| | | // 创建摇杆面板 |
| | | JPanel joystickPanel = new JPanel(new GridLayout(1, 2, 20, 0)); |
| | | joystickPanel.setOpaque(false); |
| | | |
| | | // 移动摇杆(绿色主题) |
| | | moveJoystick = new ModernJoystickComponent("前进/后退", |
| | | moveJoystick = new ModernJoystickComponent(" ", |
| | | new Color(46, 204, 113), true); // 绿色主题 |
| | | moveJoystick.setJoystickListener(new JoystickListener() { |
| | | @Override |
| | |
| | | // 限制在 [-100, 100] |
| | | forwardVal = Math.max(-100, Math.min(100, forwardVal)); |
| | | |
| | | // 更新目标速度 |
| | | targetForwardSpeed = forwardVal; |
| | | |
| | | if (Math.abs(y) > 0.1) { |
| | | applyForwardSpeed(forwardVal); |
| | | // 摇杆不在中心位置,启动持续发送定时器 |
| | | startForwardControlTimer(); |
| | | } else { |
| | | // 前后 |
| | | // 摇杆回到中心位置,停止发送 |
| | | stopForwardControlTimer(); |
| | | stopForward(); |
| | | } |
| | | |
| | |
| | | } |
| | | }); |
| | | // 转向摇杆(蓝色主题) |
| | | turnJoystick = new ModernJoystickComponent("左转/右转", |
| | | turnJoystick = new ModernJoystickComponent("", |
| | | new Color(52, 152, 219), false); // 蓝色主题 |
| | | turnJoystick.setJoystickListener(new JoystickListener() { |
| | | @Override |
| | |
| | | int steeringVal = (int) Math.round(x * 100.0); |
| | | steeringVal = Math.max(-100, Math.min(100, steeringVal)); |
| | | |
| | | // 更新目标速度 |
| | | targetSteeringSpeed = steeringVal; |
| | | |
| | | if (Math.abs(x) > 0.1) { |
| | | applySteeringSpeed(steeringVal); |
| | | // 摇杆不在中心位置,启动持续发送定时器 |
| | | startSteeringControlTimer(); |
| | | } else { |
| | | // 左右 |
| | | // 摇杆回到中心位置,停止发送 |
| | | stopSteeringControlTimer(); |
| | | stopSteering(); |
| | | } |
| | | |
| | |
| | | getContentPane().add(contentPanel); |
| | | } |
| | | |
| | | /** |
| | | * 创建带标签的按钮面板(垂直布局:按钮在上,标签在下) |
| | | * @param button 按钮 |
| | | * @param label 标签 |
| | | * @return 包含按钮和标签的面板 |
| | | */ |
| | | private JPanel createButtonWithLabel(JButton button, JLabel label) { |
| | | JPanel panel = new JPanel(new BorderLayout()); |
| | | panel.setOpaque(false); |
| | | panel.add(button, BorderLayout.CENTER); |
| | | panel.add(label, BorderLayout.SOUTH); |
| | | panel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); |
| | | return panel; |
| | | } |
| | | |
| | | /** |
| | | * 创建可切换图标的按钮(带标签文字切换) |
| | | * @param defaultIconPath 默认图标路径 |
| | | * @param clickedIconPath 点击后的图标路径 |
| | | * @param width 图标宽度 |
| | | * @param height 图标高度 |
| | | * @param label 标签组件 |
| | | * @param defaultText 默认文字 |
| | | * @param clickedText 点击后的文字 |
| | | * @param controlType 控制指令类型:"POWER"表示启动/熄火,"LIGHT"表示开灯/关灯,null表示无控制指令 |
| | | * @return 配置好的按钮 |
| | | */ |
| | | private JButton createIconButtonWithLabel(String defaultIconPath, String clickedIconPath, |
| | | int width, int height, JLabel label, |
| | | String defaultText, String clickedText, String controlType) { |
| | | JButton button = new JButton(); |
| | | button.setPreferredSize(new Dimension(width, height)); |
| | | button.setMinimumSize(new Dimension(width, height)); |
| | | button.setMaximumSize(new Dimension(width, height)); |
| | | button.setContentAreaFilled(false); |
| | | button.setBorderPainted(false); |
| | | button.setFocusPainted(false); |
| | | |
| | | // 加载默认图标和点击图标 |
| | | ImageIcon defaultIcon = loadIcon(defaultIconPath, width, height); |
| | | ImageIcon clickedIcon = loadIcon(clickedIconPath, width, height); |
| | | |
| | | if (defaultIcon != null) { |
| | | button.setIcon(defaultIcon); |
| | | } |
| | | |
| | | // 使用 clientProperty 来跟踪按钮状态(false=默认图标,true=点击图标) |
| | | button.putClientProperty("isClicked", false); |
| | | button.putClientProperty("defaultIcon", defaultIcon); |
| | | button.putClientProperty("clickedIcon", clickedIcon); |
| | | button.putClientProperty("label", label); |
| | | button.putClientProperty("defaultText", defaultText); |
| | | button.putClientProperty("clickedText", clickedText); |
| | | button.putClientProperty("controlType", controlType); |
| | | |
| | | // 添加点击事件,切换图标和文字,并发送控制指令 |
| | | button.addActionListener(e -> { |
| | | Boolean isClicked = (Boolean) button.getClientProperty("isClicked"); |
| | | ImageIcon defaultIconRef = (ImageIcon) button.getClientProperty("defaultIcon"); |
| | | ImageIcon clickedIconRef = (ImageIcon) button.getClientProperty("clickedIcon"); |
| | | JLabel labelRef = (JLabel) button.getClientProperty("label"); |
| | | String defaultTextRef = (String) button.getClientProperty("defaultText"); |
| | | String clickedTextRef = (String) button.getClientProperty("clickedText"); |
| | | String controlTypeRef = (String) button.getClientProperty("controlType"); |
| | | |
| | | if (isClicked == null || !isClicked) { |
| | | // 当前是默认图标,切换到点击图标 |
| | | if (clickedIconRef != null) { |
| | | button.setIcon(clickedIconRef); |
| | | button.putClientProperty("isClicked", true); |
| | | } |
| | | // 更新标签文字 |
| | | if (labelRef != null && clickedTextRef != null) { |
| | | labelRef.setText(clickedTextRef); |
| | | } |
| | | // 发送控制指令(开启) |
| | | if ("POWER".equals(controlTypeRef)) { |
| | | boolean success = Control05.sendPowerOnIfDebugSerialOpen(); |
| | | if (!success) { |
| | | showSerialClosedWarning(); |
| | | } |
| | | } else if ("LIGHT".equals(controlTypeRef)) { |
| | | boolean success = Control07.sendLightOnIfDebugSerialOpen(); |
| | | if (!success) { |
| | | showSerialClosedWarning(); |
| | | } |
| | | } |
| | | } else { |
| | | // 当前是点击图标,切换回默认图标 |
| | | if (defaultIconRef != null) { |
| | | button.setIcon(defaultIconRef); |
| | | button.putClientProperty("isClicked", false); |
| | | } |
| | | // 更新标签文字 |
| | | if (labelRef != null && defaultTextRef != null) { |
| | | labelRef.setText(defaultTextRef); |
| | | } |
| | | // 发送控制指令(关闭) |
| | | if ("POWER".equals(controlTypeRef)) { |
| | | boolean success = Control05.sendPowerOffIfDebugSerialOpen(); |
| | | if (!success) { |
| | | showSerialClosedWarning(); |
| | | } |
| | | } else if ("LIGHT".equals(controlTypeRef)) { |
| | | boolean success = Control07.sendLightOffIfDebugSerialOpen(); |
| | | if (!success) { |
| | | showSerialClosedWarning(); |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | |
| | | return button; |
| | | } |
| | | |
| | | /** |
| | | * 创建可切换图标的按钮 |
| | | * @param defaultIconPath 默认图标路径 |
| | | * @param clickedIconPath 点击后的图标路径 |
| | | * @param width 图标宽度 |
| | | * @param height 图标高度 |
| | | * @return 配置好的按钮 |
| | | */ |
| | | private JButton createIconButton(String defaultIconPath, String clickedIconPath, int width, int height) { |
| | | JButton button = new JButton(); |
| | | button.setPreferredSize(new Dimension(width, height)); |
| | | button.setMinimumSize(new Dimension(width, height)); |
| | | button.setMaximumSize(new Dimension(width, height)); |
| | | button.setContentAreaFilled(false); |
| | | button.setBorderPainted(false); |
| | | button.setFocusPainted(false); |
| | | |
| | | // 加载默认图标和点击图标 |
| | | ImageIcon defaultIcon = loadIcon(defaultIconPath, width, height); |
| | | ImageIcon clickedIcon = loadIcon(clickedIconPath, width, height); |
| | | |
| | | if (defaultIcon != null) { |
| | | button.setIcon(defaultIcon); |
| | | } |
| | | |
| | | // 使用 clientProperty 来跟踪按钮状态(false=默认图标,true=点击图标) |
| | | button.putClientProperty("isClicked", false); |
| | | button.putClientProperty("defaultIcon", defaultIcon); |
| | | button.putClientProperty("clickedIcon", clickedIcon); |
| | | |
| | | // 添加点击事件,切换图标 |
| | | button.addActionListener(e -> { |
| | | Boolean isClicked = (Boolean) button.getClientProperty("isClicked"); |
| | | ImageIcon defaultIconRef = (ImageIcon) button.getClientProperty("defaultIcon"); |
| | | ImageIcon clickedIconRef = (ImageIcon) button.getClientProperty("clickedIcon"); |
| | | |
| | | if (isClicked == null || !isClicked) { |
| | | // 当前是默认图标,切换到点击图标 |
| | | if (clickedIconRef != null) { |
| | | button.setIcon(clickedIconRef); |
| | | button.putClientProperty("isClicked", true); |
| | | } |
| | | } else { |
| | | // 当前是点击图标,切换回默认图标 |
| | | if (defaultIconRef != null) { |
| | | button.setIcon(defaultIconRef); |
| | | button.putClientProperty("isClicked", false); |
| | | } |
| | | } |
| | | }); |
| | | |
| | | return button; |
| | | } |
| | | |
| | | /** |
| | | * 创建固定图标的按钮 |
| | | * @param iconPath 图标路径 |
| | | * @param width 图标宽度 |
| | | * @param height 图标高度 |
| | | * @return 配置好的按钮 |
| | | */ |
| | | private JButton createFixedIconButton(String iconPath, int width, int height) { |
| | | JButton button = new JButton(); |
| | | button.setPreferredSize(new Dimension(width, height)); |
| | | button.setMinimumSize(new Dimension(width, height)); |
| | | button.setMaximumSize(new Dimension(width, height)); |
| | | button.setContentAreaFilled(false); |
| | | button.setBorderPainted(false); |
| | | button.setFocusPainted(false); |
| | | |
| | | ImageIcon icon = loadIcon(iconPath, width, height); |
| | | if (icon != null) { |
| | | button.setIcon(icon); |
| | | } |
| | | |
| | | return button; |
| | | } |
| | | |
| | | /** |
| | | * 创建刀盘升降控制按钮(支持点击和长按) |
| | | * @param defaultIconPath 默认图标路径 |
| | | * @param clickedIconPath 点击/长按时的图标路径 |
| | | * @param width 图标宽度 |
| | | * @param height 图标高度 |
| | | * @param isUp true表示刀盘升,false表示刀盘降 |
| | | * @return 配置好的按钮 |
| | | */ |
| | | private JButton createBladeControlButton(String defaultIconPath, String clickedIconPath, |
| | | int width, int height, boolean isUp) { |
| | | JButton button = new JButton(); |
| | | button.setPreferredSize(new Dimension(width, height)); |
| | | button.setMinimumSize(new Dimension(width, height)); |
| | | button.setMaximumSize(new Dimension(width, height)); |
| | | button.setContentAreaFilled(false); |
| | | button.setBorderPainted(false); |
| | | button.setFocusPainted(false); |
| | | |
| | | // 加载图标 |
| | | ImageIcon defaultIcon = loadIcon(defaultIconPath, width, height); |
| | | ImageIcon clickedIcon = loadIcon(clickedIconPath, width, height); |
| | | |
| | | if (defaultIcon != null) { |
| | | button.setIcon(defaultIcon); |
| | | } |
| | | |
| | | button.putClientProperty("defaultIcon", defaultIcon); |
| | | button.putClientProperty("clickedIcon", clickedIcon); |
| | | button.putClientProperty("isUp", isUp); |
| | | button.putClientProperty("isPressed", false); |
| | | |
| | | // 长按定时器 |
| | | Timer longPressTimer = new Timer(100, e -> { // 每100ms执行一次 |
| | | if (button.getClientProperty("isPressed") == Boolean.TRUE) { |
| | | boolean isUpButton = (Boolean) button.getClientProperty("isUp"); |
| | | int currentHeight = Control06.getCurrentBladeHeight(); |
| | | |
| | | // 使用Control06的方法发送指令 |
| | | boolean success; |
| | | if (isUpButton) { |
| | | success = Control06.sendBladeUpIfDebugSerialOpen(1); |
| | | } else { |
| | | success = Control06.sendBladeDownIfDebugSerialOpen(1); |
| | | } |
| | | |
| | | if (!success) { |
| | | showSerialClosedWarning(); |
| | | } else { |
| | | // 更新按钮标签显示当前数值 |
| | | updateBladeButtonLabel(button); |
| | | } |
| | | } |
| | | }); |
| | | longPressTimer.setInitialDelay(500); // 长按500ms后开始连续变化 |
| | | button.putClientProperty("longPressTimer", longPressTimer); // 存储定时器引用 |
| | | |
| | | // 鼠标按下事件 |
| | | button.addMouseListener(new MouseAdapter() { |
| | | @Override |
| | | public void mousePressed(MouseEvent e) { |
| | | button.putClientProperty("isPressed", true); |
| | | |
| | | // 立即切换图标 |
| | | ImageIcon clickedIconRef = (ImageIcon) button.getClientProperty("clickedIcon"); |
| | | if (clickedIconRef != null) { |
| | | button.setIcon(clickedIconRef); |
| | | } |
| | | |
| | | // 点击时立即增加/减少10,使用Control06的方法发送指令 |
| | | boolean isUpButton = (Boolean) button.getClientProperty("isUp"); |
| | | boolean success; |
| | | if (isUpButton) { |
| | | success = Control06.sendBladeUpIfDebugSerialOpen(10); |
| | | } else { |
| | | success = Control06.sendBladeDownIfDebugSerialOpen(10); |
| | | } |
| | | |
| | | if (!success) { |
| | | showSerialClosedWarning(); |
| | | } else { |
| | | // 更新按钮标签显示当前数值 |
| | | updateBladeButtonLabel(button); |
| | | } |
| | | |
| | | // 启动长按定时器 |
| | | longPressTimer.start(); |
| | | } |
| | | |
| | | @Override |
| | | public void mouseReleased(MouseEvent e) { |
| | | button.putClientProperty("isPressed", false); |
| | | |
| | | // 停止长按定时器 |
| | | longPressTimer.stop(); |
| | | |
| | | // 恢复默认图标 |
| | | ImageIcon defaultIconRef = (ImageIcon) button.getClientProperty("defaultIcon"); |
| | | if (defaultIconRef != null) { |
| | | button.setIcon(defaultIconRef); |
| | | } |
| | | |
| | | // 恢复默认文字 |
| | | JLabel labelRef = (JLabel) button.getClientProperty("label"); |
| | | String defaultTextRef = (String) button.getClientProperty("defaultText"); |
| | | if (labelRef != null && defaultTextRef != null) { |
| | | labelRef.setText(defaultTextRef); |
| | | } |
| | | } |
| | | }); |
| | | |
| | | return button; |
| | | } |
| | | |
| | | /** |
| | | * 更新刀盘按钮标签显示当前数值 |
| | | * @param button 按钮 |
| | | */ |
| | | private void updateBladeButtonLabel(JButton button) { |
| | | JLabel labelRef = (JLabel) button.getClientProperty("label"); |
| | | if (labelRef != null) { |
| | | String defaultTextRef = (String) button.getClientProperty("defaultText"); |
| | | int currentHeight = Control06.getCurrentBladeHeight(); |
| | | String displayText = defaultTextRef + " " + currentHeight; |
| | | labelRef.setText(displayText); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 加载并缩放图标 |
| | | * @param iconPath 图标路径 |
| | | * @param width 目标宽度 |
| | | * @param height 目标高度 |
| | | * @return 缩放后的图标 |
| | | */ |
| | | private ImageIcon loadIcon(String iconPath, int width, int height) { |
| | | try { |
| | | java.net.URL imgURL = getClass().getClassLoader().getResource(iconPath); |
| | | if (imgURL == null) { |
| | | // 尝试从文件系统加载 |
| | | java.io.File imgFile = new java.io.File(iconPath); |
| | | if (imgFile.exists()) { |
| | | ImageIcon originalIcon = new ImageIcon(imgFile.getAbsolutePath()); |
| | | Image scaledImage = originalIcon.getImage().getScaledInstance(width, height, Image.SCALE_SMOOTH); |
| | | ImageIcon scaledIcon = new ImageIcon(scaledImage); |
| | | scaledIcon.setDescription(iconPath); |
| | | return scaledIcon; |
| | | } |
| | | } else { |
| | | ImageIcon originalIcon = new ImageIcon(imgURL); |
| | | Image scaledImage = originalIcon.getImage().getScaledInstance(width, height, Image.SCALE_SMOOTH); |
| | | ImageIcon scaledIcon = new ImageIcon(scaledImage); |
| | | scaledIcon.setDescription(iconPath); |
| | | return scaledIcon; |
| | | } |
| | | } catch (Exception e) { |
| | | System.err.println("无法加载图标: " + iconPath + " - " + e.getMessage()); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private JPanel createStatusPanel(String label, String value, Color color) { |
| | | JPanel panel = new JPanel(new BorderLayout(0, 5)); |
| | | panel.setOpaque(false); |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 启动前进/后退控制定时器,持续发送控制指令 |
| | | */ |
| | | private void startForwardControlTimer() { |
| | | // 如果定时器已经在运行,先停止它 |
| | | if (forwardControlTimer != null && forwardControlTimer.isRunning()) { |
| | | forwardControlTimer.stop(); |
| | | } |
| | | |
| | | // 创建新的定时器,每100ms发送一次指令 |
| | | forwardControlTimer = new Timer(100, new ActionListener() { |
| | | @Override |
| | | public void actionPerformed(ActionEvent e) { |
| | | // 持续发送目标速度的指令 |
| | | applyForwardSpeedContinuously(targetForwardSpeed); |
| | | } |
| | | }); |
| | | forwardControlTimer.setInitialDelay(0); |
| | | forwardControlTimer.start(); |
| | | } |
| | | |
| | | /** |
| | | * 停止前进/后退控制定时器 |
| | | */ |
| | | private void stopForwardControlTimer() { |
| | | if (forwardControlTimer != null && forwardControlTimer.isRunning()) { |
| | | forwardControlTimer.stop(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 启动转向控制定时器,持续发送控制指令 |
| | | */ |
| | | private void startSteeringControlTimer() { |
| | | // 如果定时器已经在运行,先停止它 |
| | | if (steeringControlTimer != null && steeringControlTimer.isRunning()) { |
| | | steeringControlTimer.stop(); |
| | | } |
| | | |
| | | // 创建新的定时器,每100ms发送一次指令 |
| | | steeringControlTimer = new Timer(100, new ActionListener() { |
| | | @Override |
| | | public void actionPerformed(ActionEvent e) { |
| | | // 持续发送目标速度的指令 |
| | | applySteeringSpeedContinuously(targetSteeringSpeed); |
| | | } |
| | | }); |
| | | steeringControlTimer.setInitialDelay(0); |
| | | steeringControlTimer.start(); |
| | | } |
| | | |
| | | /** |
| | | * 停止转向控制定时器 |
| | | */ |
| | | private void stopSteeringControlTimer() { |
| | | if (steeringControlTimer != null && steeringControlTimer.isRunning()) { |
| | | steeringControlTimer.stop(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 持续发送前进/后退速度指令 |
| | | */ |
| | | private void applyForwardSpeedContinuously(int targetSpeed) { |
| | | int currentSpeed = Control03.getCurrentForwardSpeed(); |
| | | int currentSteeringSpeed = Control03.getCurrentSteeringSpeed(); |
| | | |
| | | // 如果已经达到目标速度,直接发送一次以保持状态 |
| | | if (currentSpeed == targetSpeed) { |
| | | // 直接发送目标速度指令以保持状态(即使速度相同也要发送) |
| | | Control03.setAndSendSpeeds(currentSteeringSpeed, targetSpeed); |
| | | } else { |
| | | // 逐步调整到目标速度 |
| | | int delta = targetSpeed > currentSpeed ? 10 : -10; |
| | | Control03.adjustForwardSpeed(delta); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 持续发送转向速度指令 |
| | | */ |
| | | private void applySteeringSpeedContinuously(int targetSpeed) { |
| | | int currentSpeed = Control03.getCurrentSteeringSpeed(); |
| | | int currentForwardSpeed = Control03.getCurrentForwardSpeed(); |
| | | |
| | | // 如果已经达到目标速度,直接发送一次以保持状态 |
| | | if (currentSpeed == targetSpeed) { |
| | | // 直接发送目标速度指令以保持状态(即使速度相同也要发送) |
| | | Control03.setAndSendSpeeds(targetSpeed, currentForwardSpeed); |
| | | } else { |
| | | // 逐步调整到目标速度 |
| | | int delta = targetSpeed > currentSpeed ? 15 : -15; |
| | | Control03.adjustSteeringSpeed(delta); |
| | | } |
| | | } |
| | | |
| | | // 更新顶部显示的摇杆数值(在 EDT 上调用),文字根据数值映射为方向描述 |
| | | private void updateJoystickValues(int forwardVal, int steeringVal) { |
| | | // 计算移动/转向描述文本 |
| | |
| | | |
| | | @Override |
| | | public void dispose() { |
| | | // 停止并清理控制定时器 |
| | | stopForwardControlTimer(); |
| | | stopSteeringControlTimer(); |
| | | if (forwardControlTimer != null) { |
| | | forwardControlTimer = null; |
| | | } |
| | | if (steeringControlTimer != null) { |
| | | steeringControlTimer = null; |
| | | } |
| | | // 前后速度更新定时器 |
| | | if (speedUpdateTimer != null) { |
| | | speedUpdateTimer.stop(); |
| | |
| | | if (turnJoystick != null) { |
| | | turnJoystick.dispose(); |
| | | } |
| | | // 停止并清理刀盘按钮的定时器 |
| | | for (JButton bladeButton : bladeButtons) { |
| | | Timer timer = (Timer) bladeButton.getClientProperty("longPressTimer"); |
| | | if (timer != null && timer.isRunning()) { |
| | | timer.stop(); |
| | | } |
| | | } |
| | | bladeButtons.clear(); |
| | | super.dispose(); |
| | | } |
| | | |