2

Javaでシリアルモニターを作成しようとしていますが、立ち往生しています。JTextArea にテキスト (シリアル入力) を追加しようとしています。SwingWorker を使用してみましたが、いくつか成功しましたが、十分ではありませんでした。

入力データを読み取るイベント(SerialEventListener)があります。このイベントでは、着信データを別のクラスで宣言されている JTextArea に追加しようとしていますが、追加メソッドは機能しません。私はそれが機能しないはずであり、SwingWorkerを使用する必要があることを読みました。問題は、SwingWorker の実行プロセスが、ボタン イベントで実行するコマンドを与えた場合にのみ開始されることです。結論として、シリアルポートからデータを取得するときに、swingworker ルーチンを実行したいと考えています。例: serialevent(到着したデータ) -> appedrutine(swingworker) -> 終了 これは私のコードです:

グラフィック コンポーネントを保持するクラス: centerPanel

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.border.TitledBorder;


public class centerPanel implements ActionListener{

private JTabbedPane tabbed_pane = new JTabbedPane();
public JPanel tab_source    = new JPanel();
public JPanel tab_graphical = new JPanel();
private updateData updateText_method;
private JTextArea data_content = new JTextArea();
private JButton Freeze, Clear, Reload;

public centerPanel(){

    tabbed_pane.setBorder(new TitledBorder("Data visualization"));

    Freeze = new JButton("Freeze");
    Freeze.addActionListener(this);

    Clear  = new JButton("Clear");
    Clear.addActionListener(this);

    Reload = new JButton("Reload");
    Reload.addActionListener(this);

    BoxLayout box_layout = new BoxLayout(tab_source,BoxLayout.Y_AXIS);
    tab_source.setLayout(box_layout);

    data_content.setEditable(false);
    data_content.setForeground(Color.WHITE);
    data_content.setBackground(Color.DARK_GRAY);

    tab_source.add(new JScrollPane(data_content));

    JPanel temp_panel = new JPanel(new GridBagLayout());
    GridBagConstraints c = new GridBagConstraints();

    temp_panel.setBorder(new TitledBorder("Data control"));
    temp_panel.setPreferredSize(new Dimension(MainFrame.window_width,(int)(MainFrame.window_height*0.07)));
    temp_panel.setMaximumSize(new Dimension(MainFrame.window_width,  (int)(MainFrame.window_height*0.12)));

    c.gridx = 0;
    c.insets = new Insets(0,8,8,0);

    temp_panel.add(Freeze,c);
    c.gridx = 1;
    temp_panel.add(Clear,c);
    c.gridx = 2;
    temp_panel.add(Reload,c);

    tab_source.add(temp_panel,BorderLayout.LINE_END);

    tabbed_pane.addTab("Text mode",tab_source);
    tabbed_pane.addTab("Graphic mode",tab_graphical);

}

public JTabbedPane getTabs(){

    return tabbed_pane;

}

public void updateData(){

     updateText_method = new updateData(data_content);
     updateText_method.execute();

}

@Override
public void actionPerformed(ActionEvent event) {

    if(event.getSource() == Clear){

        updateData();

    }

}

}

これが私のserialMonitorクラスです(シリアルポートから読み取ります)

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.comm.CommPortIdentifier;
import javax.comm.SerialPort;
import javax.comm.SerialPortEvent;
import javax.comm.SerialPortEventListener;
import javax.swing.JOptionPane;


public class serialMonitor implements SerialPortEventListener {

private static CommPortIdentifier pid;
private static SerialPort port;
private InputStream inputstream;
private static OutputStream outputstream;
public static int data ;


public void openPort(String portname, int baudrate){

    System.out.println(new String(""+ baudrate + "xx" +portname));
    try {

         pid=CommPortIdentifier.getPortIdentifier(portname);

         port=(SerialPort)pid.open("owner",2000);
         port.setSerialPortParams(baudrate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
         outputstream=port.getOutputStream();
         inputstream=port.getInputStream();
         port.addEventListener(this);
         port.notifyOnDataAvailable(true);

     } catch (Exception e) {
         e.printStackTrace();
         JOptionPane.showMessageDialog(new Frame("Info"), "Connection problems!");} 


}

public void closePort(String mesaj){

    try{
         port.close();
       } catch (Exception e) {JOptionPane.showMessageDialog(new Frame("Info"), "Connection problems!");}

}

@Override
public void serialEvent(SerialPortEvent sE) {

    try {

        inputstream=port.getInputStream();

    } catch (Exception e) {

        JOptionPane.showMessageDialog(new Frame("Info"), "Connection problem! Cant read data from quadcopter");
    }

    if (sE.getEventType()==SerialPortEvent.DATA_AVAILABLE) {

        try
        {
            while ( ( data = inputstream.read()) > -1 ){

              System.out.println(data);

              { 
                 //This is where i want to make the update
                 //something like centerPanel_obj.updataData()
                 //
              } 

            }

        }
        catch ( IOException e )
        {
            e.printStackTrace();
            System.exit(-1);
        }

    }



}





}

これが私のupdataDataクラスです(SwingWorkerがある場所)

import java.util.List;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;

public class updateData extends SwingWorker<Integer, String> {

private final JTextArea messagesTextArea;

public updateData(final JTextArea messagesTextArea) {
this.messagesTextArea = messagesTextArea;
}

 @Override
 protected Integer doInBackground() throws Exception {

int i;
  for ( i = 0; i<50; i++) 
    publish(new String(""+i));

 return 1;

}

@Override
protected void process(final List<String> chunks) {

for (final String string : chunks) {
  messagesTextArea.append(string);
  messagesTextArea.append("\n");
  }
}

}

注: 私は自分のコードと説明に関するすべての批評を受け入れます。ありがとうございました!

4

1 に答える 1

2

あなたが取り組めることがたくさんあります。しかし、私はあなたに基本を与えます。

エンド ユーザーがアプリケーションで行うことはすべて、意図的に別のスレッドに配置しない限り、単一のスレッド (イベント ディスパッチ スレッド (EDT)) で実行されます。そのため、ユーザーがボタンをクリックして、しばらく時間がかかる操作を開始すると、操作が完了するまで UI がフリーズします。

これを回避する簡単な方法は、作業を行う新しいスレッドを開始することです。

しかし... また、UI の更新も EDT で行う必要があることを考慮する必要があります (ああ、いや!)。 SwingUtilities.invokeLater(Runnable doRun)は、プロセスをキューに入れて EDT で実行できるようにするために作成されました。

SwingWorker の仕事は、このリガマロール全体を簡単にすることです。1) EDT から離れたスレッドでのコードの実行、および 2) EDT のスレッドでのコードの実行 (最初のスレッドが終了した後) のためのインターフェースを提供します。


さて、あなたの質問から不明確なことがいくつかあります:

  • serialMonitorコードの一部でさえありません-あなたがそれで何をしたいのかわかりません
  • ユーザー アクションによって UI の更新をトリガーするか、シリアル ポートでのイベント (通信) によって更新をトリガーする必要があるかは不明です。

SerialMonitor独自のスレッド (EDT ではなく) で既に実行している場合は、UI を更新する必要があるときはいつでも、次のように呼び出しをラップするだけです。

SwingUtilities.invokeLater(new Runnable(){

    @Override
    public void run() {
        //Insert your code to update UI here
    }
});

SerialMonitor更新するには、UI ピースへのアクセスを許可する必要があります。

于 2013-07-17T17:46:45.390 に答える