位置とサイズを記憶するHTA2007年05月07日 01時20分20秒

アプリっぽくなる

以前HTAコネタで起動時に位置とサイズを設定するTIPS(てほどでもないが)を紹介したが、それにちょっとひねりを加えて、自動的に位置とサイズを記憶、次回自動時にそれを再現するサンプルを書いてみる。なんとなく、デスクトップアプリっぽいしょ?

なお、サンプルでは、矩形情報の読み込み・保存にjson.orgのJSONライブラリを利用しているが、単純なシリアライズ・デシリアライズなので自前でメソッドを用意できるなら特にjson.jsは必要ない。

処理のタイミング

まず、前のエントリでも書いたが、ウィンドウの位置とサイズを設定するタイミングは、HTA:APPLICATIONタグの出現前にしないと気になるちらつきが発生する。なので、json.jsをロード(または同等の機能の定義・ロード)してからhta:applicationが出現するまでに

  • 保存したウィンドウ矩形情報のロード
  • ロードした矩形情報を元にリサイズと位置の確定
の処理をする必要がある。

また、最終的な矩形情報の保存のタイミングだが、後述の通りdocument.bodyのプロパティを参照するので、window.onbeforeunloadにする。onunloadではdocument.bodyへアクセスできないためエラーになる。

ウィンドウの位置とサイズの取得方法

一番面倒なのは、ウィンドウの位置とサイズの正確な取得方法だ。

まず位置情報。IEにはwindow.screenLeft/screenTopというプロパティがあるが、これはウィンドウボーダーとタイトルバーのサイズを除いた情報しか取得できない。

また、サイズについてはdocument.bodyのoffsetWidth/offsetHeightが取得可能なもっとも外側のサイズのようで、これまたタイトルバーやらとの差がある。

で、どうするかというと

起動直後に位置とサイズを調整するのだからその情報を元に、document.bodyのレンダリングがすんだ時点で差分を取得しておく。で、保存時はその差分を加えた情報を保存する。
という、ややベタな方法をとることにする。 具体的には、window.onload時に
// offsetRectはleft/top/width/heightの
//   プロパティに、測定サイズと実サイズの差を格納する。
// initialRectはwindow.resizeTo/moveToに使用した値を
//   格納している。
with( offsetRect ) {
	left = initialRect.left - window.screenLeft;
	top = initialRect.top - window.screenTop;
	width = initialRect.width - document.body.offsetWidth;
	height = initialRect.height - document.body.offsetHeight;
}
としてオフセット情報を取得し、window.onbeforeunload時に
// savePrefは指定オブジェクトのJSONデータを保存する関数。
// window.screenLeft/Topとdocument.body.offsetWidht/Heightに
//   offsetRectの補正値を加える。
savePref( {
	left : window.screenLeft + offsetRect.left,
	top : window.screenTop + offsetRect.top,
	width : document.body.offsetWidth + offsetRect.width,
	height: document.body.offsetHeight + offsetRect.height
} );
の要領で補正した矩形情報を保存する。

サンプルコード

実際に位置とサイズを自動保存するHTAのサンプルコードは以下のとおり。

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<meta http-equiv="Content-Style-Type" content="text/css">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<title>テスト</title>
<script src="json.js"></script>
<script>
// 最後に保存した矩形情報をロードし、矩形オブジェクトとして返す
function loadPref() {
	var fso = new ActiveXObject("Scripting.FileSystemObject");
	var stream;
	try {
		// 起動ディレクトリの「preference.json」に決めうち
		stream = fso.OpenTextFile( "preference.json", 1 );
		return stream.ReadAll().parseJSON();
	} catch(e) {
		with( { w : 320, h : 240 } ) {
			return {
				width : w,
				height : h,
				left : parseInt( ( screen.width - w ) / 2 ),
				top : parseInt( ( screen.height - h ) / 2 )
			}
		}
	} finally {
		if( stream ) stream.Close();
	}
}

function savePref(obj) {
	var fso = new ActiveXObject("Scripting.FileSystemObject");
	var stream;
	try {
		// 起動ディレクトリの「preference.json」に決めうち
		stream = fso.CreateTextFile( "preference.json" );
		stream.Write( obj.toJSONString() );
	} finally {
		if( stream ) stream.Close();
	}
}

// 設定ロード直後の実ウィンドウサイズ
var initialRect = loadPref();
// 実サイズとdocument.bodyの矩形とのオフセット
var offsetRect = {
	left : 0,
	top : 0,
	width : 0,
	height : 0
};

with( { rect : initialRect } ) {
	window.moveTo( rect.left, rect.top );
	window.resizeTo( rect.width, rect.height );
}
</script>
<hta:application innerBorder="no" scroll="no"></hta:application>
</head>
<body>
</body>
<script>
window.onload = function() {
	// document.bodyのレンダリングが完了したのでoffsetRectを算出
	with( offsetRect ) {
		left = initialRect.left - window.screenLeft;
		top = initialRect.top - window.screenTop;
		width = initialRect.width - document.body.offsetWidth;
		height = initialRect.height - document.body.offsetHeight;
	}
}
window.onbeforeunload = function() {
	// offsetRectを加えた矩形情報を保存
	savePref( {
		left : window.screenLeft + offsetRect.left,
		top : window.screenTop + offsetRect.top,
		width : document.body.offsetWidth + offsetRect.width,
		height: document.body.offsetHeight + offsetRect.height
	} );
}
</script>
</html>
まあ、こんな機能なくてもいいんだけど、ちょっとデスクトップアプリ気分に浸れるので。

コメント

コメントをどうぞ

※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。

※なお、送られたコメントはブログの管理者が確認するまで公開されません。

名前:
メールアドレス:
URL:
コメント:

トラックバック

このエントリのトラックバックURL: http://dara-j.asablo.jp/blog/2007/05/07/1489431/tb

※なお、送られたトラックバックはブログの管理者が確認するまで公開されません。