sprout2000

PC・スマホに関する備忘録

MonoDevelop Gtk# チュートリアル(意訳)

以下のドキュメントは、*基本的には*MonoDevelop サイトに掲載されている Gtk# チュートリアルの訳です。

ただし現在(2017年夏)の MonoDevelop の状況に合わないものやスクリーンショットなどは適宜改変しています。

訳者の環境

OS : Ubuntu 16.04 LTS

MonoDevelop 5.10

以下カッコ内※印は訳者注

Stetic GUI Designer | MonoDevelop

 

MonoDevelop Gtk# チュートリアル

 

イントロダクション
このドキュメントは Stetic ( MonoDevelop 統合開発環境GUI 開発ツール)の初歩的なチュートリアルを目的としている。
チュートリアルとして、ログファイルを閲覧するためのシンプルなプログラムを組み立ててみよう。
このチュートリアルでは、 GTK# ライブラリに含まれているウィジェットたちを扱う。
メニューバーなんかも含む GUI のレイアウトをどうやって作るのか、その GUI をプログラミングコードにどうやって結びつけるのかを学ぼう。

Nate’s Log Viewer
これからわれわれが作っていくサンプルプログラムは、テキスト形式のログファイルを見るためのシンプルなビューアだ。
これはたくさんの派手な仕掛けがあるものじゃないけど、 Stetic を使っていくうえでとても参考になると思う。
その GUI の見た目はこんな感じだ。

f:id:sprout2000:20170711181518p:plain

 

ステップ1: あたらしいプロジェクトの作成
Monodevelop を起動し、メニューから File -> New -> Solution... へと選択しよう。こんな感じのウィンドウが開いたはずだ。

f:id:sprout2000:20170711181223p:plain

f:id:sprout2000:20170711181307p:plain

左側のペインから .NET を選択し、 Gtk# 2.0 Project を選んで Next ボタンをクリックしてほしい。

f:id:sprout2000:20170711181708p:plain


Name エントリにプロジェクト名、 Location エントリにプロジェクトの置き場所を指定しよう。
"Create separate Solution subdirectory" にチェックが入っていることを確認して "Create" ボタンをクリックだ。

f:id:sprout2000:20170711181730p:plain

見て分かる通り MonoDevelop がからっぽのソリューションとプロジェクトを作ってくれた。ここで "Solution" パッドの "MainWindow.cs" をダブルクリックしてみよう。 Main クラスや Main 関数まで用意してくれているのが分かるはずだ。

ナイス! もうアプリケーションをビルドして実行することだって出来る。 Run メニューから "Start Debugging" を選択するか、 F5 キーを叩くか、下の画像のように Run ボタンを押せばいい。

f:id:sprout2000:20170711181756p:plain

こうすることでプロジェクトを保存してビルドし、その実行結果を確かめることができる。こんな感じだ。

f:id:sprout2000:20170711181633p:plain

興奮しないかい? ここではとりあえずウィンドウの "X" をクリックしてアプリケーションを閉じ、さっそく GUI で開発していこう。

 

ステップ2: GUI を編集する
まず最初に "MainWindow.cs" ファイルを開かなくてはいけない。 "Solution" パッドの "MainWindow.cs" をダブルクリックしよう。エディタウィンドウに新しいタブが作られて、このファイルが編集できるようになった。インターフェイスに2つのちいさな変化があったことに気付いたかな?

f:id:sprout2000:20170711181913p:plain

"MainWindow.cs" タブの下に2つのボタンがあらわれたのがひとつ、 "Properties" パッドがあらわれたのがひとつだ。
(※環境によって実際のパッドの配置は異なります。各パッドは "View" メニューから表示させ、ドラッグアンドドロップで好きな場所に配置したり、フロートさせたり出来ます。)

この2つのボタンでソースコードエディタと GUI デザイナーを切り替えることが出来る。さっそく "Designer" ボタンをクリックして Stetic GUI デザイナーを立ち上げよう。

f:id:sprout2000:20170711181958p:plain

ほら GUI だ。からっぽのウィンドウがあらわれた。
このウィンドウのタイトルをもっとマシなものに変えてみよう。このウィンドウをクリックして選択するか、 Stetic 上部のプルダウンメニューから選択しよう。

