| | |
| | | import javax.swing.Timer; |
| | | |
| | | import baseStation.BaseStation; |
| | | import set.Setsys; |
| | | import baseStation.BaseStationDialog; |
| | | |
| | | import java.awt.*; |
| | | import java.awt.event.*; |
| | | |
| | | import chuankou.dellmessage; |
| | | import dikuai.Dikuai; |
| | | import dikuai.Dikuaiguanli; |
| | | import dikuai.addzhangaiwu; |
| | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Locale; |
| | | import java.util.Objects; |
| | | import java.util.function.Consumer; |
| | | import java.awt.geom.Point2D; |
| | | |
| | | /** |
| | |
| | | private JButton areaSelectBtn; |
| | | private JButton baseStationBtn; |
| | | private JButton bluetoothBtn; |
| | | private JLabel dataPacketCountLabel; |
| | | private JLabel mowerSpeedValueLabel; |
| | | private JLabel mowerSpeedUnitLabel; |
| | | private JLabel mowingProgressLabel; |
| | | private FixQualityIndicator fixQualityIndicator; |
| | | |
| | | // 导航按钮 |
| | | private JButton homeNavBtn; |
| | |
| | | private BaseStationDialog baseStationDialog; |
| | | private Sets settingsDialog; |
| | | private BaseStation baseStation; |
| | | |
| | | private final Consumer<String> serialLineListener = line -> SwingUtilities.invokeLater(this::updateDataPacketCountLabel); |
| | | |
| | | // 地图渲染器 |
| | | private MapRenderer mapRenderer; |
| | |
| | | instance = this; |
| | | baseStation = new BaseStation(); |
| | | baseStation.load(); |
| | | dellmessage.registerLineListener(serialLineListener); |
| | | initializeUI(); |
| | | setupEventHandlers(); |
| | | } |
| | |
| | | add(controlPanel, BorderLayout.SOUTH); |
| | | |
| | | // 初始化地图渲染器 |
| | | mapRenderer = new MapRenderer(visualizationPanel); |
| | | mapRenderer = new MapRenderer(visualizationPanel); |
| | | applyIdleTrailDurationFromSettings(); |
| | | |
| | | // 初始化对话框引用为null,延迟创建 |
| | | legendDialog = null; |
| | |
| | | initializeDefaultAreaSelection(); |
| | | refreshMapForSelectedArea(); |
| | | } |
| | | |
| | | private void applyIdleTrailDurationFromSettings() { |
| | | if (mapRenderer == null) { |
| | | return; |
| | | } |
| | | int durationSeconds = MapRenderer.DEFAULT_IDLE_TRAIL_DURATION_SECONDS; |
| | | String configuredValue = Setsys.getPropertyValue("idleTrailDurationSeconds"); |
| | | if (configuredValue != null) { |
| | | String trimmed = configuredValue.trim(); |
| | | if (!trimmed.isEmpty()) { |
| | | try { |
| | | int parsed = Integer.parseInt(trimmed); |
| | | if (parsed >= 5 && parsed <= 600) { |
| | | durationSeconds = parsed; |
| | | } |
| | | } catch (NumberFormatException ignored) { |
| | | durationSeconds = MapRenderer.DEFAULT_IDLE_TRAIL_DURATION_SECONDS; |
| | | } |
| | | } |
| | | } |
| | | mapRenderer.setIdleTrailDurationSeconds(durationSeconds); |
| | | } |
| | | |
| | | private void createHeaderPanel() { |
| | | headerPanel = new JPanel(new BorderLayout()); |
| | |
| | | |
| | | mainContentPanel.add(visualizationPanel, BorderLayout.CENTER); |
| | | |
| | | startMowerSpeedUpdates(); |
| | | startMowerSpeedUpdates(); |
| | | } |
| | | |
| | | private void createControlPanel() { |
| | |
| | | } |
| | | } |
| | | |
| | | Device device = new Device(); |
| | | device.initFromProperties(); |
| | | Device device = Device.getGecaoji(); |
| | | if (device == null) { |
| | | device = new Device(); |
| | | device.initFromProperties(); |
| | | Device.setGecaoji(device); |
| | | } |
| | | |
| | | if (baseStationDialog == null) { |
| | | baseStationDialog = new BaseStationDialog(dialogParent, THEME_COLOR, device, baseStation); |
| | |
| | | return; |
| | | } |
| | | startButtonShowingPause = !startButtonShowingPause; |
| | | if (startButtonShowingPause) { |
| | | if (!startButtonShowingPause) { |
| | | statusLabel.setText("作业中"); |
| | | if (stopButtonActive) { |
| | | stopButtonActive = false; |
| | | updateStopButtonIcon(); |
| | | } |
| | | if (!beginMowingSession()) { |
| | | startButtonShowingPause = false; |
| | | startButtonShowingPause = true; |
| | | statusLabel.setText("待机"); |
| | | updateStartButtonAppearance(); |
| | | return; |
| | |
| | | } |
| | | |
| | | private JPanel createSpeedIndicatorPanel() { |
| | | JPanel panel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 0)); |
| | | JPanel panel = new JPanel(new BorderLayout()); |
| | | panel.setOpaque(false); |
| | | panel.setBorder(BorderFactory.createEmptyBorder(10, 20, 5, 20)); |
| | | |
| | | JPanel rightPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 0)); |
| | | rightPanel.setOpaque(false); |
| | | |
| | | fixQualityIndicator = new FixQualityIndicator(); |
| | | fixQualityIndicator.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); |
| | | fixQualityIndicator.addMouseListener(new MouseAdapter() { |
| | | @Override |
| | | public void mouseClicked(MouseEvent e) { |
| | | if (SwingUtilities.isLeftMouseButton(e) && mapRenderer != null) { |
| | | mapRenderer.showMowerInfo(); |
| | | } |
| | | } |
| | | }); |
| | | mowingProgressLabel = new JLabel("--%"); |
| | | mowingProgressLabel.setFont(new Font("微软雅黑", Font.BOLD, 12)); |
| | | mowingProgressLabel.setForeground(THEME_COLOR); |
| | |
| | | mowerSpeedUnitLabel.setFont(new Font("微软雅黑", Font.BOLD, 9)); |
| | | mowerSpeedUnitLabel.setForeground(THEME_COLOR); |
| | | |
| | | panel.add(mowingProgressLabel); |
| | | panel.add(mowerSpeedValueLabel); |
| | | panel.add(mowerSpeedUnitLabel); |
| | | dataPacketCountLabel = new JLabel("--"); |
| | | dataPacketCountLabel.setFont(new Font("微软雅黑", Font.BOLD, 12)); |
| | | dataPacketCountLabel.setForeground(THEME_COLOR); |
| | | |
| | | rightPanel.add(fixQualityIndicator); |
| | | |
| | | JSeparator areaSeparator = new JSeparator(SwingConstants.VERTICAL); |
| | | areaSeparator.setPreferredSize(new Dimension(1, 16)); |
| | | rightPanel.add(areaSeparator); |
| | | |
| | | rightPanel.add(mowingProgressLabel); |
| | | JSeparator speedSeparator = new JSeparator(SwingConstants.VERTICAL); |
| | | speedSeparator.setPreferredSize(new Dimension(1, 16)); |
| | | rightPanel.add(speedSeparator); |
| | | rightPanel.add(mowerSpeedValueLabel); |
| | | rightPanel.add(mowerSpeedUnitLabel); |
| | | |
| | | JSeparator separator = new JSeparator(SwingConstants.VERTICAL); |
| | | separator.setPreferredSize(new Dimension(1, 16)); |
| | | rightPanel.add(separator); |
| | | |
| | | rightPanel.add(dataPacketCountLabel); |
| | | |
| | | panel.add(rightPanel, BorderLayout.EAST); |
| | | updateFixQualityIndicator(); |
| | | updateDataPacketCountLabel(); |
| | | return panel; |
| | | } |
| | | |
| | |
| | | mowerSpeedUnitLabel.setText("km/h"); |
| | | } |
| | | updateMowingProgressLabel(); |
| | | updateFixQualityIndicator(); |
| | | updateDataPacketCountLabel(); |
| | | } |
| | | |
| | | private void updateDataPacketCountLabel() { |
| | | if (dataPacketCountLabel == null) { |
| | | return; |
| | | } |
| | | int udpCount = UDPServer.getReceivedPacketCount(); |
| | | int serialCount = dellmessage.getProcessedLineCount(); |
| | | int displayCount = Math.max(udpCount, serialCount); |
| | | |
| | | if (displayCount <= 0) { |
| | | dataPacketCountLabel.setText("--"); |
| | | dataPacketCountLabel.setToolTipText(null); |
| | | } else { |
| | | dataPacketCountLabel.setText(String.valueOf(displayCount)); |
| | | dataPacketCountLabel.setToolTipText(String.format("串口: %d UDP: %d", serialCount, udpCount)); |
| | | } |
| | | } |
| | | |
| | | private void updateFixQualityIndicator() { |
| | | if (fixQualityIndicator == null) { |
| | | return; |
| | | } |
| | | Device device = Device.getGecaoji(); |
| | | String code = null; |
| | | if (device != null) { |
| | | code = sanitizeDeviceValue(device.getPositioningStatus()); |
| | | } |
| | | fixQualityIndicator.setQuality(code); |
| | | } |
| | | |
| | | private Color resolveFixQualityColor(String code) { |
| | | if (code == null) { |
| | | return new Color(160, 160, 160); |
| | | } |
| | | switch (code) { |
| | | case "0": |
| | | return new Color(160, 160, 160); |
| | | case "1": |
| | | return new Color(52, 152, 219); |
| | | case "2": |
| | | return new Color(26, 188, 156); |
| | | case "3": |
| | | return new Color(155, 89, 182); |
| | | case "4": |
| | | return THEME_COLOR; |
| | | case "5": |
| | | return new Color(241, 196, 15); |
| | | case "6": |
| | | return new Color(231, 76, 60); |
| | | case "7": |
| | | return new Color(230, 126, 34); |
| | | default: |
| | | return new Color(95, 95, 95); |
| | | } |
| | | } |
| | | |
| | | private String resolveFixQualityDescription(String code) { |
| | | if (code == null) { |
| | | return "未知"; |
| | | } |
| | | switch (code) { |
| | | case "0": |
| | | return "未定位"; |
| | | case "1": |
| | | return "单点定位"; |
| | | case "2": |
| | | return "码差分"; |
| | | case "3": |
| | | return "无效PPS"; |
| | | case "4": |
| | | return "固定解"; |
| | | case "5": |
| | | return "浮点解"; |
| | | case "6": |
| | | return "正在估算"; |
| | | case "7": |
| | | return "人工输入固定值"; |
| | | default: |
| | | return "其他"; |
| | | } |
| | | } |
| | | |
| | | private String sanitizeSpeedValue(String raw) { |
| | |
| | | return trimmed; |
| | | } |
| | | |
| | | private String sanitizeDeviceValue(String raw) { |
| | | if (raw == null) { |
| | | return null; |
| | | } |
| | | String trimmed = raw.trim(); |
| | | if (trimmed.isEmpty() || "-1".equals(trimmed) || "null".equalsIgnoreCase(trimmed)) { |
| | | return null; |
| | | } |
| | | return trimmed; |
| | | } |
| | | |
| | | private void updateMowingProgressLabel() { |
| | | if (mowingProgressLabel == null) { |
| | | return; |
| | |
| | | return; |
| | | } |
| | | circleGuidanceStep = step; |
| | | |
| | | if (step == 1) { |
| | | circleGuidanceLabel.setText("采集第1个点"); |
| | | circleGuidancePrimaryButton.setText("确认第1点"); |
| | |
| | | return !"未选择地块".equals(trimmed); |
| | | } |
| | | |
| | | private final class FixQualityIndicator extends JComponent { |
| | | private static final long serialVersionUID = 1L; |
| | | private static final int DIAMETER = 16; |
| | | private String currentCode; |
| | | private Color currentColor = new Color(160, 160, 160); |
| | | |
| | | private FixQualityIndicator() { |
| | | setPreferredSize(new Dimension(DIAMETER, DIAMETER)); |
| | | setMinimumSize(new Dimension(DIAMETER, DIAMETER)); |
| | | setMaximumSize(new Dimension(DIAMETER, DIAMETER)); |
| | | setToolTipText("未知"); |
| | | } |
| | | |
| | | private void setQuality(String code) { |
| | | if (Objects.equals(currentCode, code)) { |
| | | return; |
| | | } |
| | | currentCode = code; |
| | | currentColor = resolveFixQualityColor(code); |
| | | setToolTipText(resolveFixQualityDescription(code)); |
| | | repaint(); |
| | | } |
| | | |
| | | @Override |
| | | protected void paintComponent(Graphics g) { |
| | | super.paintComponent(g); |
| | | Graphics2D g2 = (Graphics2D) g.create(); |
| | | try { |
| | | g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); |
| | | int diameter = Math.min(getWidth(), getHeight()) - 2; |
| | | int x = (getWidth() - diameter) / 2; |
| | | int y = (getHeight() - diameter) / 2; |
| | | g2.setColor(currentColor); |
| | | g2.fillOval(x, y, diameter, diameter); |
| | | g2.setColor(new Color(255, 255, 255, 128)); |
| | | g2.drawOval(x, y, diameter, diameter); |
| | | } finally { |
| | | g2.dispose(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 测试方法 |
| | | public static void main(String[] args) { |
| | | JFrame frame = new JFrame("AutoMow - 首页"); |