GUIをサブの処理で使いたい
GUIをメインの処理と別に立てたい場合の処理です。
例えば、言語処理系を記述していたとして
処理系が処理するスクリプトからフレームを作るように命令されたとき、
処理系はフレームを立てなければなりません。
これはJFrame frame = new JFrame();
だけ実行すれば済む話でしょうが、
Frameにボタンをつけたり、描写したりするよう命令されると話は別です。
Canvasクラスをframeに追加したとします。canvasのpaintメソッドをオーバーライドしますが、paintメソッドはコーダが呼び出すのではなく、frame側が必要なとき呼び出すのです。
これは少し厄介です。本当は処理系がframeに描写命令を与えたいところですが、frameがcanvasに描写命令を出すのです。この流れだとcanvasが処理系を呼び出す破目になります。
今は言語処理系に限った話をしましたが、CUIからGUIの操作をしたい場合なども当てはまるでしょう。
GUIをメインスレッドと別スレッドに立てる
Threadを継承したクラスでrunをオーバーライドします。
このrun内でGUIの生成を行います。そして、mainではGUIのクラス類には触らず、
このThreadを継承したクラスをstartして利用します。
データのやり取りはLinkedBlockingQueueを使う
クラスLinkedBlockingQueue
このクラスはtakeするときは要素が来るまでthreadを待たせたり、簡単に排他制御を行えます。
GUIはこのキューを見ることで処理をこなしていきます。
サンプル
以下のプログラムはlineの座標をキューで待たせておいて届いた順で描画しています。
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;
import javax.swing.JFrame;
public class Test {
public static LinkedBlockingQueue<int[]> drawQueue = null;
static {
drawQueue = new LinkedBlockingQueue<int[]>();
}
public static void main(String[] args) {
Thread canvasThread = new CanvasThread();
canvasThread.start();
Random rand = new Random(System.currentTimeMillis());
for (int i = 0; i < 120; i++) {
drawQueue.add(new int[] { rand.nextInt(CanvasThread.WIDTH),
rand.nextInt(CanvasThread.HEIGHT),
rand.nextInt(CanvasThread.WIDTH),
rand.nextInt(CanvasThread.HEIGHT) });
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
drawQueue.add(new int[]{});
}
}
class CanvasThread extends Thread {
public static final int HEIGHT = 400;
public static final int WIDTH = 600;
@Override
public void run() {
JFrame frame = new JFrame("test");
frame.setSize(WIDTH, HEIGHT);
frame.setVisible(true);
frame.add(new Canvas() {
@Override
public void paint(Graphics g) {
System.out.println("print start");
int[] x = null;
Random rand = new Random(System.currentTimeMillis());
try {
while ((x = Test2.drawQueue.take()).length == 4) {
g.setColor(new Color(rand.nextInt(256), rand
.nextInt(256), rand.nextInt(256)));
g.drawLine(x[0], x[1], x[2], x[3]);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("paint end");
}
});
}
}