選択できたら、"Properties" パッドに注目してみてほしい。
(※実際にはプロパティリストがうまく表示されないことがよくあります。いろんな方法を試してみてください。)

f:id:sprout2000:20170711182111p:plain

これらのエントリーにそれぞれのウィジェットで設定可能なすべてのプロバティが表示されている。
では、われわれの新生アプリの "Window Title" プロバティと "Icon" プロパティを変更しよう。
注意すべきは "Common Widget Properties" の中にある "Sensitive" プロパティだ。これがウィジェットをグレーアウトさせるかどうかを決める。 "true" にチェックが入っていればグレーアウトされることはない。

"Window Title" の右隣のボックスをクリックすると編集可能な状態になる。 "MainWindow" というテキストを "Nate’s Log Viewer” とか、もしくは自分の好きな名前に変更してほしい。

"Icon" の右隣のボックスをクリックすると "..." というボタンがあらわれるので、アイコンから "gtk-bold" を選択して OK ボタンだ。

(※ "Window Title" プロパティと "Icon" プロパティは "Window Properties" セクションにあります。)

f:id:sprout2000:20170711182229p:plain

これでわれわれのアプリは適切なタイトルとアイコンを持つようになった。では、メニューバーとログファイル表示用のウィジェットも追加してやろう。

 

ステップ2a: メニューバーの作成
Stetic でメニューバーを作ることは簡単だ。ドラッグして、ドロップして、クリックして、名前をつけるだけ。まあ実際にはもうちょっと複雑なんだけど、それほど大変でもない。

まず最初にコンテナを用意しなければならない。Gtk ライブラリのすべてのウィジェットは、なんらかのコンテナの中に置かれなければならないからだ。コンテナは親ウィンドウの上に置かれたウィジェットたちのレイアウトをコントロールする。実際、ウィンドウそのものもひとつのコンテナなのだ。コンテナに置かれたウィジェットは、そのコンテナを満たす。たとえば、試しにボタンをメインウィンドウの上へドラッグしてみてほしい。つぎのようになるはずだ。

(※現在ではコンテナを用意しないでウィジェットをウィンドウに追加しようとすると下のような警告が出ます。)

f:id:sprout2000:20170711182338p:plain

f:id:sprout2000:20170711182358p:plain

ボタンがどのようにウィンドウ全体を満たしているか見てほしい。これが僕の言わんとするところなんだ。
では、ウィンドウに役割を持たせるために他のいくつかのコンテナでウィンドウを分割させようじゃないか。
コンテナにはさまざまな形式がある。それぞれに異なる役割があり、これらとウィジェットを組み合わせることで望むタイプの GUI を作ることが出来る。
君に必要なウィジェットとコンテナのコンビを見つけられない時でも、いつでもカスタマイズしたウィジェットを作成することも出来る。

それでは、このボタンを削除して、われわれの GUI を作っていくこととしよう。 "button1" を右クリックして "Delete" を選択してほしい。

目的とする GUI レイアウトを考えると、水平に2分割されたエリアが必要だ。ウィンドウ上部のメニューバーとその下のログファイル表示エリアだ。 "Vbox" の出番だろう。

"MainWindow""Vbox"ドラッグアンドドロップしよう。

f:id:sprout2000:20170711182437p:plain

メインウィンドウが3つのコンテナで分割された。でも必要なのは2つだけなので、ひとつを右クリックして削除を選択しよう。そしてメニューバーを一番上のコンテナへドラッグしよう。

想像していたのとは違う結果になったかもしれない。なぜメニューバーはウィンドウ上半分のすべてを満たさないのだろうか? そう、ウィジェットによってはデフォルトのサイズというものがあるからだ。
メニューバーウィジェットはウィンドウ上端を占有することが想定されている。そして、実際そのように振る舞う。

この振る舞いを変えるためにできることも2つある。ひとつは "Vbox""Homogeneous" プロパティを変更することだ。これを有効にすれば、 そのウィジェット"VBox" と同じサイズになるように強制できる。試してみてほしい。

もうひとつがメニューバーの "Auto Size" プロパティ( "Box Child Layout" セクションの中にある)をオフにして、 "Expand" プロパティをオンにするか、 "Expand" と "Fill" プロパティの両方をオンにすることだ。

