自分好みのガジェットを作る! Windowsサイドバーガジェット作り入門

第5回ガジェットの設定周り、ドッキング、デバッグ

今回は設定画面と設定の保存/読み出し、ドッキング、デバッグについての解説をしていきます。

設定画面と設定の保存と読み出し

天気予報を表示するガジェットなのに予報の地域の指定ができない。そんな不便なガジェットは普通ありません。したがって、ガジェットの設定をユーザが変更できるよう、設定画面を表示する機能をつけたくなることは当然出てくる話です。

必要とされる機能ということで、Windowsサイドバーにはガジェットの設定画面を表示するための仕組みが提供されていますので、その使い方について説明します。

まずは設定画面がどのようなものなのか、Windows Vistaに標準でインストールされていて設定画面を持っている「天気」ガジェットを例に見てみます。設定画面を持っているガジェットは、マウスをホバーしたとき、閉じるボタンの下にスパナマークのボタンが表示されます。

図1 ⁠天気」ガジェット。マウスをホバーしたとき閉じるボタンの下にスパナマークのボタンが表示される
図1 「天気」ガジェット

このボタンをクリックすると、アニメーションとともに次のような設定画面が表示されます。

図2 ⁠天気」ガジェットの設定画面
図2 「天気」ガジェットの設定画面

この設定画面の中身もFlyout同様にHTMLです。Flyoutと異なるのは、

  • この設定画面がモーダルであること―つまり表示中にガジェット本体を触ることができなくなる―
  • 「OK」ボタンと「キャンセル」ボタンが用意されていること
  • Flyoutがガジェット側から表示・非表示を行うのに対して、設定画面はユーザのアクションによって表示され、閉じられる

という点があります。

また、設定画面があったとしても、毎度毎度設定するというのは普通に考えてありえませんので、当然設定の保存と読み出しも必要となります。

そこで、設定画面をガジェットで利用する方法について説明します。サンプルとして、設定画面で入力した文字列を覚えておく、というものを作ります。

設定画面

設定画面の表示にあたって必要な手順はHTMLを作り、ガジェットのプロパティにファイル名を指定するだけです。先ほどの説明したとおりFlyoutと違い設定画面はユーザが表示したいときに表示されユーザによって閉じられるので表示を指示する必要はありません。その代わりに閉じれもしないので、設定が完了したことを通知するイベントが用意されています。そのイベントでガジェットに設定を反映します。

