2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

D言語Advent Calendar 2020

Day 10

パッケージ arsd-official : simpledisplay の使い方

Last updated at Posted at 2021-01-09

はじめに

D言語のポピュラーなDUBパッケージの中にarsd-officialがあります。
この記事では、arsd-officialのサブパッケージsimpledisplayの使い方を紹介します。

開発環境

その1-ウィンドウ画面作成

simpledisplayは、ウィンドウ画面の作成や表示処理が簡単に実装できるような機能が提供されています。
まずは、ウィンドウ作成に必要な最小限のソースコード実装例です。
この記事を参考にSingle-file packagesで実装しました。

sample1.d
/+ dub.sdl:
	name "sample1"
	dependency "arsd-official:simpledisplay" version="~>10.7.0"
+/
// dub run --single sample1.d
import arsd.simpledisplay;
void main() {
	auto window = new SimpleWindow(500, 500, "Sample1");
	window.eventLoop(0);
}

これだけのソースコードでウィンドウの作成とイベント処理ができます。
SimpleWindowでウィンドウを作成します。ウィンドウの幅、高さ、タイトルを引数にセットしています。
eventLoopはウィンドウのイベント処理を行います。
引数に0のみをセットした場合、simpledisplayが用意したデフォルトのイベント処理を行います。

以下はコンパイルと実行結果です。

コマンドプロンプト
D:\Dev> dub run --single sample1.d
parsePackageRecipe dub.sdl
Fetching arsd-official 10.7.0 (getting selected version)...
Performing "debug" build using D:\Dev\dmd2\windows\bin64\dmd.exe for x86_64.
arsd-official:color_base 10.7.0: building configuration "library"...
arsd-official:simpledisplay 10.7.0: building configuration "normal"...
sample1 ~master: building configuration "application"...
Linking...
Running sample1.exe

ウィンドウの最小化、最大化、サイズ変更、閉じるなどのイベントはsimpledisplayが処理してくれています。
sample1.png

その2-イベント処理の実装

eventLoopを使って、イベント処理を実装します。
simpledisplayのソースコード内のサンプルコードを参考に実装しました。
他にもサンプルコードが紹介されているので、興味がある方はソースコードを参照してください。

sample2.d
/+ dub.sdl:
	name "sample2"
	dependency "arsd-official:simpledisplay" version="~>10.7.0"
+/
// dub run --single sample2.d
import std.conv;
import arsd.simpledisplay;

void main() {
	auto window = new SimpleWindow(Size(500, 500), "Event example - simpledisplay.d");
	int y = 0;
	void addLine(string text) {
		auto painter = window.draw();
		if(y + painter.fontHeight >= window.height) {
			painter.scrollArea(Point(0, 0), window.width, window.height, 0, painter.fontHeight);
			y -= painter.fontHeight;
		}
		painter.outlineColor = Color.green;
		painter.fillColor = Color.black;
		painter.drawRectangle(Point(0, y), window.width, painter.fontHeight);
		painter.outlineColor = Color.white;
		painter.drawText(Point(10, y), text);
		y += painter.fontHeight;
	}
	window.eventLoop(1000,
		(){
			addLine("Timer went off!");
		},
		(KeyEvent event){
			addLine(to!string(event));
		},
		(MouseEvent event){
			addLine(to!string(event));
		},
		(dchar ch){
			addLine(to!string(ch));
		}
	);
}

eventLoop内の(){~}は、タイマーイベント処理です。
eventLoopの第1引数に正数をセットすると、その時間間隔ごとにタイマーイベントが発生します。単位はミリ秒です。

(KeyEvent event){~}は、キーボード操作のイベント処理です。
キーを押した場合、キーを離した場合にイベントが発生します。

(MouseEvent event){~}は、マウス操作のイベント処理です。
ウィンドウ上でマウスを動かした場合、クリックした場合にイベントが発生します。

(dchar ch){~}では、キーボードから入力された文字ごとの処理を実装します。

以下はコンパイルと実行結果です。

コマンドプロンプト
D:\Dev> dub run --single sample2.d
parsePackageRecipe dub.sdl
Performing "debug" build using D:\Dev\dmd2\windows\bin64\dmd.exe for x86_64.
arsd-official:color_base 10.7.0: target for configuration "library" is up to date.
arsd-official:simpledisplay 10.7.0: target for configuration "normal" is up to date.
sample2 ~master: building configuration "application"...
Linking...
To force a rebuild of up-to-date targets, run again with --force.
Running sample2.exe

どのイベントでもaddLine関数が呼び出されています。
addLine関数内のwindow.draw()で、ウィンドウの描画処理に必要なpainter(struct ScreenPainter)を取得しています。
ScreenPainterのデストラクタが呼び出される際にウィンドウの表示を更新する仕組みとのことです。

