位置とサイズを記憶するHTA ― 2007年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が取得可能なもっとも外側のサイズのようで、これまたタイトルバーやらとの差がある。
で、どうするかというと
// 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>まあ、こんな機能なくてもいいんだけど、ちょっとデスクトップアプリ気分に浸れるので。
JSDBのhttp取得・おかわり ― 2007年05月07日 13時14分13秒
しつこいなぁ > 自分
いいかげん誰も興味がないだろうが、JSDBのhttp取得をさらに調べた。
Keep-Aliveかい!?
ローカルホストに環境変数を返すasp設置して試したら、リクエストヘッダに「Connection」の指定がなかった。
ということは、Connection: keep-alive扱いですか。そうですか。
んじゃ、Connection: closeを送りつけたらどうなるかを試そうと思ったが、Streamコンストラクタにhttp://渡した場合はリクエストヘッダのカスタマイズができないぽい。リファレンス確認したら
To simply open a socket to the server and send your own headers, use a = new Stream('net://server.com:80/'); a.writeln('POST /file.cgi/ HTTP/1.1\r\n').とか書いてあるので以下のようなコードを実行。
js>var stream = new Stream("net://localhost:80") js>stream.writeln( "GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n" ) 52 js>stream.canRead true js>writeln( stream.read() ) HTTP/1.1 200 OK Server: Microsoft-IIS/5.1 Date: Mon, 07 May 2007 04:25:46 GMT X-Powered-By: ASP.NET Connection: close Content-Length: 11519 Content-Type: text/html Set-Cookie: myCounter=1; path=/ Set-Cookie: ASPSESSIONIDASBRTBDS=PJEHLAFDDOAGKOAIHFNJHMNI; path=/ Cache-control: private : (略)返ってくるじゃん!!
結局
以前のエントリ(これやこれ)でハングするだなんだぶつぶついっていたのは、HTTPキープアライブのタイムアウト待ち状態だったということのようだ。実際、IISの設定でHTTPキープアライブのタイムアウトを10秒程度にしたら、待ち時間がそのくらいで制御が帰ってきた。うあ~、このくらいちゃんと調べろよ > 自分
まあ、このことから、「Stream#read()で一括読み込みしようとしたら、長い長いタイムアウト待ちになる可能性がある」ということになるので、webのリソースを単純に引っ張ってくるにはこの方法は向かないってことになる。
さらに恥ずかしいことに(こればっか)、最初のエントリで行単位読み込みのループがうまくいかなかったのはStream#eofを頼りにしていたからと判明。Stream#canReadはちゃんと意図した動作をするので、
while( stream.canRead ) { writeln( stream.readln() ); }で、最初のリクエストに対する応答を全部読み込み終わった時点でループを脱出する。
まとめ
- JSDBのStreamをhttpで初期化するとHTTPキープアライブアプリケーションとして動作する
- リクエストヘッダをカスタマイズするにはnet://で初期化して、いちいちリクエストをwriteln()してやる必要がある
- 行単位のループ処理をする場合はcanReadプロパティをみるべし
- Stream#read()なんて不精をするとタイムアウト待ちに巻き込まれる可能性があるので注意
JSDB日本語リファレンス ― 2007年05月07日 13時47分06秒
JSDBがらみでちょろちょろ検索かけてたら、シンテック株式会社というCAD製品なんかやっている企業さんに行き着いた。
自社製品のオンラインマニュアルに、JSDBリファレンスの日本語訳版も加えておられる模様。
Cosmos Referenceへ飛ぶと、「分類」フレームに「JSDBライブラリー」のリンクがある。
ざっと見たところ、手持ちのリファレンス(4/27版に付属)のものと若干内容が異なる部分があるみたいなので、バージョンが違うものかもしれないが、dara-jみたいに「英語読むのマンドクセェ」ってな方には助けになるかも。
最近のコメント