しいしせねっとAmazon.co.jp アソシエイト
[Java] [J2EE]

Java AWTのいろいろ

意外と知られていないAWTの正しい使い方?

java.awt.Window

作って閉じる

Window や Frame は、dispose() でリソースを開放する。WindowEvent.WINDOW_CLOSEDを発行する?

×ボタンを押してから閉じるまで、いろいろ処理があります。基本的な手順はこんなかんじ?

  1. WindowListener を登録
  2. ×ボタンが押される
  3. windowClosing イベントが起きる
  4. windowClosing 内で dispose() を呼び出し対象ウインドウを破棄する。
  5. windowClosed イベントが起き、ウインドウやスレッドが他にないなら何もしなくても終了します。

入門書などで紹介されている windowClosing() のなかで System.exit() をしてしまう強引な作法は、なんとなく怖いですね。dispose() でリソースが破棄されると、他にスレッドがなければ勝手に終了してくれるので System.exit() などは使わない方がいいです。

WindowListener を使わなくていい方法もあります。

JFrame.setDefaultCloseOperation() です。こっちの方がお手軽かも。やってることは System.exit() みたいなものですが。

java.awt.Component

サイズ指定

Componentなどのサイズを指定するには、3つのサイズがあります。

最小サイズ(minimumSize)、最大サイズ(maximumSize)、推奨サイズ(preferredSize)。

この内、LayoutManagerを使うときに指定しなければならないのは、推奨サイズのようです。

minimumSizeやsizeだけを指定してみても、小さくなってしまう場合があります。

AWTで画像を読む

