Canvasクラスは、Drawableインターフェイスの実装クラスで、Compositeクラスのサブクラスです。 Canvasクラスは、任意の描画をするために用意されたキャンバスとして利用されます。
Canvas(Composite parent, int style)style引数には、NO_MERGE_PAINTS、NO_FOCUS、NO_REDRAW_RESIZE、NO_BACKGROUNDを指定することができます。
canvasにGCオブジェクトを使用して円を描画するサンプルプログラムです。 canvasへの描画作業は、ウィンドウをオープンしてからです。 shell.open()の命令によってウィンドウが作成されるまで、ウィンドウ自体が表示されていないので、 そこに描画してもなんの意味もなさないからです。
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class CanvasDrawDemonstrate {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setText("CanvasDrawDemonstrate");
Canvas canvas = new Canvas(shell, SWT.NONE);
canvas.setBounds(0, 0, 100, 100);
shell.pack();
// まずウィンドウをオープンする
shell.open();
/* canvasに円を描く */
// GCインスタンス作成
GC gc = new GC(canvas);
// canvasのサイズを取得
Point canvasSize = canvas.getSize();
// canvasいっぱいに円を描く
gc.drawOval(0, 0, canvasSize.x - 1, canvasSize.y - 1);
// GCの保持しているリソースを開放する
gc.dispose();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
GCオブジェクトを使い終わったら、すぐにdispose()メソッドを呼び出して、システムリソースを開放します。
ここで表示された円は、gc.drawOval(int,int,int,int)メソッドによって描画されたものです。 ただしこの円は、ウィンドウが最小化されたり、他のウィンドウによって隠されてしまうと、 消えてしまいます。 円を本当に画面上に表示しただけで、その内容をプログラムが保つ努力をしていないからです。
最小化や他のウィンドウによって隠されてしまった描画内容を、 いつでも再描画したい場合には、PaintListenerインターフェイスを使用して、そこに再描画の処理内容を記述します。 PaintListener#paintControl(PaintEvent)は、ウィンドウが再表示される時や、リサイズされる時に呼び出されます。
先ほどのプログラムを、最小化や他ウィンドウで隠れても、再び描画内容が表示されるように改善したソースを示します。
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class CanvasDrawDemonstrate2 {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setText("CanvasDrawDemonstrate");
final Canvas canvas = new Canvas(shell, SWT.NONE);
canvas.setBounds(0, 0, 100, 100);
canvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
/* canvasに円を描く */
// GCインスタンスをPaintEventのeから取得
GC gc = e.gc;
// canvasいっぱいに円を描く
Point canvasSize = canvas.getSize();
gc.drawOval(0, 0, canvasSize.x - 1, canvasSize.y - 1);
// gc.dispose()は、Eclipse Frameworkが行うので、
// ここでは行わない。
}
});
shell.pack();
// まずウィンドウをオープンする
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
Canvasクラスへの描画作業は、直接GCオブジェクトを自分で作成して行うのではなく、 PaintEvent#paintControl(PaintEvent)で行うことが推奨されています。 もしもウィンドウの再表示やリサイズ等のアクションがユーザからされていないときに描画作業を行いたいときには、 Canvasクラスのスーパークラスである、Cntrolクラスのradraw()メソッドを呼び出します。 radraw()メソッドによって再描画が行われてもそうでなくても、すぐにメソッドはリターンするので、 確実に再描画を行いたい場合には、update()メソッドも呼んでおきます。 そうすると、 登録してあるPaintEventのpaintControl(PaintEvent)が呼び出されるまで、update()メソッドはブロックします。
PaintEventのフィールドには、以下のものがあります。
int count GC gc int height int width int x int y
先ほどのサンプルプログラムでは、gcフィールドを使用しました。 これは、PaintEventが生成するときに、Eclipse APIフレームワークが自動的に生成してくれる、 イベント発生元に対するGCオブジェクトでした。
countフィールドは、未解決のペイント操作キューの数を表しますが、 通常、フリーズでもしていない限り、この値は常に0です。
x、y、width、heightは、今回のイベントで描画する必要のある領域を示します。 これは、クリップ領域の概念と同じで、この領域内にしか描画できないことを示します。