|











|
 | 簡単なモバイルアプリケーション開発8
Amedas 情報の表示 (WZero3DeAmedas V1.2)
|
開発環境: Visual Studio 2005
|
|
1.目次
2.目的
3.参考書
4.作り方
5.ダウンロード
6.ソースコード
7.まとめ
|
|
|
簡単なモバイルアプリケーション開発7
Amedas 情報の表示を
作りましたが、予想外に反響が大きく、地域などのプリセット、画像の拡大縮小、画像の保存位置情報等いくつか要望があがってきました。もともと、そこまで作るつもりはなかったのですが、自分自身でもこの1週間使ってみたところ、結構使えるので、
設定の保存ぐらいしたくなり、拡張することにしました。
ということで、要望をまとめると、次のようになります。
- 種類、位置情報の保持
- 画像情報の拡大縮小
- 画像情報の保存
しかし、画像情報の拡大縮小、画像情報の保存を実施しようと思うと、WebBrowser
コントロールでブラウズする方法では対応できません。このため、そもそもの設計を変更し、気象情報を画像としてダウンロードして、PictureBox
コントロールに表示させる必要が出てきます。この場合、URL
を組み立てて、ファイルを取得して、あとはその画像のビューアーを作るという形になります。しかし、ファイルに落とすには、わかりやすい名前でファイルをダウンロードする必要があります。そのためには、種類、地域、時間情報からファイル名を作成し、再度オープンするような仕組みが必要になります。
このような画像を表示するような実装に変更するとなると、画像ビューアーを作ることになるので、かなりの拡張が必要になると思われます。
しかし、V1.0.0.0の実装は、Form.cs
にべたに書いているので、今後拡張していこうと思うと行数が多くなり、また拡張性もよくありません。そこで、今後の拡張を考えて、種類、地域、時間を扱いやす形にリファクタリングし
ます。
また、要望1の、「種類、位置情報の保持」ができるようにします。