"Expand"ウィジェットにそのデフォルトサイズのままでいることを命ずるが、コンテナの中央に位置させて残りは背景で満たすことにする。 "Fill" はコンテナをそのウィジェットで満たすよう命じる。
この2つの特性を試してみたいなら、"VBox" の下半分にボタンを置いてみて、 "Expand""Expand + Fill" を切り替えてみてほしい。終わったら、そのボタンは削除すること。

メニューバーに戻ろう。 "Menu Bar" ウィジェットを選択(プルダウンメニューから選んだり、ただ単に GUI デザイナー上でクリックしたりして)し、 “Click to create menu.” というテキストを左クリックしよう。

f:id:sprout2000:20170711182538p:plain

あらわれたエントリに "File" とタイプして Enter を押す。メニューに最初のアイテムが加えられた。いま "File" アイテムがアウトライン化されてサブメニューが表示されていることに注意してほしい。さっきと同様にファイルメニューにさらなるアイテムを追加することも出来るのだ。それは後でやることにして、とりあえず "File" メニューエントリに機能を付け加えていこう。

"Properties" パッドを見返してほしい。 "Label" プロパティを "_File" に変更し、 “Accelerator” プロパティをクリックして、キーボードで <alt>+F を叩こう。これでこのアプリにフォーカスがあるときに <alt>+F のショートカットで "File" を選択できるようになった。この手順が終わったら "Properties" パッドは下のようになっているはずだ。

f:id:sprout2000:20170711182618p:plain

それでは "File" のサブメニューに "Open", "Close" そして "Exit" のアクションを付け加えていこう。 "File" の下のサブメニューをクリックすればエントリがあらわれる。そのエントリで "File" の時と同様に "Open" とタイプし、 Enter を叩こう。 "Properties" パッドでその "Label""_Open" に変更し、ショートカットを <ctrl>+O に設定する。
同様に "Close""C_lose" とし、ショートカットは <ctrl>+L へ、 "Exit""E_xit"<ctrl>+X としよう。

"File" エントリに続いて、サブメニューに "About" を持つ "Help" エントリも作ろう。近道として、 GUI デザイナーで "Click to create menu" をクリックするとあらわれるエントリで "_Help" とタイプすればいい。ショートカットに <ctrl>+H を指定することも忘れないように。

(※原文では下図のように Action タブを利用した設定方法も紹介されていますが、この機能が現時点では不安定であるため割愛します。)

f:id:sprout2000:20170711182651p:plain

オーケー。ではアプリをビルド&実行して作ったばかりのメニューバーを見てみよう。 "Run" ボタンをクリックだ。

どのメニューエントリも何の動作もしないことにガッカリしたかもしれない。なので、これらをシグナルハンドラに接続し、そのコードを書いていかなければならない。

そのためには、 "Properties" パッドの "Signals" タブを使わなければならない。"File" エントリの "Open" サブメニューを選択し、 "Signals" タブをクリックしよう。
(※原文では "Action" タブを使って同様の設定を行うよう解説されています。)

3つある。 "Activated”, “Changed” そして “Toggled” だ。このプログラムでは "Activated" を使う。

"Activated" につづく “Click here to add a new handler” をクリックし、エントリに "OnOpen" とタイプして Enter を押そう。こんな感じだ。

f:id:sprout2000:20170711182813p:plain

そこで GUI デザイナー下部の "Source" ボタンをクリックすると、自動的に MonoDevelop"MainWindow" クラスへスケルトンの "OnOpen" 関数を作ってくれているのが分かる。これが "Open" メニューが選択されたときに呼ばれる関数だ。
(※実際には関数が二重登録されてしまうことがよくあります。)

f:id:sprout2000:20170711182930p:plain

では、 "Close", "Exit", "About" のメニューアイテムにもそれぞれ "OnClose", "OnExit", "OnAbout" というイベントハンドラを追加しよう。それが終わったら、 ソースコードウィンドウを再度表示して、 "OnExit" 関数にすこしコードを付け加えよう。

"OnExit" 関数へ "Application.Quit();" というコマンドを付け加えたら、こんな風になっている。
(※現在はイベントハンドラを自動生成すると、 "throw new NotImplementedException ();" というコードが自動的に記述されます。この扱いについてはこのドキュメントでは触れません。)

f:id:sprout2000:20170711183004p:plain