以下の実行結果を補足します。

  • 1000ミリ秒ごとにTimer went off!が出力されています。
  • キーボードのaを押した際、離した際にKeyEventが発生しています。
  • (dchar ch){~}で引数chに、押したキーであるaがセットされて呼び出されています。
  • マウス操作のイベントMouseEventも発生しています。
    マウス動かした際にMouseEvent(motion, ~、クリックした際にMouseEvent(buttonPressed, ~MouseEvent(buttonReleased, ~が発生しています。

sample2.png

その3-OS固有のイベント処理の実装

その2では、タイマー、キーボード、マウスイベントの処理方法を紹介しました。
その3では、その他のウィンドウイベントの処理実装例になります。
また、arsd-officialは汎用的なパッケージため、WindowsX11のいずれでも使用可能ですが、OS固有のイベントを処理できる仕組みも用意されています。

sample3.d
/+ dub.sdl:
	name "sample3"
	dependency	"arsd-official:simpledisplay" version="~>10.7.0"
	dependency	"arsd-official:image_files"   version="~>10.7.0"
+/
// dub run --single sample3.d
import core.sys.windows.windows;
import std.conv;
import arsd.image;
import arsd.simpledisplay;

void main()
{
	auto window = new SimpleWindow(Size(500, 500), "Arsd Viewer");
	MemoryImage image;
	void draw(int width, int height){
		auto painter = window.draw();
		painter.clear();
		if ( image !is null ){
			if ( (cast(double)width) / image.width > (cast(double)height) / image.height ){
				width  = image.width  * height / image.height;
			} else {
				height = image.height * width  / image.width;
			}
			TrueColorImage winImage = image.imageResize(width, height);
			painter.drawImage(Point(0, 0), Image.fromMemoryImage(winImage));
		}
	}
	window.windowResized = (int width, int height){
		draw(width, height);
	};
	window.handleNativeEvent =
		delegate int(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, out int r){
			switch ( msg ){
				case WM_DROPFILES:
					const MAX_SIZE = 256;
					wchar[] fileName = new wchar[MAX_SIZE];
					int nSize = DragQueryFile(cast(HDROP)wParam, 0, fileName.ptr, cast(int)(fileName.length));
					try {
						image = loadImageFromFile(fileName[0 .. nSize].to!string);
					} catch (Exception e){
					}
					draw(window.width, window.height);
					r = 1;
					return ( 0 );
				default:
			}
			return ( 1 );
		};
	draw(window.width, window.height);
	window.eventLoop(0);
}

ウィンドウの描画イベントを処理するためにdraw関数を用意しました。
draw関数では、MemoryImage imageに格納された画像情報をウィンドウ画面に表示します。

window.windowResizedは、ウィンドウのサイズを変更した際に発生するイベントです。draw関数を呼び出すように実装しました。

window.handleNativeEventで、OS固有イベントの処理方法を実装します。
今回は、ファイルをドラッグ&ドロップした際(WindowsWM_DROPFILESイベント)に、ファイルをMemoryImageに読み込み、draw関数を呼び出します。
handleNativeEventを実装する際の注意点として、自分で処理したイベントは戻り値0、自分で処理しないイベントは戻り値1を返すことです。
戻り値1を返すことで、simpledisplayが用意したデフォルトのイベント処理を行います。
戻り値0を返すとイベント処理を何も行わないため、ご注意ください。

以下はコンパイルと実行結果です。

コマンドプロンプト
D:\Dev> dub run --single sample3.d
parsePackageRecipe dub.sdl
Performing "debug" build using D:\Dev\dmd2\windows\bin64\dmd.exe for x86_64.
arsd-official:color_base 10.7.0: target for configuration "library" is up to date.
arsd-official:bmp 10.7.0: target for configuration "library" is up to date.
arsd-official:imageresize 10.7.0: target for configuration "library" is up to date.
arsd-official:jpeg 10.7.0: target for configuration "library" is up to date.
arsd-official:png 10.7.0: target for configuration "library" is up to date.
arsd-official:svg 10.7.0: target for configuration "library" is up to date.
arsd-official:image_files 10.7.0: target for configuration "library" is up to date.
arsd-official:simpledisplay 10.7.0: target for configuration "normal" is up to date.
sample3 ~master: building configuration "application"...
Linking...
To force a rebuild of up-to-date targets, run again with --force.
Running sample3.exe

以下は、ファイル(Qiitaのロゴ画像)をウィンドウにドラッグ&ドロップした際の結果です。
ウィンドウサイズを変えると、ロゴマークが拡大縮小表示されます。

sample3.png

ウィンドウイベント一覧(Windows用)

用意されているWindowS用のウィンドウイベントをまとめました。
X11用のウィンドウイベントなど、さらに詳細を知りたい方は、ソースコードを参照してください。

イベント関数 説明
void delegate(KeyEvent ke) handleKeyEvent キーボード操作イベント
void delegate(dchar c) handleCharEvent キーボードで押した文字処理イベント
void delegate() handlePulse タイマーイベント
void delegate(bool) onFocusChange ウィンドウのフォーカス有効無効イベント
void delegate() onClosing ウィンドウを閉じるイベント
void delegate() onDestroyed ウィンドウのリソース開放イベント
void delegate(MouseEvent) handleMouseEvent マウス操作イベント
void delegate() paintingFinished ウィンドウ描画終了時イベント
void delegate(int width, int height) windowResized ウィンドウサイズ変更イベント

更新履歴

  • 2021.1.9 初回投稿
  • 2022.3.26 開発環境のバージョンを更新。ソースコードを更新。
2
0
0

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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?