等待在 Java 中打开按钮事件上的 COM 端口,而不是控制台输入的端口选择



下面是我用来打开 com 端口的代码 - 它等待控制台扫描程序的用户输入编号打开 JComboBox 中列出的端口。我有一个带有按钮的事件侦听器,我想用它来打开 com 端口。但我不确定在用户按下按钮打开端口之前"停止"进一步执行的最佳实践。(控制台扫描程序方便地允许程序在当前等待选择(。我只希望程序仅在按下后打开端口时继续。 一个jcombo框显示了端口,我可以使用getSelectedIndex((获取端口号

package testPackage;
import java.awt.BorderLayout;
import java.awt.ItemSelectable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.PrintWriter;
import java.util.Scanner;
import com.fazecast.jSerialComm.*;
import javax.swing.*;

//To test - Select option 5, from select a port dialogue (Com0Com port 6)
//open terminal program - select port Com0Com 7 
//send numbers as Ascii
public class Main {
static SerialPort serialPort; 
public static void main(String[] args) {
Window1 window1 = new Window1();
JComboBox<String> commList = new JComboBox<>();
window1.add(commList);  
JButton bigButton = new JButton("Select Comm port");
window1.add(bigButton);
window1.pack();
window1.setVisible(true);
JLabel label = new JLabel("My label");
window1.add(label, BorderLayout.CENTER);
SerialPort[] ports = SerialPort.getCommPorts();
System.out.println("Select a port:");
int i = 1;
for(SerialPort port : ports) {
System.out.println(i++ +  ": " + port.getSystemPortName());
commList.addItem(port.getSystemPortName());
}
bigButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Clicked");
label.setText("Selected");
System.out.println("Selected: " + commList.getSelectedItem());
System.out.println("Position: " + commList.getSelectedIndex());  
// SerialPort serialPort = ports[commList.getSelectedIndex()];
open_serial();
}
private void open_serial() {
serialPort = ports[commList.getSelectedIndex()];

}
});     
Scanner s = new Scanner(System.in);
int chosenPort = s.nextInt();
SerialPort serialPort = ports[chosenPort - 1];
//      System.out.println("Chosen port : " + chosenPort);
//        System.out.println("Selected: " + commList.getSelectedItem());
//        System.out.println("Position: " + commList.getSelectedIndex());
if(serialPort.openPort())
System.out.println("Port opened successfully.");
else {
System.out.println("Unable to open the port.");
s.close();
return;
}   
serialPort.setBaudRate(9600);
serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 0, 0);
Scanner data = new Scanner(serialPort.getInputStream());
int value = 0;
//Thread thread = new Thread();
PrintWriter output = new PrintWriter(serialPort.getOutputStream());
output.print("Hiya"); 
output.flush();
System.out.println("printing1");

while(data.hasNextLine()){
System.out.println(value);
try{value = Integer.parseInt(data.nextLine());}catch(Exception e){}
output.print("Received"); 
output.flush();
}
System.out.println("Done.");
data.close();
s.close();
}
};
//-here is the window1 class
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.UIManager;
public class Window1 extends JFrame{
/**
* 
*/
private static final long serialVersionUID = 1L;
JButton BigButton;

public Window1() {
super("Programmer");
setLookAndFeel();
this.setPreferredSize(new Dimension(400, 300));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FlowLayout flo = new FlowLayout();
setLayout(flo);
setVisible(true);  
}

private void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
);
} catch (Exception exc) {
// ignore error
}
}

}  
但我

不确定在用户按下按钮打开端口之前"停止"进一步执行的最佳实践。