これでビルド&実行すれば、 もう "Exit" メニューエントリと <ctrl+X> ショートカットが機能するようになったことが確認できるはずだ。

あとでその他のシグナルハンドラにもコードを追加するが、とりあえず残りの GUI 部分を仕上げてしまおう。

 

ステップ2b: TextView を作成する
"Main Window" の下半分にログファイルを表示するために、 "Scrolled Window" コンテナとその中に置く "Text View" ウィジェットを用意しよう。

まずは "Scrolled Window" コンテナをメインウィンドウ内の "VBox" の下半分へドラッグアンドドロップする。

f:id:sprout2000:20170711183051p:plain

そして "TextView" ウィジェット"Scrolled Window" に残されている空白スペースへドラッグアンドドロップする。 "Properties" パッドのプロパティタブにある "Name" プロパティを "logTextView" に変更しよう。こんな感じだ。

f:id:sprout2000:20170711183113p:plain

MonoDevelop はウィンドウ内のすべてのウィジェットのためにフィールドを作成するので、実行時にはウィジェットのプロパティにアクセスするためにこのフィールドを利用することが出来る。

このフィールドは所与のウィンドウクラスにおいて作られたものではない。なぜなら、そのクラスは「部分的」なアクセス修飾子を持っていて、それによりいくつかのファイルへクラスを分割することが出来るからだ。

とくに必須というわけではないが、"logTextView" ウィジェットでは "Coursor Visible" プロパティと "Editable" プロパティのチェックは外しておいたほうがいいだろう。

これでわれわれはすべての GUI 部品を正しく配置できた。素晴らしい!
それではコーディングへと進むことにしよう。

 

ステップ3: C# コードを書く
"MainWindow.cs""Source" ボタンを押して中身を見てみよう。

f:id:sprout2000:20170711183245p:plain

われわれのプログラムを完成し機能させるためには、その基礎となるコードを追加しなければならない。
これは C#チュートリアルではないため、必要なコードを記述するだけにする。プログラムへコピーペーストして欲しい。

"OnOpen" メソッド

protected void OnOpen(object sender, System.EventArgs e)
{
// Reset the logTreeView and change the window back to original size
int width, height;
this.GetDefaultSize( out width, out height );
this.Resize( width, height );

logTextView.Buffer.Text = "";

// Create and display a fileChooserDialog
FileChooserDialog chooser = new FileChooserDialog(
"Please select a logfile to view ...",
this,
FileChooserAction.Open,
"Cancel", ResponseType.Cancel,
"Open", ResponseType.Accept );

if( chooser.Run() == ( int )ResponseType.Accept )
{
// Open the file for reading.
System.IO.StreamReader file =
System.IO.File.OpenText( chooser.Filename );

// Copy the contents into the logTextView
logTextView.Buffer.Text = file.ReadToEnd();

// Set the MainWindow Title to the filename.
this.Title = "Nate's Log Viewer -- " + chooser.Filename.ToString();

// Make the MainWindow bigger to accomodate the text in the logTextView
this.Resize( 640, 480 );

// Close the file so as to not leave a mess.
file.Close();
} // end if
chooser.Destroy();
} // end method OnOpen

 

"OnClose" メソッド

protected void OnClose(object sender, System.EventArgs e)
{
// Reset the logTreeView and change the window back to original size
int width, height;
this.GetDefaultSize( out width, out height );
this.Resize( width, height );

logTextView.Buffer.Text = "";

// Change the MainWindow Title back to the default.
this.Title = "Nate's Log Viewer";
} // end method OnClose

 

"OnAbout" メソッド

protected void OnAbout(object sender, System.EventArgs e)
{
// Create a new About dialog
AboutDialog about = new AboutDialog();

// Change the Dialog's properties to the appropriate values.
about.ProgramName = "Nate's Log Viewer";
about.Version = "1.0.0";

// Show the Dialog and pass it control
about.Run();

// Destroy the dialog
about.Destroy();
} // end method OnAbout

 

すべてを正しい位置に配置できれば、あとは "Run" ボタンをクリックしてログを表示させるだけだ。最終的に動作するようになったプログラムの様子を掲げておく。

f:id:sprout2000:20170711183408p:plain

----------------------------------------------

以上、適宜改変のうえ訳出。