LoginSignup
3
2

More than 5 years have passed since last update.

JavaのGUIを別スレッドで立ててメインを生かす

Posted at

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の座標をキューで待たせておいて届いた順で描画しています。

WS000044.JPG

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");
            }
        });
    }

}
3
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2