JavaのSWTライブラリを用いて画像表示をする方法2種
この記事で説明しているプログラムのEclipseプロジェクトファイル(zipエクスポート)はこちらからダウンロード(20150411-javaimageviewer.zip) 。
Labelに画像表示
これが、最も単純な方法。画像のリサイズ等は行われず、表示領域より画像が大きい場合は中央付近のみが表示される。
public class ImageViewerTest extends Shell {
/**
* @param args
*/
public static void main(String[] args) {
try {
Display display = new Display();
Shell shell = new ImageViewerTest(display, SWT.SHELL_TRIM);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @param display
* @param style
*/
public ImageViewerTest(Display display, int style) {
super(display, style);
Shell shell = this.getShell();
// レイアウトの定義
shell.setSize(450, 350);
this.setText("イメージ ビューワ");
shell.setLayout(new GridLayout(2, false));
// レイアウトに配置する要素(ヴィジェット)
Label label1 = new Label(shell, SWT.NONE);
label1.setText("Image");
Label labelImage = new Label(shell, SWT.BORDER);
GridData gridData = new GridData();
gridData.horizontalAlignment = SWT.FILL;
gridData.grabExcessHorizontalSpace = true;
gridData.verticalAlignment = SWT.FILL;
gridData.grabExcessVerticalSpace = true;
labelImage.setLayoutData(gridData);
labelImage.setText("まだ画像が読み込まれていません");
Composite composite = new Composite(shell, SWT.NONE);
composite.setLayout(new FillLayout(SWT.HORIZONTAL));
Button btnFileOpen = new Button(composite, SWT.NULL);
btnFileOpen.setText("ファイルを開く");
Button btnClose = new Button(composite, SWT.NULL);
btnClose.setText("閉じる");
gridData = new GridData(GridData.HORIZONTAL_ALIGN_END);
gridData.horizontalSpan = 2;
composite.setLayoutData(gridData);
// 「ファイルを開く」ボタンの処理
btnFileOpen.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
// 読み込み用ダイアログを開く
FileDialog fileDlg = new FileDialog(shell, SWT.OPEN);
String[] exts = { "*.jpg", "*.*" };
fileDlg.setFilterExtensions(exts);
String[] filterNames = { "jpegファイル(*.jpg)", "全てのファイル(*.*)" };
fileDlg.setFilterNames(filterNames);
fileDlg.setText("画像ファイルを開く");
String selectedFilename = fileDlg.open();
if (selectedFilename != null && !selectedFilename.isEmpty()) {
ReadFromImageFile_Label(labelImage, selectedFilename);
}
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
// 「閉じる」ボタンの処理
btnClose.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
shell.dispose();
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
}
/**
* 画像ファイルを読み込み、Labelヴィジェットに表示する
* @param label
* @param filename
*/
private void ReadFromImageFile_Label(Label label, String filename) {
try {
Image image = new Image(this.getDisplay(), filename);
label.setImage(image);
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* (非 Javadoc)
*
* @see org.eclipse.swt.widgets.Decorations#checkSubclass()
*/
@Override
protected void checkSubclass() {
// super.checkSubclass(); // 自動作成後、手動でコメントアウト
}
}
Canvasに画像表示(リサイズ有り)
Canvasに画像表示する。画像はウインドウの伸縮に合わせ、縦横比率を維持して自動的にリサイズされる。まずは完成形を示す。
public class ImageViewerTest extends Shell {
/**
* @param args
*/
public static void main(String[] args) {
try {
Display display = new Display();
Shell shell = new ImageViewerTest(display, SWT.SHELL_TRIM);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @param display
* @param style
*/
public ImageViewerTest(Display display, int style) {
super(display, style);
Shell shell = this.getShell();
// レイアウトの定義
shell.setSize(450, 350);
this.setText("イメージ ビューワ");
shell.setLayout(new GridLayout(2, false));
// レイアウトに配置する要素(ヴィジェット)
Label label1 = new Label(shell, SWT.NONE);
label1.setText("Image");
Canvas canvas = new Canvas(shell, SWT.BORDER);
GridData gridData = new GridData();
gridData.horizontalAlignment = SWT.FILL;
gridData.grabExcessHorizontalSpace = true;
gridData.verticalAlignment = SWT.FILL;
gridData.grabExcessVerticalSpace = true;
canvas.setLayoutData(gridData);
Composite composite = new Composite(shell, SWT.NONE);
composite.setLayout(new FillLayout(SWT.HORIZONTAL));
Button btnFileOpen = new Button(composite, SWT.NULL);
btnFileOpen.setText("ファイルを開く");
Button btnClose = new Button(composite, SWT.NULL);
btnClose.setText("閉じる");
gridData = new GridData(GridData.HORIZONTAL_ALIGN_END);
gridData.horizontalSpan = 2;
composite.setLayoutData(gridData);
// 「ファイルを開く」ボタンの処理
btnFileOpen.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
// 読み込み用ダイアログを開く
FileDialog fileDlg = new FileDialog(shell, SWT.OPEN);
String[] exts = { "*.jpg", "*.*" };
fileDlg.setFilterExtensions(exts);
String[] filterNames = { "jpegファイル(*.jpg)", "全てのファイル(*.*)" };
fileDlg.setFilterNames(filterNames);
fileDlg.setText("画像ファイルを開く");
String selectedFilename = fileDlg.open();
if (selectedFilename != null && !selectedFilename.isEmpty()) {
if(canvas.isListening(SWT.Paint)){
// 既に PaintListener が存在する場合は、それを削除する
canvas.removeListener(SWT.Paint, (TypedListener)canvas.getListeners(SWT.Paint)[0]);
}
ReadFromImageFile_Canvas(canvas, selectedFilename);
}
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
// 「閉じる」ボタンの処理
btnClose.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
shell.dispose();
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
}
/**
* 画像ファイルを読み込み、Canvasヴィジェットに表示する
* @param canvas
* @param filename
*/
private void ReadFromImageFile_Canvas(Canvas canvas, String filename) {
Image image;
try {
image = new Image(canvas.getDisplay(), filename);
} catch (Exception e1) {
e1.printStackTrace();
return;
}
canvas.addPaintListener(new PaintListener() {
@Override
public void paintControl(PaintEvent e) {
float imageRatio = (float)image.getImageData().width / (float)image.getImageData().height;
if(canvas.getSize().y * imageRatio > canvas.getSize().x){
e.gc.drawImage(image, 0, 0, image.getImageData().width, image.getImageData().height,
0, 0, canvas.getSize().x, (int)(canvas.getSize().x / imageRatio));
} else {
e.gc.drawImage(image, 0, 0, image.getImageData().width, image.getImageData().height,
0, 0, (int)(canvas.getSize().y * imageRatio), canvas.getSize().y);
}
}
});
canvas.redraw();
}
/*
* (非 Javadoc)
*
* @see org.eclipse.swt.widgets.Decorations#checkSubclass()
*/
@Override
protected void checkSubclass() {
// super.checkSubclass(); // 自動作成後、手動でコメントアウト
}
}
試行錯誤 : PaintListenerの多重登録で過去の画像が残存する
新たな画像を読み込んだ時に、過去のPaintListenerが自動的に削除されるわけではないため、「明示的に」PaintListenerを削除しないといけないという教訓。下の例は、PaintListenerが多重登録され、2つの画像が同時に表示されてしまっている。
下記ソースコード抜粋部分で緑着色部分が、既に存在しているPaintListenerを検知して削除する部分。
String selectedFilename = fileDlg.open();
if (selectedFilename != null && !selectedFilename.isEmpty()) {
if(canvas.isListening(SWT.Paint)){
canvas.removeListener(SWT.Paint, (TypedListener)canvas.getListeners(SWT.Paint)[0]);
}
ReadFromImageFile_Canvas(canvas, selectedFilename);
}
試行錯誤 : PaintListenerを使わない場合
ウインドウを伸縮すると、再描画されない。ソースコードの抜粋を示す。
/**
* 画像ファイルを読み込み、Canvasヴィジェットに表示する
* @param canvas
* @param filename
*/
private void ReadFromImageFile_Canvas(Canvas canvas, String filename) {
Image image;
try {
image = new Image(canvas.getDisplay(), filename);
} catch (Exception e1) {
e1.printStackTrace();
return;
}
GC gc = new GC(canvas);
gc.drawImage(image, 0, 0, image.getImageData().width, image.getImageData().height,
0, 0, canvas.getSize().x, canvas.getSize().y);
gc.dispose(); // GCを使い終わったら、必ず明示的に破棄
}


