Hatena::ブログ(Diary)

Imaginable Reality

2014-07-22

PAppletの中でさらにPAppletを動かす

Processingで画面内に独立した描画領域を作りたいときのテクニックです。PGraphicsを使う方法もありますが、ここではPAppletを使う方法を紹介します。

f:id:kougaku-navi:20140722191250g:image

LocalApplet local_app;

void setup() {
  size(500, 300);
  local_app = new LocalApplet(this);
  local_app.setLocation(50, 50);
}

void draw() {
  background(255);
  if ( mousePressed ) {
    fill(0, 0, 255);
  } else {
    fill(0, 255, 255);
  }
  ellipse(mouseX, mouseY, 100, 100);
}

void keyPressed() {
  // This does not work
  println("keyPressed in global");
}

void mousePressed() {
  println("mousePressed in global");
}


class LocalApplet extends PApplet {

  LocalApplet(PApplet app_parent) {    
    init();
    app_parent.setLayout(null);
    app_parent.add(this);
  }

  void setLocation(int x, int y) {
    setBounds( x, y, this.width, this.height );
  }
  
  void setup() {
    size(300, 200);
  }

  void draw() {
    background(50);
    if (mousePressed) {
      fill(255, 0, 0);
    } else {
      fill(0, 255, 0);
    }
    ellipse( mouseX, mouseY, 100, 100 );
  }

  void keyPressed() {
    println("keyPressed in LocalApplet");
  }

  void mousePressed() {
    println("mousePressed in LocalApplet");
  }
}

解説

独立した描画領域の処理を担っているのはLocalAppletというクラスです。このクラスはPAppletの派生クラスとして作られているので、setup()やdraw()、mousePressed()などのイベント処理を持つことができます。

LocalAppletのコンストラクタ内で行われている処理について順番に説明します。まず、init()によってPAppletの初期化処理をやります。これをやらないとPAppletでの描画処理がはじまりません。その次にsetLayout(null)をやっているのはsetBounds()による配置処理を有効にするためです。最後にapp_parent.add(this)によって、親のPAppletが埋め込まれているフレームに対して自分(LocalApplet)を追加します。

LocalAppletの描画領域内でマウスをクリックしたときはLocalAppletの中にあるmousePressed()が反応し、領域外にカーソルがあるときは、グローバルで定義されているmousePressed()が反応します。

一方、キーイベントについてはLocalAppletのほうに奪われてしまうようなので注意してください。なにか回避方法があるかもしれませんが…(´・ω・`)


【2015/08/25追記】

キーイベントがLocalAppletのほうに奪われちゃう問題に関しては、LocalAppletのキーイベント関数の中で、親のキーイベント関数を呼び出す作りにするのが一手かな。