Imaginary Code

from kougaku-navi.net

Processingでシリアルポート選択のUIを作る(JComboBox版)

ProcessingでArduinoとかとシリアル通信するとき、ポートと通信速度をリストから選べるUIが欲しいですよね。はい、作りましょう。

f:id:kougaku-navi:20200226210449p:plain

import processing.awt.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import processing.serial.*;

class SerialSetting {
  final int COMBO_PORT_WIDTH  = 100;
  final int COMBO_PORT_HEIGHT = 20;
  final int COMBO_RATE_WIDTH  = 80;
  final int COMBO_RATE_HEIGHT = 20;  
  final Integer[] list_rate = {300, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200, 230400, 250000, 500000, 1000000, 2000000};  
  String[] list_port = null;

  JComboBox combo_port;
  JComboBox combo_rate;
  String current_port = null;
  int    current_rate = 0;

  Serial serial = null;
  PApplet parent = null;

  SerialSetting(PApplet app, int x, int y, String default_port, int default_rate) {
    parent = app;
    String[] list_port = Serial.list();

    Canvas canvas =(Canvas)surface.getNative();
    JLayeredPane pane =(JLayeredPane)canvas.getParent().getParent();

    // combobox(port)
    combo_port = new JComboBox(list_port);
    combo_port.addActionListener( new SelectActionListener() );
    combo_port.setBounds( x, y, COMBO_PORT_WIDTH, COMBO_PORT_HEIGHT);
    pane.add(combo_port);

    // combobox(rate)
    combo_rate = new JComboBox(list_rate);
    combo_rate.addActionListener( new SelectActionListener() );
    combo_rate.setBounds(x + COMBO_PORT_WIDTH + 10, y, COMBO_RATE_WIDTH, COMBO_RATE_HEIGHT);
    pane.add(combo_rate);

    // select items
    combo_port.setSelectedItem(default_port);
    combo_rate.setSelectedItem(default_rate);    
    combo_port.updateUI();
    combo_rate.updateUI();
  }
  
  class SelectActionListener implements ActionListener {
    @Override
      public void actionPerformed(ActionEvent e) {

      // update params
      current_port = (String)combo_port.getItemAt(combo_port.getSelectedIndex());
      current_rate = (int)combo_rate.getItemAt(combo_rate.getSelectedIndex());      

      // connect
      if ( serial != null ) {
        serial.stop();
      }
      if ( current_port != null ) {
        serial = new Serial(parent, current_port, current_rate );
      }
    }
  }
}

// -----------------------------------------------------------------------------------
// ここから下がメインプログラム。ここより上を別ファイルにすると良い。

SerialSetting setting;

void setup() {
  size(400, 300);

  // 表示位置 x=30, y=20, デフォルトのポート=COM16, デフォルトの速度=115200
  // ここで指定したポートおよび速度が実際のリストにない場合は、リスト先頭のものが選ばれる。
  setting = new SerialSetting(this, 30, 20, "COM16", 115200);
}

void draw() {  
}

void serialEvent(Serial port) {
  if ( port.available() > 0 ) {
    String s = port.readStringUntil('\n');
    if ( s != null ) {
      print(s);
    }
  }
}

以前も作った

以前にもこういうの作ってるんですが、前回はリストの表示にControlP5を使ってて、今回はSwingのJComboBoxを使ってます。
kougaku-navi.hatenablog.com

メモ

  • Processing v3対応。PAppletまわりの仕様が2→3で変わってるので2.xでは使えないかも。
  • プログラム実行中にUSBケーブルを抜き差ししたときにリフレッシュできるようにしたかったんですが、ケーブルを抜いてからポートのリストが更新されるまで数秒ラグがあるみたいで、そのせいで存在しないポートに接続しようとして怒られる、みたいなことになって結局あきらめました。基本、プログラム実行中にケーブルを抜くのはやめましょう。
  • シリアルポートを同時に2個以上使いたいときにSerialSettingオブジェクトを2個作ると、コンフリクトが発生するかも。