package gecaoji;
|
|
import javax.swing.*;
|
|
import publicway.buttonset;
|
|
import java.awt.*;
|
import java.awt.event.WindowAdapter;
|
import java.awt.event.WindowEvent;
|
import java.text.SimpleDateFormat;
|
import java.util.Date;
|
|
// Manages the mower info dialog to keep MapRenderer focused on rendering.
|
public class GecaojiMeg {
|
private static final SimpleDateFormat TIMESTAMP_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
private final JPanel anchorPanel;
|
private final Gecaoji mower;
|
|
private JDialog infoDialog;
|
private Timer refreshTimer;
|
|
private JLabel mowerNumberLabel;
|
private JLabel realtimeXLabel;
|
private JLabel realtimeYLabel;
|
private JLabel positioningStatusLabel;
|
private JLabel satelliteCountLabel;
|
private JLabel realtimeSpeedLabel;
|
private JLabel headingLabel;
|
private JLabel updateTimeLabel;
|
|
public GecaojiMeg(JPanel anchorPanel, Gecaoji mower) {
|
this.anchorPanel = anchorPanel;
|
this.mower = mower;
|
}
|
|
public void showMowerInfo() {
|
Device device = Device.getGecaoji();
|
if (device == null) {
|
JOptionPane.showMessageDialog(
|
anchorPanel,
|
"无设备数据",
|
"割草机信息",
|
JOptionPane.INFORMATION_MESSAGE
|
);
|
return;
|
}
|
|
ensureDialog();
|
updateLabels();
|
positionDialog();
|
if (!infoDialog.isVisible()) {
|
infoDialog.setVisible(true);
|
} else {
|
infoDialog.toFront();
|
}
|
startTimer();
|
}
|
|
public void dispose() {
|
stopTimer();
|
if (infoDialog != null) {
|
infoDialog.dispose();
|
infoDialog = null;
|
}
|
resetLabels();
|
}
|
|
private void ensureDialog() {
|
if (infoDialog != null) {
|
return;
|
}
|
|
Window owner = anchorPanel == null ? null : SwingUtilities.getWindowAncestor(anchorPanel);
|
JDialog dialog = new JDialog(owner, "割草机信息", Dialog.ModalityType.MODELESS);
|
dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
|
// 设置对话框字体和颜色
|
dialog.getContentPane().setBackground(new Color(245, 245, 245));
|
|
JPanel content = new JPanel(new BorderLayout(0, 8)); // 减小垂直间距为8
|
content.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20)); // 减小内边距
|
content.setBackground(new Color(245, 245, 245));
|
|
// 创建信息面板 - 使用GridBagLayout以获得更精细的控制
|
JPanel grid = new JPanel(new GridBagLayout());
|
grid.setBackground(new Color(255, 255, 255));
|
grid.setBorder(BorderFactory.createCompoundBorder(
|
BorderFactory.createLineBorder(new Color(220, 220, 220), 1),
|
BorderFactory.createEmptyBorder(10, 12, 10, 12) // 减小内边距
|
));
|
|
GridBagConstraints gbc = new GridBagConstraints();
|
gbc.insets = new Insets(5, 8, 5, 8); // 单元格间距缩小为原来的一半
|
gbc.fill = GridBagConstraints.HORIZONTAL;
|
gbc.anchor = GridBagConstraints.WEST;
|
|
// 设置标题标签样式
|
Font titleFont = new Font("Microsoft YaHei", Font.BOLD, 13);
|
Font valueFont = new Font("Microsoft YaHei", Font.PLAIN, 13);
|
|
// 第一行
|
gbc.gridx = 0; gbc.gridy = 0;
|
gbc.weightx = 0.3;
|
JLabel label1 = new JLabel("设备编号:");
|
label1.setFont(titleFont);
|
label1.setForeground(new Color(102, 102, 102));
|
grid.add(label1, gbc);
|
|
gbc.gridx = 1; gbc.gridy = 0;
|
gbc.weightx = 0.7;
|
mowerNumberLabel = createValueLabel();
|
mowerNumberLabel.setFont(valueFont);
|
grid.add(mowerNumberLabel, gbc);
|
|
// 第二行
|
gbc.gridx = 0; gbc.gridy = 1;
|
gbc.weightx = 0.3;
|
JLabel label2 = new JLabel("实时X坐标:");
|
label2.setFont(titleFont);
|
label2.setForeground(new Color(102, 102, 102));
|
grid.add(label2, gbc);
|
|
gbc.gridx = 1; gbc.gridy = 1;
|
gbc.weightx = 0.7;
|
realtimeXLabel = createValueLabel();
|
realtimeXLabel.setFont(valueFont);
|
grid.add(realtimeXLabel, gbc);
|
|
// 第三行
|
gbc.gridx = 0; gbc.gridy = 2;
|
gbc.weightx = 0.3;
|
JLabel label3 = new JLabel("实时Y坐标:");
|
label3.setFont(titleFont);
|
label3.setForeground(new Color(102, 102, 102));
|
grid.add(label3, gbc);
|
|
gbc.gridx = 1; gbc.gridy = 2;
|
gbc.weightx = 0.7;
|
realtimeYLabel = createValueLabel();
|
realtimeYLabel.setFont(valueFont);
|
grid.add(realtimeYLabel, gbc);
|
|
// 第四行
|
gbc.gridx = 0; gbc.gridy = 3;
|
gbc.weightx = 0.3;
|
JLabel label4 = new JLabel("定位质量:");
|
label4.setFont(titleFont);
|
label4.setForeground(new Color(102, 102, 102));
|
grid.add(label4, gbc);
|
|
gbc.gridx = 1; gbc.gridy = 3;
|
gbc.weightx = 0.7;
|
positioningStatusLabel = createValueLabel();
|
positioningStatusLabel.setFont(valueFont);
|
grid.add(positioningStatusLabel, gbc);
|
|
// 第五行
|
gbc.gridx = 0; gbc.gridy = 4;
|
gbc.weightx = 0.3;
|
JLabel label5 = new JLabel("卫星颗数:");
|
label5.setFont(titleFont);
|
label5.setForeground(new Color(102, 102, 102));
|
grid.add(label5, gbc);
|
|
gbc.gridx = 1; gbc.gridy = 4;
|
gbc.weightx = 0.7;
|
satelliteCountLabel = createValueLabel();
|
satelliteCountLabel.setFont(valueFont);
|
grid.add(satelliteCountLabel, gbc);
|
|
// 第六行
|
gbc.gridx = 0; gbc.gridy = 5;
|
gbc.weightx = 0.3;
|
JLabel label6 = new JLabel("行驶速度:");
|
label6.setFont(titleFont);
|
label6.setForeground(new Color(102, 102, 102));
|
grid.add(label6, gbc);
|
|
gbc.gridx = 1; gbc.gridy = 5;
|
gbc.weightx = 0.7;
|
realtimeSpeedLabel = createValueLabel();
|
realtimeSpeedLabel.setFont(valueFont);
|
grid.add(realtimeSpeedLabel, gbc);
|
|
// 第七行
|
gbc.gridx = 0; gbc.gridy = 6;
|
gbc.weightx = 0.3;
|
JLabel label7 = new JLabel("运动航向:");
|
label7.setFont(titleFont);
|
label7.setForeground(new Color(102, 102, 102));
|
grid.add(label7, gbc);
|
|
gbc.gridx = 1; gbc.gridy = 6;
|
gbc.weightx = 0.7;
|
headingLabel = createValueLabel();
|
headingLabel.setFont(valueFont);
|
grid.add(headingLabel, gbc);
|
|
// 第八行
|
gbc.gridx = 0; gbc.gridy = 7;
|
gbc.weightx = 0.3;
|
JLabel label8 = new JLabel("更新时间:");
|
label8.setFont(titleFont);
|
label8.setForeground(new Color(102, 102, 102));
|
grid.add(label8, gbc);
|
|
gbc.gridx = 1; gbc.gridy = 7;
|
gbc.weightx = 0.7;
|
updateTimeLabel = createValueLabel();
|
updateTimeLabel.setFont(valueFont);
|
grid.add(updateTimeLabel, gbc);
|
|
content.add(grid, BorderLayout.CENTER);
|
|
// 按钮面板美化
|
JButton closeButton = buttonset.createStyledButton("关闭", new Color(0, 102, 204));
|
closeButton.setFont(new Font("Microsoft YaHei", Font.BOLD, 13));
|
closeButton.setBorder(BorderFactory.createCompoundBorder(
|
BorderFactory.createLineBorder(new Color(0, 80, 180), 1),
|
BorderFactory.createEmptyBorder(5, 18, 5, 18) // 减小按钮内边距
|
));
|
closeButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
|
// 鼠标悬停效果
|
closeButton.addMouseListener(new java.awt.event.MouseAdapter() {
|
public void mouseEntered(java.awt.event.MouseEvent evt) {
|
closeButton.setBackground(new Color(0, 122, 255));
|
}
|
public void mouseExited(java.awt.event.MouseEvent evt) {
|
closeButton.setBackground(new Color(0, 102, 204));
|
}
|
});
|
|
closeButton.addActionListener(e -> dialog.dispose());
|
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
|
buttonPanel.setBackground(new Color(245, 245, 245));
|
buttonPanel.add(closeButton);
|
content.add(buttonPanel, BorderLayout.SOUTH);
|
|
dialog.setContentPane(content);
|
dialog.pack();
|
dialog.setResizable(false);
|
dialog.addWindowListener(new WindowAdapter() {
|
@Override
|
public void windowClosed(WindowEvent e) {
|
stopTimer();
|
resetLabels();
|
infoDialog = null;
|
}
|
});
|
|
infoDialog = dialog;
|
}
|
|
private void positionDialog() {
|
if (infoDialog == null || anchorPanel == null) {
|
return;
|
}
|
int panelWidth = anchorPanel.getWidth();
|
int panelHeight = anchorPanel.getHeight();
|
int dialogHeight = infoDialog.getHeight();
|
if (dialogHeight <= 0) {
|
dialogHeight = infoDialog.getPreferredSize().height;
|
}
|
if (panelWidth > 0) {
|
infoDialog.setSize(panelWidth, dialogHeight);
|
}
|
|
try {
|
Point panelOnScreen = anchorPanel.getLocationOnScreen();
|
int dialogWidth = infoDialog.getWidth();
|
int targetX = panelOnScreen.x + (panelWidth - dialogWidth) / 2;
|
int targetY = panelOnScreen.y + panelHeight / 3 - dialogHeight / 2;
|
infoDialog.setLocation(targetX, targetY);
|
} catch (IllegalComponentStateException ignored) {
|
// panel not yet visible, skip positioning for now
|
}
|
}
|
|
private JLabel createValueLabel() {
|
JLabel label = new JLabel("--");
|
label.setHorizontalAlignment(SwingConstants.LEFT);
|
label.setForeground(new Color(51, 51, 51));
|
return label;
|
}
|
|
private void startTimer() {
|
if (refreshTimer == null) {
|
refreshTimer = new Timer(1000, e -> updateLabels());
|
refreshTimer.setRepeats(true);
|
}
|
if (!refreshTimer.isRunning()) {
|
refreshTimer.start();
|
}
|
}
|
|
private void stopTimer() {
|
if (refreshTimer != null) {
|
refreshTimer.stop();
|
refreshTimer = null;
|
}
|
}
|
|
private void resetLabels() {
|
mowerNumberLabel = null;
|
realtimeXLabel = null;
|
realtimeYLabel = null;
|
positioningStatusLabel = null;
|
satelliteCountLabel = null;
|
realtimeSpeedLabel = null;
|
headingLabel = null;
|
updateTimeLabel = null;
|
}
|
|
private void updateLabels() {
|
if (mowerNumberLabel == null) {
|
return;
|
}
|
|
Device device = Device.getGecaoji();
|
if (device == null) {
|
setLabels("--");
|
return;
|
}
|
|
mower.refreshFromDevice();
|
|
mowerNumberLabel.setText(formatDeviceValue(device.getMowerNumber()));
|
realtimeXLabel.setText(formatDeviceValue(device.getRealtimeX()));
|
realtimeYLabel.setText(formatDeviceValue(device.getRealtimeY()));
|
positioningStatusLabel.setText(formatFixQualityValue(device.getPositioningStatus()));
|
satelliteCountLabel.setText(formatDeviceValue(device.getSatelliteCount()));
|
realtimeSpeedLabel.setText(formatDeviceValue(device.getRealtimeSpeed()));
|
headingLabel.setText(formatDeviceValue(device.getHeading()));
|
updateTimeLabel.setText(formatTimestamp(device.getGupdateTime()));
|
}
|
|
private void setLabels(String value) {
|
if (mowerNumberLabel != null) mowerNumberLabel.setText(value);
|
if (realtimeXLabel != null) realtimeXLabel.setText(value);
|
if (realtimeYLabel != null) realtimeYLabel.setText(value);
|
if (positioningStatusLabel != null) positioningStatusLabel.setText(value);
|
if (satelliteCountLabel != null) satelliteCountLabel.setText(value);
|
if (realtimeSpeedLabel != null) realtimeSpeedLabel.setText(value);
|
if (headingLabel != null) headingLabel.setText(value);
|
if (updateTimeLabel != null) updateTimeLabel.setText(value);
|
}
|
|
private String sanitizeDeviceValue(String value) {
|
if (value == null) {
|
return null;
|
}
|
String trimmed = value.trim();
|
if (trimmed.isEmpty() || "-1".equals(trimmed)) {
|
return null;
|
}
|
return trimmed;
|
}
|
|
private String formatDeviceValue(String value) {
|
String sanitized = sanitizeDeviceValue(value);
|
return sanitized == null ? "--" : sanitized;
|
}
|
|
private String formatFixQualityValue(String value) {
|
String sanitized = sanitizeDeviceValue(value);
|
if (sanitized == null) {
|
return "--";
|
}
|
switch (sanitized) {
|
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 "人工输入固定值";
|
case "8":
|
return "模拟模式";
|
case "9":
|
return "WAAS差分";
|
default:
|
return sanitized;
|
}
|
}
|
|
private String formatTimestamp(String value) {
|
String sanitized = sanitizeDeviceValue(value);
|
if (sanitized == null) {
|
return "--";
|
}
|
try {
|
long millis = Long.parseLong(sanitized);
|
return TIMESTAMP_FORMAT.format(new Date(millis));
|
} catch (NumberFormatException ex) {
|
return sanitized;
|
}
|
}
|
}
|