DlangUI入門

  • 12
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

Windows,Linux,OSXに対応しており、D言語ネイティブ。そんな便利そうなGUIライブラリの入門記事です。
公式のGetting Startedと内容はほぼ同じですが...

どんなものが作れるか

dman_optimized.gif
こんなものが割と簡単に作れます。
この記事ではこれを何も見ずに作れるように記事を書いていきます

DUBでプロジェクトを作る

今回はDlangManという名前でプロジェクトを作ります。
dub init DlangMan
として、dub.sdlを

dub.sdl
name "dlangman"
description "A minimal D application."
copyright "Copyright © 2015, namachan"
authors "namachan"
dependency "dlangui" version="~master"

としてもいいですが、
dub init DlangMan dlanguiとすると自動的にDlangUIの最新版が使えるので楽です。

動かしてみる

では次に、プロジェクトのディレクトリの中のsourceディレクトリにあるapp.dを次のように書き換えてください

app.d
import dlangui;

mixin APP_ENTRY_POINT;

extern(C) int UIAppMain(string[] args)
{
    Platform.instance.uiLanguage="en";
    Platform.instance.uiTheme="theme_default";

    auto window = Platform.instance.createWindow("DlangMan",null);
    auto button = new Button;
    button.text = "DlangMan";
    window.mainWidget = button;
    window.show;
    return Platform.instance.enterMessageLoop();
}

これを実行するとScreenshot_from_2015-12-19 22:32:58.png
このような画面が表示されます。
Platform.instance.uiLanguageは言語の設定をする関数です。一見変数に直接代入しているように見えますが、実際は@propertyを付けてあたかも変数のように扱えるようにした関数です。
使用できる言語は、英語、フランス語、ロシア語を指定でき、それぞれen,fr,ruと表記します。
Platform.instance.uiThemeはUIのテーマを指定でき、theme_darkとtheme_defaultがもともとあります。また、Android APIのテーマと同じ形式で記述されたテーマファイルを使うことでテーマをカスタマイズすることが可能です。
Platform.instance.createWindowの第一引数にはウィンドウのタイトルバーの文字列、第二引数には親ウィンドウを渡します。今回は親ウィンドウが無いのでnullを渡します。
第三引数にはWindowFlagで定義されているフラグを渡すことでフルスクリーン、モーダルウィンドウ、大きさ変更可能なウィンドウに出来ます。それぞれ、WindowFlag.Fullscreen,WindowFlag.Modal,WindowFlag.Resizableです。
今回はwindow.mainWidgetに直接Buttonをセットしていますが、実際にはLayoutにウィジェットやLayoutを追加していき、それをセットすることが多いと思います。
Platform.instance.enterMessageLoop();でメッセージループに入り、ボタンなどが使用できるようになります。

Buttonを使ってみる

まずは押すと標準出力にpushと出力するボタンを作ってみましょう。最初のプログラムに少し付け加えるだけです。
ボタンは、

auto button = new Button
button.text = "push!";

これで、ボタンをヒープに生成して表示する文字をセットします。
引数を取るコンストラクタもあるのですが、まだよく分かりません...。

button.addOnClickListener(delegate(Widget src)
    {
          "pushed".writeln;
    });

でクリックされた際に呼び出されるデリゲートをセットします。
そしてこのbuttonwindowmainWidgetに設定すればボタンを押すと標準出力にpushedと表示されるはずです。
Screenshot_from_2015-12-21 01:12:52.png

import dlangui;
import std.stdio;

mixin APP_ENTRY_POINT;

extern(C) int UIAppMain(string[] args)
{
    Platform.instance.uiLanguage = "en";
    Platform.instance.uiTheme = "theme_default";
    auto window = Platform.instance.createWindow("push",null);
    auto button = new Button;
    button.text = "push!";
    button.addOnClickListener(delegate(Widget src)
            {
                "pushed".writeln;
                return true;
            });
    window.mainWidget = button;
    window.show;
    return Platform.instance.enterMessageLoop();
}

画像の読み込みと描画

画像の読み込みは簡単です。
dlangui.graphics.image.loadImageを使うことで、画像をDrawBufとして読み込めます。DrawBufはJavaで言うBuffredImageみたいなもので、DrawBufに線やフォントやDrawBufを描画したり出来ます。
では早速

import std.stdio;
import dlangui;

mixin APP_ENTRY_POINT;

