2010-07-31

Mono で GUI プログラミング (2)

C# の練習に、電卓プログラムを作ってみました。Fedora では、mono 用の IDE として MonoDevelop が利用できますが、GUI については Gkt# が利用できるようになっており、.NET Framework の Form クラスを手軽に利用出来るようになっていなかったので、とりあえずテキストエディタでガリガリ記述してみました。

やや長いですが、ソース (dentaku.cs) を以下に示します。

///////////////////////////////////////////////////////////////////////////////
// dentaku.cs - 電卓プログラム
//
// created by Fuhito Suguri, 31-Jul-2010
///////////////////////////////////////////////////////////////////////////////

using System;
using System.Drawing;
using System.Windows.Forms;
//
namespace bitWalk
{
class Program
{
static void Main()
{
Application.Run(new Dentaku());
}
}
/////////////////////////////////////////////////////////////////////////////
// class Dentaku
/////////////////////////////////////////////////////////////////////////////

class Dentaku : Form
{
// DISPLAY
private Label lab_0;
// KEY
private Button but_dot;
private Button but_equal;
private Button but_plus;
private Button but_minus;
private Button but_mul;
private Button but_div;
private Button but_mrc;
private Button but_mminus;
private Button but_mplus;
private Button but_clear;
private Button but_sign;
private Button but_percent;
private Button but_root;
private Button but_00;
private Button but_0;
private Button but_1;
private Button but_2;
private Button but_3;
private Button but_4;
private Button but_5;
private Button but_6;
private Button but_7;
private Button but_8;
private Button but_9;
// background color of KEY
private Color bgcolor_Disp = Color.PaleGreen;
private Color bgcolor_Num = Color.LightCyan;
private Color bgcolor_Dot = Color.PowderBlue;
private Color bgcolor_Op = Color.Lavender;
private Color bgcolor_Eq = Color.LavenderBlush;
private Color bgcolor_Func = Color.LemonChiffon;
private Color bgcolor_Memo = Color.LightPink;
private Color bgcolor_Cls = Color.HotPink;
// KEY size
private Size key_Size = new Size(50, 30);
private Size key_Size2 = new Size(50, 60);
// layout
private int[] row = {10, 60, 90, 120, 150, 180};
private int[] col = {10, 60, 110, 160, 210};
// for dentaku calculation
private bool entry_started = false;
private bool entry_dot = false;
private decimal entry_result = 0;
private decimal entry_memory = 0;
private string entry_operation = null;
/////////////////////////////////////////////////////////////////////////////
// Dentaku constructor

public Dentaku()
{
this.Width = 280;
this.Height = 250;
this.Text = "電卓";
this.FormBorderStyle
= System.Windows.Forms.FormBorderStyle.FixedDialog;
// DISPLAY
this.lab_0 = new Label();
this.lab_0.Font = new Font("MS UI Gothic", 14);
this.lab_0.BackColor = bgcolor_Disp;
this.lab_0.BorderStyle = BorderStyle.FixedSingle;
this.lab_0.Location = new Point(col[0], row[0]);
this.lab_0.Name = "lab0";
this.lab_0.Size = new Size(250, 40);
this.lab_0.Padding = new Padding(5);
this.lab_0.Text = "0";
this.lab_0.TextAlign = ContentAlignment.MiddleRight;
this.Controls.Add(this.lab_0);
// KEY √
this.but_root = new Button();
this.but_root.BackColor = bgcolor_Func;
this.but_root.Location = new Point(col[0], row[1]);
this.but_root.Size = key_Size;
this.but_root.Text = "√";
this.but_root.Click += new EventHandler(but_func_Click);
this.Controls.Add(this.but_root);
// KEY MRC
this.but_mrc = new Button();
this.but_mrc.BackColor = bgcolor_Memo;
this.but_mrc.Location = new Point(col[1], row[1]);
this.but_mrc.Size = key_Size;
this.but_mrc.Text = "MRC";
this.but_mrc.Click += new EventHandler(but_memo_Click);
this.Controls.Add(this.but_mrc);
// KEY M-
this.but_mminus = new Button();
this.but_mminus.BackColor = bgcolor_Memo;
this.but_mminus.Location = new Point(col[2], row[1]);
this.but_mminus.Size = key_Size;
this.but_mminus.Text = "M-";
this.but_mminus.Click += new EventHandler(but_memo_Click);
this.Controls.Add(but_mminus);
// KEY M+
this.but_mplus = new Button();
this.but_mplus.BackColor = bgcolor_Memo;
this.but_mplus.Location = new Point(col[3], row[1]);
this.but_mplus.Size = key_Size;
this.but_mplus.Text = "M+";
this.but_mplus.Click += new EventHandler(but_memo_Click);
this.Controls.Add(this.but_mplus);
// KEY ÷
this.but_div = new Button();
this.but_div.BackColor = bgcolor_Op;
this.but_div.Location = new Point(col[4], row[1]);
this.but_div.Size = key_Size;
this.but_div.Text = "÷";
this.but_div.Click += new EventHandler(but_ope_Click);
this.Controls.Add(this.but_div);
// KEY %
this.but_percent = new Button();
this.but_percent.BackColor = bgcolor_Func;
this.but_percent.Location = new Point(col[0], row[2]);
this.but_percent.Size = key_Size;
this.but_percent.Text = "%";
this.but_percent.Click += new EventHandler(this.but_func_Click);
this.Controls.Add(this.but_percent);
// KEY 7
this.but_7 = new Button();
this.but_7.BackColor = bgcolor_Num;
this.but_7.Location = new Point(col[1], row[2]);
this.but_7.Size = key_Size;
this.but_7.Text = "7";
this.but_7.Click += new EventHandler(but_num_Click);
this.Controls.Add(this.but_7);
// KEY 8
this.but_8 = new Button();
this.but_8.BackColor = bgcolor_Num;
this.but_8.Location = new Point(col[2], row[2]);
this.but_8.Size = key_Size;
this.but_8.Text = "8";
this.but_8.Click += new EventHandler(but_num_Click);
this.Controls.Add(this.but_8);
// KEY 9
this.but_9 = new Button();
this.but_9.BackColor = bgcolor_Num;
this.but_9.Location = new Point(col[3], row[2]);
this.but_9.Size = key_Size;
this.but_9.Text = "9";
this.but_9.Click += new EventHandler(but_num_Click);
this.Controls.Add(this.but_9);
// KEY ×
this.but_mul = new Button();
this.but_mul.BackColor = this.bgcolor_Op;
this.but_mul.Location = new Point(this.col[4], this.row[2]);
this.but_mul.Size = this.key_Size;
this.but_mul.Text = "×";
this.but_mul.Click += new EventHandler(this.but_ope_Click);
this.Controls.Add(this.but_mul);
// KEY ±
this.but_sign = new Button();
this.but_sign.BackColor = bgcolor_Func;
this.but_sign.Location = new Point(col[0], row[3]);
this.but_sign.Size = key_Size;
this.but_sign.Text = "±";
this.but_sign.Click += new EventHandler(but_func_Click);
this.Controls.Add(this.but_sign);
// KEY 4
this.but_4 = new Button();
this.but_4.BackColor = bgcolor_Num;
this.but_4.Location = new Point(col[1], row[3]);
this.but_4.Size = key_Size;
this.but_4.Text = "4";
this.but_4.Click += new EventHandler(but_num_Click);
this.Controls.Add(this.but_4);
// KEY 5
this.but_5 = new Button();
this.but_5.BackColor = bgcolor_Num;
this.but_5.Location = new Point(col[2], row[3]);
this.but_5.Size = key_Size;
this.but_5.Text = "5";
this.but_5.Click += new EventHandler(but_num_Click);
this.Controls.Add(this.but_5);
// KEY 6
this.but_6 = new Button();
this.but_6.BackColor = bgcolor_Num;
this.but_6.Location = new Point(col[3], row[3]);
this.but_6.Size = key_Size;
this.but_6.Text = "6";
this.but_6.Click += new EventHandler(but_num_Click);
this.Controls.Add(this.but_6);
// KEY −
this.but_minus = new Button();
this.but_minus.BackColor = bgcolor_Op;
this.but_minus.Location = new Point(col[4], row[3]);
this.but_minus.Size = key_Size;
this.but_minus.Text = "−";
this.but_minus.Click += new EventHandler(but_ope_Click);
this.Controls.Add(this.but_minus);
// KEY C
this.but_clear = new Button();
this.but_clear.BackColor = bgcolor_Cls;
this.but_clear.Location = new Point(col[0], row[4]);
this.but_clear.Size = key_Size;
this.but_clear.Text = "C";
this.but_clear.Click += new EventHandler(but_clear_Click);
this.Controls.Add(this.but_clear);
// KEY 1
this.but_1 = new Button();
this.but_1.BackColor = bgcolor_Num;
this.but_1.Location = new Point(col[1], row[4]);
this.but_1.Size = key_Size;
this.but_1.Text = "1";
this.but_1.Click += new EventHandler(but_num_Click);
this.Controls.Add(this.but_1);
// KEY 2
this.but_2 = new Button();
this.but_2.BackColor = bgcolor_Num;
this.but_2.Location = new Point(col[2], row[4]);
this.but_2.Size = key_Size;
this.but_2.Text = "2";
this.but_2.Click += new EventHandler(but_num_Click);
this.Controls.Add(this.but_2);
// KEY 3
this.but_3 = new Button();
this.but_3.BackColor = bgcolor_Num;
this.but_3.Location = new Point(col[3], row[4]);
this.but_3.Size = key_Size;
this.but_3.Text = "3";
this.but_3.Click += new EventHandler(but_num_Click);
this.Controls.Add(this.but_3);
// KEY +
this.but_plus = new Button();
this.but_plus.BackColor = bgcolor_Op;
this.but_plus.Location = new Point(col[4], row[4]);
this.but_plus.Size = key_Size2;
this.but_plus.Text = "+";
this.but_plus.Click += new EventHandler(but_ope_Click);
this.Controls.Add(this.but_plus);
// KEY 0
this.but_0 = new Button();
this.but_0.BackColor = bgcolor_Num;
this.but_0.Location = new Point(col[0], row[5]);
this.but_0.Size = key_Size;
this.but_0.Text = "0";
this.but_0.Click += new EventHandler(but_num_Click);
this.Controls.Add(this.but_0);
// KEY 00
this.but_00 = new Button();
this.but_00.BackColor = bgcolor_Num;
this.but_00.Location = new Point(col[1], row[5]);
this.but_00.Size = key_Size;
this.but_00.Text = "00";
this.but_00.Click += new EventHandler(but_num_Click);
this.Controls.Add(this.but_00);
// KEY ・
this.but_dot = new Button();
this.but_dot.BackColor = bgcolor_Dot;
this.but_dot.Location = new Point(col[2], row[5]);
this.but_dot.Size = key_Size;
this.but_dot.Text = "・";
this.but_dot.Click += new EventHandler(but_dot_Click);
this.Controls.Add(this.but_dot);
// KEY =
this.but_equal = new Button();
this.but_equal.BackColor = bgcolor_Eq;
this.but_equal.Location = new Point(col[3], row[5]);
this.but_equal.Size = key_Size;
this.but_equal.Text = "=";
this.but_equal.Click += new EventHandler(but_equal_Click);
this.Controls.Add(this.but_equal);
}
///////////////////////////////////////////////////////////////////////////
// but_num_Click - NUMBER key enter

private void but_num_Click(object sender, EventArgs e)
{
Button but = (Button)sender;
string n = "0";
switch (but.Text)
{
case "0" : n = "0"; break;
case "00" : n = "00"; break;
case "1" : n = "1"; break;
case "2" : n = "2"; break;
case "3" : n = "3"; break;
case "4" : n = "4"; break;
case "5" : n = "5"; break;
case "6" : n = "6"; break;
case "7" : n = "7"; break;
case "8" : n = "8"; break;
case "9" : n = "9"; break;
}
if (entry_started == false)
{
lab_0.Text = "0";
}
if (lab_0.Text == "0")
{
if (n != "00")
{
lab_0.Text = n;
}
}
else
{
lab_0.Text = lab_0.Text + n;
}
entry_started = true;
}
///////////////////////////////////////////////////////////////////////////
// but_dot_Click - DOT key enter

private void but_dot_Click(object sender, EventArgs e)
{
if (entry_dot == false)
{
if (entry_started == false)
{
lab_0.Text = "0.";
}
else
{
lab_0.Text = lab_0.Text + ".";
}
entry_started = true;
entry_dot = true;
}
}
///////////////////////////////////////////////////////////////////////////
// but_func_Click - Function key enter

private void but_func_Click(object sender, EventArgs e)
{
decimal n;
Button but = (Button)sender;
switch (but.Text)
{
case "±" :
n = decimal.Parse(lab_0.Text) * -1;
lab_0.Text = n.ToString();
break;
case "%" :
n = (decimal)(double.Parse(lab_0.Text) / 100);
lab_0.Text = n.ToString();
break;
case "√" :
try
{
n = (decimal)Math.Sqrt((double)decimal.Parse(lab_0.Text));
lab_0.Text = n.ToString();
}
catch
{
lab_0.Text = "E";
}
break;
}
entry_started = false;
entry_dot = false;
}
///////////////////////////////////////////////////////////////////////////
// but_ope_Click - OPERATION key enter

private void but_ope_Click(object sender, EventArgs e)
{
Button but = (Button)sender;
if (entry_operation != null)
{
but_equal_calculation();
}
entry_operation = but.Text;
entry_result = decimal.Parse(lab_0.Text);
entry_started = false;
entry_dot = false;
}
///////////////////////////////////////////////////////////////////////////
// but_equal_Click - EQUAL key enter

private void but_equal_Click(object sender, EventArgs e)
{
if (entry_operation != null)
{
but_equal_calculation();
}
entry_started = false;
entry_dot = false;
}
///////////////////////////////////////////////////////////////////////////
// but_equal_calculation - sub for EQUAL key enter

private void but_equal_calculation()
{
decimal n = 0;
switch (entry_operation)
{
case "+" :
n = entry_result + decimal.Parse(lab_0.Text);
lab_0.Text = n.ToString();
break;
case "−" :
n = entry_result - decimal.Parse(lab_0.Text);
lab_0.Text = n.ToString();
break;
case "×" :
n = entry_result * decimal.Parse(lab_0.Text);
lab_0.Text = n.ToString();
break;
case "÷" :
try
{
n = entry_result / decimal.Parse(lab_0.Text);
lab_0.Text = n.ToString();
}
catch
{
lab_0.Text = "E";
}
break;
}
entry_operation = null;
}
///////////////////////////////////////////////////////////////////////////
// but_clear_Click - CLEAR key enter

private void but_clear_Click(object sender, EventArgs e)
{
lab_0.Text = "0";
entry_started = false;
entry_dot = false;
entry_result = 0;
entry_operation = null;
}
///////////////////////////////////////////////////////////////////////////
// but_memo_Click - MEMORY key enter

private void but_memo_Click(object sender, EventArgs e)
{
Button but = (Button)sender;
switch (but.Text)
{
case "M+" :
entry_memory = entry_memory + decimal.Parse(lab_0.Text);
break;
case "M-" :
entry_memory = entry_memory - decimal.Parse(lab_0.Text);
break;
case "MRC" :
lab_0.Text = entry_memory.ToString();
entry_memory = 0;
break;
}
entry_started = false;
entry_dot = false;
}
}
}
// END PROGRAM