注意:
- このアプリケーションによる気象情報は、すべての気象庁の防災気象情報をカバーしていませんので、クリティカルな用途には使わないでください。
- 気象庁の防災気象情報の気象情報URLが変更になってしまうと、動かなくなってしまいます。
|
|
|
(1) 気象庁の防災気象情報
|
|
|
|
4.1 種類、位置情報のセーブとロード
|
.NET Compact Framework では、System.Configuration クラスがサポートされておらず、System.Configuration
を使った設定ファイルの取り扱いができません。
このため、種類、地域情報のセーブとロードをするため、自分で設定項目をリード、ライトするコードを実装する必要があります。実現方法は、レジストリを使用するか、ファイルを使用するかになりますが、レジストリに書き込むのは好きではないので、ファイルにXML形式で書きだすことにします。ファイルへのXMLのリード、ライトは、System.Xml,
System.IO がサポートされているため、簡単に実装できます。そこで、設定ファイルのリード、ライトを行うクラス
ClassConfigFile.cs を追加し、次のように実装します。
class
ConfigFile
{
private
string
typeName;
public
string TypeName
{
get
{ return
typeName; }
set
{ typeName = value;
}
}
private
string
locName;
public
string
LocationName
{
get
{ return
locName; }
set
{ locName = value;
}
}
private
string
configFilePath = GetCurrentDirectory() +
"\\config.xml";
public
void
WriteConfigFile(string
typeName, string
locName)
{
using
(XmlTextWriter
xtw = new
XmlTextWriter(configFilePath,
Encoding.Unicode))
{
xtw.WriteStartElement("configuration");
xtw.WriteElementString("種類",
typeName);
xtw.WriteElementString("地域",
locName);
xtw.WriteEndElement();
xtw.Close();
}
}
public
void
ReadConfigFile()
{
// 設定ファイルがない場合は、何もしない
if
(!File.Exists(configFilePath))
return;
using
(XmlTextReader
xtr = new
XmlTextReader(configFilePath))
{
xtr.ReadStartElement("configuration");
typeName = xtr.ReadElementString("種類");
locName = xtr.ReadElementString("地域");
xtr.ReadEndElement();
xtr.Close();
}
}
ここで、Windows Mobile 固有の問題があります。それは、Windows
Mobile では、ファイルのアクセスは相対パスで行うことができず、絶対パスで指定する必要があるということです。設定ファイルは、exeのおかれる場所に置きたいですよね。そのためには次の
GetCurrentDirectory メソッドで、exeのアセンブリから絶対パスを取得します。
private
static
string
GetCurrentDirectory()
{
string
fqn = Assembly.GetExecutingAssembly().ManifestModule.FullyQualifiedName;
FileInfo finfo =
new
FileInfo(fqn);
return
finfo.DirectoryName;
}
以上より、次のような簡単な XML ファイルのリード・ライトをするためのクラスの出来上がりです。
|
4.2 種類、位置情報のセーブとロードを行うダイアログ
|
種類、位置情報のセーブとロードを行うダイアログを実装します。そこで、次のようなFormConfig.cs
を追加し、ラベル、コンボボックス、ボタンを次のように配置します。

次に、メインフォームのメニューに「設定」を追加し、次のように呼び出します。
private
void
menuItemConfig_Click(object
sender, EventArgs
e)
{
FormConfig
formConfig = new
FormConfig(menuItemLocation,
menuItemType);
formConfig.ShowDialog();
}
ここで、コンボボックスに表示する種類と、地域ですが、メインフォームのメインメニューにほとんど同じ項目をセットする必要があります。
単純に実装すると、メインメニューに全国、北海道、・・・と実装し、この設定用のコンボボックスでも、同様に全国、北海道、・・・と実装と実装することになってしまいます。しかし、複数の箇所で、同じ
項目があると、将来的な拡張やメインテナンスが面倒になります。そこで、コンボボックスに表示する項目は、メインフォームのメインメニューからデータを読み取り、このコンボボックスに追加するようにします。
つまり、メインフォームのメインメニューがマスターということになります。もう少し拡張性を持たせるのであれば、ファイルにメニューに必要な情報を格納しておき、それを元にメニューを構築するという手もありますが、この程度のアプリならそこまでは必要ないでしょう
w。
種類メニューの一部は、警報→洪水
というように階層構造になっているので、末端(リーフ)のメニュー項目だけを追加します。末端(リーフ)のメニュー項目かどうかは、MenuItems.Count
== 0で判断します。複数階層の場合には、再帰呼び出しをすればいいのですが、ここでは2階層までの前提でサーチすることにします。
///
<summary>
/// 種類メニューに値をセットする
///
</summary>
///
<param name="menuItemType">メインフォームの種類メニュー</param>
private
void
SetAmedasType(MenuItem
menuItemType)
{
foreach (MenuItem
mi in
menuItemType.MenuItems)
{
if
(mi.MenuItems.Count == 0)
comboBoxType.Items.Add(mi.Text);
else
foreach (MenuItem
miSecondLevel in
mi.MenuItems)
comboBoxType.Items.Add(miSecondLevel.Text);
}
comboBoxType.SelectedIndex = 0;
}
同様に、地域メニューをメインメニューから設定するようにします。
///
<summary>
/// 地域メニューに場所をセットする
///
</summary>
///
<param name="amedasLocation">メインフォームの地域メニュー</param>
private
void
SetAmedasLocation(MenuItem
amedasLocation)
{
foreach (MenuItem
al in
amedasLocation.MenuItems)
{
comboBoxLocation.Items.Add(al.Text);
}
comboBoxLocation.SelectedIndex = 0;
}
次に、セーブボタンが押された時のイベントハンドラを追加し、XMLファイルへ書き込みます。書き込めなかった場合などの例外を処理したい場合は、try-catch
のエラー処理を追加してください。
private
void buttonSave_Click(object
sender, EventArgs e)
{
configFile.WriteConfigFile(
(string)comboBoxType.SelectedItem,
(string)comboBoxLocation.SelectedItem);
Close();
}
設定ファイルを読み込みは、次のようにXmlTextReaderで読み込み、種類、地域を読み込みます。その値をコンボボックスのSelectedItemにセットしてあげます。
///
<summary>
/// 設定ファイルをロードして、表示する。
///
</summary>
private
void
LoadConfig()
{
configFile.ReadConfigFile();
// 種類メニューを設定
foreach(object
o in
comboBoxType.Items)
if (((string)o)
== configFile.TypeName)
comboBoxType.SelectedItem = o;
// 場所メニューを設定
foreach (object
o in
comboBoxLocation.Items)
if (((string)o)
== configFile.LocationName)
comboBoxLocation.SelectedItem = o;
buttonSave.Focus();
}
以上により、次のような設定ダイアログが表示できます。

|
4.3 種類メニューのリファクタリング
|
V1.0.0.0の種類メニューの処理がいまいちだったので、次のようにリファクタリングしました。考え方は、class MenuItem
から継承したクラスAmedasTypeMenuItem を作成し、MenuItem で必要な情報をすべて持たせる方法です。
各MenuItemは、URL 生成のための文字列フォーマット(urlFormat)と、その文字列フォーマットに位置情報が必要かどうか(bool
locationMenu)、場所情報が必要かどうか(bool timeMenu)を持たせます。
using System;
using System.Collections.Generic;
using
System.Windows.Forms;
namespace
Uchukamen.WZero3.WZero3DeAmedas
{
public
class
AmedasTypeMenuItem
: MenuItem
{
internal
bool
timeMenu;
internal
bool
locationMenu;
internal
string
urlFormat;
public
AmedasTypeMenuItem(string
name, bool
loc, bool
time, EventHandler
eh, string
sformat)
{
Text = name;
locationMenu = loc;
timeMenu = time;
urlFormat = sformat;
Click +=
new System.EventHandler(eh);
}
}
public
class
AmedasTypeMenu
{
public
void Set(MenuItem
mi, EventHandler
eh)
{
mi.MenuItems.Add(new
AmedasTypeMenuItem("天気予報",
true,
false, eh,
"http://www.jma.go.jp/jp/yoho/images/g1/{0}_telop_today.png"));
mi.MenuItems.Add(new
AmedasTypeMenuItem("レーダー・降水ナウキャスト",
true,
true, eh,
"http://www.jma.go.jp/jp/radnowc/imgs/{2}/{0}/{1}.png"));
int
isat = mi.MenuItems.Add(new
AmedasTypeMenuItem("気象衛星",
false,
false, eh,
null));
mi.MenuItems[isat].MenuItems.Add(new
AmedasTypeMenuItem("赤外線",
false,
true, eh,
"http://www.jma.go.jp/jp/gms/imgs_c/0/infrared/1/{0}.png"));
mi.MenuItems[isat].MenuItems.Add(new
AmedasTypeMenuItem("可視光",
false,
true, eh,
"http://www.jma.go.jp/jp/gms/imgs_c/0/visible/1/{0}.png"));
中略
}
}
}
これらの初期設定は、メインメニューから次のように行います。
private
void
CreateTypeMenu()
{
AmedasTypeMenu
atm = new
AmedasTypeMenu();
atm.Set(menuItemType, menuItemType_Click);
}
これで、種類メニュー関連をこの1つのクラスに集中させます。
|
4.4 時間メニューのリファクタリング
|
同様に、V1.0.0.0
では、時間メニューも1つのファイルに作っていましたので、これも別クラスとして分離します。基本的な考え方は、種類メニューと同様に、MenuItem
から継承した AmedasTimeMenuItem クラスを作成し、そこにメニューに表示する時間(Text)と URL
を作成する際に必要となる時間のパラメータ(TimeCommand) を格納します。
public
class
AmedasTimeMenuItem
: MenuItem
{
public
DateTime
Time;
public
string
TimeCommand;
public
AmedasTimeMenuItem(){ }
public
AmedasTimeMenuItem(string
menuText, DateTime
time, string
timeCmd)
{
Text = menuText;
Time = time;
TimeCommand = timeCmd;
}
}
また、時間メニューには、次の2つの種類があります。
- 通常の過去12時間分(1時間おき)の List<AmedasTimeMenuItem> normalTime
- 過去6時間分(1時間おき)と1時間後まで(10分おき)の List<AmedasTimeMenuItem>
normalTime
これらの2つの時間メニューを AmedasTimeSet クラスが管理します。
public
class
AmedasTimeSet
{
public
List<AmedasTimeMenuItem>
normalTime = new
List<AmedasTimeMenuItem>();
public
List<AmedasTimeMenuItem>
nowCastTime = new
List<AmedasTimeMenuItem>();
///
<summary>
///
レーダー・降水ナウキャスト以外の場合の時間メニューを作成
///
過去12時間まで1時間刻み
///
</summary>
public
void
CreateNormalTime()
{
中略
}
///
<summary>
///
レーダー・降水ナウキャストの場合の時間メニューを作成
///
1時間後まで10分刻みの予想と
///
過去6時間まで1時間刻み
///
</summary>
public
void
CreateNowCastTime()
{
中略
}
}
時間メニューは、時間が経過すると後にアップデートする必要があります。そこで、時間メニューを定期的に更新するための
UpdateTimeMenu() メソッドで、時間メニューの更新を行います。時間メニューには、通常の normalTime と予想時の
nowCastTime の2つがありますので、それぞれ必要に応じて更新します。
private
void
UpdateTimeMenu()
{
if (selectedTypeMenu.Text.EndsWith("ナウキャスト"))
{
atm.CreateNowCastTime();
currentTimeCommand = atm.SetNowCastTimeMenu(menuItemTimeMain,
menuItemNowCastTimeEvent);
}
else
{
atm.CreateNormalTime();
currentTimeCommand = atm.SetNormalTimeMenu(menuItemTimeMain,
menuItemNormalTimeEvent);
}
}
|
4.5 地域メニューのリファクタリング
|
同様に地域メニューも独立したファイルにリファクタリングします。基本的な考え方は同じで、MenuItemから継承した
AmedasLocationMenuItem クラスを作成し、地域名表示のための(Text)と、地域コード(locationCode)
を合わせて管理します。
public
class
AmedasLocatoinMenuItem
: MenuItem
{
internal
string
locationCode;
public
AmedasLocatoinMenuItem(string
locCode, string
name, EventHandler
eh)
{
locationCode = locCode;
Text = name;
Click +=
new System.EventHandler(eh);
}
}
また、このMenuItem をまとめて処理するためのクラス AmedasLocationMenu を追加します。
public
class
AmedasLocationMenu
{
public
void Set(MenuItem
mi, EventHandler
eh)
{
mi.MenuItems.Add(new
AmedasLocatoinMenuItem("000",
"全国", eh));
mi.MenuItems.Add(new
AmedasLocatoinMenuItem("201",
"北海道地方(北西部)",
eh));
中略
mi.MenuItems.Add(new
AmedasLocatoinMenuItem("219",
"宮古・八重山地方",
eh));
}
}
これにより、メインフォームからは、地域メニューの作成は、次のような呼び出しに集約することができます。イベントハンドラは、menuItemLocationEventにまとめてしまいます。
///
<summary>
/// 地域メニューを作成
///
</summary>
private
void
CreateLocationMenu()
{
AmedasLocationMenu
alm = new
AmedasLocationMenu();
alm.Set(menuItemLocation, menuItemLocationEvent);
}
|
4.6 メインルーチンのリファクタリング
|
V1.0.0.0
では、種類のメニューごとに、次のようなコードがつらつらと10以上も並んでいて、拡張性が悪いです。そこで、もう少しこのあたりを整理します。
///
/// レーダー・予測
///
private void menuItemRadar_Click(object sender, EventArgs e)
{
ClearAllMenuItemTypeChecked();
menuItemRadar.Checked = true;
menuItemLocation.Enabled = true;
menuItemTimeMain.Enabled = true;
SetNowCastTimeMenu();
ShowAmedas();
}
基本的な考え方は、地域、時間をメニューよりセットした時に、次のパラメータに格納します。
- 地域コード private
string
locationCode;
- 時間パラメータ private
string
currentTimeCommand;
次に、その時の種類、場所、時間の3つのパラメータの組み合わせにより、BuildUrl() メソッドにより URL を作成します。
private
Uri BuildUrl()
{
Uri amedasUrl =
null;
bool loc = selectedTypeMenu.locationMenu;
bool time =
selectedTypeMenu.timeMenu;
string strFormat =
selectedTypeMenu.urlFormat;
if (strFormat.IndexOf("radnowc")
>= 0)
amedasUrl = new
Uri(string.Format(strFormat,
locationCode, currentTimeCommand, nowCastCommand));
else
if (loc ==
true && time ==
true)
amedasUrl = new
Uri(string.Format(strFormat,
locationCode, currentTimeCommand));
中略
else if (loc ==
false && time ==
false)
amedasUrl = new
Uri(string.Format(strFormat));
return amedasUrl;
}
この URL を WebBrowserで Navigate することにより、画像を表示します。
///
<summary>
/// アメダス情報を表示する
///
</summary>
private
void ShowAmedas()
{
if (selectedTypeMenu ==
null)
return;
Uri amedasUrl = BuildUrl();
webBrowser1.Navigate(amedasUrl);
}
|
4.7 スタートメニューに追加
|
「スタート->プログラムで本ソフトが起動できるようになるとよいのですが。」というコメントをいただいたのですが、普段ローンチャーを使用しているので、スタート->プログラムでソフト起動というのは思いもよりませんでした。
スタート メニューにアイコンを追加するには、Cab
プロジェクトの中で、次のように対象コンピュータ上のファイルシステムを右クリックし、特別なフォルダの追加→スタートアップフォルダを指定します。

すると、次のようにスタート メニューが追加されます。そこで、プライマリー出力を右クリックして、ショートカットを作成します。

そのショートカットをスタート メニュー
フォルダに移動します。このとき、名前を適切に変更しないとビルドに失敗しますので、注意してください。

以上により、Cab ファイルからインストールすると、スタート→プログラムにショートカットが追加されます。
|
4.8 今後の予定
|
機能的には種類、地域の設定ができるようにしたことと、時間メニューの更新が適切に行えていなかったバグを修正しただけですが、大幅に作り変えてしまいました。
クラスダイアグラムは、ざっくりと次のような構成です。


これで、WebBrowser から PictureBox に切り替えるための基本的な準備はできたと思うので、次期バージョンV2.0
で画像の拡大・縮小を実装したいと考えています。
|
|
|
WZero3DeAmedas.CAB Version 1.1.0.0
2007/7/22
V1.0.0.0 からの修正点は次の通り。
種類、地域情報をプリセットできるようにした。
時間メニューの更新がタイムリーに行えないバグを修正。
WZero3DeAmedas.CAB Version 1.2.0.0 2007/7/23
今日、通勤途上で V1.1.0.0 を使っていたら、バグを見つけてしまいました。
ごめんなさい。m_ _m 修正版です。
V1.1.0.0 からの修正点は次の通りです。
バグ修正: 他の表示種類から、レーダー・降水ナウキャストを指定した時のURLのバグを修正。
バグ修正: 時間メニューの更新がタイムリーに行えないバグ(その2)を修正。
その他: インストール時に、スタート→プログラムにショートカットを追加。
その他: アイコンを修正。
WZero3DeAmedas Version
2.0.0.0 Beta1 2007/8/3 を公開しました。
動作環境
.NET Compact Framework 2.0 が必要です。
検証
WS004SH で動作確認をしました。
注意
- 動作は保証しません。クリティカルな用途には使わないでください。
- 気象庁の防災気象情報の一部しか対応ていません。
- 気象庁の防災気象情報の気象情報URLが変更になってしまうと、動かなくなってしまいます。
- 1つの画像に対して、数十KB〜数百KBの通信が必要です。通信コストにご注意ください。
- データが無い場合、"Not Found"
エラーになる場合があります。原因としては、パラメータを渡す際のバグ、データ作成が間に合っていないこととが考えられます。
- 種類を変更した場合、時間は最も近い過去の時間に再設定します。
|
|
|
主なソースコードです。 FormMain.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Reflection;
using System.Xml;
using System.IO;
namespace Uchukamen.WZero3.WZero3DeAmedas
{
public partial class FormMain : Form
{
public FormMain()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// 種類のメニューを作成する
CreateTypeMenu();
// 場所のメニューを作成する
CreateLocationMenu();
// 設定ファイルを読み込む
LoadConfig();
// 時間のメニューを作成する
UpdateTimeMenu();
// データを表示する
ShowAmedas();
}
#region 設定ファイルを読み込む
private void LoadConfig()
{
ConfigFile configFile = new ConfigFile();
configFile.ReadConfigFile();
// 種類メニューを設定
MenuItem miType = FindMenu(menuItemType, configFile.TypeName);
if (miType != null)
{
miType.Checked = true;
selectedTypeMenu = (AmedasTypeMenuItem)miType;
UpdateTimeMenu();
}
// 種類によっては、場所メニュー、時間メニューの有効、無効が違う
menuItemLocation.Enabled = selectedTypeMenu.locationMenu;
menuItemTimeMain.Enabled = selectedTypeMenu.timeMenu;
// 場所メニューを設定
MenuItem miLoc = FindMenu(menuItemLocation,
configFile.LocationName);
if (miLoc != null)
{
miLoc.Checked = true;
locationCode = ((AmedasLocatoinMenuItem)miLoc).locationCode;
}
}
private void UpdateTimeMenu()
{
if (selectedTypeMenu.Text.EndsWith("ナウキャスト"))
{
atm.CreateNowCastTime();
currentTimeCommand = atm.SetNowCastTimeMenu(menuItemTimeMain,
menuItemNowCastTimeEvent);
}
else
{
atm.CreateNormalTime();
currentTimeCommand = atm.SetNormalTimeMenu(menuItemTimeMain,
menuItemNormalTimeEvent);
}
}
///
/// メニューの文字列が一致するメニューを返す
///
/// 探すMenuItem
/// 探す文字列
/// 成功: MenuItem、失敗:null
private MenuItem FindMenu(MenuItem menuItem, string text)
{
foreach (MenuItem mi in menuItem.MenuItems)
{
if (mi.MenuItems.Count == 0 && text == mi.Text)
return mi;
if (mi.MenuItems.Count != 0)
{
MenuItem res = FindMenu(mi, text);
if (res != null)
return res;
}
}
return null;
}
#endregion
# region メニューのイベントハンドラー
///
/// 終了
///
private void menuItemTerminate_Click(object sender, EventArgs e)
{
Application.Exit();
}
///
/// About、バージョン情報
///
private void menuItemAbout_Click(object sender, EventArgs e)
{
FormAbout fb = new FormAbout();
fb.ShowDialog();
}
# endregion
#region 表示メソッド
///
/// アメダス情報を表示する
///
private void ShowAmedas()
{
if (selectedTypeMenu == null)
return;
Uri amedasUrl = BuildUrl();
webBrowser1.Navigate(amedasUrl);
}
private Uri BuildUrl()
{
Uri amedasUrl = null;
bool loc = selectedTypeMenu.locationMenu;
bool time = selectedTypeMenu.timeMenu;
string strFormat = selectedTypeMenu.urlFormat;
if (strFormat.IndexOf("radnowc") >= 0)
amedasUrl = new Uri(string.Format(strFormat,
locationCode, currentTimeCommand, nowCastCommand));
else if (loc == true && time == true)
amedasUrl = new Uri(string.Format(strFormat,
locationCode, currentTimeCommand));
else if (loc == true && time == false)
amedasUrl = new Uri(string.Format(strFormat,
locationCode));
else if (loc == false && time == true)
amedasUrl = new Uri(string.Format(strFormat,
currentTimeCommand));
else if (loc == false && time == false)
amedasUrl = new Uri(string.Format(strFormat));
return amedasUrl;
}
#endregion
#region 地域のメニュー
private string locationCode;
///
/// 地域メニューを作成
///
private void CreateLocationMenu()
{
AmedasLocationMenu alm = new AmedasLocationMenu();
alm.Set(menuItemLocation, menuItemLocationEvent);
}
///
/// 地域を選択した
///
private void menuItemLocationEvent(object sender, EventArgs e)
{
// Location メニューのチェックマークを更新
ClearMenuCheck(menuItemLocation);
((MenuItem)sender).Checked = true;
locationCode = ((AmedasLocatoinMenuItem)sender).locationCode;
ShowAmedas();
}
#endregion
#region 時間メニュー
private string currentTimeCommand = "";
AmedasTimeSet atm = new AmedasTimeSet();
private void menuItemNormalTimeEvent(object sender, EventArgs e)
{
// Location メニューのチェックマークを更新
ClearMenuCheck(menuItemTimeMain);
((MenuItem)sender).Checked = true;
currentTimeCommand = ((AmedasTimeMenuItem)sender).TimeCommand;
ShowAmedas();
}
string nowCastCommand = "radar";
private void menuItemNowCastTimeEvent(object sender, EventArgs e)
{
// Location メニューのチェックマークを更新
ClearMenuCheck(menuItemTimeMain);
((MenuItem)sender).Checked = true;
currentTimeCommand = ((AmedasTimeMenuItem)sender).TimeCommand;
if (((MenuItem)sender).Text.EndsWith("(予想)"))
nowCastCommand = "nowcast";
else
nowCastCommand = "radar";
ShowAmedas();
}
private void menuItemTimeMain_Popup(object sender, EventArgs e)
{
UpdateTimeMenu();
}
#endregion
#region 設定メニュー
private void menuItemConfig_Click(object sender, EventArgs e)
{
FormConfig formConfig = new FormConfig(
menuItemLocation, menuItemType);
formConfig.ShowDialog();
}
#endregion
#region アメダスの種類を選択するメニュー
///
///
///
public void menuItemType_Click(object sender, EventArgs e)
{
// Location メニューのチェックマークを更新
ClearMenuCheck(menuItemType);
((MenuItem)sender).Checked = true;
MenuTypeChanged((AmedasTypeMenuItem)sender);
}
// 現在のメニューの種類
AmedasTypeMenuItem selectedTypeMenu = null;
///
/// メニュー:種類が変更になった
///
///
private void MenuTypeChanged(AmedasTypeMenuItem mi)
{
mi.Checked = true;
selectedTypeMenu = mi;
menuItemLocation.Enabled = mi.locationMenu;
menuItemTimeMain.Enabled = mi.timeMenu;
nowCastCommand = "radar";
if (mi.timeMenu)
{
UpdateTimeMenu();
}
ShowAmedas();
}
private void CreateTypeMenu()
{
AmedasTypeMenu atm = new AmedasTypeMenu();
atm.Set(menuItemType, menuItemType_Click);
selectedTypeMenu = (AmedasTypeMenuItem)(
menuItemType.MenuItems[0]);
}
#endregion
///
/// メニューのチェックをクリアする
///
///
private void ClearMenuCheck(MenuItem menuItem)
{
foreach (MenuItem mi in menuItem.MenuItems)
{
if (mi.Checked) mi.Checked = false;
if (mi.MenuItems.Count != 0)
foreach (MenuItem miSecond in mi.MenuItems)
if (miSecond.Checked) miSecond.Checked = false;
}
}
private void menuItemMenuMain_Popup(object sender, EventArgs e)
{
UpdateTimeMenu();
}
}
} |
FormConfig.cs
using System;
using System.Windows.Forms;
namespace Uchukamen.WZero3.WZero3DeAmedas
{
public partial class FormConfig : Form
{
public FormConfig(MenuItem amedasLocation, MenuItem menuItemType)
{
InitializeComponent();
SetAmedasType(menuItemType);
SetAmedasLocation(amedasLocation);
LoadConfig();
}
ConfigFile configFile = new ConfigFile();
///
/// 設定ファイルをロードして、表示する。
///
private void LoadConfig()
{
configFile.ReadConfigFile();
// 種類メニューを設定
foreach(object o in comboBoxType.Items)
if (((string)o) == configFile.TypeName)
comboBoxType.SelectedItem = o;
// 場所メニューを設定
foreach (object o in comboBoxLocation.Items)
if (((string)o) == configFile.LocationName)
comboBoxLocation.SelectedItem = o;
buttonSave.Focus();
}
///
/// 種類メニューに値をセットする
///
/// メインフォームの種類メニュー
private void SetAmedasType(MenuItem menuItemType)
{
foreach (MenuItem mi in menuItemType.MenuItems)
{
if (mi.MenuItems.Count == 0)
comboBoxType.Items.Add(mi.Text);
else
foreach (MenuItem miSecondLevel in mi.MenuItems)
comboBoxType.Items.Add(miSecondLevel.Text);
}
comboBoxType.SelectedIndex = 0;
}
///
/// 地域メニューに場所をセットする
///
/// メインフォームの地域メニュー
private void SetAmedasLocation(MenuItem amedasLocation)
{
foreach (MenuItem al in amedasLocation.MenuItems)
comboBoxLocation.Items.Add(al.Text);
comboBoxLocation.SelectedIndex = 0;
}
private void buttonSave_Click(object sender, EventArgs e)
{
configFile.WriteConfigFile(
(string)comboBoxType.SelectedItem,
(string)comboBoxLocation.SelectedItem);
Close();
}
private void buttonCancel_Click(object sender, EventArgs e)
{
Close();
}
}
} |
ClassConfigFile.cs
using System.Text;
using System.Xml;
using System.Reflection;
using System.IO;
namespace Uchukamen.WZero3.WZero3DeAmedas
{
class ConfigFile
{
private string typeName = "天気予報";
public string TypeName
{
get { return typeName; }
set { typeName = value; }
}
private string locName = "全国";
public string LocationName
{
get { return locName; }
set { locName = value; }
}
private string configFilePath = GetCurrentDirectory() + "\\config.xml";
public void WriteConfigFile(string typeName, string locName)
{
using (XmlTextWriter xtw = new XmlTextWriter(configFilePath, Encoding.Unicode))
{
xtw.WriteStartElement("configuration");
xtw.WriteElementString("種類", typeName);
xtw.WriteElementString("地域", locName);
xtw.WriteEndElement();
xtw.Close();
}
}
public void ReadConfigFile()
{
// 設定ファイルがない場合は、何もしない
if (!File.Exists(configFilePath))
return;
using (XmlTextReader xtr = new XmlTextReader(configFilePath))
{
xtr.ReadStartElement("configuration");
typeName = xtr.ReadElementString("種類");
locName = xtr.ReadElementString("地域");
xtr.ReadEndElement();
xtr.Close();
}
}
private static string GetCurrentDirectory()
{
string fqn = Assembly.GetExecutingAssembly().ManifestModule.FullyQualifiedName;
FileInfo finfo = new FileInfo(fqn);
return finfo.DirectoryName;
}
}
}
|
ClassMenuLocation.cs
using System;
using System.Windows.Forms;
namespace Uchukamen.WZero3.WZero3DeAmedas
{
public class AmedasLocatoinMenuItem : MenuItem
{
internal string locationCode;
public AmedasLocatoinMenuItem(string locCode, string name, EventHandler eh)
{
locationCode = locCode;
Text = name;
Click += new System.EventHandler(eh);
}
}
public class AmedasLocationMenu
{
public void Set(MenuItem mi, EventHandler eh)
{
mi.MenuItems.Add(new AmedasLocatoinMenuItem("000", "全国", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("201", "北海道地方(北西部)", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("202", "北海道地方(東部)", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("203", "北海道地方(南西部)", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("204", "東北地方(北部)", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("205", "東北地方(南部)", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("206", "関東地方", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("207", "甲信地方", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("208", "北陸地方(東部)", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("209", "北陸地方(西部)", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("210", "東海地方", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("211", "近畿地方", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("212", "中国地方", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("213", "四国地方", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("214", "九州地方(北部)", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("215", "九州地方(南部)", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("216", "奄美地方", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("217", "沖縄・大東島地方", eh));
mi.MenuItems.Add(new AmedasLocatoinMenuItem("219", "宮古・八重山地方", eh));
}
}
}
|
ClassMenuTime.cs
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace Uchukamen.WZero3.WZero3DeAmedas
{
public class AmedasTimeMenuItem : MenuItem
{
public DateTime Time;
public string TimeCommand;
public AmedasTimeMenuItem()
{ }
public AmedasTimeMenuItem(string menuText,
DateTime time, string timeCmd)
{
Text = menuText;
Time = time;
TimeCommand = timeCmd;
}
}
public class AmedasTimeSet
{
public List normalTime = new List();
public List nowCastTime = new List();
///
/// レーダー・降水ナウキャスト以外の場合の時間メニューを作成
/// 過去12時間まで1時間刻み
///
public void CreateNormalTime()
{
// リアルタイムでAmedasのデータは取得できない。
// 大体20分ぐらい遅れるので、現在時刻ー20分する。
DateTime nowMinus20Min = DateTime.Now.Subtract(
new TimeSpan(0, 20, 0));
// その時の時間(H)をベースの時間とする。
DateTime baseHour = new DateTime(
nowMinus20Min.Year, nowMinus20Min.Month, nowMinus20Min.Day,
nowMinus20Min.Hour, 0, 0);
normalTime.Clear();
for (int i = 0; i < 12; i++)
{
DateTime t = baseHour.Subtract(new TimeSpan(i, 0, 0));
string timeCmd = t.ToString("yyyyMMddHHmm") + "-00";
normalTime.Add(new AmedasTimeMenuItem(t.ToString("HH:mm"),
t, timeCmd));
}
}
///
/// レーダー・降水ナウキャストの場合の時間メニューを作成
/// 1時間後まで10分刻みの予想と
/// 過去6時間まで1時間刻み
///
public void CreateNowCastTime()
{
// リアルタイムでAmedasのデータは取得できない。
// 大体20分ぐらい遅れるので、現在時刻ー20分する。
DateTime nowMinus20Min = DateTime.Now.Subtract(
new TimeSpan(0, 20, 0));
// その時の時間(10分単位)をベースの時間(baseHourMin)とする。
DateTime baseHourMin = nowMinus20Min.Subtract
(new TimeSpan(0, nowMinus20Min.Minute % 10, 0));
// その時の時間(1時間単位)をベースの時間(baseHour)とする。
DateTime baseHour = new DateTime(
nowMinus20Min.Year, nowMinus20Min.Month, nowMinus20Min.Day,
nowMinus20Min.Hour, 0, 0);
nowCastTime.Clear();
// 1時間後まで10分刻みの予想
for (int i = 6; i > 0; i--)
{
DateTime t = baseHourMin.Add(new TimeSpan(0, 10 * i, 0));
string timeCmd = baseHourMin.ToString("yyyyMMddHHmm") +
"-0" + i.ToString();
nowCastTime.Add(new AmedasTimeMenuItem
(t.ToString("HH:mm(予想)"), t, timeCmd));
}
// 過去6時間まで、1時間刻み
for (int i = 0; i < 6; i++)
{
DateTime t = baseHour.Subtract(new TimeSpan(i, 0, 0));
string timeCmd = t.ToString("yyyyMMddHHmm") + "-00";
nowCastTime.Add(new AmedasTimeMenuItem(t.ToString("HH:mm"),
t, timeCmd));
}
}
public string SetNormalTimeMenu(Menu menu, EventHandler eh)
{
menu.MenuItems.Clear();
foreach (AmedasTimeMenuItem at in normalTime)
{
int i = menu.MenuItems.Add(at);
menu.MenuItems[i].Click += new System.EventHandler(eh);
}
ClearMenuCheck(menu);
normalTime[0].Checked = true;
return normalTime[0].TimeCommand;
}
public string SetNowCastTimeMenu(Menu menu, EventHandler eh)
{
menu.MenuItems.Clear();
foreach (AmedasTimeMenuItem at in nowCastTime)
{
int i = menu.MenuItems.Add(at);
menu.MenuItems[i].Click += new System.EventHandler(eh);
}
ClearMenuCheck(menu);
menu.MenuItems[6].Checked = true;
return nowCastTime[6].TimeCommand;
}
private void ClearMenuCheck(Menu menuItem)
{
// メニューのチェックをクリアする
foreach (MenuItem mi in menuItem.MenuItems)
{
if (mi.Checked) mi.Checked = false;
if (mi.MenuItems.Count != 0)
foreach (MenuItem miSecond in mi.MenuItems)
if (miSecond.Checked) miSecond.Checked = false;
}
}
}
} |
ClassMenuType.cs
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace Uchukamen.WZero3.WZero3DeAmedas
{
public class AmedasTypeMenuItem : MenuItem
{
internal bool timeMenu;
internal bool locationMenu;
internal string urlFormat;
public AmedasTypeMenuItem(string name, bool loc,
bool time, EventHandler eh, string sformat)
{
Text = name;
locationMenu = loc;
timeMenu = time;
urlFormat = sformat;
Click += new System.EventHandler(eh);
}
}
public class AmedasTypeMenu
{
public void Set(MenuItem mi, EventHandler eh)
{
mi.MenuItems.Add(new AmedasTypeMenuItem("天気予報", true, false, eh,
"http://www.jma.go.jp/jp/yoho/images/g1/{0}_telop_today.png"));
mi.MenuItems.Add(new AmedasTypeMenuItem("レーダー・降水ナウキャスト", true, true, eh,
"http://www.jma.go.jp/jp/radnowc/imgs/{2}/{0}/{1}.png"));
int isat = mi.MenuItems.Add(new AmedasTypeMenuItem("気象衛星", false, false, eh,
null));
mi.MenuItems[isat].MenuItems.Add(new AmedasTypeMenuItem("赤外線", false, true, eh,
"http://www.jma.go.jp/jp/gms/imgs_c/0/infrared/1/{0}.png"));
mi.MenuItems[isat].MenuItems.Add(new AmedasTypeMenuItem("可視光", false, true, eh,
"http://www.jma.go.jp/jp/gms/imgs_c/0/visible/1/{0}.png"));
mi.MenuItems[isat].MenuItems.Add(new AmedasTypeMenuItem("水蒸気", false, true, eh,
"http://www.jma.go.jp/jp/gms/imgs_c/0/watervapor/1/{0}.png"));
mi.MenuItems.Add(new AmedasTypeMenuItem("降水量", true, true, eh,
"http://www.jma.go.jp/jp/amedas/imgs/rain/{0}/{1}.png"));
mi.MenuItems.Add(new AmedasTypeMenuItem("気温", true, true, eh,
"http://www.jma.go.jp/jp/amedas/imgs/temp/{0}/{1}.png"));
mi.MenuItems.Add(new AmedasTypeMenuItem("日照時間", true, true, eh,
"http://www.jma.go.jp/jp/amedas/imgs/sun/{0}/{1}.png"));
mi.MenuItems.Add(new AmedasTypeMenuItem("風向・風速", true, true, eh,
"http://www.jma.go.jp/jp/amedas/imgs/wind/{0}/{1}.png"));
mi.MenuItems.Add(new AmedasTypeMenuItem("積雪深", true, true, eh,
"http://www.jma.go.jp/jp/amedas/imgs/snow/{0}/{1}.png"));
mi.MenuItems.Add(new AmedasTypeMenuItem("台風", false, false, eh,
"http://www.jma.go.jp/jp/typh/images/wide/all-00.png"));
mi.MenuItems.Add(new AmedasTypeMenuItem("ウィンドプロファイラ", false, true, eh,
"http://www.jma.go.jp/jp/windpro/imgs/000/{0}.png"));
int iwarn = mi.MenuItems.Add(new AmedasTypeMenuItem("警報", false, false, eh,
null));
mi.MenuItems[iwarn].MenuItems.Add(new AmedasTypeMenuItem("すべて", true, false, eh,
"http://www.jma.go.jp/jp/warn/imgs/{0}/99.png"));
mi.MenuItems[iwarn].MenuItems.Add(new AmedasTypeMenuItem("大雨", true, false, eh,
"http://www.jma.go.jp/jp/warn/imgs/{0}/02.png"));
mi.MenuItems[iwarn].MenuItems.Add(new AmedasTypeMenuItem("洪水", true, false, eh,
"http://www.jma.go.jp/jp/warn/imgs/{0}/03.png"));
mi.MenuItems[iwarn].MenuItems.Add(new AmedasTypeMenuItem("暴風(強風)", true, false, eh,
"http://www.jma.go.jp/jp/warn/imgs/{0}/04.png"));
mi.MenuItems[iwarn].MenuItems.Add(new AmedasTypeMenuItem("波浪", true, false, eh,
"http://www.jma.go.jp/jp/warn/imgs/{0}/06.png"));
mi.MenuItems[iwarn].MenuItems.Add(new AmedasTypeMenuItem("雷", true, false, eh,
"http://www.jma.go.jp/jp/warn/imgs/{0}/08.png"));
mi.MenuItems[iwarn].MenuItems.Add(new AmedasTypeMenuItem("濃霧", true, false, eh,
"http://www.jma.go.jp/jp/warn/imgs/{0}/10.png"));
mi.MenuItems[iwarn].MenuItems.Add(new AmedasTypeMenuItem("低温", true, false, eh,
"http://www.jma.go.jp/jp/warn/imgs/{0}/13.png"));
}
}
}
|
|
|
|
V1.0.0.0 と V1.1.0.0 では、ほとんど機能的には変わらないのに、リファクタリングで大幅に変わりました。Visual
Studio 2005 のリファクタリング機能がないと、とてもやってられなかったですね。
あと、NowCast の時間の取り扱いが変則で、だいぶ醜いコードになってしまいました。orz。Web Service
を提供してほしい。強くお願い。>>気象庁
さて、準備は整ったし、たぶん今の枠組みを大きく変えなくても、V2.0はできると思うけれど・・・・・あとは、時間が取れたらということで・・・。
|
|