VC# Express で Windows Mobile 開発 第 2 回資料
第1 回まとめ → http://7shi.net/wmee/初期設定
VC# 2010 でやっておくと便利な設定。
ツール→設定→上級者設定
ツール→オプションo
チェックする:すべての設定を表示o
テキストエディター→すべての言語→全般
チェックする:行番号 描画が乱れる場合は以下の設定を推奨。
ツール→オプション→環境→全般o
チェックを外す:クライアントのパフォーマンスに基づいて視覚的効果を自動的に調整するo
チェックを外す:可能ならハードウェアのグラフィックスアクセラレータを使用するプロジェクト作成
1. VC# 2010 Express を起動 2. Windows フォームアプリケーションを新規作成 3. すべて保存 4. ソリューションエクスプローラー 1. プロジェクトを右クリック→プロパティ 1. ビルド→詳細設定→「mscorlib.dll を参照しない」をチェック→OK 2. 参照パスを追加: C:¥Program Files¥Microsoft.NET¥SDK¥CompactFramework¥v2.0¥WindowsCE 3. アプリケーション→対象のフレームワークを変更: .NET Framework 2.0 2. 以下を削除 1. Properties/Resources.resx 2. Properties/Settings.settings 3. app.config 4. Form1.cs/Form1.Designer.cs 5. すべて保存 6. VC# 2010 Express を閉じる 7. プロジェクトファイルをエディタで開き、<ItemGroup>内の<Reference Include=...>を以下のように書き換える <ItemGroup> <Reference Include="mscorlib" /> <Reference Include="System" /> <Reference Include="System.Data" /> <Reference Include="System.Drawing" /> <Reference Include="System.Windows.Forms" /> <Reference Include="System.Xml" /> </ItemGroup> ソリューションを開いて実行してみる。エラーが出てくるので、行ごと削除すると実行できるようになる。EXE をコピーすると端末で動くが、終了する手段がない。[OK]で終了できるようにする。WM 6.5.3 ではメニューバーに[OK]が表 示されるため、空メニューを作成。Form1 のコンストラクタに以下のコードを追加。
public Form1() {
MinimizeBox = false; Menu = new MainMenu();
後は、GUI デザイナが使えない以外は、普通に開発できる。普段はエミュレータなしで開発して、たまにエミュレータに転送して 動作確認。
エミュレータ
Pocket PC は Windows Mobile と一部動作が異なるため、たまに Windows Mobile で動作確認。
Windows 7 ではショートカットが作成されないことがあるので、その場合はショートカットだけをコピーする。 プロジェクトのDebug フォルダを共有しておくと、デバッグが簡単。
ファイル→構成→全般→共有フォルダ共有フォルダはエクスプローラでStorage Card 扱いとなる。表示しっぱなしにしておいて、デバッグしたいときに EXE をクリッ クして起動する。 動作がおかしくなったときはソフトリセットすればすぐに復旧する。
GUI
※ この節のコードはすべてForm1 クラス内に記述することが前提。 画面サイズ指定などの決まり文句を含めたテンプレートは以下の通り。Layout や AutoScale 関係は自動調整のために必要。 機種によってはAutoScaleMode の指定を解除しないといけないという報告あり。要実機確認。 public Form1() { Text = "アプリ";Size = new Size(240, 320); MinimizeBox = false; SuspendLayout();
AutoScaleDimensions = new SizeF(96, 96); AutoScaleMode = AutoScaleMode.Dpi; Menu = new MainMenu();
InitializeComponent(); ResumeLayout(false); }
private void InitializeComponent() {
}
コントロール配置の定型。
button は InitializeComponent()以外でも使えるようにするため、外で定義。 button.Bounds の行の Rectangle の数値は画面上の位置とサイズ。(下図参照) private Button button = new Button();
private void InitializeComponent() {
button.Text = "ボタン";
button.Bounds = new Rectangle(10, 50, 100, 40); button.Click += new EventHandler(button_Click); Controls.Add(button);
}
void button_Click(object sender, EventArgs e) { MessageBox.Show("hello"); }
10
50
100
40
+= の部分で
[+][=][Tab][Tab]
と入力すれば簡単
その他のコントロール
Button, CheckBox, ComboBox, DateTimePicker, DomainUpDown, HScrollBar, Label, LinkLabel, ListBox, ListView, MonthCalendar, NumericUpDown, Panel, PictureBox, ProgressBar, RadioButton, Splitter, StatusBar, TabControl, TabPage, TextBox, ToolBar, TrackBar, TreeView, VScrollBar, WebBrowserWindows 7 上でテストすると、TextBox で MS-IME が使えない。Google 日本語入力では可能という報告あり。
描画
基本的なコード
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
using (var pen = new Pen(Color.Red))
using (var brush = new SolidBrush(Color.Blue)) {
e.Graphics.DrawLine(pen, 0, 0, 20, 20); e.Graphics.DrawLine(pen, 0, 20, 20, 0); e.Graphics.FillRectangle(brush, 5, 5, 10, 10); e.Graphics.DrawString("abc", Font, brush, 0, 20); }
}
EXE と同じフォルダの画像を読み込んで表示。test.png はプロジェクトに DnD して、プロパティでコピー設定しておく。 private Bitmap image;
private void InitializeComponent() {
var exe = Assembly.GetExecutingAssembly().ManifestModule.FullyQualifiedName; var path = Path.GetDirectoryName(exe);
var png = Path.Combine(path, "test.png"); image = new Bitmap(png);
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
e.Graphics.DrawImage(image, 5, 5); }
画像の一部だけを表示する。出力先・画像の使用部分の順で指定。GraphicsUnit 以降は決まり文句。
e.Graphics.DrawImage(image, new Rectangle(30, 30, 20, 20), 10, 20, 30, 40, GraphicsUnit.Pixel, new ImageAttributes());
※この例ではサイズを変更して出力しているが、Windows Mobile でのサイズ変更はとても遅いため、なるべく避ける。
10
20
40
30
画像
画面
30
30
20
20
[O][V][Space][O][N][P][Enter]
と入力すれば簡単
ゲームでキャラクタの周辺を透過したい場合、Windows Mobile ではα値が無視されるため、透過色を指定する。以下の例ではマゼ ンタを透過色とする。画像中のマゼンタは表示されずに背景が透過する。
var imgattr = new ImageAttributes();
imgattr.SetColorKey(Color.Magenta, Color.Magenta); int w = image.Width, h = image.Height;
e.Graphics.DrawImage(image, new Rectangle(0, 0, w, h), 10, 10, w, h, GraphicsUnit.Pixel, imgattr);
一定時間ごとに動かす(ちらつく) private int x = 0;
private void InitializeComponent() {
var timer = new Timer(); timer.Interval = 50;
timer.Tick += new EventHandler(timer_Tick); timer.Enabled = true;
}
void timer_Tick(object sender, EventArgs e) {
x += 4;
if (x >= ClientSize.Width) x = 0; Invalidate();
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
using (var brush = new SolidBrush(Color.Red)) { e.Graphics.FillEllipse(brush, x, 0, 16, 16); } } 画面に直接表示すると、描画過程が見えるためちらつく。ちらつきを抑えるには、メモリに画面と同じサイズの画像(これをバッフ ァと呼ぶ)を作成して、バッファに描画してから画面に表示する。これをダブルバッファと呼ぶ。 バッファは見えないため、丸や三角などを描画する過程は見えない。すべて揃った状態で画面に描画するため、ちらつかない。 バッファはnew Bitmap で作成。Graphics.FromImage 経由でバッファに描画。
var bmp = new Bitmap(240, 320);
using (var g = Graphics.FromImage(bmp)) using (var pen = new Pen(Color.Red))
using (var brush = new SolidBrush(Color.Blue)) {
g.DrawLine(pen, 0, 0, 20, 20); g.DrawLine(pen, 0, 20, 20, 0); g.FillRectangle(brush, 5, 5, 10, 10); g.DrawString("abc", Font, brush, 0, 20); }
画像(バッファ)
画面
+= の部分で
[+][=][Tab][Tab]
と入力すれば簡単
ダブルバッファの例。OnPaint の内容は固定で、DrawBuffer の中で描画処理を行う。 private Bitmap bmp = new Bitmap(240, 320);
private int x = 0;
private void InitializeComponent() {
var timer = new Timer(); timer.Interval = 50;
timer.Tick += new EventHandler(timer_Tick); timer.Enabled = true;
DrawBuffer(); }
void timer_Tick(object sender, EventArgs e) {
x += 4;
if (x >= ClientSize.Width) x = 0; DrawBuffer();
using (var g = CreateGraphics()) g.DrawImage(bmp, 0, 0); }
private void DrawBuffer() {
using (var g = Graphics.FromImage(bmp)) using (var brush = new SolidBrush(Color.Red)) {
g.Clear(BackColor);
g.FillEllipse(brush, x, 0, 16, 16); }
}
protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); e.Graphics.DrawImage(bmp, 0, 0); }
クリック
クリックしたところに○を移動 private int x = 120, y = 160;protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); x = e.X; y = e.Y; Invalidate(); }
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
using (var brush = new SolidBrush(Color.Red))
e.Graphics.FillEllipse(brush, x - 8, y - 8, 16, 16);
[O][V][Space][O][N][M][O]
と入力して、出てきた候補から
OnMouseDown
を選択して[Enter]を押すと簡単
+= の部分で
[+][=][Tab][Tab]
と入力すれば簡単
先ほどの例では、クリックしたところに移動するだけで、ドラッグは感知しない。ドラッグ対応は以下を追加。 protected override void OnMouseMove(MouseEventArgs e)
{ base.OnMouseMove(e); if (e.Button == MouseButtons.Left) { x = e.X; y = e.Y; Invalidate(); } }
ネットワーク
PC 用の.NET Framework には WebClient というクラスがあって、簡単にファイルをダウンロードすることができる。 .NET Compact Framework には WebClient クラスがないので、自前でストリームを処理する必要がある。
HTTP からファイルをダウンロードする例
public static void DownloadFile(string url, string file) {
var req = WebRequest.Create(url) as HttpWebRequest;
req.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows XP)"; var res = req.GetResponse();
using (var s = res.GetResponseStream())
using (var fs = new FileStream(file, FileMode.Create)) {
var buf = new byte[4096]; for (; ; )
{
int len = s.Read(buf, 0, buf.Length); if (len == 0) break; fs.Write(buf, 0, len); } } } 使用例 DownloadFile("http://www.yahoo.co.jp/", "yahoo.html"); HTML を文字列として読み込む例
public static string DownloadString(string url, Encoding enc) {
var req = WebRequest.Create(url) as HttpWebRequest;
req.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows XP)"; var res = req.GetResponse();
using (var s = res.GetResponseStream()) using (var sr = new StreamReader(s, enc)) return sr.ReadToEnd();
}
使用例
var html = DownloadString("http://www.yahoo.co.jp", Encoding.UTF8);
.NET Framework の WebClient は文字コードを自動判定するため Encoding を指定する必要はない。しかし自動判定まで真似する と複雑になるため、手動でEncoding を指定するようにした。
[O][V][Space][O][N][M][O]
と入力して、出てきた候補から
OnMouseMove
Yahoo のトップページを読み込んでテキストボックスに表示 private TextBox tb = new TextBox();
private void InitializeComponent() {
var mi = new MenuItem(); mi.Text = "ダウンロード";
mi.Click += new EventHandler(mi_Click); Menu.MenuItems.Add(mi); tb.Dock = DockStyle.Fill; tb.Multiline = true; tb.WordWrap = false; tb.ScrollBars = ScrollBars.Both; Controls.Add(tb); }
void mi_Click(object sender, EventArgs e) {
tb.Text = DownloadString("http://www.yahoo.co.jp/", Encoding.UTF8); }
スクレイピング
Yahoo のトップページからトピックスを抜き出す例 void mi_Click(object sender, EventArgs e) {
var sw = new StringWriter();
var html = DownloadString("http://www.yahoo.co.jp/", Encoding.UTF8); int p = html.IndexOf("<div class=\"topicsindex\">");
if (p >= 0) {
int end = html.IndexOf("</ul>", p); for (; ; ) { p = html.IndexOf("<a href", p); if (p < 0 || p > end) break; p = html.IndexOf(">", p) + 1; int p2 = html.IndexOf("<", p); sw.WriteLine(html.Substring(p, p2 - p)); } } tb.Text = sw.ToString(); } あらかじめ対象となるHTML を分析して、構造を把握しておく必要がある。上の例ではまず <div class="topicsindex"> という箇 所を探して、その後で <a href> ~ </a> のタグの間のテキストを抜き出している。
HTML 構造が複雑になると処理が複雑になり過ぎるため、HTML パーサを作成した。 http://d.hatena.ne.jp/n7shi/20100527
テクニック集
Main に[STAThread]を指定できるようにする。指定しないと OpenFileDialog などが使えない。 namespace System
{
public class STAThreadAttribute : Attribute { }
+= の部分で
[+][=][Tab][Tab]
と入力すれば簡単
画面全体に広げる
文字列の中で ” を使うには ¥” とする
この ¥ をエスケープシーケンスと呼ぶ
.NET 2.0 でも拡張メソッドが使えるようにする。 namespace System.Runtime.CompilerServices {
public class ExtensionAttribute : Attribute { } }
WM かどうかを判定して動作を変える。
if (Environment.OSVersion.Platform == PlatformID.WinCE) ...
EXE と同じフォルダのファイルにアクセス。
var exe = Assembly.GetExecutingAssembly().ManifestModule.FullyQualifiedName; var path = Path.GetDirectoryName(exe);
var ini = Path.Combine(path, "app.ini");
.NET 2.0 では委譲型を定義しておくと便利。 namespace System
{
public delegate void Action();
public delegate void Action<T1, T2>(T1 a, T2 b);
public delegate void Action<T1, T2, T3>(T1 a, T2 b, T3 c); public delegate TR Func<TR>();
public delegate TR Func<T1, TR>(T1 a);
public delegate TR Func<T1, T2, TR>(T1 a, T2 b); }
第 3 回について
奇数月の第3 土曜日開催です。次回は 3 月 19 日開催です。 → http://atnd.org/events/11717
Windows Phone 7 を視野に入れて Silverlight 勉強会にすることも検討しています。ご意見をお願いします。
偶数月は別の勉強会を開催する予定になっているため、Silverlight の勉強会を別に開催すると 3 つ掛け持ちになってしまい、手が 回りません。ちなみに2 月に予定している別の勉強会は定員に達しました。 → http://atnd.org/events/11721
Silverlight 勉強会を構想した背景
Silverlight は Microsoft が Flash 対抗で開発したブラウザプラグインです。Flash と同じようにウェブページ内に貼り付けることが できます。
Windows Phone 7 では Windows Mobile とはプログラムの作り方が変わりました。Silverlight と XNA という API を使用します。 大雑把に分類すると、Silverlight は一般アプリ用、XNA はゲーム用です。
しかし、現段階ではWindows Phone 7 のプログラミングは制約が厳しいです。 1. 英語版のアプリを開発するだけならフリーで可能。
2. 日本語版が出ていない。そのため日本では実機が発売されていない。日本語版は今年後半の予定。 3. 実機を個人輸入しても、自作アプリを動かすには年間1 万円で登録が必要。
ブラウザで動かすSilverlight は開発も実行もフリーです。そのため Windows Phone 7 への準備として、現段階ではブラウザで動 かすSilverlight を勉強するのが落とし所ではないかと考えました。今までの Windows Mobile 開発との違いを比べながら勉強すると、 理解も早まるかもしれません。今までの勉強会とのつながりは、そういう部分の説明に反映させたいです。