我正在研究用于仓库管理的软件(用于存放衣服)。仓库中的所有项目都在里面有rfid,唯一的id存储为String。我正在尝试创建一个模块,允许用户从逐个项目中读取rfid,并自动在GUI jLabels
之一中显示收到的ID。天线通过rs232
与PC连接。我设法让班级从天线读取数据并且工作正常。它打开通信端口,设置属性并在可用时读取数据(通过SerialPortEvent.DATA_AVAILABLE event
)。
但后来我遇到了问题:
我希望该类的实例在不同的线程中运行,因此天线将等待扫描,每次扫描后,jLabel将根据项目的ID进行更改(稍后我将对与此数据库连接的此ID进行更复杂的操作,但现在我只是希望它显示在某处。)
我正在开始我的Java冒险,我不知道如何处理多线程
在这种情况下,我想从我的Netbeans GUI jFrame
开始扫描,当扫描正在进行时,jFrame
应根据上次扫描的项目动态刷新jLabel
的值。
场景:
用户按下按钮开始扫描,扫描一些项目,每个扫描项目的ID在扫描之间的时间内转到jLabel (jReadLabel)
,扫描完成后用户按下按钮停止,所以应用程序知道何时停止该线程
我在我的ReadCOM类(getChipID()
)中创建了getter方法,但我不知道每次事件发生时如何将数据传递给jFrame。
这是我到目前为止所做的:
import java.io.*;
import java.util.*;
import javax.comm.*;
public class ReadCOM implements Runnable, SerialPortEventListener {
static CommPortIdentifier portId;
static CommPortIdentifier saveportId;
static Enumeration portList;
InputStream inputStream;
SerialPort serialPort;
public static Thread readThread;
static OutputStream outputStream;
static boolean outputBufferEmptyFlag = false;
public String defaultPort;
boolean isRunning = true;
private String chip_id="";
public CzytajCOM(CommPortIdentifier portId, String defaultPort) {
this.defaultPort = defaultPort;
try {
serialPort = (SerialPort) portId.open("Magazyn", 2000);
} catch (PortInUseException e) {
System.out.println("Connection Error. Port in use.");
}
try {
inputStream = serialPort.getInputStream();
} catch (IOException e) {
}
try {
serialPort.addEventListener(this);
} catch (TooManyListenersException e) {
}
serialPort.notifyOnDataAvailable(true);
try {
serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
} catch (UnsupportedCommOperationException e) {
}
readThread = new Thread(this);
readThread.start();
}
public void initwritetoport() {
try {
outputStream = serialPort.getOutputStream();
} catch (IOException e) {
}
try {
serialPort.notifyOnOutputEmpty(true);
} catch (Exception e) {
System.exit(-1);
}
}
public void writetoport() {
}
public void run() {
while (isRunning) {
try {
while (isRunning) {
Thread.sleep(100);
}
} catch (Exception e) {
isRunning = false;
}
}
}
public void serialEvent(SerialPortEvent event) {
switch (event.getEventType()) {
case SerialPortEvent.BI:
case SerialPortEvent.OE:
case SerialPortEvent.FE:
case SerialPortEvent.CD:
case SerialPortEvent.CTS:
case SerialPortEvent.DSR:
case SerialPortEvent.RI:
break;
case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
break;
case SerialPortEvent.DATA_AVAILABLE:
Object obj = event.getSource();
if (obj instanceof javax.comm.SerialPort) {
serialPort = (SerialPort) obj;
try {
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(serialPort.getInputStream()));
chip_id = bufferedReader.readLine();
//System.out.println("Data: "+chip_id);
bufferedReader.close();
} catch (Exception ex) {
System.out.println("Reading from device failed!");
}
}
break;
}
}
public boolean isRunning() {
return isRunning;
}
public String getChipId() {
return chip_id;
}
public void setIsRunning(boolean isRunning) {
this.isRunning = isRunning;
}
} 在我的jFrame文件中,这里是ButtonActionPerformed的代码(启动和停止阅读的按钮,我丢失的部分......):
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
if(isRead==false) {
jStatus.setText("Reading in progress...");
jLabel1.setText("Press the button to stop reading.");
isRead=true;
try {
portId1=CommPortIdentifier.getPortIdentifier("COM4");
ReadCOM reader=new ReadCOM(portId1, portId1.getName());
reader.setIsRunning(true); //
jReadLabel.setText(reader.getChipId());
}
catch (Exception ex){
System.out.println("Error in button pressed method.");
}
}
else {
jStatus.setText("Reading stopped.");
jLabel1.setText("Press the button to start reading.");
isRead=false;
}
}//GEN-LAST:event_jButton1ActionPerformed
答案 0 :(得分:1)
从串口读取线程执行:
SwingUtilities.invokeLater(new Runnable() { public void run() {
// code that updates the label's contents
}});
所以这是一种推送方法:你不拉动rfid,你将它推入GUI,特别注意在Event-Dispatching Thread(EDT)上执行这样的代码。这就是invokeLater
的用途。
答案 1 :(得分:1)
1)方法setText()
被声明为线程安全但工作直到当前线程没有被Thread.sleep(int)
冻结,
2)方法setText()
包含在invokeLater()
或Runnable#run()
的{{1}}中,但您的util.Timer#run()
不在这些API之内,因此可能锁定事件到Thread.sleep(int)
3)您从EventDispatchThread
打开CommPort
,然后Swing GUI冻结或不是不负责任的,直到ActionListener
的所有事件都结束,ActionListener
中无法发送任何内容
4)你必须移动(从CommPort读取值)到后台任务
JLabel
或CommPort
调用Runnable.Thread
(然后不需要使用util.Timer
暂停循环)但最好的,我建议使用
Thread.sleep()
调用,然后您可以在方法SwingWorker
内使用Thread.sleep()
或util.Timer
,方法doInBackground()
或publish()
的输出可以是在process()