1


我正在开发仓库管理软件(用于存放衣服)。仓库中的所有物品内部都有 rfid,唯一的 id 存储为字符串。
我正在尝试制作允许用户通过天线从项目中读取 rfid 并自动在其中一个 GUI 中显示接收到的 ID 的模块jLabels。天线通过 与 PC 连接rs232
我设法让课程从天线读取数据,它工作正常。它打开通信端口,设置属性并在可用时读取数据(通过SerialPortEvent.DATA_AVAILABLE event)。
但是后来我遇到了问题:
我希望该类的实例在不同的线程中运行,因此天线将等待扫描,并且每次扫描后 jLabel 都会根据项目的 ID 进行更改(稍后我将对与我的数据库连接的这个 ID 进行更复杂的操作,但现在我只是希望它显示在某个地方)。
我正在开始我的 Java 冒险,但我不知道如何处理多线程。
在这种情况下,我想从我的 Netbeans GUI 开始扫描jFrame,当扫描正在进行时,应该根据最后扫描jFrame的项目动态刷新值。场景:用户按下按钮开始扫描,扫描一定数量的项目,每个扫描项目的 ID 转到jLabel

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    
4

2 回答 2

1

从您的串行端口读取线程执行以下操作:

SwingUtilities.invokeLater(new Runnable() { public void run() {
  // code that updates the label's contents
}});

所以这是一种推送方法:您不拉 rfid,而是将其推送到 GUI 中,特别注意此类代码在事件调度线程 (EDT) 上执行。这invokeLater就是为了。

于 2012-04-12T11:22:04.337 回答
1

1) 方法setText()被声明为线程安全的,但在当前线程未被冻结之前一直有效Thread.sleep(int)

2) 方法setText()工作包在invokeLater()from Runnable#run()orutil.Timer#run()中,但您Thread.sleep(int)在这些 API 之外,然后可能会将事件锁定到EventDispatchThread

3)您CommPort从 开始ActionListener,然后 Swing GUI 被冻结或不负责任,直到所有事件ActionListener结束,什么都不能显示JLabel

4)您必须移动(从 CommPort 读取值)到后台任务

  • CommPortRunnable.Thread或从调用util.Timer(然后不需要通过 using 暂停循环Thread.sleep()

但最好的,我建议使用

  • 调用 from SwingWorker,然后您可以在方法内部使用Thread.sleep()or并从方法输出,或者可以在上调用事件util.TimerdoInBackground()publish()process()EDT
于 2012-04-12T11:40:58.727 回答