[Work/Class/Java with Processing/4_SwingInProcessing]

アート系学生のためのJAVA with Processing - その4-6 Processingのウィンドウをもう一つ作り,そちらをメイン表示にする.

導入

前項でコントーラを分離したので,今度は表示部分を別のProcessingのWindow,つまりPAppletを継承したクラスによって定義する.

注意点はsize関数である.(Processing3以降)PAppletを継承したクラスを定義すると,void setup()中でウィンドウサイズを指定するsize()関数が使えないので,別にpublic void settings()という関数を用意し,その中でsize()関数を実行する.

それ以外通常void setup()関数内で実行する関数は普通に使うことができる.

コード

//SwingInProcessing_YATP5Window
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

String actionCommand;
boolean inStopMode;

// インナークラスとして定義するProcessing第2のウィンドウ
YATP5Window yatP5Window;
// 前項と同じくインナークラスとして定義するコントロールウィンドウ
ControlWindow controlWindow;

void setup(){
  // not use this PApplet Class
  // 本来のProcessingのメインウィンドウであるこの大元のPAppletを継承したクラスは使わない

  // PAppletを起動するのに必要な引数Stringの配列を指定.ここではウィンドウの名前だけ
  String[] args = {"Child Window"};
  
  // PAppletを継承したクラス,Processing第2のウィンドウのオブジェクトインスタンスを生成
  yatP5Window = new YATP5Window();

  // Static Method of PApplet Class 
  // to run child window as sketch
  // PAppletを継承したクラスのオブジェクトインスタンス化後の初期化する静的メソッド
  // ここでは名前とオブジェクトインスタンスを渡す
  PApplet.runSketch(args, yatP5Window);
  
  // 前項と同じくコントローラウィンドウの生成
  controlWindow = new ControlWindow(this);
  inStopMode = true;
  
  // Only Initialize Child Windows 
  // in this Parent Window setup()

  // Processing本来のウィンドウのsetup()では他に何もしない
}

void draw(){
  // Nothing to Draw in Parent Window
  // draw()でも何もしない
}

void eventsCalledFromControlWindow(){
  // コントーラがイベントを検知した時に呼ぶ関数
  if(actionCommand.equals("startButton_Pushed"))
    inStopMode = false;
  else if(actionCommand.equals("stopButton_Pushed"))
    inStopMode = true;
}

class YATP5Window extends PApplet{
  // Processingの第2のウィンドウ PAppletを継承して作る
  // インナークラスとして設計
  int xPos, yPos;

  YATP5Window(){
    // Constructor
    // コンストラクタ
    super();

    // 親クラスのコンストラクタを呼ぶだけならば,
    // コンストラクタの定義は実は必要がない
    // 配列等,プリミティブ型の変数以外のインスタンス化を伴う場合,コンストラクタが必要
  }
  
  @Override
  public void settings(){
    // For second PApplet window
    // not write size() in "void setup()"
    // write into "public void settings()"
    // PAppletやそれを継承したクラスのオブジェクトが複数存在する場合,
    // ウィンドウサイズを指定するsize()関数だけは,本来のsetup()内ではなく,
    // settings()内に書かなければならない.
    // 複数PAppletウィンドウがある場合,
    // 元のメインスケッチクラスでも,settings()内でthis.size()を実行しなければならない
    this.size(640, 480);
  }
  
  @Override
  void setup(){
    //それ以外は通常のProcessingのsetup関数を書く
    this.colorMode(RGB, 255);
    this.background(255, 255, 255);
    this.frameRate(10);
    inStopMode = true;
  }
  
  @Override
  void draw(){
    this.fill(255, 255, 255, 60);
    this.rect(0, 0, this.width, this.height);
    
    this.fill(60, 60, 60, 0);
    this.ellipse(this.xPos, this.yPos, 30, 30);
    if(!inStopMode){
     this.xPos += 10;
     this.yPos += 10;
    }
  }
}

class ControlWindow extends JFrame implements ActionListener{
  // 前項のコントローラウィンドウのまま
  // インナークラスとして設計
  JButton startButton, stopButton;
  JTextField textField;
  JPanel panel; 

  SwingInProcessing_YATP5Window parentWindow;
  
  ControlWindow(SwingInProcessing_YATP5Window parentWindow){
   //Constructor 
   super("Control window");
   // Set the Parent Window
   this.parentWindow = parentWindow;
   
   this.setSize(320, 240);
   panel = new JPanel();
   panel.setLayout(new BorderLayout());

   startButton = new JButton("Start");
   startButton.setActionCommand("startButton_Pushed");
   startButton.addActionListener(this);
   panel.add(startButton, BorderLayout.NORTH);
   stopButton = new JButton("Stop");
   stopButton.setActionCommand("stopButton_Pushed");
   stopButton.addActionListener(this);
   panel.add(stopButton, BorderLayout.SOUTH);
   textField = new JTextField("Control Panel Text Field");
   panel.add(textField, BorderLayout.CENTER);

    // JFrameの一番奥の表示格納領域(Content Pane)を持ってきて,
    // そこに今までボタンなどを追加してきたpanelを追加して表示できるようにする.
    this.getContentPane().add(panel);
  
   this.setVisible(true);
  }
  
  @Override
  public void actionPerformed(ActionEvent e){
    // インナークラスでは,外のクラスの変数をそのまま使える
    // 外のクラス(メインスケッチ)の,actionCommand変数に代入する
    actionCommand = e.getActionCommand();
    textField.setText(actionCommand);

    // 外のクラスの関数を呼ぶ
    //(関数の判断に必要なactionCommand変数は外のクラスが持っているので,引数で渡さない)
    parentWindow.eventsCalledFromControlWindow();

    // 逆にこのControlWindowクラスを外部クラス
    // つまりProcessingのIDEでタブを作ってそちらに配置する場合は,
    // actionCommand変数は,このControlWindowクラスが持って,
    // 外のクラス(メインスケッチの)parentWindow.eventsCalledFromControlWindow()関数を呼ぶときに引数で渡す
  }
}
SwingInProcessing_YATP5Window.pdeの実行結果.前項で作ったコントロール用のウィンドウに加え,Processingの2番目のウィンドウが表示され,そこに描画されている.

前項で作ったコントロール用のウィンドウに加え,PAppletクラスを継承して作ったProcessingの2番目のウィンドウが表示され,そこにアニメーションが表示される.本来のProcessingで作られるウィンドウには何も表示しない.

(Processingは大元のmain関数がPAppletであり,main関数が入っているウィンドウを消すのにはさらなる手間が必要であるため,とりあえず表示させておく)