まず、設定画面のHTMLの雛形を作ります。ファイル名はsetting.htmlとします(ほかのHTMLと同様に自由につけられます⁠⁠。内容は以下のようにします。

<title>Settings</title>
<style type="text/css">
body {  margin: 0; padding: 0; width: 240px; height: 140px; border: 1px solid red; }
</style>
<p>入力: <input type="text" name="inputText"></p>

ガジェット本体、FlyoutのHTMLと同様body要素にサイズの指定が必要です。これはサンプルなのでどこが表示領域なのかわかりやすくするためにborderを入れています。

HTMLファイルができたら「ガジェット側のスクリプト」でファイルを指定します。設定画面のHTMLの指定はSystem.Gadget.settingsUIプロパティにファイル名をセットすることで行います。

System.Gadget.settingsUI = "setting.html";

これを書いてガジェットをサイドバーに追加すると、設定ボタンが表示されるようになり、ボタンをクリックすると次の図のような画面が表示されます。

図3 ⁠天気」ガジェットの設定画面
図3 「天気」ガジェットの設定画面

設定画面のイベント

後述する設定の保存・読み込みのためには、設定画面関連のイベントを使う必要があります。設定画面関連のイベントは以下のようなものがあります。

System.Gadget.onSettingsClosingイベント

設定画面が「OK」ボタンまたは「キャンセル」ボタンで閉じられようとしているときに発生します。このイベントは引数にSystem.Gadget.Settings.ClosingEventオブジェクトが渡されます。ClosingEventオブジェクトには以下のプロパティが用意されています。

closeActionプロパティ設定画面を閉じた理由を取得できます。e.Action.commit(OKボタン)またはe.Action.cancel(キャンセルボタン)が格納されます(引数をeとしています)
cancelプロパティ設定画面を閉じることをキャンセルするかどうかをbooleanで指定します。trueを指定した場合「OK」ボタンをクリックしても閉じることができなくなります。例えば入力エラーがある場合などに利用します
cancellableプロパティユーザによってキャンセルされたかどうかをbooleanで取得できます。trueの場合、キャンセルされたことを表します
System.Gadget.onSettingsClosedイベント設定画面が閉じられた際に呼ばれるイベントです。ガジェット側に設定を反映する場合などに利用できます
System.Gadget.onShowSettingsイベント設定画面が表示された際に呼ばれるイベントです。ガジェットの動作を一時的に止めるなどに利用できます

以下にイベントを利用するサンプルコードを載せます。

// 例
function onSettingsClosing (event) {
  // 閉じようとしているときのイベント
  if (event.closeAction == event.Action.commit) {
    // OK ボタン
    if (!入力内容のチェックメソッドなど) {
      // 入力内容が正しくなかったらキャンセル
      event.cancel = true;
    }
  }
}
function onSettingsClosed () {
  // 閉じられたときのイベント
  ...設定の反映等...
}
function onShow() {
  // 表示されたときのイベント
}
System.Gadget.onSettingsClosing = onSettingsClosing;
System.Gadget.onSettingsClosed = onSettingsClosed;
System.Gadget.onShowSettings = onShow;

設定の保存と読み込み

設定の保存と読み込みのAPI

設定の保存と読み込みにはSystem.Gadget.Settingsオブジェクトのメソッドを利用します。このオブジェクトのメソッドを利用することで、開発者は設定ファイルのありかについて考えたりや読み書きにファイル操作等の手間を省くことができます。

なお、この仕組みを利用した場合の設定単位は「サイドバーに配置したガジェット」単位となります。つまり同じガジェットを複数登録しても設定は別々となりますし、設定の寿命は「ガジェットを追加して表示している間」となります。サイドバー自体を終了した場合などには残りますが、ユーザがガジェットをサイドバーから取り除いた場合には削除されます。

設定の保存と読み込みで利用するメソッドは、以下のものが用意されています。

System.Gadget.Settings.writeメソッド/
System.Gadget.Settings.writeStringメソッド

設定をガジェットの設定ファイル書き込みます。1つ目の引数に設定名を指定し、2つ目の引数に値を指定することで設定ファイルに値を書き込みます。

System.Gadget.Settings.readメソッド/
System.Gadget.Settings.readStringメソッド

write/writeStringメソッドで保存した値を読み出します。引数は1つだけ受け取り、1つ目の引数に設定名を指定します。読み出されると戻り値として値が返ってきます。

write, readメソッドにはともに対応するwriteString, readStringメソッドが用意されています。この2種類のメソッドの違いは値の型の扱いにあります。Stringつきメソッドは書き込みも読み込みもString型として扱います。それに対してStringなしメソッドの場合は型を推測して変換します。以下に簡単な例を示します。

System.Gadget.Settings.writeString("foo", "1000000000000000000000");
System.Gadget.Settings.read("foo"); // => 1e+21 (number)
System.Gadget.Settings.readString("foo"); // => "1000000000000000000000" (string)

なお、APIを利用して保存した設定は%USERPROFILE%\AppData\Local\Microsoft\Windows Sidebar\Settings.iniというファイルに保存されます。興味があれば一度覗いてみるとよいでしょう。

フォームに組み込む

以上で説明したことをまとめて、次のようなスクリプトを設定画面のHTMLに追加します。

<script type="text/javascript">
function onSettingsClosing (event) {
  if (event.closeAction == event.Action.commit) {
    // OK ボタンを押すと入力された文字列を設定項目InputTextに格納する
    System.Gadget.Settings.writeString("InputText", document.getElementById('inputText').value);
  }
}
function onLoad () {
  // 表示されたら設定項目InputTextから読み出してテキストボックスに入れる
  document.getElementById('InputText').value = System.Gadget.Settings.readString("InputText");
}

// 設定画面を閉じるときのイベント
System.Gadget.onSettingsClosing = onSettingsClosing;
// 設定画面が読み込まれたときのイベント(onShowSettingsイベントはガジェット側で使うもの)
window.onload = onLoad;
</script>

この状態で設定画面を開いて、何か入力して「OK」ボタンをクリックして再度開くと入力した内容が入っていることを確認できます。

ガジェット側に反映する

ガジェット側に反映するには、onSettingsClosedイベントを使って再読み込みするなどの方法があります。たとえば、以下のようなコードをガジェット側に書けばよいでしょう。

System.Gadget.onSettingsClosed = function (e) {
  document.getElementById('inputText').innerText = System.Gadget.Settings.readString("InputText");
};

楽をするためのヒント

ところで、設定の保存と読み込みは基本的に1つの項目に1つの値で保存されるのですが、そうすると読み込みなどが案外面倒になります。そこで前々回も説明した、JSONの利用をオススメします。

オブジェクトを文字列にシリアライズして保存し、読み込みはevalすればまとめて元のオブジェクトに戻すことができるため、扱いがとてもお手軽になります。

ドッキング

ガジェットはサイドバー上のみではなく、離してデスクトップ上に表示することもできます。サイドバーから離せるのであれば、サイドバーとくっついているときと離したときで、ガジェットの形を変えたいと思うこともあるでしょう。

たとえば、先ほども例として紹介した「天気」ガジェットですが、これはサイドバーから離すとサイズが変化し情報量が増えます。

図4 サイドバーから離した「天気」ガジェット
図4 サイドバーから離した「天気」ガジェット

このような動作をサポートするため、以下のイベントがSystem.Gadgetオブジェクトに用意されています。

System.Gadget.onDockイベント

サイドバーにガジェットがくっついた際に発生するイベントです。

System.Gadget.onUndockイベント

ガジェットがサイドバーから離れた際に発生するイベントです。これらのイベントを受け取ってガジェットに反映させるだけなので簡単です。

System.Gadget.onDock = function () { /* サイズを大きくする等 */ };
System.Gadget.onUndock = function () { /* サイズを小さくする等 */ };

デバッグ

ガジェットに限らずプログラムを作るとき、コードを書いて一発で完璧に動作することは稀というかまずありえないので、大抵の場合ガッカリしながらデバッグをすることになります。そんなデバッグをガジェットに対して行うための方法をいくつか説明します。

alertを利用したデバッグ

残念ながらそのままではalertを使えないので無理です。Webページ向けのJavaScriptを書いたことのある人は何度と無く、コード中にalertを書いて変数の中身を表示したことがあるかと思いますが、ガジェットではalertメソッドを使うことができないのでこの方法は取れないのです[1]⁠。

System.Debug.outputStringメソッドを利用したデバッグ

System.Debug.outputStringメソッドは文字列を引数にとり、デバッグ出力するものです。alertやいわゆるprintfデバッグなどと同じです。一見簡単に呼び出せて便利ですが、これも微妙に面倒があります。

このメソッドでのデバッグ出力は文字列をWin32 APIのDebugOutputStringで出力するということであり、DebugOutputStringを使うということは、それを補足できるツールを別途用意する必要があるのです。そのようなツールには以下のようなものがあります。

  • DebugView(次の図5を参照)
  • Visual Studio
図5 DebugView
図5 DebugView

組み込みで用意されている機能なので、ツールを使うところ以外はまあまあお手軽ですが、正直、この方法でのデバッグはあまり効率の良いよいものではありません。

自分でガジェット上にデバッグ表示領域を作る

System.Debug.outputStringメソッドではなく、ガジェットの上にpre要素などのデバッグ出力領域を作り出して独自に出力してしまうという手もあります。

System.Debug.outputStringとどっちがよいかというと、これはまた微妙なところです。

デバッグヘルパースクリプトを利用したデバッグ

私が作成したものですが、⁠自分でガジェット上にデバッグ表示領域を作る」と似たような発想でInternet Explorerのウィンドウを開き、そこに情報を出力しようというための簡易的なスクリプトです。高度なことはできませんが、System.Debug.outputStringなどよりは多少楽をするために作成しました。

スクリプトを組み込んでガジェットをサイドバーに追加すると、次の図のようなデバッグ出力用のコンソールが自動で表示されます。

図6 デバッグヘルパースクリプトを利用した、デバッグ出力用のコンソール
図6 デバッグヘルパースクリプトを利用した、デバッグ出力用のコンソール

組込みはJavaScriptファイルを一つ読み込むだけで、あとはデバッグ出力用のメソッドを呼ぶとコンソールに出力できます。

<script src="gadgetDebugHelper.js" type="text/javascript"></script>
<script type="text/javascript">
  Debug.writeLine("Debug: {0}", "テスト"); // => "Debug: テスト"
</script>

また、evalした結果を出力する機能もあるので、現在の状態を調べるのにも簡易的ですが役立てられます。

欠点はデバッグ出力のメソッドがSystem.Debug.outputStringメソッドではないので、そのままリリースには利用できないという点が挙げられます。できることならSystem.Debug.outputStringを置き換えたかったのですが、それは不可能なようなのでこのスクリプトではあきらめました。

このスクリプトの入手と詳細な使い方は著者のサイトを参照してください。

Visual Studioを利用したデバッグ

サイドバーガジェットのデバッグを行うためのデバッガとしてVisual Studio 2003/2005を利用することもできます。

Visual StudioのIDEを使った場合、C#などのデバッグと同様に変数を覗くことやステップ実行などを簡単に行えるのが利点で、デバッグするなら一番オススメですが、Visual Studioを必要する点で若干難易度が上がります。また、残念ながらExpress Editionではアタッチできないためデバッグできません。

それでは、Visual Studio 2005を利用したデバッグ方法を説明していきます。

Visual Studioでデバッグするには、あらかじめInternet Explorerのスクリプトのデバッグを有効な状態にしておく必要があります。スクリプトのデバッグを有効にするにはInternet Explorerの「ツール」メニューから「インターネット オプション」を開いて「詳細設定」タブを選択します。中ほどに「スクリプトのデバッグを使用しない(その他⁠⁠」というチェック項目があるのでチェックをはずした状態にして「OK」で保存してください。

図7 ⁠インターネット オプション」「詳細設定」タブを選択して、項目「スクリプトのデバッグを使用しない(その他⁠⁠」のチェックをはずす
図7

ここで一度、念のためにサイドバーを再起動します。再起動はタスクバーの通知領域のアイコンから終了し、スタートから再度立ち上げましょう。

そしてVisual Studioを立ち上げます。立ち上がったらそのままメニューから「デバッグ」「プロセスにアタッチ」を選択します。

図8 メニューから「デバッグ」「プロセスにアタッチ」を選択する
図8 メニューから「デバッグ」の「プロセスにアタッチ」を選択する

アタッチするプロセスを選択するための「プロセスにアタッチ」ダイアログが開きます。

図9 ⁠プロセスにアタッチ」ダイアログ
図9 「プロセスにアタッチ」ダイアログ

このとき「アタッチ先」「自動: (選択項目によって異なる)」または「スクリプト コード」となっていることを確認します。もしどちらでもない場合「選択」ボタンを押して「コードの種類の選択」ダイアログで「デバッグするコードの種類を自動的に判断する」を選んでおきます。

そして「選択可能なプロセス」というプロセスの一覧をみてみます。この一覧からsidebar.exeというプロセスを探し、選択してください。複数存在する場合はShiftキーを押しながら選択することで複数選択できます。

図10 Shiftキーを使えば複数のプロセスを選択できる
図10 Shiftキーを使えば複数のプロセスを選択できる

プロセスを選択したら、ダイアログ右下の「アタッチ」ボタンをクリックしてダイアログを閉じます。

ダイアログを閉じるとVisual Studioが若干デバッグ中っぽい表示に変わります(デバッグツールバーやウォッチウィンドウなどが表示されたりします⁠⁠。

図11 Visual Studioのデバッグモード
図11 Visual Studioのデバッグモード

そしてこの状態でガジェットのソースコードを開きます。開く方法はどのような方法でもかまいません(ドラッグアンドドロップや開くダイアログなど⁠⁠。

試しにwww.misuzilla.org/dist/gadgets/vistaface/>VistaFaceでデバッガを利用してみたいと思います[2]⁠。なおVistaFaceは既にサイドバーに追加していますが、ガジェットは後からでも追加はできます。

ソースコードを開くという話でしたのでメインとなるJavaScriptを覗いてみることにします。VistaFaceのメインのコードはVistaFace.gadget\common\js\vistaFace.jsですので、このファイルを開きます。

デバッグといえばブレークポイントですよねということで早速止めてみます。止め方というかブレークポイントの設定方法はC#やVB、など普通のVisual Studioと同じようにコードの横をクリックして設定できます。

図12 VistaFaceのメインコードであるvistaFace.jsのデバッグ(ブレークポイントの設定)
図12 VistaFaceのメインコードであるvistaFace.jsのデバッグ(ブレークポイントの設定)

そしてこのコード行を通過しようとすると、ブレークポイントに引っかかり一時停止します。

図13 VistaFaceのメインコードであるvistaFace.jsのデバッグ(実行時)
図13 VistaFaceのメインコードであるvistaFace.jsのデバッグ(実行時)

ほかの言語と同じように、ステップ実行や実行位置の変更などが可能です。ただし残念ながら、C#などにあるエディットアンドコンティニュー(コードを変更して即反映)はできません。

その他にも、ウォッチ式やイミディエイトウィンドウ、便利な変数内容表示や修正などなども普通に利用できます。

当然ですが、前に説明したSystem.Debug.outputStringメソッドでの出力も受け取ることができます。

図14 VistaFaceのメインコードであるvistaFace.jsのデバッグ(System.Debug.outputStringメソッドでの出力)
図11 VistaFaceのメインコードであるvistaFace.jsのデバッグ(System.Debug.outputStringメソッドでの出力)

Visual Studio 2005でのデバッグについての説明は以上です。アタッチしてファイルを開くところ以降はほぼ普通のVisual Studioによるデバッグですので、Visual Studioを利用している方であればすんなりと入れるかと思います[3]⁠。

Visual Studioを持ってなくて、でも最低限でもいいのでデバッガ使いたいという場合

実際に動作確認を行っていませんが、以下の2つはデバッグに利用できるかもしれません。

  • OfficeシリーズについてくるMicrosoft Script Editor(HTMLソース編集というOfficeツール)
  • Microsoft Script Debugger。古いのが難点

おすすめ記事

記事・ニュース一覧