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を使い終わったら、必ず明示的に破棄
}