| | |
| | | |
| | | import dikuai.Dikuai; |
| | | import dikuai.Dikuaiguanli; |
| | | import dikuai.addzhangaiwu; |
| | | import gecaoji.Device; |
| | | import set.Sets; |
| | | import udpdell.UDPServer; |
| | |
| | | private ImageIcon pauseIcon; |
| | | private ImageIcon pauseActiveIcon; |
| | | private ImageIcon endIcon; |
| | | private JPanel circleGuidancePanel; |
| | | private JLabel circleGuidanceLabel; |
| | | private JButton circleGuidancePrimaryButton; |
| | | private JButton circleGuidanceSecondaryButton; |
| | | private int circleGuidanceStep; |
| | | private JDialog circleGuidanceDialog; |
| | | private boolean circleDialogMode; |
| | | private ComponentAdapter circleDialogOwnerAdapter; |
| | | |
| | | public Shouye() { |
| | | instance = this; |
| | |
| | | setNavigationActive(homeNavBtn); |
| | | |
| | | initializeDefaultAreaSelection(); |
| | | refreshMapForSelectedArea(); |
| | | } |
| | | |
| | | private void createHeaderPanel() { |
| | |
| | | JPanel buttonPanel = new JPanel(new GridLayout(1, 2, 20, 0)); |
| | | buttonPanel.setBackground(PANEL_BACKGROUND); |
| | | |
| | | startBtn = createControlButton("开始", THEME_COLOR); |
| | | pauseBtn = createControlButton("暂停", Color.ORANGE); |
| | | startBtn = createControlButton("开始", THEME_COLOR); |
| | | applyButtonIcon(startBtn, "image/startzuoye.png"); |
| | | pauseBtn = createControlButton("暂停", Color.ORANGE); |
| | | applyButtonIcon(pauseBtn, "image/zantingzuoye.png"); |
| | | pauseBtn.setEnabled(false); |
| | | |
| | | buttonPanel.add(startBtn); |
| | |
| | | |
| | | return button; |
| | | } |
| | | |
| | | private void applyButtonIcon(JButton button, String imagePath) { |
| | | try { |
| | | ImageIcon icon = new ImageIcon(imagePath); |
| | | Image scaledImage = icon.getImage().getScaledInstance(28, 28, Image.SCALE_SMOOTH); |
| | | button.setIcon(new ImageIcon(scaledImage)); |
| | | button.setHorizontalAlignment(SwingConstants.CENTER); |
| | | button.setIconTextGap(10); |
| | | button.setHorizontalTextPosition(SwingConstants.RIGHT); |
| | | button.setVerticalTextPosition(SwingConstants.CENTER); |
| | | } catch (Exception e) { |
| | | System.err.println("无法加载按钮图标: " + imagePath + " -> " + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | private JButton createNavButton(String text, String icon) { |
| | | JButton button = new JButton("<html><center>" + icon + "<br>" + text + "</center></html>"); |
| | |
| | | } |
| | | |
| | | public void showEndDrawingButton(Runnable callback) { |
| | | ensureFloatingIconsLoaded(); |
| | | showEndDrawingButton(callback, null); |
| | | } |
| | | |
| | | public void showEndDrawingButton(Runnable callback, String drawingShape) { |
| | | endDrawingCallback = callback; |
| | | applyDrawingPauseState(false, false); |
| | | circleDialogMode = drawingShape != null && "circle".equalsIgnoreCase(drawingShape); |
| | | |
| | | if (circleDialogMode) { |
| | | hideFloatingDrawingControls(); |
| | | ensureCircleGuidancePanel(); |
| | | showCircleGuidanceStep(1); |
| | | visualizationPanel.revalidate(); |
| | | visualizationPanel.repaint(); |
| | | return; |
| | | } |
| | | |
| | | circleDialogMode = false; |
| | | hideCircleGuidancePanel(); |
| | | |
| | | ensureFloatingIconsLoaded(); |
| | | ensureFloatingButtonInfrastructure(); |
| | | |
| | | endDrawingButton.setVisible(true); |
| | | if (drawingPauseButton != null) { |
| | | drawingPauseButton.setVisible(true); |
| | | } |
| | | |
| | | floatingButtonPanel.setVisible(true); |
| | | if (floatingButtonPanel.getParent() != visualizationPanel) { |
| | | visualizationPanel.add(floatingButtonPanel, BorderLayout.SOUTH); |
| | | } |
| | | |
| | | rebuildFloatingButtonColumn(); |
| | | visualizationPanel.revalidate(); |
| | | visualizationPanel.repaint(); |
| | | } |
| | | |
| | | private void ensureFloatingButtonInfrastructure() { |
| | | if (endDrawingButton == null) { |
| | | endDrawingButton = createFloatingIconButton(); |
| | | endDrawingButton.addActionListener(e -> { |
| | |
| | | floatingButtonColumn = new JPanel(); |
| | | floatingButtonColumn.setOpaque(false); |
| | | floatingButtonColumn.setLayout(new BoxLayout(floatingButtonColumn, BoxLayout.Y_AXIS)); |
| | | floatingButtonColumn.add(drawingPauseButton); |
| | | floatingButtonColumn.add(Box.createRigidArea(new Dimension(0, 10))); |
| | | floatingButtonColumn.add(endDrawingButton); |
| | | floatingButtonPanel.add(floatingButtonColumn, BorderLayout.EAST); |
| | | } else if (floatingButtonColumn != null) { |
| | | floatingButtonColumn.removeAll(); |
| | | floatingButtonColumn.add(drawingPauseButton); |
| | | floatingButtonColumn.add(Box.createRigidArea(new Dimension(0, 10))); |
| | | floatingButtonColumn.add(endDrawingButton); |
| | | } |
| | | |
| | | endDrawingCallback = callback; |
| | | endDrawingButton.setVisible(true); |
| | | if (drawingPauseButton != null) { |
| | | drawingPauseButton.setVisible(true); |
| | | } |
| | | applyDrawingPauseState(false, false); |
| | | floatingButtonPanel.setVisible(true); |
| | | if (floatingButtonPanel.getParent() != visualizationPanel) { |
| | | visualizationPanel.add(floatingButtonPanel, BorderLayout.SOUTH); |
| | | } |
| | | visualizationPanel.revalidate(); |
| | | visualizationPanel.repaint(); |
| | | } |
| | | |
| | | public void hideEndDrawingButton() { |
| | | if (endDrawingButton != null) { |
| | | endDrawingButton.setVisible(false); |
| | | } |
| | | private void hideFloatingDrawingControls() { |
| | | if (drawingPauseButton != null) { |
| | | drawingPauseButton.setVisible(false); |
| | | } |
| | | if (endDrawingButton != null) { |
| | | endDrawingButton.setVisible(false); |
| | | } |
| | | if (floatingButtonPanel != null) { |
| | | floatingButtonPanel.setVisible(false); |
| | | } |
| | | if (!circleDialogMode) { |
| | | rebuildFloatingButtonColumn(); |
| | | } |
| | | } |
| | | |
| | | private void rebuildFloatingButtonColumn() { |
| | | if (floatingButtonColumn == null) { |
| | | return; |
| | | } |
| | | floatingButtonColumn.removeAll(); |
| | | boolean added = false; |
| | | if (!circleDialogMode && circleGuidancePanel != null && circleGuidancePanel.isVisible()) { |
| | | floatingButtonColumn.add(circleGuidancePanel); |
| | | added = true; |
| | | } |
| | | if (!circleDialogMode && drawingPauseButton != null && drawingPauseButton.isVisible()) { |
| | | if (added) { |
| | | floatingButtonColumn.add(Box.createRigidArea(new Dimension(0, 10))); |
| | | } |
| | | floatingButtonColumn.add(drawingPauseButton); |
| | | added = true; |
| | | } |
| | | if (!circleDialogMode && endDrawingButton != null && endDrawingButton.isVisible()) { |
| | | if (added) { |
| | | floatingButtonColumn.add(Box.createRigidArea(new Dimension(0, 10))); |
| | | } |
| | | floatingButtonColumn.add(endDrawingButton); |
| | | } |
| | | floatingButtonColumn.revalidate(); |
| | | floatingButtonColumn.repaint(); |
| | | } |
| | | |
| | | private void showCircleGuidanceStep(int step) { |
| | | ensureCircleGuidancePanel(); |
| | | if (circleGuidancePanel == null) { |
| | | return; |
| | | } |
| | | circleGuidanceStep = step; |
| | | if (step == 1) { |
| | | circleGuidanceLabel.setText("是否将当前点设置为圆心?"); |
| | | circleGuidancePrimaryButton.setText("是"); |
| | | circleGuidanceSecondaryButton.setText("返回"); |
| | | circleGuidanceSecondaryButton.setVisible(true); |
| | | } else if (step == 2) { |
| | | circleGuidanceLabel.setText("是否将当前点设置为半径点?"); |
| | | circleGuidancePrimaryButton.setText("是"); |
| | | circleGuidanceSecondaryButton.setVisible(false); |
| | | } else { |
| | | hideCircleGuidancePanel(); |
| | | return; |
| | | } |
| | | circleGuidancePanel.setVisible(true); |
| | | |
| | | if (circleDialogMode) { |
| | | ensureCircleGuidanceDialog(); |
| | | if (circleGuidanceDialog != null) { |
| | | circleGuidanceDialog.pack(); |
| | | positionCircleGuidanceDialog(); |
| | | circleGuidanceDialog.setVisible(true); |
| | | circleGuidanceDialog.toFront(); |
| | | } |
| | | } else { |
| | | rebuildFloatingButtonColumn(); |
| | | } |
| | | } |
| | | |
| | | private void ensureCircleGuidancePanel() { |
| | | if (circleGuidancePanel != null) { |
| | | return; |
| | | } |
| | | circleGuidancePanel = new JPanel(); |
| | | circleGuidancePanel.setLayout(new BoxLayout(circleGuidancePanel, BoxLayout.Y_AXIS)); |
| | | circleGuidancePanel.setOpaque(true); |
| | | circleGuidancePanel.setBackground(new Color(255, 255, 255, 235)); |
| | | circleGuidancePanel.setBorder(BorderFactory.createCompoundBorder( |
| | | BorderFactory.createLineBorder(THEME_COLOR, 1), |
| | | BorderFactory.createEmptyBorder(10, 12, 10, 12))); |
| | | circleGuidancePanel.setAlignmentX(Component.LEFT_ALIGNMENT); |
| | | |
| | | circleGuidanceLabel = new JLabel(); |
| | | circleGuidanceLabel.setFont(new Font("微软雅黑", Font.BOLD, 13)); |
| | | circleGuidanceLabel.setForeground(new Color(33, 37, 41)); |
| | | circleGuidanceLabel.setAlignmentX(Component.LEFT_ALIGNMENT); |
| | | |
| | | JPanel buttonRow = new JPanel(); |
| | | buttonRow.setLayout(new BoxLayout(buttonRow, BoxLayout.X_AXIS)); |
| | | buttonRow.setOpaque(false); |
| | | buttonRow.setAlignmentX(Component.LEFT_ALIGNMENT); |
| | | |
| | | circleGuidancePrimaryButton = createGuidanceButton("是", THEME_COLOR, Color.WHITE, true); |
| | | circleGuidancePrimaryButton.addActionListener(e -> onCircleGuidancePrimary()); |
| | | |
| | | circleGuidanceSecondaryButton = createGuidanceButton("否", Color.WHITE, THEME_COLOR, false); |
| | | circleGuidanceSecondaryButton.addActionListener(e -> onCircleGuidanceSecondary()); |
| | | |
| | | buttonRow.add(circleGuidancePrimaryButton); |
| | | buttonRow.add(Box.createRigidArea(new Dimension(8, 0))); |
| | | buttonRow.add(circleGuidanceSecondaryButton); |
| | | |
| | | circleGuidancePanel.add(circleGuidanceLabel); |
| | | circleGuidancePanel.add(Box.createRigidArea(new Dimension(0, 8))); |
| | | circleGuidancePanel.add(buttonRow); |
| | | circleGuidancePanel.setVisible(false); |
| | | } |
| | | |
| | | private void ensureCircleGuidanceDialog() { |
| | | if (circleGuidancePanel == null) { |
| | | return; |
| | | } |
| | | if (circleGuidanceDialog != null) { |
| | | if (circleGuidancePanel.getParent() != circleGuidanceDialog.getContentPane()) { |
| | | detachCircleGuidancePanel(); |
| | | circleGuidanceDialog.getContentPane().removeAll(); |
| | | circleGuidanceDialog.getContentPane().add(circleGuidancePanel, BorderLayout.CENTER); |
| | | circleGuidanceDialog.pack(); |
| | | } |
| | | return; |
| | | } |
| | | |
| | | Window owner = SwingUtilities.getWindowAncestor(this); |
| | | circleGuidanceDialog = new JDialog(owner, "绘制提示", Dialog.ModalityType.MODELESS); |
| | | circleGuidanceDialog.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); |
| | | circleGuidanceDialog.setResizable(false); |
| | | circleGuidanceDialog.setAlwaysOnTop(true); |
| | | |
| | | if (owner != null && circleDialogOwnerAdapter == null) { |
| | | circleDialogOwnerAdapter = new ComponentAdapter() { |
| | | @Override |
| | | public void componentMoved(ComponentEvent e) { |
| | | positionCircleGuidanceDialog(); |
| | | } |
| | | |
| | | @Override |
| | | public void componentResized(ComponentEvent e) { |
| | | positionCircleGuidanceDialog(); |
| | | } |
| | | }; |
| | | owner.addComponentListener(circleDialogOwnerAdapter); |
| | | } |
| | | |
| | | detachCircleGuidancePanel(); |
| | | circleGuidanceDialog.getContentPane().setLayout(new BorderLayout()); |
| | | circleGuidanceDialog.getContentPane().add(circleGuidancePanel, BorderLayout.CENTER); |
| | | circleGuidanceDialog.pack(); |
| | | } |
| | | |
| | | private void detachCircleGuidancePanel() { |
| | | if (circleGuidancePanel == null) { |
| | | return; |
| | | } |
| | | Container parent = circleGuidancePanel.getParent(); |
| | | if (parent != null) { |
| | | parent.remove(circleGuidancePanel); |
| | | parent.revalidate(); |
| | | parent.repaint(); |
| | | } |
| | | } |
| | | |
| | | private void positionCircleGuidanceDialog() { |
| | | if (circleGuidanceDialog == null) { |
| | | return; |
| | | } |
| | | Window owner = SwingUtilities.getWindowAncestor(this); |
| | | if (owner == null || !owner.isShowing()) { |
| | | return; |
| | | } |
| | | try { |
| | | Point ownerLocation = owner.getLocationOnScreen(); |
| | | int x = ownerLocation.x + owner.getWidth() - circleGuidanceDialog.getWidth() - 30; |
| | | int y = ownerLocation.y + owner.getHeight() - circleGuidanceDialog.getHeight() - 40; |
| | | x = Math.max(ownerLocation.x, x); |
| | | y = Math.max(ownerLocation.y, y); |
| | | circleGuidanceDialog.setLocation(x, y); |
| | | } catch (IllegalComponentStateException ex) { |
| | | // Owner not yet displayable; skip positioning |
| | | } |
| | | } |
| | | |
| | | private JButton createGuidanceButton(String text, Color bg, Color fg, boolean filled) { |
| | | JButton button = new JButton(text); |
| | | button.setFont(new Font("微软雅黑", Font.BOLD, 12)); |
| | | button.setForeground(fg); |
| | | button.setBackground(bg); |
| | | button.setOpaque(true); |
| | | button.setFocusPainted(false); |
| | | button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); |
| | | button.setAlignmentX(Component.LEFT_ALIGNMENT); |
| | | if (filled) { |
| | | button.setBorder(BorderFactory.createEmptyBorder(6, 14, 6, 14)); |
| | | } else { |
| | | button.setBackground(Color.WHITE); |
| | | button.setOpaque(true); |
| | | button.setBorder(BorderFactory.createCompoundBorder( |
| | | BorderFactory.createLineBorder(THEME_COLOR, 1), |
| | | BorderFactory.createEmptyBorder(5, 12, 5, 12))); |
| | | } |
| | | button.addMouseListener(new MouseAdapter() { |
| | | @Override |
| | | public void mouseEntered(MouseEvent e) { |
| | | if (filled) { |
| | | button.setBackground(THEME_HOVER_COLOR); |
| | | } else { |
| | | button.setBackground(new Color(245, 245, 245)); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void mouseExited(MouseEvent e) { |
| | | if (filled) { |
| | | button.setBackground(bg); |
| | | } else { |
| | | button.setBackground(Color.WHITE); |
| | | } |
| | | } |
| | | }); |
| | | return button; |
| | | } |
| | | |
| | | private void onCircleGuidancePrimary() { |
| | | if (circleGuidanceStep == 1) { |
| | | showCircleGuidanceStep(2); |
| | | } else { |
| | | handleCircleCompletion(); |
| | | } |
| | | } |
| | | |
| | | private void onCircleGuidanceSecondary() { |
| | | if (circleGuidanceStep == 1) { |
| | | handleCircleAbort(null); |
| | | } else if (circleGuidanceStep == 2) { |
| | | handleCircleAbort(null); |
| | | } else { |
| | | hideCircleGuidancePanel(); |
| | | } |
| | | } |
| | | |
| | | private void hideCircleGuidancePanel() { |
| | | circleGuidanceStep = 0; |
| | | if (circleGuidancePanel != null) { |
| | | circleGuidancePanel.setVisible(false); |
| | | } |
| | | if (circleGuidanceDialog != null) { |
| | | circleGuidanceDialog.setVisible(false); |
| | | } |
| | | if (!circleDialogMode) { |
| | | rebuildFloatingButtonColumn(); |
| | | } |
| | | } |
| | | |
| | | private void handleCircleAbort(String message) { |
| | | // Return the wizard to step 2 without committing any captured points |
| | | hideEndDrawingButton(); |
| | | addzhangaiwu.abortCircleDrawingAndReturn(message); |
| | | } |
| | | |
| | | private void handleCircleCompletion() { |
| | | hideCircleGuidancePanel(); |
| | | if (endDrawingCallback != null) { |
| | | endDrawingCallback.run(); |
| | | } else { |
| | | addzhangaiwu.finishDrawingSession(); |
| | | } |
| | | } |
| | | |
| | | public void hideEndDrawingButton() { |
| | | hideCircleGuidancePanel(); |
| | | hideFloatingDrawingControls(); |
| | | circleDialogMode = false; |
| | | applyDrawingPauseState(false, false); |
| | | endDrawingCallback = null; |
| | | visualizationPanel.revalidate(); |
| | |
| | | } |
| | | } |
| | | |
| | | private void refreshMapForSelectedArea() { |
| | | if (mapRenderer == null) { |
| | | return; |
| | | } |
| | | |
| | | String currentLandNumber = Dikuaiguanli.getCurrentWorkLandNumber(); |
| | | if (isMeaningfulValue(currentLandNumber)) { |
| | | Dikuai current = Dikuai.getDikuai(currentLandNumber); |
| | | String landName = current != null ? current.getLandName() : null; |
| | | Dikuaiguanli.setCurrentWorkLand(currentLandNumber, landName); |
| | | return; |
| | | } |
| | | |
| | | String labelName = areaNameLabel != null ? areaNameLabel.getText() : null; |
| | | if (!isMeaningfulAreaName(labelName)) { |
| | | Dikuaiguanli.setCurrentWorkLand(null, null); |
| | | return; |
| | | } |
| | | |
| | | Map<String, Dikuai> all = Dikuai.getAllDikuai(); |
| | | for (Dikuai dikuai : all.values()) { |
| | | if (dikuai == null) { |
| | | continue; |
| | | } |
| | | String candidateName = dikuai.getLandName(); |
| | | if (candidateName != null && candidateName.trim().equals(labelName.trim())) { |
| | | Dikuaiguanli.setCurrentWorkLand(dikuai.getLandNumber(), candidateName); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | Dikuaiguanli.setCurrentWorkLand(null, null); |
| | | } |
| | | |
| | | private boolean isMeaningfulValue(String value) { |
| | | if (value == null) { |
| | | return false; |
| | | } |
| | | String trimmed = value.trim(); |
| | | return !trimmed.isEmpty() && !"-1".equals(trimmed); |
| | | } |
| | | |
| | | private boolean isMeaningfulAreaName(String value) { |
| | | if (value == null) { |
| | | return false; |
| | | } |
| | | String trimmed = value.trim(); |
| | | if (trimmed.isEmpty()) { |
| | | return false; |
| | | } |
| | | return !"未选择地块".equals(trimmed); |
| | | } |
| | | |
| | | // 测试方法 |
| | | public static void main(String[] args) { |
| | | JFrame frame = new JFrame("AutoMow - 首页"); |