| | |
| | | private Sets settingsDialog; |
| | | private BaseStation baseStation; |
| | | |
| | | private final Consumer<String> serialLineListener = line -> SwingUtilities.invokeLater(this::updateDataPacketCountLabel); |
| | | |
| | | // 地图渲染器 |
| | | private MapRenderer mapRenderer; |
| | | |
| | | private final Consumer<String> serialLineListener = line -> { |
| | | SwingUtilities.invokeLater(() -> { |
| | | updateDataPacketCountLabel(); |
| | | // 如果收到$GNGGA数据,立即更新拖尾 |
| | | if (line != null && line.trim().startsWith("$GNGGA")) { |
| | | if (mapRenderer != null) { |
| | | mapRenderer.forceUpdateIdleMowerTrail(); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | private static final int FLOAT_ICON_SIZE = 32; |
| | | private JButton endDrawingButton; |
| | | private JButton drawingPauseButton; |
| | |
| | | SwingUtilities.invokeLater(() -> { |
| | | Shouye.this.checkIdentifiersAndPromptIfNeeded(); |
| | | Shouye.this.showInitialMowerSelfCheckDialogIfNeeded(); |
| | | // 设置窗口关闭监听器,在关闭时保存缩放比例 |
| | | setupWindowCloseListener(); |
| | | }); |
| | | } |
| | | } |
| | |
| | | addHierarchyListener(listener); |
| | | } |
| | | |
| | | /** |
| | | * 设置窗口关闭监听器,在窗口关闭时保存当前缩放比例 |
| | | */ |
| | | private void setupWindowCloseListener() { |
| | | Window window = SwingUtilities.getWindowAncestor(this); |
| | | if (window != null && window instanceof JFrame) { |
| | | JFrame frame = (JFrame) window; |
| | | frame.addWindowListener(new WindowAdapter() { |
| | | @Override |
| | | public void windowClosing(WindowEvent e) { |
| | | // 保存当前缩放比例 |
| | | saveCurrentScale(); |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 保存当前地图缩放比例到配置文件 |
| | | */ |
| | | public void saveCurrentScale() { |
| | | if (mapRenderer != null) { |
| | | double currentScale = mapRenderer.getScale(); |
| | | Setsys setsys = new Setsys(); |
| | | setsys.updateProperty("mapScale", String.valueOf(currentScale)); |
| | | } |
| | | } |
| | | |
| | | private void showInitialMowerSelfCheckDialogIfNeeded() { |
| | | // 已移除进入主页时的自检提示(按用户要求删除) |
| | | // 以前这里会调用 zijian.showInitialPromptIfNeeded(...) 展示自检对话框,现已禁用。 |
| | |
| | | |
| | | // 可视化区域 - 使用MapRenderer进行绘制 |
| | | visualizationPanel = new JPanel() { |
| | | private ImageIcon gecaojiIcon = null; |
| | | private static final int GECAOJI_ICON_X = 37; |
| | | private static final int GECAOJI_ICON_Y = 10; |
| | | private static final int GECAOJI_ICON_SIZE = 20; |
| | | |
| | | { |
| | | // 加载割草机图标,大小20x20像素 |
| | | gecaojiIcon = loadScaledIcon("image/gecaoji.png", GECAOJI_ICON_SIZE, GECAOJI_ICON_SIZE); |
| | | // 启用工具提示 |
| | | setToolTipText(""); |
| | | } |
| | | |
| | | /** |
| | | * 检查鼠标位置是否在割草机图标区域内 |
| | | */ |
| | | private boolean isMouseOnGecaojiIcon(Point mousePoint) { |
| | | return mousePoint.x >= GECAOJI_ICON_X && |
| | | mousePoint.x <= GECAOJI_ICON_X + GECAOJI_ICON_SIZE && |
| | | mousePoint.y >= GECAOJI_ICON_Y && |
| | | mousePoint.y <= GECAOJI_ICON_Y + GECAOJI_ICON_SIZE; |
| | | } |
| | | |
| | | @Override |
| | | public String getToolTipText(MouseEvent event) { |
| | | // 如果鼠标在割草机图标区域内,显示提示文字 |
| | | if (isMouseOnGecaojiIcon(event.getPoint())) { |
| | | return "以割草机为中心"; |
| | | } |
| | | return super.getToolTipText(event); |
| | | } |
| | | |
| | | @Override |
| | | protected void paintComponent(Graphics g) { |
| | | super.paintComponent(g); |
| | |
| | | if (mapRenderer != null) { |
| | | mapRenderer.renderMap(g); |
| | | } |
| | | // 在地图左上角绘制割草机图标 |
| | | // 水平方向与速度指示器对齐(x=37) |
| | | // 垂直方向与卫星状态图标对齐(y=10,速度指示器面板顶部边距10像素,使图标中心对齐) |
| | | if (gecaojiIcon != null) { |
| | | g.drawImage(gecaojiIcon.getImage(), GECAOJI_ICON_X, GECAOJI_ICON_Y, null); |
| | | } |
| | | } |
| | | }; |
| | | visualizationPanel.setLayout(new BorderLayout()); |
| | | |
| | | // 添加鼠标点击监听器,检测是否点击了割草机图标 |
| | | visualizationPanel.addMouseListener(new MouseAdapter() { |
| | | @Override |
| | | public void mouseClicked(MouseEvent e) { |
| | | if (SwingUtilities.isLeftMouseButton(e)) { |
| | | Point clickPoint = e.getPoint(); |
| | | // 检查是否点击了割草机图标区域(37, 10, 20, 20) |
| | | if (clickPoint.x >= 37 && clickPoint.x <= 57 && |
| | | clickPoint.y >= 10 && clickPoint.y <= 30) { |
| | | // 点击了割草机图标,将地图视图中心移动到割草机位置 |
| | | if (mapRenderer != null) { |
| | | Gecaoji mower = mapRenderer.getMower(); |
| | | if (mower != null && mower.hasValidPosition()) { |
| | | Point2D.Double mowerPosition = mower.getPosition(); |
| | | if (mowerPosition != null) { |
| | | // 获取当前缩放比例 |
| | | double currentScale = mapRenderer.getScale(); |
| | | // 设置视图变换,使割草机位置对应到屏幕中心 |
| | | // translateX = -mowerX, translateY = -mowerY 可以让割草机在屏幕中心 |
| | | mapRenderer.setViewTransform(currentScale, -mowerPosition.x, -mowerPosition.y); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | |
| | | JPanel speedIndicatorPanel = createSpeedIndicatorPanel(); |
| | | visualizationPanel.add(speedIndicatorPanel, BorderLayout.NORTH); |
| | | |
| | | // 创建功能按钮面板(放在左上角) |
| | | // 创建功能按钮面板 |
| | | JPanel functionButtonsPanel = new JPanel(); |
| | | functionButtonsPanel.setLayout(new BoxLayout(functionButtonsPanel, BoxLayout.Y_AXIS)); |
| | | functionButtonsPanel.setOpaque(false); |