我可以想到两种在等待用户输入时"暂停"Swing GUI 的主要方法:

  1. 如果程序应该完全停止,则将端口选择放入模型对话框中,例如 JOptionPane 或更通用的模式 JDialog。这可以防止调用代码(主 GUI(与用户交互,直到对话框不再可见(已处理(,或者
  2. 使用状态设计模式类型的程序,在选择端口之前,您根本不响应用户输入,例如将 if 块位于用户可能交互的位置,检查端口选择的状态并仅在端口选择有效之前处理用户交互。例如,您可以在其他侦听器(不涉及端口选择的侦听器(中有一个变量,SerialPort selectedPort = null;和其他侦听器中的其他地方位于顶部:if (selectedPort == null) { return; }

如果您想了解更多详细信息,请考虑创建并发布一个有效的最小、可重现的示例,我可以帮助您适应您的需求。请查看此宝贵工具的链接。


这是我的意思的一个例子。运行它以试用它。

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import javax.swing.*;
@SuppressWarnings("serial")
public class MyPortExample extends JPanel {
private JTextArea fromPortArea = new JTextArea(20, 40);
private Action sendAction = new SendAction("Send");
private Action setUpPortAction = new SetUpPortAction("Set Up Port", this);
private JTextField toPortField = new JTextField(35);
private JTextField portNameField = new JTextField(15);
private JButton sendTextBtn = new JButton(sendAction);
private PrintStream outFromPort = null;
private MockSerialPort serialPort = null;
public MyPortExample() {
portNameField.setFocusable(false);
JPanel topPanel = new JPanel();
topPanel.add(new JButton(setUpPortAction));
topPanel.add(portNameField);
JScrollPane scrollPane = new JScrollPane(fromPortArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
sendAction.setEnabled(false);
toPortField.setAction(sendAction);
fromPortArea.setFocusable(false);
JPanel sendPanel = new JPanel();
sendPanel.add(toPortField);
sendPanel.add(sendTextBtn);
setLayout(new BorderLayout());
add(topPanel, BorderLayout.PAGE_START);
add(scrollPane);
add(sendPanel, BorderLayout.PAGE_END);
}
public void setSerialPort(MockSerialPort port) {
this.serialPort = port;
outFromPort = (PrintStream) port.getOutputStream();
InputStream in = port.getInputStream();
new PortWorker(in, fromPortArea).execute();
portNameField.setText(port.getSystemPortName());
sendAction.setEnabled(true);
}
public MockSerialPort getSerialPort() {
return serialPort;
}
private class PortWorker extends SwingWorker<Void, String> {
private Scanner portScanner;
private JTextArea textArea;
public PortWorker(InputStream in, JTextArea fromPortArea) {
this.textArea = fromPortArea;
portScanner = new Scanner(in);
}
@Override
protected Void doInBackground() throws Exception {
while (portScanner.hasNextLine()) {
publish(portScanner.nextLine());
}
return null;
}
@Override
protected void process(List<String> chunks) {
for (String text : chunks) {
textArea.append(text + "n");
}
}
}
private class SendAction extends AbstractAction {
public SendAction(String name) {
super(name);
putValue(MNEMONIC_KEY, KeyEvent.VK_S);
}
@Override
public void actionPerformed(ActionEvent e) {
if (outFromPort != null) {
String text = toPortField.getText();
outFromPort.println(text);
toPortField.selectAll();
toPortField.requestFocusInWindow();
} else {
System.err.println("No output stream available");
}
}
}
private static class SetUpPortAction extends AbstractAction {
private MyPortExample myPortExample;
public SetUpPortAction(String name, MyPortExample myPortExample) {
super(name);
putValue(MNEMONIC_KEY, KeyEvent.VK_P);
this.myPortExample = myPortExample;
}
@Override
public void actionPerformed(ActionEvent e) {
int messageType = JOptionPane.PLAIN_MESSAGE;
MockSerialPort port = (MockSerialPort) JOptionPane.showInputDialog(myPortExample, "Please select a port",
"Port Selection", messageType, null, MockSerialPort.getCommPorts(), null);
if (port != null) {
myPortExample.setSerialPort(port);
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
MyPortExample mainPanel = new MyPortExample();
JFrame frame = new JFrame("MyPortExample");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private static class MockSerialPort {
public static final String TIMEOUT_READ_SEMI_BLOCKING = "timeout read semi blocking";
private String portName;
private int baudRate;
public MockSerialPort(String name) {
this.portName = name;
}
public String getSystemPortName() {
return portName;
}
public OutputStream getOutputStream() {
return System.out;
}
public InputStream getInputStream() {
return System.in;
}
public void setComPortTimeouts(String timeoutReadSemiBlocking, int i, int j) {
// TODO ??? not sure what goes here
}
public void setBaudRate(int baudRate) {
this.baudRate = baudRate;
}
public boolean openPort() {
return true;
}
@Override
public String toString() {
return portName;
}
public static MockSerialPort[] getCommPorts() {
List<MockSerialPort> ports = new ArrayList<>();
for (int i = 0; i < 20; i++) {
ports.add(new MockSerialPort("Port " + (i + 1)));
}
return ports.toArray(new MockSerialPort[] {});
}
}
}

GUI 被禁用,直到通过顶部的按钮选择端口,然后启用底部的 JTextField 和按钮以通过.setEnabled(true)将数据发送到端口。

它还包含一个我没有的串行端口类的"模拟"类。

最新更新