電卓の機能についてはデバッグが不十分です、ご了承ください。
Fedora 上でのビルド、および実行は次のようにします。

$ gmcs -pkg:dotnet -target:winexe dentaku.cs
$ mono dentaku.exe &


Windows XP へ dentaku.exe をコピーして、(ダブルクリックして)実行した結果を以下に示しました。

 

2010-07-25

Mono で GUI プログラミング (1)

Monoは、Ecma 標準に準じた .NET Framework 互換の環境を実現するためのオープンソースソフトウェアプロジェクトです。
FAQ [1] によると、Mono はスペイン語で猿の意味で、We like monkeys とあります。ロゴはゴリラをデザインしたもののようです。

Mono を利用すると、クロスプラットフォーム間(ここでは Linux と Windows)で簡単に同一の GUI アプリケーションを動作させることができそうです。

自宅では Linux、会社では Windows(しかもいまだに Windows XP)を使っているので、手軽に双方で動作するアプリケーションを Linux で開発するのであれば、Mono はまさにピッタリの開発環境です。MinGW クロスコンパイル環境よりもお手軽な感すらあります。

そこで、(C# 使いの Windows ユーザの方にとっては「今更」な感があるでしょうが)Windows 上で動作させることを意識した Mono の GUI プログラミングについて、調べた結果をまとめていきたいと思います。

最初は Hello World


まずは、おきまりの Hello World プログラムで動作確認です。当面は C# を使います。以下のソースを hello.cs として適当な場所に保存しておきます。

using System;
using System.Windows.Forms;
 
class HelloWorldApp {
public static void Main() {
MessageBox.Show("こんにちは、世界!", "mono");
}
}


mono のインストール


乱暴な方法ですが、私は以下のように mono- で始まるパッケージ(と関連するパッケージ)を全部インストールしてしまっています。使用している Linux は Fedora 13、mono のバージョンは 2.6.4 です。

$ su
パスワード:
# yum install mono-*
読み込んだプラグイン:presto, refresh-packagekit
...
(以下省略)


C# コンパイラとビルド


Mono 2.6.4 で利用できる C# コンパイラは以下の 4 種類です。[2]

mcs: compiler to target 1.1 runtime (to be deprecated with Mono 2.8).
gmcs: compiler to target the 2.0 runtime.
smcs: compiler to target the 2.1 runtime, to build Moonlight applications.
dmcs: the C# 4.0 compiler, and references the 4.0 runtime.

ここでは gmcs を使い、次のように hello.cs をビルド・実行します。

$ gmcs -pkg:dotnet -target:winexe hello.cs
$ mono hello.exe


コンパイルの際、-target:winexe を省略すると、Windows 上で実行した時に、コマンドプロンプトのウィンドウも表示されます。

同じく Linux 上の Wine で実行した結果を以下に示しました。

$ wine hello.exe


Wine には .Net Framework 2.0 をインストールしています。


Windows XP へ hello.exe をコピーして実行した結果は以下の様になります。

ちなみに XP では .Net Framework 3.5 までインストールされています。そのため、今のところ gmcs を使っていれば十分のようです。

参考サイト


[1] FAQ: General - Mono
[2] CSharp Compiler - Mono
 

【注記】情報が古くなりましたので、下記で内容を更新しました。