extern(C) int UIAppMain(string[] args)
{
    Platform.instance.uiLanguage = "en";
    Platform.instance.uiTheme = "theme_default";
    auto window = Platform.instance.createWindow("dman",null);
    auto dman = new Dman;
    window.mainWidget = dman;
    window.show;
    return Platform.instance.enterMessageLoop();
}

class Dman : Widget
{
private:
    DrawBuf image;          
public:
    this()
    {
        image = loadImage("dman.png");
    }
    override void onDraw(DrawBuf buf)
    {
        buf.drawImage(0,0,image);
    }
}

ここでは、ButtonLayoutなどのスーパークラスであるWidgetを継承し、そのonDraw関数をオーバーライドして描画します。このonDraw関数は、画面の再描画時に呼び出される関数で、渡されるDrawBufに描画することでWidgetの見た目が変化します。
再描画を要求する関数はinvalidate()です。

フォントの変更

僕の環境では日本語を描画すると豆腐になってしまうのでフォントの変更は必須です。

import std.stdio;
import dlangui;

mixin APP_ENTRY_POINT;

extern(C) int UIAppMain(string[] args)
{
    Platform.instance.uiLanguage = "en";
    Platform.instance.uiTheme = "theme_default";
    auto window = Platform.instance.createWindow("dman",null);
    auto button = new JaButton;
    window.mainWidget = button;
    button.text = "D言語くん可愛い";
    window.show;
    return Platform.instance.enterMessageLoop();
}

class JaButton : Button
{
private:
    FontRef jaFont;
public:
    this()
    {
        jaFont = FontManager.instance.getFont(20,FontWeight.Normal,false,FontFamily.MonoSpace,"JKゴシックM");
    }
    override FontRef font() @property const
    {
        return cast(FontRef)jaFont;
    }
}

フォント名のところは自分の環境にある日本語フォントに読み替えてください。
Screenshot_from_2015-12-21 00:05:00.png
ここでは、Buttonで日本語を表示できるようにしました。
Button@propertyの付いたfontという関数を使ってフォントを取得しています。そのため、このfont関数をオーバーライドすることで比較的簡単に表示されるフォントを変更することが出来ます。
フォントには、通常のFontと、FreeTypeを利用したFreeTypeFontがあり、それぞれFontManagerFreeTypeFontManagerで読み込みます。
DrawBufに文字列を描画する関数は、DrawBufにではなく、Fontに用意されてあるので注意してください。

Layoutについて

僕自身、まだ全然わからないのですが、これが使えないとGUI組めないので解説します。
デフォルトで用意されているLayoutは主に5つあり、

  • VerticalLayout
  • HorizontalLayout
  • TableLayout
  • LinerLayout
  • FrameLayout

です。
WidgetLayoutを追加するにはaddChild()関数を利用します。

VerticalLayout

名前の通り垂直に並べます
Screenshot_from_2015-12-21 00:25:39.png

HorizontalLayout

同じく平行に並べますScreenshot_from_2015-12-21 00:27:46.png

FrameLayoutScreenshot_from_2015-12-21 00:30:10.png

こうなってしまいます。
これはButtonの大きさとかマージンとか考えずに上に重ねてしまうからです。

TableLayout

Excelみたいに並べるやつです
Screenshot_from_2015-12-21 00:33:40.png

また、これらのレイアウト以外にも自作のレイアウトを使うことも出来ます。

DMLの利用

DML(DlangUI Markup Language)という言語を使ってレイアウトを作ることが出来ます。

import std.stdio;
import dlangui;

mixin APP_ENTRY_POINT;

extern(C) int UIAppMain(string[] args)
{
    Platform.instance.uiLanguage = "en";
    Platform.instance.uiTheme = "theme_default";
    auto window = Platform.instance.createWindow("dman",null);
    auto layout = parseML(q{
        TableLayout {
            colCount: 2
            margins: 30;padding: 20
            Button {text: "button1"}
            Button {text:"button2"}
            Button {text:"button3"}
            HorizontalLayout {
                Button {text:"button4"}
                Button {text:"button5"}
            }
        }
    });
    window.mainWidget = layout;
    window.show;
    return Platform.instance.enterMessageLoop();
}

DMLを中括弧を宣言の次の行に書くFreeBSDスタイルで書くとエラーが出ます(経験済み)
Screenshot_from_2015-12-21 00:44:01.png

終わりに

大変遅れてしまいました...
当初はD言語くんAdventCalenderのプログラムに関してなにか書こうと思っていたのですが、書くことが無さ過ぎてDlangUIの入門記事に変更しました。

この投稿は D言語 Advent Calendar 201511日目の記事です。