From b315a6943e6c0d6bdf0d5f7565c570d719154d6c Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期三, 17 十二月 2025 14:56:58 +0800
Subject: [PATCH] 新增了障碍物管理页面
---
src/dikuai/ObstacleManagementPage.java | 759 +++++++++++++++++++++++++++++++++
dikuai.properties | 6
src/dikuai/addzhangaiwu.java | 3
src/lujing/MowingPathGenerationPage.java | 121 +++++
image/gecaojishijiao1.png | 0
image/gecaojishijiao2.png | 0
src/zhuye/MapRenderer.java | 24 +
set.properties | 4
src/zhuye/Shouye.java | 22
Obstacledge.properties | 7
src/zhuye/buttonset.java | 128 +++-
src/dikuai/Dikuaiguanli.java | 256 ++++++----
12 files changed, 1,168 insertions(+), 162 deletions(-)
diff --git a/Obstacledge.properties b/Obstacledge.properties
index 2bc1283..91afaf5 100644
--- a/Obstacledge.properties
+++ b/Obstacledge.properties
@@ -1,5 +1,5 @@
# 鍓茶崏鏈哄湴鍧楅殰纰嶇墿閰嶇疆鏂囦欢
-# 鐢熸垚鏃堕棿锛�2025-12-17T12:03:32.881913900
+# 鐢熸垚鏃堕棿锛�2025-12-17T13:28:00.386604500
# 鍧愭爣绯伙細WGS84锛堝害鍒嗘牸寮忥級
# ============ 鍦板潡鍩哄噯绔欓厤缃� ============
@@ -12,3 +12,8 @@
# 鏍煎紡锛歱lot.[鍦板潡缂栧彿].obstacle.[闅滅鐗╁悕绉癩.originalCoords=[鍧愭爣涓瞉
# 鏍煎紡锛歱lot.[鍦板潡缂栧彿].obstacle.[闅滅鐗╁悕绉癩.xyCoords=[鍧愭爣涓瞉
+# --- 鍦板潡LAND1鐨勯殰纰嶇墿 ---
+plot.LAND1.obstacle.闅滅鐗�1.shape=1
+plot.LAND1.obstacle.闅滅鐗�1.originalCoords=0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E;0.000000,N;0.000000,E
+plot.LAND1.obstacle.闅滅鐗�1.xyCoords=81.22,-22.17;81.21,-22.17;81.19,-22.18;81.20,-22.19;81.18,-22.21;81.07,-22.54;80.94,-23.05;80.44,-23.54;79.84,-23.83;79.27,-24.19;78.63,-24.52;78.11,-24.79;77.69,-25.22;77.43,-25.75;77.15,-26.45;77.08,-27.23;77.10,-27.92;77.08,-28.67;77.08,-29.32;77.15,-29.97;77.27,-30.57;77.53,-31.19;77.92,-31.45;78.22,-31.73;78.92,-31.87;79.65,-31.77;80.35,-31.60;80.90,-31.17;81.27,-30.63;81.70,-30.11;81.90,-29.48;81.95,-28.92;81.90,-28.38;81.73,-27.83;81.73,-27.30;81.52,-26.81;81.42,-26.24;81.26,-25.76;81.27,-25.25;81.04,-25.07;81.11,-24.98;81.11,-25.00;81.12,-25.00
+
diff --git a/dikuai.properties b/dikuai.properties
index 026cea7..69f66e5 100644
--- a/dikuai.properties
+++ b/dikuai.properties
@@ -1,5 +1,5 @@
#Dikuai Properties
-#Wed Dec 17 12:03:32 CST 2025
+#Wed Dec 17 13:50:43 CST 2025
LAND1.angleThreshold=-1
LAND1.baseStationCoordinates=3949.90238860,N,11616.75692000,E
LAND1.boundaryCoordinates=77.19,-32.68;80.71,-54.97;80.99,-55.90;83.54,-56.46;85.04,-55.55;85.94,-53.74;83.24,-35.82;84.55,-34.54;94.02,-31.92;94.10,-31.11;90.88,-20.39;90.35,-19.53;88.33,-19.00;84.12,-19.47;78.92,-22.36;76.63,-25.55;76.93,-29.84;77.06,-31.26;77.19,-32.68
@@ -13,7 +13,7 @@
LAND1.mowingPattern=骞宠绾�
LAND1.mowingTrack=
LAND1.mowingWidth=40
-LAND1.plannedPath=77.17,-29.65;81.28,-55.71;81.70,-55.80;76.93,-25.57;77.26,-25.10;82.12,-55.89;82.54,-55.98;77.59,-24.64;77.92,-24.18;82.96,-56.08;83.38,-56.17;78.25,-23.72;78.59,-23.25;83.76,-56.03;84.13,-55.81;78.92,-22.79;79.27,-22.45;84.50,-55.58;84.87,-55.33;79.64,-22.24;80.01,-22.04;85.18,-54.72;85.48,-54.10;80.39,-21.83;80.76,-21.62;83.00,-35.83;83.34,-35.38;81.13,-21.42;81.50,-21.21;83.69,-35.03;84.04,-34.69;81.88,-21.00;82.25,-20.80;84.39,-34.35;84.77,-34.22;82.62,-20.59;82.99,-20.38;85.16,-34.11;85.55,-34.00;83.37,-20.18;83.74,-19.97;85.94,-33.90;86.32,-33.79;84.11,-19.76;84.50,-19.68;86.71,-33.68;87.10,-33.57;84.90,-19.63;85.30,-19.59;87.49,-33.47;87.88,-33.36;85.70,-19.55;86.09,-19.50;88.26,-33.25;88.65,-33.15;86.49,-19.46;86.89,-19.41;89.04,-33.04;89.43,-32.93;87.29,-19.37;87.69,-19.32;89.82,-32.82;90.20,-32.72;88.08,-19.28;88.49,-19.30;90.59,-32.61;90.98,-32.50;88.91,-19.41;89.34,-19.52;91.37,-32.39;91.76,-32.29;89.76,-19.63;90.18,-19.74;92.14,-32.18;92.53,-32.07;90.76,-20.88;91.62,-23.72;92.92,-31.96;93.31,-31.86;92.47,-26.56;93.33,-29.40;93.70,-31.75
+LAND1.plannedPath=77.45,-31.44;81.28,-55.71;81.70,-55.80;77.91,-31.78;78.05,-31.91;78.17,-31.98;78.35,-32.01;82.12,-55.89;82.54,-55.98;78.77,-32.09;78.95,-32.12;79.17,-32.09;82.96,-56.08;83.38,-56.17;79.57,-32.03;79.96,-31.95;83.76,-56.03;84.13,-55.81;80.35,-31.86;80.50,-31.80;80.72,-31.63;84.50,-55.58;84.87,-55.33;81.08,-31.34;81.41,-30.87;85.18,-54.72;85.48,-54.10;81.75,-30.45;81.89,-30.27;81.94,-30.19;82.05,-29.82;83.00,-35.83;83.34,-35.38;81.43,-23.31;81.47,-22.18;81.43,-22.04;81.32,-21.94;81.21,-21.92;81.13,-21.42;81.50,-21.21;83.69,-35.03;84.04,-34.69;81.88,-21.00;82.25,-20.80;84.39,-34.35;84.77,-34.22;82.62,-20.59;82.99,-20.38;85.16,-34.11;85.55,-34.00;83.37,-20.18;83.74,-19.97;85.94,-33.90;86.32,-33.79;84.11,-19.76;84.50,-19.68;86.71,-33.68;87.10,-33.57;84.90,-19.63;85.30,-19.59;87.49,-33.47;87.88,-33.36;85.70,-19.55;86.09,-19.50;88.26,-33.25;88.65,-33.15;86.49,-19.46;86.89,-19.41;89.04,-33.04;89.43,-32.93;87.29,-19.37;87.69,-19.32;89.82,-32.82;90.20,-32.72;88.08,-19.28;88.49,-19.30;90.59,-32.61;90.98,-32.50;88.91,-19.41;89.34,-19.52;91.37,-32.39;91.76,-32.29;89.76,-19.63;90.18,-19.74;92.14,-32.18;92.53,-32.07;90.76,-20.88;91.62,-23.72;92.92,-31.96;93.31,-31.86;92.47,-26.56;93.33,-29.40;93.70,-31.75;81.40,-22.00;81.27,-21.93;81.21,-21.92;81.08,-21.96;80.98,-22.05;79.85,-23.55;79.64,-22.24;80.01,-22.04;80.22,-23.37;80.58,-23.05;80.39,-21.83;80.76,-21.62;80.87,-22.34;77.96,-24.59;77.63,-24.92;77.59,-24.64;77.92,-24.18;77.99,-24.57;78.36,-24.38;78.25,-23.72;78.59,-23.25;78.73,-24.19;79.11,-23.99;78.92,-22.79;79.27,-22.45;79.48,-23.76;77.99,-24.57;77.93,-24.62;77.51,-25.05;77.47,-25.11;77.20,-25.66;77.01,-26.12;76.93,-25.57;77.26,-25.10;77.31,-25.43
LAND1.returnPointCoordinates=-1
-LAND1.updateTime=2025-12-17 12\:03\:32
+LAND1.updateTime=2025-12-17 13\:50\:43
LAND1.userId=-1
diff --git a/image/gecaojishijiao1.png b/image/gecaojishijiao1.png
new file mode 100644
index 0000000..17c4c56
--- /dev/null
+++ b/image/gecaojishijiao1.png
Binary files differ
diff --git a/image/gecaojishijiao2.png b/image/gecaojishijiao2.png
new file mode 100644
index 0000000..a73111b
--- /dev/null
+++ b/image/gecaojishijiao2.png
Binary files differ
diff --git a/set.properties b/set.properties
index 4e56433..835a658 100644
--- a/set.properties
+++ b/set.properties
@@ -1,12 +1,12 @@
#Mower Configuration Properties - Updated
-#Wed Dec 17 12:04:00 CST 2025
+#Wed Dec 17 14:56:25 CST 2025
appVersion=-1
currentWorkLandNumber=LAND1
cuttingWidth=200
firmwareVersion=-1
handheldMarkerId=
idleTrailDurationSeconds=60
-mapScale=15.31
+mapScale=12.92
mowerId=1234
serialAutoConnect=true
serialBaudRate=115200
diff --git a/src/dikuai/Dikuaiguanli.java b/src/dikuai/Dikuaiguanli.java
index 5f0218e..5adb9c5 100644
--- a/src/dikuai/Dikuaiguanli.java
+++ b/src/dikuai/Dikuaiguanli.java
@@ -226,12 +226,12 @@
// 鍦板潡缂栧彿
contentPanel.add(createCardInfoItem("鍦板潡缂栧彿:", getDisplayValue(dikuai.getLandNumber(), "鏈煡")));
- contentPanel.add(Box.createRigidArea(new Dimension(0, 20)));
-
+ contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
+
// 娣诲姞鏃堕棿
contentPanel.add(createCardInfoItem("娣诲姞鏃堕棿:", getDisplayValue(dikuai.getCreateTime(), "鏈煡")));
- contentPanel.add(Box.createRigidArea(new Dimension(0, 20)));
-
+ contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
+
// 鍦板潡闈㈢Н
String landArea = dikuai.getLandArea();
if (landArea != null && !landArea.equals("-1")) {
@@ -240,14 +240,14 @@
landArea = "鏈煡";
}
contentPanel.add(createCardInfoItem("鍦板潡闈㈢Н:", landArea));
- contentPanel.add(Box.createRigidArea(new Dimension(0, 20)));
-
+ contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
+
// 杩斿洖鐐瑰潗鏍囷紙甯︿慨鏀规寜閽級
- contentPanel.add(createCardInfoItemWithButton("杩斿洖鐐瑰潗鏍�:",
- getDisplayValue(dikuai.getReturnPointCoordinates(), "鏈缃�"),
+ contentPanel.add(createCardInfoItemWithButton("杩斿洖鐐瑰潗鏍�:",
+ getDisplayValue(dikuai.getReturnPointCoordinates(), "鏈缃�"),
"淇敼", e -> editReturnPoint(dikuai)));
- contentPanel.add(Box.createRigidArea(new Dimension(0, 20)));
-
+ contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
+
// 鍦板潡杈圭晫鍧愭爣锛堝甫鏄剧ず椤剁偣鎸夐挳锛�
JPanel boundaryPanel = createBoundaryInfoItem(dikuai,
getTruncatedValue(dikuai.getBoundaryCoordinates(), 12, "鏈缃�"));
@@ -256,27 +256,31 @@
() -> editBoundaryCoordinates(dikuai),
"鐐瑰嚮鏌ョ湅/缂栬緫鍦板潡杈圭晫鍧愭爣");
contentPanel.add(boundaryPanel);
- contentPanel.add(Box.createRigidArea(new Dimension(0, 20)));
-
+ contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
+
ObstacleSummary obstacleSummary = getObstacleSummaryFromCache(dikuai.getLandNumber());
JPanel obstaclePanel = createCardInfoItemWithButton("闅滅鐗�:",
obstacleSummary.buildDisplayValue(),
"鏂板",
e -> addNewObstacle(dikuai));
setInfoItemTooltip(obstaclePanel, obstacleSummary.buildTooltip());
+ // 璁╅殰纰嶇墿鏍囬鍙偣鍑伙紝鎵撳紑闅滅鐗╃鐞嗛〉闈�
+ configureInteractiveLabel(getInfoItemTitleLabel(obstaclePanel),
+ () -> showObstacleManagementPage(dikuai),
+ "鐐瑰嚮鏌ョ湅/绠$悊闅滅鐗�");
contentPanel.add(obstaclePanel);
- contentPanel.add(Box.createRigidArea(new Dimension(0, 20)));
+ contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
// 璺緞鍧愭爣锛堝甫鏌ョ湅鎸夐挳锛�
- JPanel pathPanel = createCardInfoItemWithButton("璺緞鍧愭爣:",
- getTruncatedValue(dikuai.getPlannedPath(), 12, "鏈缃�"),
+ JPanel pathPanel = createCardInfoItemWithButton("璺緞鍧愭爣:",
+ getTruncatedValue(dikuai.getPlannedPath(), 12, "鏈缃�"),
"澶嶅埗", e -> copyCoordinatesAction("璺緞鍧愭爣", dikuai.getPlannedPath()));
setInfoItemTooltip(pathPanel, dikuai.getPlannedPath());
configureInteractiveLabel(getInfoItemTitleLabel(pathPanel),
() -> editPlannedPath(dikuai),
"鐐瑰嚮鏌ョ湅/缂栬緫璺緞鍧愭爣");
contentPanel.add(pathPanel);
- contentPanel.add(Box.createRigidArea(new Dimension(0, 20)));
+ contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
JPanel baseStationPanel = createCardInfoItemWithButton("鍩虹珯鍧愭爣:",
getTruncatedValue(dikuai.getBaseStationCoordinates(), 12, "鏈缃�"),
@@ -286,7 +290,7 @@
() -> editBaseStationCoordinates(dikuai),
"鐐瑰嚮鏌ョ湅/缂栬緫鍩虹珯鍧愭爣");
contentPanel.add(baseStationPanel);
- contentPanel.add(Box.createRigidArea(new Dimension(0, 20)));
+ contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
JPanel boundaryOriginalPanel = createCardInfoItemWithButton("杈圭晫鍘熷鍧愭爣:",
getTruncatedValue(dikuai.getBoundaryOriginalCoordinates(), 12, "鏈缃�"),
@@ -296,7 +300,7 @@
() -> editBoundaryOriginalCoordinates(dikuai),
"鐐瑰嚮鏌ョ湅/缂栬緫杈圭晫鍘熷鍧愭爣");
contentPanel.add(boundaryOriginalPanel);
- contentPanel.add(Box.createRigidArea(new Dimension(0, 20)));
+ contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
JPanel mowingPatternPanel = createCardInfoItemWithButton("鍓茶崏妯″紡:",
getTruncatedValue(dikuai.getMowingPattern(), 12, "鏈缃�"),
@@ -306,7 +310,7 @@
() -> editMowingPattern(dikuai),
"鐐瑰嚮鏌ョ湅/缂栬緫鍓茶崏妯″紡");
contentPanel.add(mowingPatternPanel);
- contentPanel.add(Box.createRigidArea(new Dimension(0, 20)));
+ contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
String mowingWidthValue = dikuai.getMowingWidth();
String widthSource = null;
@@ -319,7 +323,7 @@
"缂栬緫", e -> editMowingWidth(dikuai));
setInfoItemTooltip(mowingWidthPanel, widthSource);
contentPanel.add(mowingWidthPanel);
- contentPanel.add(Box.createRigidArea(new Dimension(0, 20)));
+ contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
JPanel completedTrackPanel = createCardInfoItemWithButton("宸插畬鎴愬壊鑽夎矾寰�:",
getTruncatedValue(dikuai.getMowingTrack(), 12, "鏈褰�"),
@@ -371,7 +375,10 @@
private JPanel createCardInfoItemWithButton(String label, String value, String buttonText, ActionListener listener) {
JPanel itemPanel = new JPanel(new BorderLayout());
itemPanel.setBackground(CARD_BACKGROUND);
- itemPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 20));
+ // 澧炲姞楂樺害浠ョ‘淇濇寜閽畬鏁存樉绀猴紙鎸夐挳楂樺害绾�24-28鍍忕礌锛屽姞涓婁笂涓嬭竟璺濓級
+ itemPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, 35));
+ itemPanel.setPreferredSize(new Dimension(Integer.MAX_VALUE, 30));
+ itemPanel.setMinimumSize(new Dimension(0, 28));
JLabel labelComp = new JLabel(label);
labelComp.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
@@ -379,13 +386,14 @@
JPanel rightPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 0));
rightPanel.setBackground(CARD_BACKGROUND);
+ // 娣诲姞鍨傜洿鍐呰竟璺濅互纭繚鎸夐挳涓嶈瑁佸壀
+ rightPanel.setBorder(BorderFactory.createEmptyBorder(2, 0, 2, 0));
JLabel valueComp = new JLabel(value);
valueComp.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
valueComp.setForeground(TEXT_COLOR);
- JButton button = createSmallButton(buttonText);
- button.addActionListener(listener);
+ JButton button = createSmallLinkButton(buttonText, listener);
rightPanel.add(valueComp);
rightPanel.add(button);
@@ -401,17 +409,19 @@
private JPanel createBoundaryInfoItem(Dikuai dikuai, String displayValue) {
JPanel itemPanel = new JPanel(new BorderLayout());
itemPanel.setBackground(CARD_BACKGROUND);
- int rowHeight = Math.max(36, BOUNDARY_TOGGLE_ICON_SIZE + 12);
+ // 澧炲姞楂樺害浠ョ‘淇濇寜閽笅杈圭紭瀹屾暣鏄剧ず锛堟寜閽珮搴�56锛屽姞涓婁笂涓嬭竟璺濓級
+ int rowHeight = Math.max(60, BOUNDARY_TOGGLE_ICON_SIZE + 16);
Dimension rowDimension = new Dimension(Integer.MAX_VALUE, rowHeight);
itemPanel.setMaximumSize(rowDimension);
itemPanel.setPreferredSize(rowDimension);
- itemPanel.setMinimumSize(new Dimension(0, 32));
+ itemPanel.setMinimumSize(new Dimension(0, 56));
JLabel labelComp = new JLabel("鍦板潡杈圭晫:");
labelComp.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
labelComp.setForeground(LIGHT_TEXT);
- int verticalPadding = Math.max(0, (rowHeight - BOUNDARY_TOGGLE_ICON_SIZE) / 2);
+ // 纭繚鎸夐挳鏈夎冻澶熺殑涓婁笅杈硅窛锛岄伩鍏嶄笅杈圭紭琚鍓�
+ int verticalPadding = Math.max(2, (rowHeight - BOUNDARY_TOGGLE_ICON_SIZE) / 2);
JPanel rightPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 0));
rightPanel.setBackground(CARD_BACKGROUND);
rightPanel.setBorder(BorderFactory.createEmptyBorder(verticalPadding, 0, verticalPadding, 0));
@@ -838,6 +848,12 @@
}
Window owner = SwingUtilities.getWindowAncestor(this);
+
+ // 鑾峰彇鍦板潡绠$悊瀵硅瘽妗嗭紝鍑嗗鍦ㄦ墦寮�璺緞瑙勫垝椤甸潰鏃跺叧闂�
+ Window managementWindow = null;
+ if (owner instanceof JDialog) {
+ managementWindow = owner;
+ }
// 鑾峰彇鍦板潡鍩烘湰鏁版嵁
String baseStationValue = prepareCoordinateForEditor(dikuai.getBaseStationCoordinates());
@@ -897,6 +913,11 @@
callback
);
+ // 鍏抽棴鍦板潡绠$悊椤甸潰
+ if (managementWindow != null) {
+ managementWindow.dispose();
+ }
+
dialog.setVisible(true);
}
@@ -1292,112 +1313,104 @@
return value;
}
+ /**
+ * 鍒涘缓绫讳技浜庨摼鎺ョ殑灏忔寜閽�
+ */
+ private JButton createSmallLinkButton(String text, ActionListener listener) {
+ JButton btn = new JButton(text);
+ btn.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 11));
+ btn.setForeground(PRIMARY_COLOR);
+ btn.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createLineBorder(PRIMARY_COLOR, 1, true),
+ BorderFactory.createEmptyBorder(2, 6, 2, 6)
+ ));
+ btn.setContentAreaFilled(false);
+ btn.setFocusPainted(false);
+ btn.setCursor(new Cursor(Cursor.HAND_CURSOR));
+ btn.addMouseListener(new MouseAdapter() {
+ public void mouseEntered(MouseEvent e) { btn.setOpaque(true); btn.setBackground(new Color(230, 250, 240)); }
+ public void mouseExited(MouseEvent e) { btn.setOpaque(false); }
+ });
+ if (listener != null) {
+ btn.addActionListener(listener);
+ }
+ return btn;
+ }
+
private JButton createSmallButton(String text) {
- return createSmallButton(text, PRIMARY_COLOR, PRIMARY_DARK);
+ return createSmallLinkButton(text, null);
}
private JButton createSmallButton(String text, Color backgroundColor, Color hoverColor) {
- JButton button = new JButton(text);
- button.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 12));
+ // 瀵逛簬闇�瑕佷笉鍚岄鑹茬殑鎸夐挳锛屼娇鐢ㄥ疄蹇冮鏍�
Color baseColor = backgroundColor == null ? PRIMARY_COLOR : backgroundColor;
- Color hover = hoverColor == null ? baseColor : hoverColor;
- button.setBackground(baseColor);
- button.setForeground(WHITE);
- button.setBorder(BorderFactory.createEmptyBorder(2, 10, 2, 10));
- button.setMargin(new Insets(0, 0, 0, 0));
- button.setFocusPainted(false);
- button.setCursor(new Cursor(Cursor.HAND_CURSOR));
-
- button.addMouseListener(new MouseAdapter() {
- public void mouseEntered(MouseEvent e) {
- button.setBackground(hover);
- }
- public void mouseExited(MouseEvent e) {
- button.setBackground(baseColor);
- }
- });
-
- return button;
+ return createStyledButton(text, baseColor, true);
}
private JButton createActionButton(String text, Color color) {
- JButton button = new JButton(text);
- button.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
- button.setBackground(color);
- button.setForeground(WHITE);
- button.setBorder(BorderFactory.createEmptyBorder(8, 16, 8, 16));
- button.setFocusPainted(false);
- button.setCursor(new Cursor(Cursor.HAND_CURSOR));
+ return createStyledButton(text, color, true); // 瀹炲績椋庢牸
+ }
- // 鎮仠鏁堟灉
- button.addMouseListener(new MouseAdapter() {
- public void mouseEntered(MouseEvent e) {
- if (color == RED_COLOR) {
- button.setBackground(RED_DARK);
+ /**
+ * 鍒涘缓鐜颁唬椋庢牸鎸夐挳 (瀹炲績/杞粨)
+ */
+ private JButton createStyledButton(String text, Color baseColor, boolean filled) {
+ JButton btn = new JButton(text) {
+ @Override
+ protected void paintComponent(Graphics g) {
+ Graphics2D g2 = (Graphics2D) g.create();
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+
+ boolean isPressed = getModel().isPressed();
+ boolean isRollover = getModel().isRollover();
+
+ if (filled) {
+ if (isPressed) g2.setColor(baseColor.darker());
+ else if (isRollover) g2.setColor(baseColor.brighter());
+ else g2.setColor(baseColor);
+ g2.fillRoundRect(0, 0, getWidth(), getHeight(), 8, 8);
+ g2.setColor(Color.WHITE);
} else {
- button.setBackground(PRIMARY_DARK);
+ g2.setColor(CARD_BACKGROUND); // 鑳屾櫙
+ g2.fillRoundRect(0, 0, getWidth(), getHeight(), 8, 8);
+
+ if (isPressed) g2.setColor(baseColor.darker());
+ else if (isRollover) g2.setColor(baseColor);
+ else g2.setColor(new Color(200, 200, 200)); // 榛樿杈规鐏�
+
+ g2.setStroke(new BasicStroke(1.2f));
+ g2.drawRoundRect(0, 0, getWidth()-1, getHeight()-1, 8, 8);
+ g2.setColor(isRollover ? baseColor : TEXT_COLOR);
}
+
+ FontMetrics fm = g2.getFontMetrics();
+ int x = (getWidth() - fm.stringWidth(getText())) / 2;
+ int y = (getHeight() - fm.getHeight()) / 2 + fm.getAscent();
+ g2.drawString(getText(), x, y);
+
+ g2.dispose();
}
- public void mouseExited(MouseEvent e) {
- if (color == RED_COLOR) {
- button.setBackground(RED_COLOR);
- } else {
- button.setBackground(PRIMARY_COLOR);
- }
- }
- });
-
- return button;
+ };
+ btn.setFocusPainted(false);
+ btn.setContentAreaFilled(false);
+ btn.setBorderPainted(false);
+ btn.setCursor(new Cursor(Cursor.HAND_CURSOR));
+ btn.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 12));
+ return btn;
}
private JButton createDeleteButton() {
- JButton button = new JButton("鍒犻櫎");
- button.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 12));
- button.setBackground(RED_COLOR);
- button.setForeground(WHITE);
- button.setBorder(BorderFactory.createEmptyBorder(6, 12, 6, 12));
- button.setFocusPainted(false);
- button.setCursor(new Cursor(Cursor.HAND_CURSOR));
-
+ JButton button = createStyledButton("鍒犻櫎", RED_COLOR, false); // 杞粨椋庢牸
ImageIcon deleteIcon = loadIcon("image/delete.png", 16, 16);
if (deleteIcon != null) {
button.setIcon(deleteIcon);
button.setIconTextGap(6);
}
-
- // 鎮仠鏁堟灉
- button.addMouseListener(new MouseAdapter() {
- public void mouseEntered(MouseEvent e) {
- button.setBackground(RED_DARK);
- }
- public void mouseExited(MouseEvent e) {
- button.setBackground(RED_COLOR);
- }
- });
-
return button;
}
private JButton createPrimaryFooterButton(String text) {
- JButton button = new JButton(text);
- button.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 12));
- button.setBackground(PRIMARY_COLOR);
- button.setForeground(WHITE);
- button.setBorder(BorderFactory.createEmptyBorder(6, 12, 6, 12));
- button.setFocusPainted(false);
- button.setCursor(new Cursor(Cursor.HAND_CURSOR));
-
- button.addMouseListener(new MouseAdapter() {
- public void mouseEntered(MouseEvent e) {
- button.setBackground(PRIMARY_DARK);
- }
-
- public void mouseExited(MouseEvent e) {
- button.setBackground(PRIMARY_COLOR);
- }
- });
-
- return button;
+ return createStyledButton(text, PRIMARY_COLOR, true); // 瀹炲績椋庢牸
}
private JButton createWorkToggleButton(Dikuai dikuai) {
@@ -1507,6 +1520,8 @@
boolean showBoundaryPoints = sanitizedLandNumber != null && boundaryPointVisibility.getOrDefault(sanitizedLandNumber, false);
renderer.setBoundaryPointsVisible(showBoundaryPoints);
renderer.setBoundaryPointSizeScale(showBoundaryPoints ? 0.5d : 1.0d);
+ // 閫�鍑洪瑙堝悗锛屼笉鏄剧ず闅滅鐗╃偣锛堥殰纰嶇墿鐐瑰彧鍦ㄩ瑙堟椂鏄剧ず锛�
+ renderer.setObstaclePointsVisible(false);
}
shouye.refreshMowingIndicators();
}
@@ -1614,6 +1629,31 @@
}
}
+ /**
+ * 鏄剧ず闅滅鐗╃鐞嗛〉闈�
+ */
+ private void showObstacleManagementPage(Dikuai dikuai) {
+ if (dikuai == null) {
+ return;
+ }
+ Window owner = SwingUtilities.getWindowAncestor(this);
+
+ // 鑾峰彇鍦板潡绠$悊瀵硅瘽妗嗭紝鍑嗗鍦ㄦ墦寮�闅滅鐗╃鐞嗛〉闈㈡椂鍏抽棴
+ Window managementWindow = null;
+ if (owner instanceof JDialog) {
+ managementWindow = owner;
+ }
+
+ ObstacleManagementPage managementPage = new ObstacleManagementPage(owner, dikuai);
+
+ // 鍏抽棴鍦板潡绠$悊椤甸潰
+ if (managementWindow != null) {
+ managementWindow.dispose();
+ }
+
+ managementPage.setVisible(true);
+ }
+
private void addNewObstacle(Dikuai dikuai) {
if (dikuai == null) {
JOptionPane.showMessageDialog(this, "鏈壘鍒板綋鍓嶅湴鍧楋紝鏃犳硶鏂板闅滅鐗�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
diff --git a/src/dikuai/ObstacleManagementPage.java b/src/dikuai/ObstacleManagementPage.java
new file mode 100644
index 0000000..43cd9e4
--- /dev/null
+++ b/src/dikuai/ObstacleManagementPage.java
@@ -0,0 +1,759 @@
+package dikuai;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import javax.swing.plaf.basic.BasicScrollBarUI;
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.geom.RoundRectangle2D;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import zhangaiwu.Obstacledge;
+import zhuye.Shouye;
+
+/**
+ * 闅滅鐗╃鐞嗛〉闈� - UI浼樺寲鐗�
+ */
+public class ObstacleManagementPage extends JDialog {
+ private static final long serialVersionUID = 1L;
+
+ // --- 灏哄甯搁噺 (淇濇寔涓嶅彉) ---
+ private static final int SCREEN_WIDTH = 400;
+ private static final int SCREEN_HEIGHT = 800;
+
+ // --- 閰嶈壊鏂规 (鏇寸幇浠g殑鑾叞杩�/鎵佸钩椋庢牸) ---
+ private static final Color PRIMARY_COLOR = new Color(46, 139, 87); // 娴疯椈缁� (涓昏壊)
+ private static final Color PRIMARY_HOVER = new Color(60, 179, 113); // 鎮仠缁�
+ private static final Color DANGER_COLOR = new Color(220, 53, 69); // 璀﹀憡绾�
+ private static final Color DANGER_HOVER = new Color(200, 35, 51);
+
+ private static final Color TEXT_PRIMARY = new Color(33, 37, 41); // 涓昏鏂囧瓧
+ private static final Color TEXT_SECONDARY = new Color(108, 117, 125); // 娆¤鏂囧瓧
+
+ private static final Color BG_MAIN = new Color(248, 249, 250); // 鏁翠綋鑳屾櫙 (鐏扮櫧)
+ private static final Color BG_CARD = Color.WHITE; // 鍗$墖鑳屾櫙
+ private static final Color BG_INPUT = new Color(241, 243, 245); // 杈撳叆妗嗚儗鏅�
+
+ private static final Color BORDER_LIGHT = new Color(233, 236, 239); // 娴呰竟妗�
+
+ private final Dikuai dikuai;
+ private JPanel cardsPanel;
+ private JScrollPane scrollPane;
+
+ public ObstacleManagementPage(Window owner, Dikuai dikuai) {
+ super(owner, "闅滅鐗╃鐞�", Dialog.ModalityType.APPLICATION_MODAL);
+ this.dikuai = dikuai;
+
+ initializeWindow();
+ initializeUI();
+
+ // 纭繚甯冨眬瀹屾垚鍚庡啀鏄剧ず鏁版嵁
+ SwingUtilities.invokeLater(this::loadAndDisplayObstacles);
+ }
+
+ private void initializeWindow() {
+ setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+ setLayout(new BorderLayout());
+ getContentPane().setBackground(BG_MAIN);
+ setSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
+ setResizable(false);
+ setLocationRelativeTo(getOwner());
+ }
+
+ private void initializeUI() {
+ // 1. 椤堕儴瀵艰埅鏍�
+ add(createHeader(), BorderLayout.NORTH);
+
+ // 2. 涓棿婊氬姩鍖哄煙
+ cardsPanel = new JPanel();
+ cardsPanel.setLayout(new BoxLayout(cardsPanel, BoxLayout.Y_AXIS));
+ cardsPanel.setBackground(BG_MAIN);
+ cardsPanel.setBorder(new EmptyBorder(15, 15, 15, 15)); // 澶栬竟璺�
+
+ scrollPane = new JScrollPane(cardsPanel);
+ scrollPane.setBorder(null); // 鏃犺竟妗�
+ scrollPane.setBackground(BG_MAIN);
+ scrollPane.getVerticalScrollBar().setUnitIncrement(20);
+
+ // 鑷畾涔夋粴鍔ㄦ潯鏍峰紡
+ customizeScrollBar(scrollPane);
+
+ add(scrollPane, BorderLayout.CENTER);
+ }
+
+ /**
+ * 鍒涘缓椤堕儴鏍囬鏍�
+ */
+ private JPanel createHeader() {
+ JPanel header = new JPanel(new BorderLayout());
+ header.setBackground(Color.WHITE);
+ header.setPreferredSize(new Dimension(SCREEN_WIDTH, 60));
+ header.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, BORDER_LIGHT)); // 搴曢儴缁嗙嚎
+
+ // 宸︿晶淇℃伅
+ JPanel infoPanel = new JPanel(new GridLayout(2, 1));
+ infoPanel.setBackground(Color.WHITE);
+ infoPanel.setBorder(new EmptyBorder(8, 20, 8, 0));
+
+ String landName = getDisplayValue(dikuai.getLandName(), "鏈煡鍦板潡");
+ String landNumber = getDisplayValue(dikuai.getLandNumber(), "--");
+
+ JLabel titleLabel = new JLabel(landName);
+ titleLabel.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 16));
+ titleLabel.setForeground(TEXT_PRIMARY);
+
+ JLabel subTitleLabel = new JLabel("缂栧彿: " + landNumber);
+ subTitleLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 12));
+ subTitleLabel.setForeground(TEXT_SECONDARY);
+
+ infoPanel.add(titleLabel);
+ infoPanel.add(subTitleLabel);
+
+ header.add(infoPanel, BorderLayout.CENTER);
+
+ // 鍙充晶鍏抽棴鎸夐挳
+ JButton closeBtn = new JButton("鉁�");
+ closeBtn.setFont(new Font("Arial", Font.BOLD, 18));
+ closeBtn.setForeground(TEXT_SECONDARY);
+ closeBtn.setBorder(new EmptyBorder(0, 15, 0, 20));
+ closeBtn.setContentAreaFilled(false);
+ closeBtn.setFocusPainted(false);
+ closeBtn.setCursor(new Cursor(Cursor.HAND_CURSOR));
+ closeBtn.addMouseListener(new MouseAdapter() {
+ public void mouseEntered(MouseEvent e) { closeBtn.setForeground(TEXT_PRIMARY); }
+ public void mouseExited(MouseEvent e) { closeBtn.setForeground(TEXT_SECONDARY); }
+ });
+ closeBtn.addActionListener(e -> dispose());
+
+ header.add(closeBtn, BorderLayout.EAST);
+
+ return header;
+ }
+
+ /**
+ * 鑷畾涔夋粴鍔ㄦ潯鏍峰紡锛堟墎骞冲寲銆佺粏鏉★級
+ */
+ private void customizeScrollBar(JScrollPane scrollPane) {
+ scrollPane.getVerticalScrollBar().setUI(new BasicScrollBarUI() {
+ @Override
+ protected void configureScrollBarColors() {
+ this.thumbColor = new Color(200, 200, 200);
+ this.trackColor = BG_MAIN;
+ }
+
+ @Override
+ protected JButton createDecreaseButton(int orientation) {
+ return createZeroButton();
+ }
+
+ @Override
+ protected JButton createIncreaseButton(int orientation) {
+ return createZeroButton();
+ }
+
+ private JButton createZeroButton() {
+ JButton jbutton = new JButton();
+ jbutton.setPreferredSize(new Dimension(0, 0));
+ jbutton.setMinimumSize(new Dimension(0, 0));
+ jbutton.setMaximumSize(new Dimension(0, 0));
+ return jbutton;
+ }
+
+ @Override
+ protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) {
+ Graphics2D g2 = (Graphics2D) g.create();
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setColor(thumbColor);
+ g2.fillRoundRect(thumbBounds.x + 2, thumbBounds.y, thumbBounds.width - 4, thumbBounds.height, 6, 6);
+ g2.dispose();
+ }
+ });
+ scrollPane.getVerticalScrollBar().setPreferredSize(new Dimension(8, 0));
+ }
+
+ /**
+ * 鍔犺浇鏁版嵁
+ */
+ private void loadAndDisplayObstacles() {
+ cardsPanel.removeAll();
+
+ List<Obstacledge.Obstacle> obstacles = loadObstacles();
+
+ if (obstacles.isEmpty()) {
+ showEmptyState();
+ } else {
+ for (Obstacledge.Obstacle obstacle : obstacles) {
+ cardsPanel.add(createObstacleCard(obstacle));
+ cardsPanel.add(Box.createVerticalStrut(15)); // 鍗$墖闂磋窛
+ }
+ }
+
+ cardsPanel.revalidate();
+ cardsPanel.repaint();
+ }
+
+ private void showEmptyState() {
+ JPanel emptyPanel = new JPanel();
+ emptyPanel.setLayout(new BoxLayout(emptyPanel, BoxLayout.Y_AXIS));
+ emptyPanel.setBackground(BG_MAIN);
+ emptyPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
+
+ JLabel iconLabel = new JLabel("馃敳"); // 绠�鍗曠殑鍗犱綅绗︼紝濡傛灉鏈夊浘鐗囨洿濂�
+ iconLabel.setFont(new Font("Segoe UI Emoji", Font.PLAIN, 48));
+ iconLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
+
+ JLabel textLabel = new JLabel("鏆傛棤闅滅鐗╂暟鎹�");
+ textLabel.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 14));
+ textLabel.setForeground(TEXT_SECONDARY);
+ textLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
+
+ emptyPanel.add(Box.createVerticalStrut(50));
+ emptyPanel.add(iconLabel);
+ emptyPanel.add(Box.createVerticalStrut(10));
+ emptyPanel.add(textLabel);
+
+ cardsPanel.add(emptyPanel);
+ }
+
+ /**
+ * 鍒涘缓鍗曚釜闅滅鐗╁崱鐗�
+ */
+ private JPanel createObstacleCard(Obstacledge.Obstacle obstacle) {
+ // 鍗$墖瀹瑰櫒 - 浣跨敤鍦嗚鐭╁舰鑳屾櫙
+ JPanel card = new JPanel() {
+ @Override
+ protected void paintComponent(Graphics g) {
+ Graphics2D g2 = (Graphics2D) g.create();
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setColor(BG_CARD);
+ // 缁樺埗鍦嗚鐭╁舰鑳屾櫙
+ g2.fillRoundRect(0, 0, getWidth() - 1, getHeight() - 1, 12, 12);
+ // 缁樺埗娣℃贰鐨勮竟妗�
+ g2.setColor(BORDER_LIGHT);
+ g2.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, 12, 12);
+ g2.dispose();
+ }
+ };
+ card.setLayout(new BoxLayout(card, BoxLayout.Y_AXIS));
+ card.setOpaque(false); // 閫忔槑浠ユ樉绀� paintComponent 鏁堟灉
+ card.setBorder(new EmptyBorder(15, 15, 15, 15)); // 鍗$墖鍐呴儴鍐呰竟璺�
+ card.setMaximumSize(new Dimension(Integer.MAX_VALUE, 380)); // 闄愬埗楂樺害锛岄槻姝㈡媺浼�
+
+ // 1. 鍗$墖鏍囬琛� (鍚嶇О + 褰㈢姸 + 鍒犻櫎)
+ JPanel titleRow = new JPanel(new BorderLayout());
+ titleRow.setOpaque(false);
+
+ String name = (obstacle.getObstacleName() == null || obstacle.getObstacleName().isEmpty())
+ ? "鏈懡鍚�" : obstacle.getObstacleName();
+ JLabel nameLabel = new JLabel(name);
+ nameLabel.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 15));
+ nameLabel.setForeground(TEXT_PRIMARY);
+ // 娣诲姞涓�涓皬鍥炬爣瑁呴グ
+ nameLabel.setIcon(new Icon() {
+ public void paintIcon(Component c, Graphics g, int x, int y) {
+ g.setColor(PRIMARY_COLOR);
+ g.fillOval(x, y + 4, 8, 8);
+ }
+ public int getIconWidth() { return 12; }
+ public int getIconHeight() { return 16; }
+ });
+
+ // 娣诲姞褰㈢姸鏄剧ず锛堝湪鍚嶇О鍙宠竟锛�
+ JLabel shapeLabel = createShapeLabel(obstacle.getShape());
+
+ // 宸︿晶闈㈡澘锛氬悕绉� + 褰㈢姸
+ JPanel leftPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 8, 0));
+ leftPanel.setOpaque(false);
+ leftPanel.add(nameLabel);
+ leftPanel.add(shapeLabel);
+
+ JButton deleteBtn = createIconButton("馃棏", DANGER_COLOR); // 浣跨敤Unicode鍨冨溇妗�
+ deleteBtn.addActionListener(e -> deleteObstacle(obstacle));
+
+ titleRow.add(leftPanel, BorderLayout.CENTER);
+ titleRow.add(deleteBtn, BorderLayout.EAST);
+
+ card.add(titleRow);
+ card.add(Box.createVerticalStrut(12));
+
+ // 鍒嗗壊绾�
+ JSeparator sep = new JSeparator();
+ sep.setForeground(BORDER_LIGHT);
+ sep.setMaximumSize(new Dimension(Integer.MAX_VALUE, 1));
+ card.add(sep);
+ card.add(Box.createVerticalStrut(12));
+
+ // 2. 鍘熷鍧愭爣鍖哄煙
+ String originalCoords = extractOriginalCoordinates(obstacle);
+ card.add(createDataField("鍘熷缁忕含搴︽暟鎹�", originalCoords, 2));
+ card.add(Box.createVerticalStrut(10));
+
+ // 3. 鐢熸垚鍧愭爣鍖哄煙
+ String genCoords = extractObstacleCoordinates(obstacle);
+ JTextArea xyArea = createDataTextArea(genCoords, 3); // 寮曠敤浠ヤ究鏇存柊
+ JScrollPane scrollXY = new JScrollPane(xyArea);
+ scrollXY.setBorder(BorderFactory.createEmptyBorder()); // 澶栭儴鐢盤anel鎻愪緵杈规
+
+ JPanel xyWrapper = createWrapperPanel("鐢熸垚鍧愭爣 (XY绫�)", scrollXY);
+ card.add(xyWrapper);
+ card.add(Box.createVerticalStrut(15));
+
+ // 4. 鎿嶄綔鎸夐挳琛�
+ JPanel actionPanel = new JPanel();
+ actionPanel.setLayout(new BoxLayout(actionPanel, BoxLayout.X_AXIS));
+ actionPanel.setOpaque(false);
+
+ JButton generateBtn = createStyledButton("閲嶆柊鐢熸垚鍧愭爣", PRIMARY_COLOR, true);
+ generateBtn.addActionListener(e -> generateObstacleCoordinates(obstacle, xyArea));
+
+ JButton previewBtn = createStyledButton("棰勮", TEXT_SECONDARY, false);
+ previewBtn.setPreferredSize(new Dimension(70, 36)); // 绋嶅井绐勪竴鐐�
+ previewBtn.addActionListener(e -> previewObstacle(obstacle));
+
+ actionPanel.add(generateBtn);
+ actionPanel.add(Box.createHorizontalStrut(10));
+ actionPanel.add(previewBtn);
+
+ card.add(actionPanel);
+
+ return card;
+ }
+
+ /**
+ * 杈呭姪鏂规硶锛氬垱寤哄甫鏍囬鐨勬暟鎹睍绀哄潡
+ */
+ private JPanel createDataField(String title, String content, int rows) {
+ JTextArea area = createDataTextArea(content, rows);
+ JScrollPane scroll = new JScrollPane(area);
+ scroll.setBorder(BorderFactory.createEmptyBorder());
+ return createWrapperPanel(title, scroll);
+ }
+
+ private JPanel createWrapperPanel(String title, JComponent content) {
+ JPanel panel = new JPanel(new BorderLayout(0, 5));
+ panel.setOpaque(false);
+
+ JLabel label = new JLabel(title);
+ label.setFont(new Font("寰蒋闆呴粦", Font.PLAIN, 12));
+ label.setForeground(TEXT_SECONDARY);
+
+ JPanel contentBox = new JPanel(new BorderLayout());
+ contentBox.setBackground(BG_INPUT);
+ contentBox.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createLineBorder(new Color(230, 230, 230), 1),
+ BorderFactory.createEmptyBorder(5, 5, 5, 5)
+ ));
+ contentBox.add(content, BorderLayout.CENTER);
+
+ panel.add(label, BorderLayout.NORTH);
+ panel.add(contentBox, BorderLayout.CENTER);
+ return panel;
+ }
+
+ private JTextArea createDataTextArea(String text, int rows) {
+ JTextArea area = new JTextArea(text);
+ area.setRows(rows);
+ area.setEditable(false);
+ area.setLineWrap(true);
+ area.setWrapStyleWord(true);
+ area.setBackground(BG_INPUT);
+ area.setForeground(new Color(50, 50, 50));
+ // 浣跨敤绛夊瀛椾綋鏄剧ず鏁版嵁锛岀湅璧锋潵鏇翠笓涓�
+ area.setFont(new Font("Monospaced", Font.PLAIN, 12));
+ return area;
+ }
+
+ /**
+ * 鍒涘缓鐜颁唬椋庢牸鎸夐挳 (瀹炲績鎴栬疆寤�)
+ */
+ private JButton createStyledButton(String text, Color baseColor, boolean filled) {
+ JButton btn = new JButton(text) {
+ @Override
+ protected void paintComponent(Graphics g) {
+ Graphics2D g2 = (Graphics2D) g.create();
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+
+ boolean isPressed = getModel().isPressed();
+ boolean isRollover = getModel().isRollover();
+
+ if (filled) {
+ if (isPressed) g2.setColor(baseColor.darker());
+ else if (isRollover) g2.setColor(new Color(baseColor.getRed(), baseColor.getGreen(), baseColor.getBlue(), 230)); // 寰�忔槑
+ else g2.setColor(baseColor);
+ g2.fill(new RoundRectangle2D.Double(0, 0, getWidth(), getHeight(), 8, 8));
+ g2.setColor(Color.WHITE);
+ } else {
+ g2.setColor(BG_CARD); // 鑳屾櫙鐧�
+ g2.fill(new RoundRectangle2D.Double(0, 0, getWidth(), getHeight(), 8, 8));
+
+ if (isPressed) g2.setColor(baseColor.darker());
+ else if (isRollover) g2.setColor(baseColor);
+ else g2.setColor(new Color(200, 200, 200));
+
+ g2.setStroke(new BasicStroke(1.2f));
+ g2.draw(new RoundRectangle2D.Double(0, 0, getWidth()-1, getHeight()-1, 8, 8));
+
+ g2.setColor(isRollover ? baseColor : TEXT_SECONDARY);
+ }
+
+ FontMetrics fm = g2.getFontMetrics();
+ int x = (getWidth() - fm.stringWidth(getText())) / 2;
+ int y = (getHeight() - fm.getHeight()) / 2 + fm.getAscent();
+ g2.drawString(getText(), x, y);
+
+ g2.dispose();
+ }
+ };
+ btn.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 12));
+ btn.setFocusPainted(false);
+ btn.setContentAreaFilled(false);
+ btn.setBorderPainted(false);
+ btn.setCursor(new Cursor(Cursor.HAND_CURSOR));
+ btn.setMaximumSize(new Dimension(Integer.MAX_VALUE, 36));
+ return btn;
+ }
+
+ /**
+ * 鍒涘缓褰㈢姸鏍囩锛堟樉绀哄渾褰㈡垨澶氳竟褰㈠浘鏍囷級
+ */
+ private JLabel createShapeLabel(Obstacledge.ObstacleShape shape) {
+ JLabel shapeLabel = new JLabel();
+ shapeLabel.setPreferredSize(new Dimension(24, 24));
+
+ if (shape == null) {
+ return shapeLabel;
+ }
+
+ // 鏍规嵁褰㈢姸鍒涘缓涓嶅悓鐨勫浘鏍�
+ Icon shapeIcon;
+ if (shape == Obstacledge.ObstacleShape.CIRCLE) {
+ // 鍦嗗舰鍥炬爣
+ shapeIcon = new Icon() {
+ @Override
+ public void paintIcon(Component c, Graphics g, int x, int y) {
+ Graphics2D g2 = (Graphics2D) g.create();
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setColor(PRIMARY_COLOR);
+ g2.setStroke(new BasicStroke(2.0f));
+ g2.drawOval(x + 2, y + 2, getIconWidth() - 4, getIconHeight() - 4);
+ g2.dispose();
+ }
+
+ @Override
+ public int getIconWidth() {
+ return 20;
+ }
+
+ @Override
+ public int getIconHeight() {
+ return 20;
+ }
+ };
+ shapeLabel.setToolTipText("鍦嗗舰");
+ } else if (shape == Obstacledge.ObstacleShape.POLYGON) {
+ // 澶氳竟褰㈠浘鏍囷紙鍏竟褰級
+ shapeIcon = new Icon() {
+ @Override
+ public void paintIcon(Component c, Graphics g, int x, int y) {
+ Graphics2D g2 = (Graphics2D) g.create();
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setColor(PRIMARY_COLOR);
+ g2.setStroke(new BasicStroke(2.0f));
+
+ // 缁樺埗鍏竟褰�
+ int centerX = x + getIconWidth() / 2;
+ int centerY = y + getIconHeight() / 2;
+ int radius = 8;
+ int[] xPoints = new int[6];
+ int[] yPoints = new int[6];
+
+ for (int i = 0; i < 6; i++) {
+ double angle = Math.PI / 3.0 * i - Math.PI / 6.0; // 浠庨《閮ㄥ紑濮�
+ xPoints[i] = centerX + (int) (radius * Math.cos(angle));
+ yPoints[i] = centerY + (int) (radius * Math.sin(angle));
+ }
+
+ g2.drawPolygon(xPoints, yPoints, 6);
+ g2.dispose();
+ }
+
+ @Override
+ public int getIconWidth() {
+ return 20;
+ }
+
+ @Override
+ public int getIconHeight() {
+ return 20;
+ }
+ };
+ shapeLabel.setToolTipText("澶氳竟褰�");
+ } else {
+ return shapeLabel; // 鏈煡褰㈢姸锛岃繑鍥炵┖鏍囩
+ }
+
+ shapeLabel.setIcon(shapeIcon);
+ return shapeLabel;
+ }
+
+ /**
+ * 鍒涘缓绾浘鏍囨寜閽紙鐢ㄤ簬鍒犻櫎锛�
+ */
+ private JButton createIconButton(String iconText, Color hoverColor) {
+ JButton btn = new JButton(iconText);
+ btn.setFont(new Font("Segoe UI Emoji", Font.PLAIN, 16));
+ btn.setForeground(TEXT_SECONDARY);
+ btn.setBorder(null);
+ btn.setContentAreaFilled(false);
+ btn.setFocusPainted(false);
+ btn.setCursor(new Cursor(Cursor.HAND_CURSOR));
+ btn.setPreferredSize(new Dimension(30, 30));
+
+ btn.addMouseListener(new MouseAdapter() {
+ public void mouseEntered(MouseEvent e) { btn.setForeground(hoverColor); }
+ public void mouseExited(MouseEvent e) { btn.setForeground(TEXT_SECONDARY); }
+ });
+ return btn;
+ }
+
+ // =================================================================================
+ // 浠ヤ笅涓哄師鏈変笟鍔¢�昏緫浠g爜锛屼繚鎸佷笉鍙橈紝浠呰皟鏁撮儴鍒嗙┖鍊煎垽鏂互閫傞厤鏂癠I
+ // =================================================================================
+
+ private void previewObstacle(Obstacledge.Obstacle obstacle) {
+ if (obstacle == null) return;
+
+ String landNumber = dikuai.getLandNumber();
+ String landName = dikuai.getLandName();
+ String boundary = dikuai.getBoundaryCoordinates();
+ String obstacleCoords = extractObstacleCoordinates(obstacle);
+
+ if (obstacleCoords == null || obstacleCoords.trim().isEmpty()) {
+ JOptionPane.showMessageDialog(this, "璇ラ殰纰嶇墿娌℃湁鍧愭爣鏁版嵁", "鎻愮ず", JOptionPane.INFORMATION_MESSAGE);
+ return;
+ }
+
+ List<Obstacledge.Obstacle> allObstacles = loadObstacles();
+ String allObstaclesCoords = buildAllObstaclesCoordinates(allObstacles);
+
+ setVisible(false);
+
+ SwingUtilities.invokeLater(() -> {
+ Shouye shouye = Shouye.getInstance();
+ if (shouye != null) {
+ shouye.startMowingPathPreview(
+ landNumber,
+ landName,
+ boundary,
+ allObstaclesCoords,
+ null,
+ () -> SwingUtilities.invokeLater(() -> setVisible(true))
+ );
+ } else {
+ JOptionPane.showMessageDialog(null, "鏃犳硶鎵撳紑涓婚〉闈㈣繘琛岄瑙�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+ setVisible(true);
+ }
+ });
+ }
+
+ private String buildAllObstaclesCoordinates(List<Obstacledge.Obstacle> obstacles) {
+ if (obstacles == null || obstacles.isEmpty()) return null;
+ List<String> coordStrings = new ArrayList<>();
+ for (Obstacledge.Obstacle obstacle : obstacles) {
+ String coords = extractObstacleCoordinates(obstacle);
+ if (coords != null && !coords.trim().isEmpty()) {
+ coordStrings.add(coords.trim());
+ }
+ }
+ return coordStrings.isEmpty() ? null : String.join(" ", coordStrings);
+ }
+
+ private String extractObstacleCoordinates(Obstacledge.Obstacle obstacle) {
+ if (obstacle == null) return "";
+ String xy = obstacle.getXyCoordsString();
+ return isMeaningfulValue(xy) ? xy.trim() : "";
+ }
+
+ private String extractOriginalCoordinates(Obstacledge.Obstacle obstacle) {
+ if (obstacle == null) return "";
+ String original = obstacle.getOriginalCoordsString();
+ return isMeaningfulValue(original) ? original.trim() : "";
+ }
+
+ private void generateObstacleCoordinates(Obstacledge.Obstacle obstacle, JTextArea coordArea) {
+ if (obstacle == null || coordArea == null) return;
+
+ String originalCoords = extractOriginalCoordinates(obstacle);
+ if (!isMeaningfulValue(originalCoords)) {
+ JOptionPane.showMessageDialog(this, "鏃犲師濮嬪潗鏍囨暟鎹紝鏃犳硶鐢熸垚", "鎻愮ず", JOptionPane.INFORMATION_MESSAGE);
+ return;
+ }
+
+ String baseStation = dikuai.getBaseStationCoordinates();
+ if (!isMeaningfulValue(baseStation)) {
+ JOptionPane.showMessageDialog(this, "鍦板潡鏈缃熀绔欏潗鏍�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+ return;
+ }
+
+ try {
+ List<Obstacledge.DMCoordinate> originalCoordsList = obstacle.getOriginalCoordinates();
+ if (originalCoordsList == null || originalCoordsList.isEmpty()) {
+ JOptionPane.showMessageDialog(this, "鍘熷鍧愭爣鏁版嵁鏃犳晥", "鎻愮ず", JOptionPane.INFORMATION_MESSAGE);
+ return;
+ }
+
+ String[] baseParts = baseStation.split(",");
+ if (baseParts.length < 4) {
+ JOptionPane.showMessageDialog(this, "鍩虹珯鍧愭爣鏍煎紡涓嶆纭�", "閿欒", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+
+ double baseLat = parseDMToDecimal(baseParts[0].trim(), baseParts[1].trim());
+ double baseLon = parseDMToDecimal(baseParts[2].trim(), baseParts[3].trim());
+
+ List<Obstacledge.XYCoordinate> xyCoords = new ArrayList<>();
+ for (int i = 0; i < originalCoordsList.size(); i += 2) {
+ if (i + 1 >= originalCoordsList.size()) break;
+ double lat = originalCoordsList.get(i).toDecimalDegree();
+ double lon = originalCoordsList.get(i + 1).toDecimalDegree();
+
+ if (Double.isFinite(lat) && Double.isFinite(lon)) {
+ double[] localXY = convertLatLonToLocal(lat, lon, baseLat, baseLon);
+ xyCoords.add(new Obstacledge.XYCoordinate(localXY[0], localXY[1]));
+ }
+ }
+
+ if (xyCoords.isEmpty()) {
+ JOptionPane.showMessageDialog(this, "鍧愭爣杞崲澶辫触", "閿欒", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+
+ obstacle.setXyCoordinates(xyCoords);
+ saveObstacleUpdate(obstacle, coordArea);
+
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ JOptionPane.showMessageDialog(this, "閿欒: " + ex.getMessage(), "閿欒", JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+ private void saveObstacleUpdate(Obstacledge.Obstacle obstacle, JTextArea coordArea) {
+ String landNumber = dikuai.getLandNumber();
+ try {
+ File configFile = new File("Obstacledge.properties");
+ Obstacledge.ConfigManager manager = new Obstacledge.ConfigManager();
+ if (configFile.exists()) manager.loadFromFile(configFile.getAbsolutePath());
+
+ Obstacledge.Plot plot = manager.getPlotById(landNumber.trim());
+ if (plot != null) {
+ plot.removeObstacleByName(obstacle.getObstacleName());
+ plot.addObstacle(obstacle);
+ manager.saveToFile(configFile.getAbsolutePath());
+
+ Dikuai.updateField(landNumber.trim(), "updateTime", getCurrentTime());
+ Dikuai.saveToProperties();
+
+ coordArea.setText(obstacle.getXyCoordsString());
+ JOptionPane.showMessageDialog(this, "鍧愭爣宸茬敓鎴愬苟淇濆瓨", "鎴愬姛", JOptionPane.INFORMATION_MESSAGE);
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ private double parseDMToDecimal(String dmm, String direction) {
+ if (dmm == null || dmm.trim().isEmpty()) return Double.NaN;
+ try {
+ String trimmed = dmm.trim();
+ int dotIndex = trimmed.indexOf('.');
+ if (dotIndex < 2) return Double.NaN;
+ int degrees = Integer.parseInt(trimmed.substring(0, dotIndex - 2));
+ double minutes = Double.parseDouble(trimmed.substring(dotIndex - 2));
+ double decimal = degrees + minutes / 60.0;
+ if ("S".equalsIgnoreCase(direction) || "W".equalsIgnoreCase(direction)) decimal = -decimal;
+ return decimal;
+ } catch (NumberFormatException ex) {
+ return Double.NaN;
+ }
+ }
+
+ private double[] convertLatLonToLocal(double lat, double lon, double baseLat, double baseLon) {
+ double deltaLat = lat - baseLat;
+ double deltaLon = lon - baseLon;
+ double meanLatRad = Math.toRadians((baseLat + lat) / 2.0);
+ double METERS_PER_DEGREE_LAT = 111320.0;
+ double eastMeters = deltaLon * METERS_PER_DEGREE_LAT * Math.cos(meanLatRad);
+ double northMeters = deltaLat * METERS_PER_DEGREE_LAT;
+ return new double[]{eastMeters, northMeters};
+ }
+
+ private void deleteObstacle(Obstacledge.Obstacle obstacle) {
+ if (obstacle == null) return;
+ String name = obstacle.getObstacleName();
+
+ int choice = JOptionPane.showConfirmDialog(this,
+ "纭畾瑕佸垹闄ら殰纰嶇墿 \"" + name + "\" 鍚楋紵",
+ "鍒犻櫎纭", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
+
+ if (choice != JOptionPane.YES_OPTION) return;
+
+ String landNumber = dikuai.getLandNumber();
+ try {
+ File configFile = new File("Obstacledge.properties");
+ Obstacledge.ConfigManager manager = new Obstacledge.ConfigManager();
+ if (configFile.exists()) manager.loadFromFile(configFile.getAbsolutePath());
+
+ Obstacledge.Plot plot = manager.getPlotById(landNumber.trim());
+ if (plot != null && plot.removeObstacleByName(name)) {
+ manager.saveToFile(configFile.getAbsolutePath());
+ Dikuai.updateField(landNumber.trim(), "updateTime", getCurrentTime());
+ Dikuai.saveToProperties();
+ Dikuaiguanli.notifyExternalCreation(landNumber.trim());
+
+ JOptionPane.showMessageDialog(this, "鍒犻櫎鎴愬姛");
+ loadAndDisplayObstacles();
+ } else {
+ JOptionPane.showMessageDialog(this, "鍒犻櫎澶辫触锛氭湭鎵惧埌璁板綍", "閿欒", JOptionPane.ERROR_MESSAGE);
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ JOptionPane.showMessageDialog(this, "寮傚父: " + ex.getMessage(), "閿欒", JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+ private String getCurrentTime() {
+ return new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date());
+ }
+
+ private List<Obstacledge.Obstacle> loadObstacles() {
+ if (dikuai == null) return Collections.emptyList();
+ String landNumber = dikuai.getLandNumber();
+ if (landNumber == null || landNumber.trim().isEmpty()) return Collections.emptyList();
+
+ try {
+ File configFile = new File("Obstacledge.properties");
+ if (!configFile.exists()) return Collections.emptyList();
+
+ Obstacledge.ConfigManager manager = new Obstacledge.ConfigManager();
+ if (!manager.loadFromFile(configFile.getAbsolutePath())) return Collections.emptyList();
+
+ Obstacledge.Plot plot = manager.getPlotById(landNumber.trim());
+ return plot != null ? new ArrayList<>(plot.getObstacles()) : Collections.emptyList();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ return Collections.emptyList();
+ }
+ }
+
+ private String getDisplayValue(String value, String defaultValue) {
+ return (value != null && !value.equals("-1") && !value.trim().isEmpty()) ? value : defaultValue;
+ }
+
+ private boolean isMeaningfulValue(String value) {
+ return value != null && !value.trim().isEmpty() && !"-1".equals(value.trim());
+ }
+}
diff --git a/src/dikuai/addzhangaiwu.java b/src/dikuai/addzhangaiwu.java
index cd6d982..5f31288 100644
--- a/src/dikuai/addzhangaiwu.java
+++ b/src/dikuai/addzhangaiwu.java
@@ -564,6 +564,9 @@
prevButton = createSecondaryButton("涓婁竴姝�");
nextButton = createPrimaryButton("涓嬩竴姝�", 16);
+ // 璁剧疆涓嬩竴姝ユ寜閽搴︿负300鍍忕礌
+ nextButton.setPreferredSize(new Dimension(300, nextButton.getPreferredSize().height));
+ nextButton.setMaximumSize(new Dimension(300, nextButton.getPreferredSize().height));
saveButton = createPrimaryButton("淇濆瓨", 16);
saveButton.setVisible(false);
diff --git a/src/lujing/MowingPathGenerationPage.java b/src/lujing/MowingPathGenerationPage.java
index 8f96af2..5c080b0 100644
--- a/src/lujing/MowingPathGenerationPage.java
+++ b/src/lujing/MowingPathGenerationPage.java
@@ -1,6 +1,7 @@
package lujing;
import javax.swing.*;
+import javax.swing.SwingUtilities;
import java.awt.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
@@ -143,14 +144,17 @@
buttonPanel.setBackground(BACKGROUND_COLOR);
JButton generateBtn = createPrimaryFooterButton("鐢熸垚鍓茶崏璺緞");
+ JButton previewBtn = createPrimaryFooterButton("棰勮");
JButton saveBtn = createPrimaryFooterButton("淇濆瓨璺緞");
JButton cancelBtn = createPrimaryFooterButton("鍙栨秷");
generateBtn.addActionListener(e -> generatePath(modeValue));
+ previewBtn.addActionListener(e -> previewPath());
saveBtn.addActionListener(e -> savePath());
cancelBtn.addActionListener(e -> dispose());
buttonPanel.add(generateBtn);
+ buttonPanel.add(previewBtn);
buttonPanel.add(saveBtn);
buttonPanel.add(cancelBtn);
add(buttonPanel, BorderLayout.SOUTH);
@@ -187,6 +191,123 @@
}
/**
+ * 棰勮璺緞
+ */
+ private void previewPath() {
+ // 鍏堜繚瀛樺綋鍓嶈矾寰勫埌鍦板潡锛堜复鏃朵繚瀛橈紝鐢ㄤ簬棰勮锛�
+ String pathNormalized = normalizeCoordinateInput(pathArea.getText());
+ if (!"-1".equals(pathNormalized)) {
+ pathNormalized = pathNormalized
+ .replace("\r\n", ";")
+ .replace('\r', ';')
+ .replace('\n', ';')
+ .replaceAll(";+", ";")
+ .replaceAll("\\s*;\\s*", ";")
+ .trim();
+ if (pathNormalized.isEmpty()) {
+ pathNormalized = "-1";
+ }
+ }
+
+ if ("-1".equals(pathNormalized)) {
+ JOptionPane.showMessageDialog(this, "璇峰厛鐢熸垚鍓茶崏璺緞", "鎻愮ず", JOptionPane.INFORMATION_MESSAGE);
+ return;
+ }
+
+ // 涓存椂淇濆瓨璺緞鍒板湴鍧楀璞★紙涓嶆寔涔呭寲锛�
+ if (saveCallback != null) {
+ saveCallback.savePlannedPath(dikuai, pathNormalized);
+ }
+
+ // 淇濆瓨褰撳墠椤甸潰鐘舵�侊紝鐢ㄤ簬杩斿洖鏃舵仮澶�
+ String currentBaseStation = baseStationField.getText();
+ String currentBoundary = boundaryArea.getText();
+ String currentObstacle = obstacleArea.getText();
+ String currentWidth = widthField.getText();
+ String currentPath = pathArea.getText();
+
+ // 鑾峰彇鍦板潡淇℃伅
+ String landNumber = dikuai.getLandNumber();
+ String landName = dikuai.getLandName();
+
+ // 澶勭悊杈圭晫鍧愭爣锛岀‘淇濆彉閲忔槸 effectively final
+ String boundaryInput = normalizeCoordinateInput(boundaryArea.getText());
+ final String boundary;
+ if (!"-1".equals(boundaryInput)) {
+ String processed = boundaryInput.replace("\r\n", ";")
+ .replace('\r', ';')
+ .replace('\n', ';')
+ .replaceAll(";+", ";")
+ .replaceAll("\\s*;\\s*", ";")
+ .trim();
+ if (processed.isEmpty()) {
+ boundary = dikuai.getBoundaryCoordinates();
+ } else {
+ boundary = processed;
+ }
+ } else {
+ boundary = dikuai.getBoundaryCoordinates();
+ }
+
+ // 澶勭悊闅滅鐗╁潗鏍囷紝纭繚鍙橀噺鏄� effectively final
+ String obstaclesInput = normalizeCoordinateInput(obstacleArea.getText());
+ final String obstacles;
+ if (!"-1".equals(obstaclesInput)) {
+ String processed = obstaclesInput.replace("\r\n", " ")
+ .replace('\r', ' ')
+ .replace('\n', ' ')
+ .replaceAll("\\s{2,}", " ")
+ .trim();
+ if (processed.isEmpty()) {
+ obstacles = null;
+ } else {
+ obstacles = processed;
+ }
+ } else {
+ obstacles = null;
+ }
+
+ // 淇濆瓨鏈�缁堝�煎埌 final 鍙橀噺锛屼互渚垮湪 lambda 涓娇鐢�
+ final String finalPathNormalized = pathNormalized;
+ final String finalLandNumber = landNumber;
+ final String finalLandName = landName;
+
+ // 鍏抽棴璺緞瑙勫垝椤甸潰
+ setVisible(false);
+
+ // 鎵撳紑涓婚〉闈㈠苟鏄剧ず璺緞棰勮
+ SwingUtilities.invokeLater(() -> {
+ zhuye.Shouye shouye = zhuye.Shouye.getInstance();
+ if (shouye != null) {
+ // 鏄剧ず璺緞棰勮锛屽苟璁剧疆杩斿洖鍥炶皟
+ shouye.startMowingPathPreview(
+ finalLandNumber,
+ finalLandName,
+ boundary,
+ obstacles,
+ finalPathNormalized,
+ () -> {
+ // 杩斿洖鍥炶皟锛氶噸鏂版墦寮�璺緞瑙勫垝椤甸潰
+ SwingUtilities.invokeLater(() -> {
+ setVisible(true);
+ // 鎭㈠涔嬪墠鐨勭姸鎬�
+ baseStationField.setText(currentBaseStation);
+ boundaryArea.setText(currentBoundary);
+ obstacleArea.setText(currentObstacle);
+ widthField.setText(currentWidth);
+ pathArea.setText(currentPath);
+ });
+ }
+ );
+ } else {
+ // 濡傛灉涓婚〉闈笉瀛樺湪锛屾彁绀虹敤鎴峰苟閲嶆柊鏄剧ず璺緞瑙勫垝椤甸潰
+ JOptionPane.showMessageDialog(null, "鏃犳硶鎵撳紑涓婚〉闈㈣繘琛岄瑙�", "鎻愮ず", JOptionPane.WARNING_MESSAGE);
+ setVisible(true);
+ }
+ });
+ }
+
+ /**
* 淇濆瓨璺緞
*/
private void savePath() {
diff --git a/src/zhuye/MapRenderer.java b/src/zhuye/MapRenderer.java
index e36d3c3..3c79352 100644
--- a/src/zhuye/MapRenderer.java
+++ b/src/zhuye/MapRenderer.java
@@ -52,6 +52,7 @@
private static final Color GRASS_FILL_COLOR = new Color(144, 238, 144, 120);
private static final Color GRASS_BORDER_COLOR = new Color(60, 179, 113);
private static final Color BOUNDARY_POINT_COLOR = new Color(128, 0, 128);
+ private static final Color OBSTACLE_POINT_COLOR = new Color(255, 140, 0); // 姗欒壊锛岀敤浜庡尯鍒嗛殰纰嶇墿鐐�
private static final Color CIRCLE_SAMPLE_COLOR = new Color(220, 20, 60, 230);
private static final double CIRCLE_SAMPLE_SIZE = 0.54d;
private static final double BOUNDARY_POINT_MERGE_THRESHOLD = 0.05;
@@ -71,6 +72,7 @@
private String currentObstacleLandNumber;
private String boundaryName;
private boolean boundaryPointsVisible;
+ private boolean obstaclePointsVisible;
private double boundaryPointSizeScale = 1.0d;
private boolean previewSizingEnabled;
private String currentBoundaryLandNumber;
@@ -385,6 +387,22 @@
);
}
+ // 缁樺埗闅滅鐗╁潗鏍囩偣
+ if (obstaclePointsVisible && hasObstacles) {
+ List<Point2D.Double> obstaclePoints = Obstacledraw.getObstaclePoints(currentObstacles);
+ if (obstaclePoints != null && !obstaclePoints.isEmpty()) {
+ double markerScale = boundaryPointSizeScale * (previewSizingEnabled ? PREVIEW_BOUNDARY_MARKER_SCALE : 1.0d);
+ pointandnumber.drawBoundaryPoints(
+ g2d,
+ obstaclePoints,
+ scale,
+ BOUNDARY_POINT_MERGE_THRESHOLD,
+ OBSTACLE_POINT_COLOR,
+ markerScale
+ );
+ }
+ }
+
if (shouldRenderIdleTrail()) {
tuowei.draw(g2d, idleMowerTrail, scale);
}
@@ -1746,6 +1764,7 @@
obstacleBounds = null;
selectedObstacleName = null;
currentObstacleLandNumber = null;
+ obstaclePointsVisible = false;
}
private List<Obstacledge.Obstacle> parseObstacles(String obstaclesData, String landNumber) {
@@ -2033,6 +2052,11 @@
visualizationPanel.repaint();
}
+ public void setObstaclePointsVisible(boolean visible) {
+ this.obstaclePointsVisible = visible;
+ visualizationPanel.repaint();
+ }
+
public void setBoundaryPointSizeScale(double sizeScale) {
double normalized = (Double.isFinite(sizeScale) && sizeScale > 0.0d) ? sizeScale : 1.0d;
if (Math.abs(boundaryPointSizeScale - normalized) < 1e-6) {
diff --git a/src/zhuye/Shouye.java b/src/zhuye/Shouye.java
index 1aa16f7..e76f5c7 100644
--- a/src/zhuye/Shouye.java
+++ b/src/zhuye/Shouye.java
@@ -320,7 +320,7 @@
}
// 鍏抽棴妯″紡鏃朵笉闇�瑕佸仛浠讳綍鎿嶄綔锛岀敤鎴峰凡缁忓彲浠ヨ嚜鐢辩Щ鍔ㄥ湴鍥�
- // 鏇存柊宸ュ叿鎻愮ず
+ // 鏇存柊鍥炬爣鏄剧ず锛堥噸缁樹互鍒囨崲鍥炬爣锛�
if (visualizationPanel != null) {
visualizationPanel.repaint();
}
@@ -564,14 +564,16 @@
// 鍙鍖栧尯鍩� - 浣跨敤MapRenderer杩涜缁樺埗
visualizationPanel = new JPanel() {
- private ImageIcon gecaojiIcon = null;
+ private ImageIcon gecaojiIcon1 = null; // 榛樿鍥炬爣
+ private ImageIcon gecaojiIcon2 = 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);
+ gecaojiIcon1 = loadScaledIcon("image/gecaojishijiao1.png", GECAOJI_ICON_SIZE, GECAOJI_ICON_SIZE);
+ gecaojiIcon2 = loadScaledIcon("image/gecaojishijiao2.png", GECAOJI_ICON_SIZE, GECAOJI_ICON_SIZE);
}
/**
@@ -607,11 +609,15 @@
if (isMowerOutsideBoundary && warningIconVisible) {
// 缁樺埗绾㈣壊涓夎褰㈣鍛婂浘鏍囷紙甯﹀徆鍙凤級
drawWarningIcon(g, GECAOJI_ICON_X, GECAOJI_ICON_Y, GECAOJI_ICON_SIZE);
- } else if (gecaojiIcon != null) {
- // 缁樺埗姝e父鐨勫壊鑽夋満鍥炬爣
- // 姘村钩鏂瑰悜涓庨�熷害鎸囩ず鍣ㄥ榻愶紙x=37锛�
- // 鍨傜洿鏂瑰悜涓庡崼鏄熺姸鎬佸浘鏍囧榻愶紙y=10锛岄�熷害鎸囩ず鍣ㄩ潰鏉块《閮ㄨ竟璺�10鍍忕礌锛屼娇鍥炬爣涓績瀵归綈锛�
- g.drawImage(gecaojiIcon.getImage(), GECAOJI_ICON_X, GECAOJI_ICON_Y, null);
+ } else {
+ // 鏍规嵁妯″紡閫夋嫨涓嶅悓鐨勫浘鏍�
+ ImageIcon iconToDraw = centerOnMowerMode ? gecaojiIcon2 : gecaojiIcon1;
+ if (iconToDraw != null) {
+ // 缁樺埗鍓茶崏鏈哄浘鏍�
+ // 姘村钩鏂瑰悜涓庨�熷害鎸囩ず鍣ㄥ榻愶紙x=37锛�
+ // 鍨傜洿鏂瑰悜涓庡崼鏄熺姸鎬佸浘鏍囧榻愶紙y=10锛岄�熷害鎸囩ず鍣ㄩ潰鏉块《閮ㄨ竟璺�10鍍忕礌锛屼娇鍥炬爣涓績瀵归綈锛�
+ g.drawImage(iconToDraw.getImage(), GECAOJI_ICON_X, GECAOJI_ICON_Y, null);
+ }
}
}
diff --git a/src/zhuye/buttonset.java b/src/zhuye/buttonset.java
index 50bad9c..2d6df18 100644
--- a/src/zhuye/buttonset.java
+++ b/src/zhuye/buttonset.java
@@ -1,70 +1,118 @@
package zhuye;
+import java.awt.BasicStroke;
import java.awt.Color;
+import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
-
-import javax.swing.BorderFactory;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.RoundRectangle2D;
import javax.swing.JButton;
+import javax.swing.border.EmptyBorder;
/**
- * 鎻愪緵缁熶竴鎸夐挳鏍峰紡鐨勫伐鍘傛柟娉曘��
+ * 鎻愪緵缁熶竴鎸夐挳鏍峰紡鐨勫伐鍘傛柟娉曪紙缇庡寲鐗堬級銆�
+ * 椋庢牸涓� ObstacleManagementPage 淇濇寔涓�鑷达細鍦嗚銆佹墎骞冲寲銆佹姉閿娇銆�
*/
public final class buttonset {
+
+ // 榛樿鎸夐挳灏哄
private static final Dimension DEFAULT_SIZE = new Dimension(90, 36);
+ // 鍦嗚鍗婂緞
+ private static final int CORNER_RADIUS = 8;
private buttonset() {
// 宸ュ叿绫讳笉闇�瑕佸疄渚嬪寲
}
/**
- * 鍒涘缓甯︽湁缁熶竴鏍峰紡鐨勬寜閽紝渚涘涓晫闈㈠鐢ㄣ��
+ * 鍒涘缓甯︽湁鐜颁唬鍖栫粺涓�鏍峰紡鐨勬寜閽紙鍦嗚銆佹墎骞抽鏍硷級銆�
*
* @param text 鎸夐挳鏄剧ず鏂囨湰
- * @param backgroundColor 鎸夐挳鑳屾櫙鑹�
+ * @param backgroundColor 鎸夐挳涓昏壊璋冿紙濡傛灉涓簄ull锛岄粯璁や娇鐢ㄧ伆钃濊壊锛�
* @return 宸插簲鐢ㄦ牱寮忕殑 JButton
*/
public static JButton createStyledButton(String text, Color backgroundColor) {
+ // 纭畾鍩虹棰滆壊锛屽鏋滄湭鎸囧畾鍒欎娇鐢ㄩ粯璁ょ殑閽㈣摑鑹�
final Color baseColor = backgroundColor != null ? backgroundColor : new Color(70, 130, 180);
- JButton button = new JButton(text);
+ // 鍒涘缓鑷畾涔夌粯鍒剁殑鎸夐挳
+ JButton button = new JButton(text) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ Graphics2D g2 = (Graphics2D) g.create();
+ // 寮�鍚姉閿娇锛屼娇鍦嗚鍜屾枃瀛楁洿骞虫粦
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
+ // 鑾峰彇鎸夐挳鐘舵��
+ boolean isPressed = getModel().isPressed();
+ boolean isRollover = getModel().isRollover();
+ int w = getWidth();
+ int h = getHeight();
+
+ // 璁$畻褰撳墠鑳屾櫙鑹�
+ if (isPressed) {
+ g2.setColor(baseColor.darker()); // 鎸変笅鍙樻繁
+ } else if (isRollover) {
+ // 鎮仠鏃剁◢寰�忔槑鎴栧彉浜紝澧炲姞浜や簰鎰�
+ g2.setColor(new Color(baseColor.getRed(), baseColor.getGreen(), baseColor.getBlue(), 220));
+ } else {
+ g2.setColor(baseColor); // 姝e父棰滆壊
+ }
+
+ // 缁樺埗鍦嗚鐭╁舰鑳屾櫙
+ g2.fill(new RoundRectangle2D.Double(0, 0, w, h, CORNER_RADIUS, CORNER_RADIUS));
+
+ // 濡傛灉闇�瑕佸湪鎸変笅鏃舵湁杞诲井鐨勮竟妗嗘晥鏋滐紙鍙�夛紝澧炲姞绔嬩綋鎰燂級
+ if (isPressed) {
+ g2.setColor(new Color(0, 0, 0, 30));
+ g2.draw(new RoundRectangle2D.Double(0.5, 0.5, w - 1, h - 1, CORNER_RADIUS, CORNER_RADIUS));
+ }
+
+ // 缁樺埗鏂囧瓧
+ g2.setColor(Color.WHITE);
+ g2.setFont(getFont());
+ FontMetrics fm = g2.getFontMetrics();
+
+ // 绮剧‘璁$畻鏂囧瓧灞呬腑浣嶇疆
+ int textX = (w - fm.stringWidth(getText())) / 2;
+ // 娉ㄦ剰锛歽鍧愭爣鏄熀绾夸綅缃紝闇�瑕佸姞涓� Ascent 骞跺噺鍘婚珮搴︾殑涓�鍗�
+ int textY = (h - fm.getHeight()) / 2 + fm.getAscent();
+
+ g2.drawString(getText(), textX, textY);
+
+ g2.dispose();
+ }
+ };
+
+ // 鍩虹灞炴�ц缃�
button.setFont(new Font("寰蒋闆呴粦", Font.BOLD, 14));
- button.setBackground(baseColor);
button.setForeground(Color.WHITE);
- button.setFocusPainted(false);
- button.setBorder(BorderFactory.createEmptyBorder(8, 18, 8, 18));
+ button.setFocusPainted(false); // 鍘婚櫎鐒︾偣铏氱嚎妗�
+ button.setContentAreaFilled(false); // 鍘婚櫎榛樿鑳屾櫙缁樺埗锛堢敱paintComponent鎺ョ锛�
+ button.setBorderPainted(false); // 鍘婚櫎榛樿杈规
+ button.setCursor(new Cursor(Cursor.HAND_CURSOR)); // 榧犳爣鍙樻垚鎵嬪瀷
+
+ // 璁剧疆鍐呰竟璺濓紙铏界劧涓昏鐢眕aintComponent鎺у埗锛屼絾瀵瑰竷灞�璁$畻鏈夊府鍔╋級
+ button.setBorder(new EmptyBorder(8, 18, 8, 18));
- Dimension preferred = button.getPreferredSize();
- int width = Math.max(preferred.width, DEFAULT_SIZE.width);
- int height = Math.max(preferred.height, DEFAULT_SIZE.height);
- Dimension adjustedSize = new Dimension(width, height);
-
- button.setPreferredSize(adjustedSize);
- button.setMinimumSize(new Dimension(DEFAULT_SIZE.width, DEFAULT_SIZE.height));
- button.setMaximumSize(adjustedSize);
-
- button.addMouseListener(new java.awt.event.MouseAdapter() {
- @Override
- public void mouseEntered(java.awt.event.MouseEvent event) {
- button.setBackground(brightenColor(baseColor));
- }
-
- @Override
- public void mouseExited(java.awt.event.MouseEvent event) {
- button.setBackground(baseColor);
- }
- });
+ // 灏哄璁$畻閫昏緫
+ Dimension preferred = button.getPreferredSize();
+ // 纭繚瀹藉害涓嶅皬浜庨粯璁ゅ�硷紝涓旀牴鎹枃瀛楅暱搴﹁嚜閫傚簲
+ int width = Math.max(preferred.width + 20, DEFAULT_SIZE.width);
+ int height = Math.max(preferred.height, DEFAULT_SIZE.height);
+
+ Dimension finalSize = new Dimension(width, height);
+ button.setPreferredSize(finalSize);
+ button.setMinimumSize(DEFAULT_SIZE);
+ button.setMaximumSize(finalSize); // 闃叉鍦ㄦ煇浜涘竷灞�涓杩囧害鎷変几
return button;
}
-
- private static Color brightenColor(Color color) {
- if (color == null) {
- return new Color(200, 200, 200);
- }
- int r = Math.min(255, color.getRed() + 30);
- int g = Math.min(255, color.getGreen() + 30);
- int b = Math.min(255, color.getBlue() + 30);
- return new Color(r, g, b);
- }
-}
+}
\ No newline at end of file
--
Gitblit v1.10.0