| bin/chuankou/Sendmsg.class | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| bin/chuankou/SerialPortService.class | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| bin/chushihua/lunxun$PollingTask.class | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| bin/chushihua/lunxun.class | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| bin/home/Homein.class | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| bin/xitongshezhi/canshushezhi$1.class | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| bin/xitongshezhi/canshushezhi$2.class | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| bin/xitongshezhi/canshushezhi.class | 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/chuankou/Sendmsg.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/chuankou/SerialPortService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/chushihua/lunxun.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/chushihua/lunxunzaixian.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/home/Homein.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/xitongshezhi/canshushezhi.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
bin/chuankou/Sendmsg.classBinary files differ
bin/chuankou/SerialPortService.classBinary files differ
bin/chushihua/lunxun$PollingTask.classBinary files differ
bin/chushihua/lunxun.classBinary files differ
bin/home/Homein.classBinary files differ
bin/xitongshezhi/canshushezhi$1.classBinary files differ
bin/xitongshezhi/canshushezhi$2.classBinary files differ
bin/xitongshezhi/canshushezhi.classBinary files differ
src/chuankou/Sendmsg.java
@@ -11,8 +11,8 @@ private static volatile SerialPortService serialService = null; private static volatile boolean isPortOpen = false; // 调试模式开关 private static final boolean DEBUG_MODE = false; // 改为非final,支持动态控制 private static boolean DEBUG_MODE = false; // 日期格式化 private static final SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss.SSS"); @@ -35,48 +35,65 @@ } /** * 发送消息到串口 * @param message 要发送的HEX格式消息 * @return 发送成功返回true,失败返回false * 发送消息到串口(带重试机制) */ public static boolean sendMessage(String message) { if (!isPortOpen || serialService == null) { if (DEBUG_MODE) { System.err.println("[" + getCurrentTime() + "] 串口未打开,无法发送数据"); } System.err.println("[" + getCurrentTime() + "] 串口未打开,无法发送数据"); return false; } if (message == null || message.trim().isEmpty()) { if (DEBUG_MODE) { System.err.println("[" + getCurrentTime() + "] 发送数据为空"); } System.err.println("[" + getCurrentTime() + "] 发送数据为空"); return false; } String text = message.trim(); int retryCount = 0; final int MAX_RETRY = 2; try { // HEX格式发送 byte[] data = hexStringToByteArray(text); if (data != null && serialService.send(data)) { // 高频调用时避免频繁的日志输出,只在调试时记录 if (DEBUG_MODE) { System.out.println("[" + getCurrentTime() + "] 发送: " + text.toUpperCase()); while (retryCount <= MAX_RETRY) { try { byte[] data = hexStringToByteArray(text); if (data == null) { System.err.println("[" + getCurrentTime() + "] HEX转换失败,数据: " + text); return false; } return true; } else { if (DEBUG_MODE) { System.err.println("[" + getCurrentTime() + "] 数据发送失败"); boolean sendResult = serialService.send(data); if (sendResult) { if (DEBUG_MODE) { System.out.println("[" + getCurrentTime() + "] 发送成功: " + text.toUpperCase()); } return true; } else { retryCount++; if (retryCount <= MAX_RETRY) { System.err.println("[" + getCurrentTime() + "] 发送失败,正在重试 (" + retryCount + "/" + MAX_RETRY + ")"); try { Thread.sleep(50); // 重试前等待 } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } else { System.err.println("[" + getCurrentTime() + "] 串口发送失败,指令: " + text.toUpperCase()); System.err.println("[" + getCurrentTime() + "] 串口状态 - 打开: " + isPortOpen + ", 服务: " + (serialService != null)); if (serialService != null) { System.err.println("[" + getCurrentTime() + "] 串口服务状态 - 是否打开: " + serialService.isOpen()); } return false; } } } catch (Exception e) { System.err.println("[" + getCurrentTime() + "] 发送异常,指令: " + text.toUpperCase()); e.printStackTrace(); return false; } } catch (Exception e) { if (DEBUG_MODE) { System.err.println("[" + getCurrentTime() + "] 数据格式错误: " + e.getMessage()); } return false; } return false; } /** @@ -84,7 +101,11 @@ * @return 串口打开状态 */ public static boolean isPortOpen() { return isPortOpen && serialService != null; boolean open = isPortOpen && serialService != null; if (!open && DEBUG_MODE) { System.err.println("[" + getCurrentTime() + "] 串口状态检查: 未打开"); } return open; } /** @@ -100,7 +121,7 @@ s = s.replaceAll("\\s+", ""); // 移除空格 int len = s.length(); if (len % 2 != 0) { throw new IllegalArgumentException("HEX字符串长度必须为偶数"); throw new IllegalArgumentException("HEX字符串长度必须为偶数,当前长度: " + len + ", 数据: " + s); } byte[] data = new byte[len / 2]; @@ -109,7 +130,7 @@ int low = Character.digit(s.charAt(i + 1), 16); if (high == -1 || low == -1) { throw new IllegalArgumentException("无效的HEX字符: " + s.charAt(i) + s.charAt(i + 1)); throw new IllegalArgumentException("无效的HEX字符: '" + s.charAt(i) + s.charAt(i + 1) + "' 在位置 " + i + "-" + (i+1) + ", 完整数据: " + s); } data[i / 2] = (byte) ((high << 4) + low); @@ -144,12 +165,25 @@ /** * 启用调试模式 * 注意:这会修改静态final变量,实际项目中不建议这样做 * 这里只是演示,实际应该通过配置文件控制 */ public static void enableDebugMode() { // 在实际项目中,应该使用可配置的方式而不是修改final变量 // 这里只是示意,实际使用时需要重新设计 System.out.println("调试模式已启用"); DEBUG_MODE = true; System.out.println("[" + getCurrentTime() + "] Sendmsg调试模式已启用"); } /** * 禁用调试模式 */ public static void disableDebugMode() { DEBUG_MODE = false; System.out.println("[" + getCurrentTime() + "] Sendmsg调试模式已禁用"); } /** * 设置调试模式 */ public static void setDebugMode(boolean debug) { DEBUG_MODE = debug; System.out.println("[" + getCurrentTime() + "] Sendmsg调试模式: " + (debug ? "启用" : "禁用")); } } src/chuankou/SerialPortService.java
@@ -10,234 +10,249 @@ public class SerialPortService { private SerialPort port; private volatile boolean capturing = false; private volatile boolean paused = true; private Thread readerThread; private Consumer<byte[]> responseConsumer; // 优化:重用缓冲区,减少内存分配 private byte[] readBuffer = new byte[200]; private ByteArrayOutputStream buffer = new ByteArrayOutputStream(1024); private Consumer<byte[]> dataReceivedCallback; // 新增:协议解析器引用 private SerialProtocolParser protocolParser = new SerialProtocolParser(); // 新增:数据条数计数器 public static int receivedDataCount = 0; private SerialPort port; private volatile boolean capturing = false; private volatile boolean paused = true; private Thread readerThread; private Consumer<byte[]> responseConsumer; // 其他现有方法保持不变... /** * 获取串口接收的数据条数 * 当条数超过1万时自动从1开始重新计数 * @return 数据条数字符串 */ public static String getReceivedDataCount() { receivedDataCount++; if (receivedDataCount > 10000) { receivedDataCount = 1; } return String.valueOf(receivedDataCount); } public static void setReceivedDataCount(int receivedDataCount) { SerialPortService.receivedDataCount = receivedDataCount; } /** * 获取协议解析器实例 */ public SerialProtocolParser getProtocolParser() { return protocolParser; } // 优化:重用缓冲区,减少内存分配 private byte[] readBuffer = new byte[200]; private ByteArrayOutputStream buffer = new ByteArrayOutputStream(1024); private Consumer<byte[]> dataReceivedCallback; // 新增:协议解析器引用 private SerialProtocolParser protocolParser = new SerialProtocolParser(); // 新增:数据条数计数器 public static int receivedDataCount = 0; // 其他现有方法保持不变... /** * 重置数据条数计数器 */ public void resetReceivedDataCount() { receivedDataCount = 0; } * 获取串口接收的数据条数 * 当条数超过1万时自动从1开始重新计数 * @return 数据条数字符串 */ public static String getReceivedDataCount() { receivedDataCount++; if (receivedDataCount > 10000) { receivedDataCount = 1; } return String.valueOf(receivedDataCount); } // 以下为原有代码,保持不变... public InputStream getInputStream() { if (port != null && port.isOpen()) { return port.getInputStream(); } return null; } public static void setReceivedDataCount(int receivedDataCount) { SerialPortService.receivedDataCount = receivedDataCount; } public OutputStream getOutputStream() { if (port != null && port.isOpen()) { return port.getOutputStream(); } return null; } public void setComPortTimeouts(int timeoutMode, int readTimeout, int writeTimeout) { if (port != null && port.isOpen()) { port.setComPortTimeouts(timeoutMode, readTimeout, writeTimeout); } } /** * 设置协议解析器 */ public void setProtocolParser(SerialProtocolParser parser) { this.protocolParser = parser; } /** * 启用调试输出,将接收到的数据打印到控制台 */ public void enableDebugOutput() { //System.out.println("串口调试输出已启用 - 开始监听串口数据..."); } /** * 获取协议解析器实例 */ public SerialProtocolParser getProtocolParser() { return protocolParser; } /** * 获取当前调试状态 */ public boolean isDebugEnabled() { return capturing; } public void startCapture() { if (dataReceivedCallback != null) { startCapture(dataReceivedCallback); } else { System.err.println("No data received callback set. Please call startCapture(Consumer<byte[]> onReceived) first."); } } /** * 重置数据条数计数器 */ public void resetReceivedDataCount() { receivedDataCount = 0; } /** * 打开串口 */ public boolean open(String portName, int baud) { if (port != null && port.isOpen()) { return true; } // 以下为原有代码,保持不变... public InputStream getInputStream() { if (port != null && port.isOpen()) { return port.getInputStream(); } return null; } port = SerialPort.getCommPort(portName); port.setComPortParameters(baud, 8, 1, SerialPort.NO_PARITY); port.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 1, 0); protocolParser.start(); return port.openPort(); } public void setResponseConsumer(Consumer<byte[]> consumer) { this.responseConsumer = consumer; } public OutputStream getOutputStream() { if (port != null && port.isOpen()) { return port.getOutputStream(); } return null; } /** * 关闭串口 */ public void close() { stopCapture(); if (port != null && port.isOpen()) { port.closePort(); } port = null; } public void setComPortTimeouts(int timeoutMode, int readTimeout, int writeTimeout) { if (port != null && port.isOpen()) { port.setComPortTimeouts(timeoutMode, readTimeout, writeTimeout); } } /** * 启动数据接收线程 */ public void startCapture(Consumer<byte[]> onReceived) { this.dataReceivedCallback = onReceived; if (capturing || port == null || !port.isOpen()) return; capturing = true; paused = false; /** * 设置协议解析器 */ public void setProtocolParser(SerialProtocolParser parser) { this.protocolParser = parser; } readerThread = new Thread(() -> { buffer.reset(); long lastReceivedTime = 0; while (capturing && port.isOpen()) { long currentTime = System.currentTimeMillis(); if (buffer.size() > 0 && (currentTime - lastReceivedTime) >= 20) { byte[] data = buffer.toByteArray(); SystemDebugDialog.appendHexData(data); // 新增:将数据传递给协议解析器 if (protocolParser != null) { protocolParser.receiveData(data); } if (!paused) { onReceived.accept(data); if (responseConsumer != null) { responseConsumer.accept(data); } } buffer.reset(); } /** * 启用调试输出,将接收到的数据打印到控制台 */ public void enableDebugOutput() { //System.out.println("串口调试输出已启用 - 开始监听串口数据..."); } int len = port.readBytes(readBuffer, readBuffer.length); currentTime = System.currentTimeMillis(); /** * 获取当前调试状态 */ public boolean isDebugEnabled() { return capturing; } if (len > 0) { buffer.write(readBuffer, 0, len); lastReceivedTime = currentTime; } if (len <= 0 && buffer.size() == 0) { try { Thread.sleep(1); } catch (InterruptedException ignore) {} } } if (buffer.size() > 0) { byte[] data = buffer.toByteArray(); SystemDebugDialog.appendHexData(data); // 新增:将数据传递给协议解析器 if (protocolParser != null) { protocolParser.receiveData(data); } if (!paused) { onReceived.accept(data); if (responseConsumer != null) { responseConsumer.accept(data); } } } }); readerThread.setDaemon(true); readerThread.start(); } public void startCapture() { if (dataReceivedCallback != null) { startCapture(dataReceivedCallback); } else { System.err.println("No data received callback set. Please call startCapture(Consumer<byte[]> onReceived) first."); } } /** * 停止数据接收线程 */ public void stopCapture() { capturing = false; if (readerThread != null) { try { readerThread.join(500); } catch (InterruptedException ignore) {} readerThread = null; } } /** * 打开串口 */ public boolean open(String portName, int baud) { if (port != null && port.isOpen()) { return true; } public void setPaused(boolean paused) { this.paused = paused; } port = SerialPort.getCommPort(portName); port.setComPortParameters(baud, 8, 1, SerialPort.NO_PARITY); port.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 1, 0); protocolParser.start(); return port.openPort(); } public boolean isPaused() { return paused; } public void setResponseConsumer(Consumer<byte[]> consumer) { this.responseConsumer = consumer; } public boolean isOpen() { return port != null && port.isOpen(); } /** * 关闭串口 */ public void close() { stopCapture(); if (port != null && port.isOpen()) { port.closePort(); } port = null; } /** * 发送数据 */ public boolean send(byte[] data) { if (!isOpen()) { return false; } return port != null && port.isOpen() && port.writeBytes(data, data.length) > 0; } /** * 启动数据接收线程 */ public void startCapture(Consumer<byte[]> onReceived) { this.dataReceivedCallback = onReceived; if (capturing || port == null || !port.isOpen()) return; capturing = true; paused = false; readerThread = new Thread(() -> { buffer.reset(); long lastReceivedTime = 0; while (capturing && port.isOpen()) { long currentTime = System.currentTimeMillis(); if (buffer.size() > 0 && (currentTime - lastReceivedTime) >= 20) { byte[] data = buffer.toByteArray(); SystemDebugDialog.appendHexData(data); // 新增:将数据传递给协议解析器 if (protocolParser != null) { protocolParser.receiveData(data); } if (!paused) { onReceived.accept(data); if (responseConsumer != null) { responseConsumer.accept(data); } } buffer.reset(); } int len = port.readBytes(readBuffer, readBuffer.length); currentTime = System.currentTimeMillis(); if (len > 0) { buffer.write(readBuffer, 0, len); lastReceivedTime = currentTime; } if (len <= 0 && buffer.size() == 0) { try { Thread.sleep(1); } catch (InterruptedException ignore) {} } } if (buffer.size() > 0) { byte[] data = buffer.toByteArray(); SystemDebugDialog.appendHexData(data); // 新增:将数据传递给协议解析器 if (protocolParser != null) { protocolParser.receiveData(data); } if (!paused) { onReceived.accept(data); if (responseConsumer != null) { responseConsumer.accept(data); } } } }); readerThread.setDaemon(true); readerThread.start(); } /** * 停止数据接收线程 */ public void stopCapture() { capturing = false; if (readerThread != null) { try { readerThread.join(500); } catch (InterruptedException ignore) {} readerThread = null; } } public void setPaused(boolean paused) { this.paused = paused; } public boolean isPaused() { return paused; } public boolean isOpen() { return port != null && port.isOpen(); } /** * 发送数据(优化版本) */ public boolean send(byte[] data) { if (!isOpen()) { return false; } // 添加发送前的串口状态检查 if (port == null || !port.isOpen()) { return false; } try { // 添加小延迟,避免连续发送 Thread.sleep(2); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return false; } int result = port.writeBytes(data, data.length); return result > 0; } } src/chushihua/lunxun.java
@@ -115,10 +115,7 @@ try { pollingThread = new Thread(new PollingTask(), "CardSlot-Polling-Thread"); pollingThread.setDaemon(true); pollingThread.start(); if (DEBUG_ENABLED) { //System.out.println("轮询查询已启动,间隔: " + pollingInterval + "ms"); } pollingThread.start(); return true; } catch (Exception e) { System.err.println("启动轮询查询线程时发生异常: " + e.getMessage()); @@ -387,7 +384,7 @@ } else { consecutiveFailures++; if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) { System.err.println("连续失败次数过多,暂停轮询"); System.err.println("lunxun连续失败次数过多,暂停轮询"); pausePolling(); break; } @@ -442,7 +439,7 @@ if (sendResult) { // 只在调试时输出,避免频繁打印 if (DEBUG_ENABLED) { SystemDebugDialog.appendAsciiData(String.format("Slot %d Send query (hasCard !=1)", slotNumber)); SystemDebugDialog.appendAsciiData(String.format("Slot %d Send query (hasCard !=1)\n", slotNumber)); } return true; } else { src/chushihua/lunxunzaixian.java
@@ -13,480 +13,494 @@ * 与原有的轮询查询类互补,专注于在线设备的持续监控 */ public class lunxunzaixian { private static final AtomicBoolean isRunning = new AtomicBoolean(false); private static final AtomicBoolean isPaused = new AtomicBoolean(false); private static final AtomicBoolean shouldStop = new AtomicBoolean(false); private static Thread onlinePollingThread; // 可配置的轮询参数(不再是final) private static int cycleInterval = 60000; // 完整轮询周期间隔:60秒 private static int slotInterval = 200; // 卡槽间查询间隔:200毫秒 // 卡槽相关常量 private static final int MIN_SLOT = 1; private static final int MAX_SLOT = 60; // 性能优化配置 private static final int BATCH_SIZE = 5; // 批量查询大小 private static int consecutiveFailures = 0; private static final int MAX_CONSECUTIVE_FAILURES = 3; /** * 启动在线轮询 - 优化版本 * @return true-启动成功, false-启动失败 */ public static boolean startOnlinePolling() { if (isRunning.get()) { SystemDebugDialog.appendAsciiData("Online polling is already in progress"); return true; } // 检查串口连接状态 if (!checkSerialConnectionWithRetry()) { System.err.println("串口未连接,无法启动在线轮询"); return false; } isRunning.set(true); isPaused.set(false); shouldStop.set(false); consecutiveFailures = 0; try { onlinePollingThread = new Thread(new OnlinePollingTask(), "Online-Polling-Thread"); onlinePollingThread.setDaemon(true); onlinePollingThread.start(); //System.out.println("在线轮询已启动,周期间隔: " + cycleInterval + "ms, 卡槽间隔: " + slotInterval + "ms"); return true; } catch (Exception e) { System.err.println("启动在线轮询线程时发生异常: " + e.getMessage()); isRunning.set(false); shouldStop.set(true); return false; } } /** * 停止在线轮询 - 修复版本 * @return true-停止成功, false-停止失败 */ public static boolean stopOnlinePolling() { if (!isRunning.get()) { //System.out.println("在线轮询未在运行"); return false; } shouldStop.set(true); isRunning.set(false); isPaused.set(false); if (onlinePollingThread != null) { onlinePollingThread.interrupt(); try { onlinePollingThread.join(3000); // 等待3秒 // 检查线程是否还在运行 if (onlinePollingThread.isAlive()) { System.err.println("在线轮询线程未在3秒内停止,标记为守护线程并忽略"); // 不强制停止,而是确保它是守护线程 onlinePollingThread.setDaemon(true); } } catch (InterruptedException e) { System.err.println("停止在线轮询时被中断: " + e.getMessage()); Thread.currentThread().interrupt(); } catch (Exception e) { System.err.println("停止在线轮询线程时发生异常: " + e.getMessage()); } finally { onlinePollingThread = null; } } shouldStop.set(false); //System.out.println("在线轮询已停止"); return true; } /** * 暂停在线轮询 * @return true-暂停成功, false-暂停失败 */ public static boolean pauseOnlinePolling() { if (!isRunning.get()) { //System.out.println("在线轮询未在运行,无法暂停"); return false; } if (isPaused.get()) { //System.out.println("在线轮询已经处于暂停状态"); return false; } isPaused.set(true); //System.out.println("在线轮询已暂停"); return true; } /** * 恢复在线轮询 * @return true-恢复成功, false-恢复失败 */ public static boolean resumeOnlinePolling() { if (!isRunning.get()) { //System.out.println("在线轮询未在运行,无法恢复"); return false; } if (!isPaused.get()) { //System.out.println("在线轮询未处于暂停状态"); return false; } // 恢复前检查串口连接 if (!checkSerialConnectionWithRetry()) { System.err.println("串口未连接,无法恢复在线轮询"); return false; } isPaused.set(false); synchronized (lunxunzaixian.class) { lunxunzaixian.class.notifyAll(); // 唤醒等待的线程 } //System.out.println("在线轮询已恢复"); return true; } /** * 检查在线轮询状态 * @return true-正在运行, false-已停止 */ public static boolean isOnlinePolling() { return isRunning.get(); } /** * 检查是否暂停 * @return true-已暂停, false-未暂停 */ public static boolean isOnlinePaused() { return isPaused.get(); } /** * 重新启动在线轮询 * @return true-重启成功, false-重启失败 */ public static boolean restartOnlinePolling() { stopOnlinePolling(); // 等待一小段时间确保线程完全停止 try { Thread.sleep(200); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return startOnlinePolling(); } /** * 设置轮询间隔参数 * @param cycleMs 完整轮询周期间隔(毫秒) * @param slotMs 卡槽间查询间隔(毫秒) */ public static void setPollingIntervals(int cycleMs, int slotMs) { cycleInterval = Math.max(cycleMs, 1000); // 最小1秒 slotInterval = Math.max(slotMs, 50); // 最小50毫秒 //System.out.println("在线轮询间隔已设置 - 周期间隔: " + cycleInterval + "ms, 卡槽间隔: " + slotInterval + "ms"); // 如果正在运行,重新启动以应用新的间隔 if (isRunning.get()) { restartOnlinePolling(); } } /** * 获取当前轮询间隔配置 * @return 间隔配置字符串 */ public static String getPollingIntervals() { return String.format("周期间隔: %dms, 卡槽间隔: %dms", cycleInterval, slotInterval); } /** * 获取在线轮询统计信息 * @return 统计信息字符串 */ public static String getOnlinePollingStats() { int totalSlots = MAX_SLOT - MIN_SLOT + 1; int cardSlots = countCardSlots(); String status; if (!isRunning.get()) { status = "已停止"; } else if (isPaused.get()) { status = "已暂停"; } else { status = "运行中"; } return String.format("在线轮询状态: %s, 有卡卡槽: %d/%d, 周期间隔: %ds, 卡槽间隔: %dms", status, cardSlots, totalSlots, cycleInterval/1000, slotInterval); } /** * 统计有卡的卡槽数量 * @return 有卡的卡槽数量 */ private static int countCardSlots() { if (SlotManager.slotArray == null) { return 0; } int count = 0; for (Fkj slot : SlotManager.slotArray) { if (slot != null && "1".equals(slot.getHasCard())) { count++; } } return count; } /** * 带重试的串口连接检查 */ private static boolean checkSerialConnectionWithRetry() { for (int i = 0; i < 3; i++) { if (lunxun.checkSerialConnection()) { return true; } try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return false; } } return false; } /** * 在线轮询任务内部类 - 优化版本 * 专门轮询有卡的卡槽,优化资源使用 */ private static class OnlinePollingTask implements Runnable { @Override public void run() { //System.out.println("在线轮询线程开始运行"); while (isRunning.get() && !Thread.currentThread().isInterrupted() && !shouldStop.get()) { try { // 检查是否暂停 if (isPaused.get()) { synchronized (lunxunzaixian.class) { while (isPaused.get() && isRunning.get() && !shouldStop.get()) { lunxunzaixian.class.wait(1000); // 等待1秒或直到被唤醒 } } continue; } // 检查串口连接状态 if (!checkSerialConnectionWithRetry()) { System.err.println("串口连接断开,暂停在线轮询"); pauseOnlinePolling(); continue; } // 执行一轮有卡卡槽的轮询 if (pollCardSlotsOptimized()) { consecutiveFailures = 0; // 重置连续失败计数 } else { consecutiveFailures++; if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) { System.err.println("连续失败次数过多,暂停在线轮询"); pauseOnlinePolling(); } } // 等待完整周期间隔 Thread.sleep(cycleInterval); } catch (InterruptedException e) { //System.out.println("在线轮询线程被中断"); Thread.currentThread().interrupt(); break; } catch (Exception e) { System.err.println("在线轮询过程中发生异常: " + e.getMessage()); consecutiveFailures++; // 发生异常时等待一段时间再继续 try { Thread.sleep(5000); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); break; } } } //System.out.println("在线轮询线程结束运行"); } /** * 优化版本:批量轮询有卡卡槽 * @return true-轮询成功, false-轮询失败 */ private boolean pollCardSlotsOptimized() { if (SlotManager.slotArray == null) { System.err.println("卡槽数组未初始化"); return false; } List<Integer> cardSlots = new ArrayList<>(); // 第一阶段:收集所有有卡卡槽 for (int i = 0; i < SlotManager.slotArray.length; i++) { if (!isRunning.get() || Thread.currentThread().isInterrupted() || shouldStop.get()) { break; } Fkj slot = SlotManager.slotArray[i]; if (slot != null && "1".equals(slot.getHasCard())) { cardSlots.add(i + 1); } } if (cardSlots.isEmpty()) { if (lunxun.DEBUG_ENABLED) { //System.out.println("没有找到有卡的卡槽"); } return true; } int polledCount = 0; int totalCardSlots = cardSlots.size(); // 第二阶段:批量查询有卡卡槽 for (int i = 0; i < cardSlots.size(); i += BATCH_SIZE) { if (!isRunning.get() || Thread.currentThread().isInterrupted() || shouldStop.get()) { break; } int end = Math.min(i + BATCH_SIZE, cardSlots.size()); List<Integer> batch = cardSlots.subList(i, end); // 批次内查询 for (int slotNumber : batch) { if (sendQueryToCardSlot(slotNumber)) { polledCount++; } } // 批次间间隔 if (end < cardSlots.size()) { try { Thread.sleep(slotInterval * BATCH_SIZE); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } } if (polledCount > 0 && lunxun.DEBUG_ENABLED) { //System.out.println("在线轮询完成,成功查询 " + polledCount + "/" + totalCardSlots + " 个有卡卡槽"); } return polledCount > 0; } /** * 向指定有卡卡槽发送查询指令 * @param slotNumber 卡槽编号 * @return true-发送成功, false-发送失败 */ private boolean sendQueryToCardSlot(int slotNumber) { try { // 使用原有的立即查询功能 boolean result = lunxun.sendImmediateQuery(slotNumber); if (result) { // 记录调试信息(减少输出频率) if (lunxun.DEBUG_ENABLED && (slotNumber == 1 || slotNumber % 10 == 0)) { //System.out.println("在线轮询 - 查询有卡卡槽 " + slotNumber); } return true; } else { System.err.println("在线轮询 - 查询有卡卡槽 " + slotNumber + " 失败"); return false; } } catch (Exception e) { System.err.println("在线轮询 - 查询有卡卡槽 " + slotNumber + " 时发生异常: " + e.getMessage()); return false; } } } /** * 手动触发立即轮询(不等待周期)- 优化版本 * @return 成功查询的卡槽数量 */ public static int triggerImmediatePolling() { if (!isRunning.get() || isPaused.get()) { System.err.println("在线轮询未运行或已暂停,无法立即轮询"); return 0; } if (!checkSerialConnectionWithRetry()) { System.err.println("串口未连接,无法执行立即轮询"); return 0; } //System.out.println("开始立即轮询有卡卡槽..."); OnlinePollingTask task = new OnlinePollingTask(); // 使用新的批量轮询方法 int cardSlotCount = countCardSlots(); // 在新线程中执行立即轮询,避免阻塞当前线程 Thread immediateThread = new Thread(() -> { try { task.pollCardSlotsOptimized(); } catch (Exception e) { System.err.println("立即轮询过程中发生异常: " + e.getMessage()); } }, "Immediate-Online-Polling"); immediateThread.setDaemon(true); immediateThread.start(); return cardSlotCount; } /** * 设置在线轮询暂停状态(供其他类调用) * @param paused true-暂停轮询, false-恢复轮询 * @return true-设置成功, false-设置失败 */ public static boolean setOnlinePollingPaused(boolean paused) { if (!isRunning.get()) { //System.out.println("在线轮询未在运行,无法设置暂停状态"); return false; } if (paused) { return pauseOnlinePolling(); } else { return resumeOnlinePolling(); } } /** * 获取性能统计信息 */ public static String getPerformanceStats() { return String.format("批量大小: %d, 周期间隔: %dms, 卡槽间隔: %dms", BATCH_SIZE, cycleInterval, slotInterval); } private static final AtomicBoolean isRunning = new AtomicBoolean(false); private static final AtomicBoolean isPaused = new AtomicBoolean(false); private static final AtomicBoolean shouldStop = new AtomicBoolean(false); private static Thread onlinePollingThread; // 可配置的轮询参数(不再是final) private static int cycleInterval = 120000; // 完整轮询周期间隔:60秒 private static int slotInterval = 200; // 卡槽间查询间隔:500毫秒 // 卡槽相关常量 private static final int MIN_SLOT = 1; private static final int MAX_SLOT = 60; // 性能优化配置 private static final int BATCH_SIZE = 5; // 批量查询大小 private static int consecutiveFailures = 0; private static final int MAX_CONSECUTIVE_FAILURES = 3; /** * 启动在线轮询 - 优化版本 * @return true-启动成功, false-启动失败 */ public static boolean startOnlinePolling() { if (isRunning.get()) { SystemDebugDialog.appendAsciiData("Online polling is already in progress"); return true; } // 检查串口连接状态 if (!checkSerialConnectionWithRetry()) { System.err.println("串口未连接,无法启动在线轮询"); return false; } isRunning.set(true); isPaused.set(false); shouldStop.set(false); consecutiveFailures = 0; try { onlinePollingThread = new Thread(new OnlinePollingTask(), "Online-Polling-Thread"); onlinePollingThread.setDaemon(true); onlinePollingThread.start(); //System.out.println("在线轮询已启动,周期间隔: " + cycleInterval + "ms, 卡槽间隔: " + slotInterval + "ms"); return true; } catch (Exception e) { System.err.println("启动在线轮询线程时发生异常: " + e.getMessage()); isRunning.set(false); shouldStop.set(true); return false; } } /** * 停止在线轮询 - 修复版本 * @return true-停止成功, false-停止失败 */ public static boolean stopOnlinePolling() { if (!isRunning.get()) { //System.out.println("在线轮询未在运行"); return false; } shouldStop.set(true); isRunning.set(false); isPaused.set(false); if (onlinePollingThread != null) { onlinePollingThread.interrupt(); try { onlinePollingThread.join(3000); // 等待3秒 // 检查线程是否还在运行 if (onlinePollingThread.isAlive()) { System.err.println("在线轮询线程未在3秒内停止,标记为守护线程并忽略"); // 不强制停止,而是确保它是守护线程 onlinePollingThread.setDaemon(true); } } catch (InterruptedException e) { System.err.println("停止在线轮询时被中断: " + e.getMessage()); Thread.currentThread().interrupt(); } catch (Exception e) { System.err.println("停止在线轮询线程时发生异常: " + e.getMessage()); } finally { onlinePollingThread = null; } } shouldStop.set(false); //System.out.println("在线轮询已停止"); return true; } /** * 暂停在线轮询 * @return true-暂停成功, false-暂停失败 */ public static boolean pauseOnlinePolling() { if (!isRunning.get()) { //System.out.println("在线轮询未在运行,无法暂停"); return false; } if (isPaused.get()) { //System.out.println("在线轮询已经处于暂停状态"); return false; } isPaused.set(true); //System.out.println("在线轮询已暂停"); return true; } /** * 恢复在线轮询 * @return true-恢复成功, false-恢复失败 */ public static boolean resumeOnlinePolling() { if (!isRunning.get()) { //System.out.println("在线轮询未在运行,无法恢复"); return false; } if (!isPaused.get()) { //System.out.println("在线轮询未处于暂停状态"); return false; } // 恢复前检查串口连接 if (!checkSerialConnectionWithRetry()) { System.err.println("串口未连接,无法恢复在线轮询"); return false; } isPaused.set(false); synchronized (lunxunzaixian.class) { lunxunzaixian.class.notifyAll(); // 唤醒等待的线程 } //System.out.println("在线轮询已恢复"); return true; } /** * 检查在线轮询状态 * @return true-正在运行, false-已停止 */ public static boolean isOnlinePolling() { return isRunning.get(); } /** * 检查是否暂停 * @return true-已暂停, false-未暂停 */ public static boolean isOnlinePaused() { return isPaused.get(); } /** * 重新启动在线轮询 * @return true-重启成功, false-重启失败 */ public static boolean restartOnlinePolling() { stopOnlinePolling(); // 等待一小段时间确保线程完全停止 try { Thread.sleep(200); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return startOnlinePolling(); } /** * 设置轮询间隔参数 * @param cycleMs 完整轮询周期间隔(毫秒) * @param slotMs 卡槽间查询间隔(毫秒) */ public static void setPollingIntervals(int cycleMs, int slotMs) { cycleInterval = Math.max(cycleMs, 1000); // 最小1秒 slotInterval = Math.max(slotMs, 50); // 最小50毫秒 //System.out.println("在线轮询间隔已设置 - 周期间隔: " + cycleInterval + "ms, 卡槽间隔: " + slotInterval + "ms"); // 如果正在运行,重新启动以应用新的间隔 if (isRunning.get()) { restartOnlinePolling(); } } /** * 获取当前轮询间隔配置 * @return 间隔配置字符串 */ public static String getPollingIntervals() { return String.format("周期间隔: %dms, 卡槽间隔: %dms", cycleInterval, slotInterval); } /** * 获取在线轮询统计信息 * @return 统计信息字符串 */ public static String getOnlinePollingStats() { int totalSlots = MAX_SLOT - MIN_SLOT + 1; int cardSlots = countCardSlots(); String status; if (!isRunning.get()) { status = "已停止"; } else if (isPaused.get()) { status = "已暂停"; } else { status = "运行中"; } return String.format("在线轮询状态: %s, 有卡卡槽: %d/%d, 周期间隔: %ds, 卡槽间隔: %dms", status, cardSlots, totalSlots, cycleInterval/1000, slotInterval); } /** * 统计有卡的卡槽数量 * @return 有卡的卡槽数量 */ private static int countCardSlots() { if (SlotManager.slotArray == null) { return 0; } int count = 0; for (Fkj slot : SlotManager.slotArray) { if (slot != null && "1".equals(slot.getHasCard())) { count++; } } return count; } /** * 带重试的串口连接检查 */ private static boolean checkSerialConnectionWithRetry() { for (int i = 0; i < 3; i++) { if (lunxun.checkSerialConnection()) { return true; } try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return false; } } return false; } /** * 在线轮询任务内部类 - 优化版本 * 专门轮询有卡的卡槽,优化资源使用 */ private static class OnlinePollingTask implements Runnable { @Override public void run() { //System.out.println("在线轮询线程开始运行"); while (isRunning.get() && !Thread.currentThread().isInterrupted() && !shouldStop.get()) { try { // 检查是否暂停 if (isPaused.get()) { synchronized (lunxunzaixian.class) { while (isPaused.get() && isRunning.get() && !shouldStop.get()) { lunxunzaixian.class.wait(1000); // 等待1秒或直到被唤醒 } } continue; } // 检查串口连接状态 if (!checkSerialConnectionWithRetry()) { System.err.println("串口连接断开,暂停在线轮询"); pauseOnlinePolling(); continue; } // 执行一轮有卡卡槽的轮询 if (pollCardSlotsOptimized()) { consecutiveFailures = 0; // 重置连续失败计数 } else { consecutiveFailures++; if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) { System.err.println("lunxunzaixian连续失败次数过多,暂停在线轮询"); pauseOnlinePolling(); } } // 等待完整周期间隔 Thread.sleep(cycleInterval); } catch (InterruptedException e) { //System.out.println("在线轮询线程被中断"); Thread.currentThread().interrupt(); break; } catch (Exception e) { System.err.println("在线轮询过程中发生异常: " + e.getMessage()); consecutiveFailures++; // 发生异常时等待一段时间再继续 try { Thread.sleep(5000); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); break; } } } //System.out.println("在线轮询线程结束运行"); } /** * 优化版本:批量轮询有卡卡槽 * @return true-轮询成功, false-轮询失败 */ private boolean pollCardSlotsOptimized() { if (SlotManager.slotArray == null) { System.err.println("卡槽数组未初始化"); return false; } List<Integer> cardSlots = new ArrayList<>(); // 第一阶段:收集所有有卡卡槽 for (int i = 0; i < SlotManager.slotArray.length; i++) { if (!isRunning.get() || Thread.currentThread().isInterrupted() || shouldStop.get()) { break; } Fkj slot = SlotManager.slotArray[i]; if (slot != null && "1".equals(slot.getHasCard())) { cardSlots.add(i + 1); } } if (cardSlots.isEmpty()) { if (lunxun.DEBUG_ENABLED) { //System.out.println("没有找到有卡的卡槽"); } return true; } int polledCount = 0; int totalCardSlots = cardSlots.size(); // 第二阶段:批量查询有卡卡槽 - 修复:每个卡槽间都有间隔 for (int i = 0; i < cardSlots.size(); i += BATCH_SIZE) { if (!isRunning.get() || Thread.currentThread().isInterrupted() || shouldStop.get()) { break; } int end = Math.min(i + BATCH_SIZE, cardSlots.size()); List<Integer> batch = cardSlots.subList(i, end); // 批次内查询 - 修复:每个卡槽间添加间隔 for (int j = 0; j < batch.size(); j++) { int slotNumber = batch.get(j); if (sendQueryToCardSlot(slotNumber)) { polledCount++; } // 重要修复:每个卡槽查询后等待指定间隔(最后一个卡槽除外) if (j < batch.size() - 1) { try { Thread.sleep(slotInterval); // 卡槽间间隔 } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } } // 批次间间隔(保持原有逻辑) if (end < cardSlots.size()) { try { Thread.sleep(slotInterval * BATCH_SIZE); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } } if (polledCount > 0 && lunxun.DEBUG_ENABLED) { System.out.println("在线轮询完成,成功查询 " + polledCount + "/" + totalCardSlots + " 个有卡卡槽"); } return polledCount > 0; } /** * 向指定有卡卡槽发送查询指令 * @param slotNumber 卡槽编号 * @return true-发送成功, false-发送失败 */ private boolean sendQueryToCardSlot(int slotNumber) { try { // 使用原有的立即查询功能 boolean result = lunxun.sendImmediateQuery(slotNumber); if (result) { // 记录调试信息(减少输出频率) if (lunxun.DEBUG_ENABLED && (slotNumber == 1 || slotNumber % 10 == 0)) { //System.out.println("在线轮询 - 查询有卡卡槽 " + slotNumber); } return true; } else { System.err.println("在线轮询 - 查询有卡卡槽 " + slotNumber + " 失败"); return false; } } catch (Exception e) { System.err.println("在线轮询 - 查询有卡卡槽 " + slotNumber + " 时发生异常: " + e.getMessage()); return false; } } } /** * 手动触发立即轮询(不等待周期)- 优化版本 * @return 成功查询的卡槽数量 */ public static int triggerImmediatePolling() { if (!isRunning.get() || isPaused.get()) { System.err.println("在线轮询未运行或已暂停,无法立即轮询"); return 0; } if (!checkSerialConnectionWithRetry()) { System.err.println("串口未连接,无法执行立即轮询"); return 0; } //System.out.println("开始立即轮询有卡卡槽..."); OnlinePollingTask task = new OnlinePollingTask(); // 使用新的批量轮询方法 int cardSlotCount = countCardSlots(); // 在新线程中执行立即轮询,避免阻塞当前线程 Thread immediateThread = new Thread(() -> { try { task.pollCardSlotsOptimized(); } catch (Exception e) { System.err.println("立即轮询过程中发生异常: " + e.getMessage()); } }, "Immediate-Online-Polling"); immediateThread.setDaemon(true); immediateThread.start(); return cardSlotCount; } /** * 设置在线轮询暂停状态(供其他类调用) * @param paused true-暂停轮询, false-恢复轮询 * @return true-设置成功, false-设置失败 */ public static boolean setOnlinePollingPaused(boolean paused) { if (!isRunning.get()) { //System.out.println("在线轮询未在运行,无法设置暂停状态"); return false; } if (paused) { return pauseOnlinePolling(); } else { return resumeOnlinePolling(); } } /** * 获取性能统计信息 */ public static String getPerformanceStats() { return String.format("批量大小: %d, 周期间隔: %dms, 卡槽间隔: %dms", BATCH_SIZE, cycleInterval, slotInterval); } } src/home/Homein.java
@@ -129,21 +129,13 @@ if (serialConnected) { // 4. 串口连接成功后,启动轮询 boolean pollingStarted = startPollingService(); startPollingService(); showMainInterface(); //启动轮询卡状态给服务器发数据 lunxunkazhuangtai.startPolling(); //启动在线的卡状态轮询 lunxunzaixian.startOnlinePolling(); if (pollingStarted) { showMainInterface(); //启动轮询卡状态给服务器发数据 lunxunkazhuangtai.startPolling(); //启动在线的卡状态轮询 lunxunzaixian.startOnlinePolling(); } else { System.err.println("轮询服务启动失败"); JOptionPane.showMessageDialog(null, "轮询服务启动失败,应用程序无法正常运行", "警告", JOptionPane.WARNING_MESSAGE); } } else { System.err.println("串口连接失败"); // 串口连接失败已经由SerialPortConnectionDialog处理,直接退出 src/xitongshezhi/canshushezhi.java
@@ -17,12 +17,14 @@ private static final int SCREEN_WIDTH = 600; private static final int SCREEN_HEIGHT = 1024; // 颜色常量 - 使用不透明颜色 // 颜色定义 - 使用mimaguanli.java中的颜色方案 private static final Color BACKGROUND_COLOR = new Color(15, 28, 48); private static final Color CARD_COLOR = new Color(26, 43, 68); private static final Color PRIMARY_COLOR = new Color(52, 152, 219); private static final Color SECONDARY_COLOR = new Color(46, 204, 113); private static final Color DARK_COLOR = new Color(15, 28, 48); private static final Color DARK_LIGHT_COLOR = new Color(26, 43, 68); private static final Color TEXT_COLOR = new Color(224, 224, 224); private static final Color TEXT_LIGHT_COLOR = new Color(160, 200, 255); private static final Color FIELD_BACKGROUND = new Color(240, 240, 240); // UI组件 private JPanel mainPanel; @@ -58,10 +60,10 @@ e.printStackTrace(); } // 创建主面板 - 不透明背景 // 创建主面板 - 使用mimaguanli的背景色 mainPanel = new JPanel(); mainPanel.setLayout(new BorderLayout()); mainPanel.setBackground(DARK_COLOR); mainPanel.setBackground(BACKGROUND_COLOR); mainPanel.setOpaque(true); mainPanel.setBorder(new EmptyBorder(12, 12, 12, 12)); @@ -82,14 +84,18 @@ titleLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 22)); titleLabel.setForeground(TEXT_COLOR); // 关闭按钮 // 关闭按钮 - 使用mimaguanli的按钮样式 JButton backButton = new JButton("关闭"); backButton.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14)); backButton.setBackground(PRIMARY_COLOR); backButton.setForeground(Color.WHITE); backButton.setOpaque(true); backButton.setFocusPainted(false); backButton.setBorder(BorderFactory.createEmptyBorder(8, 16, 8, 16)); backButton.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(new Color(40, 120, 180), 1), BorderFactory.createEmptyBorder(8, 16, 8, 16) )); backButton.setCursor(new Cursor(Cursor.HAND_CURSOR)); backButton.addActionListener(e -> dispose()); // 关闭按钮悬停效果 @@ -130,12 +136,14 @@ scrollPane.setOpaque(false); scrollPane.getViewport().setOpaque(false); // 基本参数设置卡片 settingsPanel.add(createBasicSettingsCard()); settingsPanel.add(Box.createRigidArea(new Dimension(0, 12))); // 自定义滚动条 JScrollBar verticalScrollBar = scrollPane.getVerticalScrollBar(); verticalScrollBar.setBackground(CARD_COLOR); verticalScrollBar.setForeground(PRIMARY_COLOR); verticalScrollBar.setUnitIncrement(20); // 设备参数设置卡片 settingsPanel.add(createDeviceSettingsCard()); // 合并的参数设置卡片 settingsPanel.add(createMergedSettingsCard()); settingsPanel.add(Box.createRigidArea(new Dimension(0, 12))); // 保存按钮 @@ -148,172 +156,148 @@ return container; } private JPanel createBasicSettingsCard() { private JPanel createMergedSettingsCard() { JPanel card = new JPanel(); card.setLayout(new BorderLayout()); card.setBackground(DARK_LIGHT_COLOR); card.setBackground(CARD_COLOR); card.setOpaque(true); card.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(new Color(52, 152, 219, 128)), BorderFactory.createEmptyBorder(15, 15, 15, 15) BorderFactory.createLineBorder(new Color(52, 152, 219, 100), 1), BorderFactory.createEmptyBorder(20, 20, 20, 20) )); // 卡头 JPanel cardHeader = new JPanel(new BorderLayout()); cardHeader.setOpaque(false); JLabel titleLabel = new JLabel("基本参数设置"); titleLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 16)); titleLabel.setForeground(TEXT_COLOR); cardHeader.add(titleLabel, BorderLayout.WEST); card.add(cardHeader, BorderLayout.NORTH); // 表单内容 - 使用网格布局实现标签在左,文本框在右 // 调整行高为80像素,为60像素高的组件提供足够的间距 JPanel formPanel = new JPanel(new GridLayout(3, 2, 10, 20)); // 表单内容 - 使用水平布局实现标签在左,文本框在右 JPanel formPanel = new JPanel(); formPanel.setLayout(new BoxLayout(formPanel, BoxLayout.Y_AXIS)); formPanel.setOpaque(false); formPanel.setBorder(new EmptyBorder(15, 0, 0, 0)); // 发卡机编号 JLabel deviceIdLabel = new JLabel("发卡机编号:"); deviceIdLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 13)); deviceIdLabel.setForeground(TEXT_COLOR); formPanel.add(deviceIdLabel); deviceIdField = new JTextField(); styleFormField(deviceIdField); formPanel.add(deviceIdField); formPanel.add(createHorizontalField("发卡机编号:", deviceIdField = new JTextField())); formPanel.add(Box.createRigidArea(new Dimension(0, 18))); // 服务器地址 JLabel serverAddressLabel = new JLabel("服务器地址:"); serverAddressLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 13)); serverAddressLabel.setForeground(TEXT_COLOR); formPanel.add(serverAddressLabel); serverAddressField = new JTextField(); styleFormField(serverAddressField); formPanel.add(serverAddressField); formPanel.add(createHorizontalField("服务器地址:", serverAddressField = new JTextField())); formPanel.add(Box.createRigidArea(new Dimension(0, 18))); // 服务器端口 JLabel serverPortLabel = new JLabel("服务器端口:"); serverPortLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 13)); serverPortLabel.setForeground(TEXT_COLOR); formPanel.add(serverPortLabel); formPanel.add(createHorizontalField("服务器端口:", serverPortField = new JTextField())); formPanel.add(Box.createRigidArea(new Dimension(0, 18))); serverPortField = new JTextField(); styleFormField(serverPortField); formPanel.add(serverPortField); // 卡槽总数 formPanel.add(createHorizontalField("卡槽总数:", slotCountField = new JTextField())); formPanel.add(Box.createRigidArea(new Dimension(0, 18))); // 读卡号模式 formPanel.add(createHorizontalComboBoxField("读卡号模式:", readModeComboBox = new JComboBox<>(new String[]{"主动模式", "被动模式"}))); card.add(formPanel, BorderLayout.CENTER); return card; } private JPanel createDeviceSettingsCard() { JPanel card = new JPanel(); card.setLayout(new BorderLayout()); card.setBackground(DARK_LIGHT_COLOR); card.setOpaque(true); card.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(new Color(52, 152, 219, 128)), BorderFactory.createEmptyBorder(15, 15, 15, 15) private JPanel createHorizontalField(String labelText, JTextField textField) { JPanel panel = new JPanel(new BorderLayout()); panel.setBackground(CARD_COLOR); panel.setMaximumSize(new Dimension(SCREEN_WIDTH - 100, 50)); // 标签 JLabel label = new JLabel(labelText); label.setFont(new Font("Microsoft YaHei", Font.BOLD, 14)); label.setForeground(TEXT_COLOR); label.setPreferredSize(new Dimension(100, 30)); // 文本框样式 - 使用mimaguanli的样式 textField.setBackground(FIELD_BACKGROUND); textField.setForeground(Color.BLACK); textField.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(new Color(200, 200, 200), 1), BorderFactory.createEmptyBorder(10, 12, 10, 12) )); textField.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14)); textField.setOpaque(true); textField.setPreferredSize(new Dimension(280, 42)); // 卡头 JPanel cardHeader = new JPanel(new BorderLayout()); cardHeader.setOpaque(false); // 创建水平布局容器 JPanel horizontalPanel = new JPanel(new BorderLayout()); horizontalPanel.setBackground(CARD_COLOR); horizontalPanel.setMaximumSize(new Dimension(SCREEN_WIDTH - 100, 50)); JLabel titleLabel = new JLabel("设备参数设置"); titleLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 16)); titleLabel.setForeground(TEXT_COLOR); horizontalPanel.add(label, BorderLayout.WEST); horizontalPanel.add(textField, BorderLayout.CENTER); cardHeader.add(titleLabel, BorderLayout.WEST); card.add(cardHeader, BorderLayout.NORTH); // 添加间距 horizontalPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0)); // 表单内容 - 使用网格布局实现标签在左,输入组件在右 // 调整行高为80像素,为60像素高的组件提供足够的间距 JPanel formPanel = new JPanel(new GridLayout(2, 2, 10, 20)); formPanel.setOpaque(false); formPanel.setBorder(new EmptyBorder(15, 0, 0, 0)); return horizontalPanel; } private JPanel createHorizontalComboBoxField(String labelText, JComboBox<String> comboBox) { JPanel panel = new JPanel(new BorderLayout()); panel.setBackground(CARD_COLOR); panel.setMaximumSize(new Dimension(SCREEN_WIDTH - 100, 50)); // 卡槽总数 JLabel slotCountLabel = new JLabel("卡槽总数:"); slotCountLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 13)); slotCountLabel.setForeground(TEXT_COLOR); formPanel.add(slotCountLabel); // 标签 JLabel label = new JLabel(labelText); label.setFont(new Font("Microsoft YaHei", Font.BOLD, 14)); label.setForeground(TEXT_COLOR); label.setPreferredSize(new Dimension(100, 30)); slotCountField = new JTextField(); styleFormField(slotCountField); formPanel.add(slotCountField); // 组合框样式 - 使用mimaguanli的样式 comboBox.setBackground(FIELD_BACKGROUND); comboBox.setForeground(Color.BLACK); comboBox.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(new Color(200, 200, 200), 1), BorderFactory.createEmptyBorder(10, 12, 10, 12) )); comboBox.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14)); comboBox.setOpaque(true); comboBox.setPreferredSize(new Dimension(280, 42)); // 读卡号模式 JLabel readModeLabel = new JLabel("读卡号模式:"); readModeLabel.setFont(new Font("Microsoft YaHei", Font.BOLD, 13)); readModeLabel.setForeground(TEXT_COLOR); formPanel.add(readModeLabel); // 创建水平布局容器 JPanel horizontalPanel = new JPanel(new BorderLayout()); horizontalPanel.setBackground(CARD_COLOR); horizontalPanel.setMaximumSize(new Dimension(SCREEN_WIDTH - 100, 50)); readModeComboBox = new JComboBox<>(new String[]{"主动模式", "被动模式"}); styleComboBox(readModeComboBox); formPanel.add(readModeComboBox); horizontalPanel.add(label, BorderLayout.WEST); horizontalPanel.add(comboBox, BorderLayout.CENTER); card.add(formPanel, BorderLayout.CENTER); // 添加间距 horizontalPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0)); return card; return horizontalPanel; } private JPanel createSaveButton() { JPanel buttonPanel = new JPanel(new BorderLayout()); JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); buttonPanel.setOpaque(false); buttonPanel.setBorder(new EmptyBorder(10, 0, 0, 0)); JButton saveButton = new JButton("保存所有设置"); saveButton.setFont(new Font("Microsoft YaHei", Font.BOLD, 16)); saveButton.setBackground(SECONDARY_COLOR); saveButton.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14)); saveButton.setBackground(PRIMARY_COLOR); saveButton.setForeground(Color.WHITE); saveButton.setOpaque(true); saveButton.setFocusPainted(false); saveButton.setPreferredSize(new Dimension(0, 60)); // 高度改为60像素 saveButton.setBorder(BorderFactory.createEmptyBorder(12, 20, 12, 20)); saveButton.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(new Color(40, 120, 180), 1), BorderFactory.createEmptyBorder(8, 16, 8, 16) )); saveButton.setCursor(new Cursor(Cursor.HAND_CURSOR)); saveButton.addActionListener(e -> saveSettings()); // 按钮悬停效果 saveButton.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseEntered(java.awt.event.MouseEvent evt) { saveButton.setBackground(brighterColor(SECONDARY_COLOR)); saveButton.setBackground(brighterColor(PRIMARY_COLOR)); } public void mouseExited(java.awt.event.MouseEvent evt) { saveButton.setBackground(SECONDARY_COLOR); saveButton.setBackground(PRIMARY_COLOR); } }); buttonPanel.add(saveButton, BorderLayout.CENTER); buttonPanel.add(saveButton); return buttonPanel; } private void styleFormField(JTextField field) { field.setPreferredSize(new Dimension(200, 60)); // 高度改为60像素 field.setBackground(Color.WHITE); // 不透明白色背景 field.setForeground(Color.BLACK); // 黑色文字 field.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(new Color(200, 200, 200)), BorderFactory.createEmptyBorder(8, 12, 8, 12) )); field.setFont(new Font("Microsoft YaHei", Font.PLAIN, 13)); field.setCaretColor(Color.BLACK); field.setOpaque(true); // 确保不透明 } private void styleComboBox(JComboBox<String> comboBox) { comboBox.setPreferredSize(new Dimension(200, 60)); // 高度改为60像素 comboBox.setBackground(Color.WHITE); // 不透明白色背景 comboBox.setForeground(Color.BLACK); // 黑色文字 comboBox.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(new Color(200, 200, 200)), BorderFactory.createEmptyBorder(8, 12, 8, 12) )); comboBox.setFont(new Font("Microsoft YaHei", Font.PLAIN, 13)); comboBox.setOpaque(true); // 确保不透明 } private void initializeData() {