アプレットやアプリケーションで画像を読み込み表示するのは、いったいどうすればいいのか?
アプレットの場合は、本を立ち読みでもすれば簡単にわかるが、アプリケーションの場合は、なかなか載っている本が無い。
よくこれでJDK1.0の頃・・・使えてたな・・・(^^;

アプレットで画像を読み込む

アプレットで画像を読み込む場合は、java.applet.Applet#getImage() メソッドを使う。

このメソッドでは画像を読み込み終わる前にすぐに次の処理に移ります。表示してみると徐々に読み込まれていくのがわかるかもしれません。アプレットを待たせないための策なのですが、一般的な処理には向かないこともあるのでMediaTracker で読み終わるまで待つこともできます。

JPEG, GIF が読み込めますがPNGなどは無理かもしれません。

アプリケーションで画像を読み込む

アプリケーションの場合は、あまり表向きのAPIが用意されていません。どうするかというと、裏方的な存在であるjava.awt.Toolkitクラスを使います。

ComponentからToolkitをgetToolkit()で取得、Toolkitクラスを使って画像を読み込む。Toolkit.getDefaultToolkit() でもいいのですが、どうなんでしょな。

あとは、Toolkit.createImage() などで画像が読み込めます。ファイルに限らずGIF、JPEGなどのバイト列からImage化することもできます。

Swing なら ImageIcon

Swingアプリケーションでただ画像を表示したいだけなら、ImageIcon クラスを使うのも手軽かもしれません。

Java Image I/O を使おう

J2SE 1.4 からは、 Java Image I/O (javax.imageio) によって画像が読み書きできるようになりました。

取得できるのは BufferedImgae です。サポートされている画像形式が他より多いかも?

Java Advanced Imaging ではさらに他の方法も?

参考

画像の基本

Javaで使える画像と呼ばれるものには、いくつかのクラスがあります。それぞれ微妙に役割が違ってくるかもしれません。

java.awt.Image, BufferedImage

JDK 1.0からある、基本的な画像格納クラスです。アニメーションGIFや透過GIFにも対応していたり、ときどき変なやつです。

データの保存にはBufferedImage の方が適していますが、それでも使いにくいところは多々あります。

java.awt.Canvas

こちらは表示のための画像保持をするところです。表示のためのものなので、アプリケーションから中身を読んでみたり、別のImageやCanvasへコピーしたりという用途には向かないかもしれません。画面に依存してビット深度なども変わるかもしれない。

javax.swing.ImgaeIcon

Swingの部品として利用できるものです。あまり使ったことはありませんが、止め絵には最適でしょうか。Canvas の後継みたいなものですかね。

表示する

表示するには、Componentのpaint(Graphigs g) メソッドの中で、g.drawImage()する。drawImage()のパラメータの中でよくわからないのがImageOvserverである。ImageObserverは、画像が読み込まれたことを通知してもらうクラスで、読み込まれたら再表示するようにしようという・・・なのかもしれない。

ちらつき防止

ちらつき防止は、update(Graphics) メソッドを変えますが、このとき、paint(Graphics)を呼び出していませんか?

Image im; // imは、updateの先頭で毎回作るか、あらかじめ準備する
public void update(Graphics g) {
    Graphics g2 = im.getGraphics();
    super.update(g2);
    g.drawImage(im);
}

これだけでいいのです。Swingでは最初からちらつき防止処理がされているようです。

また、複数のAWT/Swing部品を組み合わせて画面を構成している場合には、更新が必要な部品だけrepaint()メソッドを使用することをおすすめします。

レイアウトしない

レイアウトマネージャは、環境に依存しない方法でレイアウトができるという点では便利なのですが、細かな調整をしたいこともよくあります。
そんなときには、setLayout(null)で、レイアウトマネージャを無効にしてしまうこともできます。
レイアウトマネージャを無効にしてしまうと、誰もコンポーネントを配置してくれないので、Component#setBounds()(だったかな・・・)を使って、自分でコンポーネントの位置決めをします。

イベントモデル

マウスの座標やボタンの状態を取得することができます。どのようにすればよいのでしょうか。
ここでは、JDK1.1以降で使われている形式を扱います。もう1.0使っているところもないでしょう・・・。

マウスの動きの受け取り方にはいくつかの方法があります。

  1. 単純にマウスの動きを知りたい場合
  2. ボタンなどのAWT部品が押された場合
  3. メニューなど
  4. Drag&Dropがしたい

これらは、だいたい同じようにして実現できます。大抵はjava.awt.event パッケージのイベント処理という形で処理されます。
各動作はイベンとという形でプログラムに通知されます。各種のイベントを受け取るには、イベントリスナーというインターフェースを継承して、対象となるAWT/Swingパーツにその継承したオブジェクトを登録します。リスナーとなるクラスとAWT/Swingのパーツは全く別のものでかまいません。イベントの処理だけなら、AWT/Swingクラスを継承しないで、イベントインターフェースを使うだけにするほうがよいです。

1.マウスの動きを知りたい場合。java.awt.event.MouseListenerと、MouseMotionListener かな。

mouseMoved() mouseClicked() などのメソッドで、MouseEvent を取得して、そこから座標やボタンの状態を得ることができます。作ったオブジェクトは、 AWT/Swing部品に、addMouseListener() などのメソッドがあるので、それを使って登録します。

2.と3,AWTボタンやメニューなどのAWT/Swing部品の場合は、java.awt.event.ActionListener を使います。

actionPerformed(ActionEvent e) を継承し、イベントを処理します。

Drag & Drop

java.awt.dnd になにやらあるようです。なかなか仕様は日本語になってくれませんね。
どちらかというと、Drop(受け側)の方から作ってみるのが簡単そうです。

Drag側のプログラム

Drop側のプログラム

import java.awt.*;
import javax.swing.*;
import java.awt.dnd.*;
import java.awt.datatransfer.*;

public class TestApplocation implements DropTargetListener {
    JFrame frame;
    DropTarget dt; // Drop処理をしてくれるjava.awt.dnd.DropTargetクラス

    TestApplication() {

        frame = new JFrame("Test");
        frame.getContentPane().add(new JPanel()); // this でも new JPanelでもなんでもいい dropしたいコンポーネント
        frame.setSize(640,340);
        frame.setVisible(true);
        frame.setDropTarget(dt = new DropTarget()); // frame か JPanelどっちでもDropしたい方のsetDropTarget()を使う
        try {
           dt.addDropTargetListener(this); // 受け取るリスナー
        } catch (java.util.TooManyListenersException e) {
       }

        // dt = new DropTarget(frame, this): の方が楽かも
    }

    public void drop(DropTargetDropEvent dtde) {
        // 受け取れる型の一覧を出してみる
        java.awt.datatransfer.DataFlavor[] dfs;
dfs = dtde.getCurrentDataFlavors();
for (int i = 0; i < dfs.length; i++) {
System.out.println(dfs[i].getMimeType());
}
// 受け取る方法を指定 dtde.acceptDrop(java.awt.dnd.DnDConstants.ACTION_COPY); // 受け取る 型Object obj = (型変換)dtde.getTransferable().getTransferData(dfs[何番目か]); } public static void main(String[] argv) { new TestApplication(); } }

こんな感じ。MouseListenerとあまり変わりませんが、いろいろな型のなかからどの型で受け取るのかの指定が大変かもしれません。

drop() 以外に dragEnter() などでも同じような処理でドラッグ中にデータを受け取ってしまうことができます。そのときには acceptDrop() の指定はいらないようです。

参考

Get Thunderbird

しいしせねっと