打ち合わせに行ってきた。
ユーザーの要望を聞き、現場を見、その都度思い出してはこうしたい、ああしたいと言うユーザーの話を聞き、とりあえずメモっておくが、何だかとんでもなく面倒な仕様に感じてくる。
聞きながら「きっと見積額が相当になるだろうなぁ」と思う。
会社に戻り、がっくり疲れて打ち合わせ内容をまとめるのも面倒になって、気晴らしをしているうちに時間がきて何もせずに仕事を終える。
次の打ち合わせまで一週間あるので、まだいいやと思って他の仕事をしているうちに数日何もそのことは考えずに過ごした。
そろそろまとめなければと思い、どうやるかを考えてみると、あれ?意外と見通しが立つ仕様になった。
最初の時に感じた面倒臭さはない。知らない間に余計な情報が消えて(忘れただけかも)主題だけが残った結果みたいだ。疑問点も具体化して次回の打ち合わせにちょうど良い。
楽して問題が解決するなんて!これって無意識の脳の働きなんだろうか?
2008年07月04日
2008年06月26日
チェックボックス、ラジオボタンを大きく表示して使う
テキストボックスやコマンドボタンはフォントのサイズや縦(Height)横(Width)を直接指定することで大きく表示することができる。しかし、チェックボックスやラジオボタンは文字の方は大きくできてもコントロールはサイズが変わらない。
年配の方やタッチスクリーンを使っている場合、見やすく操作し易いようにするためにこの部分を大きくできないかという依頼があったとき、正直こんなに苦労するとは思わなかった。
いろいろ試行錯誤した挙句、完成したのがこのサンプルのような使い方である。
サンプルソース:bigctrsamp.lzh (2008.07.03修正)
サンプル実行図

サーバーコントロールはWebコントロールではなくHTMLコントロールを使う。Webコントロールではどうしても大きくできない。また、サーバーサイドで利用するため「サーバーコントロールとして実行」を有効にするが、クライアントサイドのJavascriptでGridView内のラジオボタンを操作する方法も組み込んである。
デザイン全体図

サーバーコントロールとして実行

サイズを指定

ラジオボタンのクライアントスクリプトでは一度ブラウザで表示された状態のソースコードで名前を調べる。
GridViewのソースコード

このソースコードから、ラジオボタンのName属性がGridView2$ctlXX$であることが判る。XXはどういうわけか02から始まる。そこでこれを操作するJavascriptも先頭が02となるように細工をする。
Javascritpコード

なお、GridViewの行数をHiddenFieldの値から取得しているが、これは以前のTipsでも紹介した方法「データソースで取得したレコードの件数を知るには」を使っている。
年配の方やタッチスクリーンを使っている場合、見やすく操作し易いようにするためにこの部分を大きくできないかという依頼があったとき、正直こんなに苦労するとは思わなかった。
いろいろ試行錯誤した挙句、完成したのがこのサンプルのような使い方である。
サンプルソース:bigctrsamp.lzh (2008.07.03修正)
サンプル実行図
サーバーコントロールはWebコントロールではなくHTMLコントロールを使う。Webコントロールではどうしても大きくできない。また、サーバーサイドで利用するため「サーバーコントロールとして実行」を有効にするが、クライアントサイドのJavascriptでGridView内のラジオボタンを操作する方法も組み込んである。
デザイン全体図
サーバーコントロールとして実行
サイズを指定
ラジオボタンのクライアントスクリプトでは一度ブラウザで表示された状態のソースコードで名前を調べる。
GridViewのソースコード
このソースコードから、ラジオボタンのName属性がGridView2$ctlXX$であることが判る。XXはどういうわけか02から始まる。そこでこれを操作するJavascriptも先頭が02となるように細工をする。
Javascritpコード
なお、GridViewの行数をHiddenFieldの値から取得しているが、これは以前のTipsでも紹介した方法「データソースで取得したレコードの件数を知るには」を使っている。
2008年04月16日
「Windows Server 2008」は「Vista」と同じバージョン
先月より公開されたWindows Server 2008の評価版を使ってみたところ、意外な点を見つけたので報告する。
それは、OSのバージョン情報である。
なんとVistaと全く同じなのである。しかも、VistaのServicePack1が公開されたばかりなので、2008の評価版(製品版と同等)にも既にServicePack1が適用済みになっているのだ。
詳しくは下図をご覧いただきたい。
msinfo32.exeを実行して表示させたものである。
1.Vista(ServicePack1適用済)

2.Windows Server 2008(製品版の評価使用中)

こうなると、プログラム上でバージョンチェックする際、プロダクト名まで調べないとVistaか2008か判定できないことになる。
それは、OSのバージョン情報である。
なんとVistaと全く同じなのである。しかも、VistaのServicePack1が公開されたばかりなので、2008の評価版(製品版と同等)にも既にServicePack1が適用済みになっているのだ。
詳しくは下図をご覧いただきたい。
msinfo32.exeを実行して表示させたものである。
1.Vista(ServicePack1適用済)
2.Windows Server 2008(製品版の評価使用中)
こうなると、プログラム上でバージョンチェックする際、プロダクト名まで調べないとVistaか2008か判定できないことになる。
2008年04月02日
「Windows Vista Service Pack 1」の効果
最近公開されたVistaの「Service Pack 1」だが、具体的に何が変わったかを実感することがほとんど無いなか、唯一私が効果有りと実感したのがエクスプローラの画面の自動更新処理である。これによりWindowsXPと同等になった。
具体的に言うと自作のフリーソフト「ファイルとフォルダの神隠し(U)」でVistaだけがファイルとフォルダの属性を変更させても即時に非表示とならなかった。わざわざ右クリックして「最新の情報に更新」をクリックしなければならなかったのが、SP1を導入することでその必要が無くなり即消えるようになった。
きっとこれはバグだったのであろう。
その後日(4/13)、更にSP1の効果を実感する事件(?)があった。これも自作のソフト「メルプリT」での不具合に対しての実感である。これも一気に解決した。
実はこの問題点は先の「ファイルとフォルダの神隠し」の不具合以上の致命的ともいえる障害だった。ソフトを起動して常駐後、30分から1、2時間経過すると突然画面が乱れて制御が効かなくなってしまうのである。通常ならデスクトップ下部にあるタスクバーが突然上部に移動したり、ソフトの一部しか表示しなくなったり、マウスの動きに合わせて画面が乱れ飛ぶ始末なのである。(下図参照)
1.正常な画面

2.乱れた画面

原因はまったく見当がつかなかった。それがServicePack1を適用した途端に直ってしまったのである。内部的なことは判らないが明らかにバグが解消され、既存アプリケーションの互換性が高まったと言って良いだろう。Vistaを実務で使うにはServicePack1は必須といえる。
具体的に言うと自作のフリーソフト「ファイルとフォルダの神隠し(U)」でVistaだけがファイルとフォルダの属性を変更させても即時に非表示とならなかった。わざわざ右クリックして「最新の情報に更新」をクリックしなければならなかったのが、SP1を導入することでその必要が無くなり即消えるようになった。
きっとこれはバグだったのであろう。
その後日(4/13)、更にSP1の効果を実感する事件(?)があった。これも自作のソフト「メルプリT」での不具合に対しての実感である。これも一気に解決した。
実はこの問題点は先の「ファイルとフォルダの神隠し」の不具合以上の致命的ともいえる障害だった。ソフトを起動して常駐後、30分から1、2時間経過すると突然画面が乱れて制御が効かなくなってしまうのである。通常ならデスクトップ下部にあるタスクバーが突然上部に移動したり、ソフトの一部しか表示しなくなったり、マウスの動きに合わせて画面が乱れ飛ぶ始末なのである。(下図参照)
1.正常な画面
2.乱れた画面
原因はまったく見当がつかなかった。それがServicePack1を適用した途端に直ってしまったのである。内部的なことは判らないが明らかにバグが解消され、既存アプリケーションの互換性が高まったと言って良いだろう。Vistaを実務で使うにはServicePack1は必須といえる。
2008年03月26日
ポップアップブロック回避策
ASP.NETに限らずWebシステムではJavascriptのwindow.open()を使いサブウィンドウを開く場面がよくある。
これがWindowsXP ServicePack2から導入され、Googleツールバーにもあるポップアップブロックによって、効かなくなることがある。それぞれ設定を解除させれば良いが、今回紹介するのは設定解除することなく、回避する方法である。
調べてみると意外に簡単に方法が見つかった。
そもそもポップアップブロックはユーザーが自らの意思でボタンを押したものには働かない。自動で(勝手に)開くウィンドウを阻止するものである。よってサーバーサイドで実行したものは必ずブロックされてしまう。
そこでクライアントサイドのOnClickイベント内で開くように変更すれば良いのである。
例:onclick="window.open('hoge.aspx');return false;"
※最後のreturn falseはonclckイベントを最終的にキャンセルさせることでwindow.open()だけを実行させる意味がある。
ただ、このサーバーサイドからクライアントサイドへの変更には結構問題が起こる。特に入力フォームの内容を取得してからでないと次の処理を決められないときなど一度ポストバックが必要な時がそれにあたる。この点に関しては事前に入力フォームのイベント内でポストバックさせて取得しておくしかない。
サンプルはこちら−>popup.lzh
なおサンプルをテストする場合、開発環境からの実行ではポップアップブロックが無視されるのでIIS等でサイトを立てて実行すること。またURLにlocalhostを使うとローカルイントラネットゾーンとなりこれもポップアップブロックが解除される(但しGoogleツールバーのポップアップブロックは有効)。IPアドレスを指定すればインターネットゾーンになりポップアップブロックが有効になるので、回避の効果が確認できる。
サンプルの実行画面
1.起動画面
上の段がサーバーサイドでのwindow.openでポップアップブロックが掛かってしまう。下の段がその回避策である。

2.ポップアップブロックが効いた

3.Googleツールバーのポップアップブロックが効いた

4.ポップアップブロック回避策で無事オープン
これがWindowsXP ServicePack2から導入され、Googleツールバーにもあるポップアップブロックによって、効かなくなることがある。それぞれ設定を解除させれば良いが、今回紹介するのは設定解除することなく、回避する方法である。
調べてみると意外に簡単に方法が見つかった。
そもそもポップアップブロックはユーザーが自らの意思でボタンを押したものには働かない。自動で(勝手に)開くウィンドウを阻止するものである。よってサーバーサイドで実行したものは必ずブロックされてしまう。
そこでクライアントサイドのOnClickイベント内で開くように変更すれば良いのである。
例:onclick="window.open('hoge.aspx');return false;"
※最後のreturn falseはonclckイベントを最終的にキャンセルさせることでwindow.open()だけを実行させる意味がある。
ただ、このサーバーサイドからクライアントサイドへの変更には結構問題が起こる。特に入力フォームの内容を取得してからでないと次の処理を決められないときなど一度ポストバックが必要な時がそれにあたる。この点に関しては事前に入力フォームのイベント内でポストバックさせて取得しておくしかない。
サンプルはこちら−>popup.lzh
なおサンプルをテストする場合、開発環境からの実行ではポップアップブロックが無視されるのでIIS等でサイトを立てて実行すること。またURLにlocalhostを使うとローカルイントラネットゾーンとなりこれもポップアップブロックが解除される(但しGoogleツールバーのポップアップブロックは有効)。IPアドレスを指定すればインターネットゾーンになりポップアップブロックが有効になるので、回避の効果が確認できる。
サンプルの実行画面
1.起動画面
上の段がサーバーサイドでのwindow.openでポップアップブロックが掛かってしまう。下の段がその回避策である。
2.ポップアップブロックが効いた
3.Googleツールバーのポップアップブロックが効いた
4.ポップアップブロック回避策で無事オープン
2008年03月19日
既存アプリのVista対応・改造計画:追加「マニフェストファイルの組込」
VistaではUAC(ユーザーアカウント制御)のため例え管理者としてログインしている場合でも標準ユーザーとしての権限でしかプログラムが実行されない。そこで管理者モードで実行できるように昇格させるためにマニフェストを用意することを以前紹介した。
このマニフェストはプログラム本体とは別ファイルになっているので、うっかりしてプログラムだけ移動したりすると使えないという問題が発生する。そこで今回はこれをプログラム内部に組み込む方法を紹介する。
VB6で作ったプログラムでもVB.NET(VB2005)で作ったプログラムでも同じ方法である。
但しVS.NET(VS2005)の開発環境が必要なのでVB6しかない方は諦めて(^^;
で、方法はというと下のURLにあります。
.NET TIPS :「マニフェスト・ファイルをアプリケーションに組み込むには?」
やはり引用先まで毎回見に行くのも面倒なので、手順のみ紹介します。
1.「ファイルを開く」で組み込み先のEXEファイルを選択

2.EXEファイルを右クリックして「リソースの追加」を選択

3.「インポート」から予め作成しておいたマニフェストファイルを選択し、リソースの種類を「RT_MANIFEST」と入力

4.IDを101から1に変更し、保存。

以上で完了。
あと訂正ですが、以前VB6でマニフェストを使うにはネイティブコンパイルをしておかないと駄目だと紹介しましたが、P-Codeコンパイルでも問題無く動きました。
(でも変だなぁ、その当時は確かにP-Codeでは動かなかったと記憶しているだけどなぁ・・・・。)
このマニフェストはプログラム本体とは別ファイルになっているので、うっかりしてプログラムだけ移動したりすると使えないという問題が発生する。そこで今回はこれをプログラム内部に組み込む方法を紹介する。
VB6で作ったプログラムでもVB.NET(VB2005)で作ったプログラムでも同じ方法である。
但しVS.NET(VS2005)の開発環境が必要なのでVB6しかない方は諦めて(^^;
で、方法はというと下のURLにあります。
.NET TIPS :「マニフェスト・ファイルをアプリケーションに組み込むには?」
やはり引用先まで毎回見に行くのも面倒なので、手順のみ紹介します。
1.「ファイルを開く」で組み込み先のEXEファイルを選択
2.EXEファイルを右クリックして「リソースの追加」を選択
3.「インポート」から予め作成しておいたマニフェストファイルを選択し、リソースの種類を「RT_MANIFEST」と入力
4.IDを101から1に変更し、保存。
以上で完了。
あと訂正ですが、以前VB6でマニフェストを使うにはネイティブコンパイルをしておかないと駄目だと紹介しましたが、P-Codeコンパイルでも問題無く動きました。
(でも変だなぁ、その当時は確かにP-Codeでは動かなかったと記憶しているだけどなぁ・・・・。)
2008年03月06日
VB6のhDCプロパティはVB.NET(VB2005)ではどうなる?
VB6でグラフィック関連のWindowsAPIを使うときは必ずと言ってよいほどコントロール(FormやPictureBox)のデバイスコンテキストであるhDCプロパティを指定する。
これをVB.NET(VB2005)で使おうとしてアップデートウィザードを使うと肝心のhDCが「'UPGRADE_ISSUE: Form プロパティ Form1.hdc はアップグレードされませんでした。」となり使えない。別件だが同じくWindowsAPIでよく使うウィンドウハンドル(.hWnd)は、.NET Frameworkでは(コントロール).Handleというプロパティになっており判りやすい。
いったいhDCはどうすれば指定できるのだ?と思い調べてみたところこんな具合になった。VB6との比較で紹介する。
例として起動したフォームの座標(x,y)地点の色(RGB値)を取得するGetPixel関数で説明する。
この関数の定義は以下の通り、最初の引数にhDCを渡す。
Declare Function GetPixel Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long
これをVB.NET(VB2005)で使おうとしてアップデートウィザードを使うと肝心のhDCが「'UPGRADE_ISSUE: Form プロパティ Form1.hdc はアップグレードされませんでした。」となり使えない。別件だが同じくWindowsAPIでよく使うウィンドウハンドル(.hWnd)は、.NET Frameworkでは(コントロール).Handleというプロパティになっており判りやすい。
いったいhDCはどうすれば指定できるのだ?と思い調べてみたところこんな具合になった。VB6との比較で紹介する。
例として起動したフォームの座標(x,y)地点の色(RGB値)を取得するGetPixel関数で説明する。
この関数の定義は以下の通り、最初の引数にhDCを渡す。
Declare Function GetPixel Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long
VB6:
Dim iro As Long
iro = GetPixel(Me.hdc, x, y) 'たったこれだけ。
VB.NET/VB2005:
Dim gp As Graphics = Me.CreateGraphics 'フォームのGraficsを作成
Dim hDC As IntPtr = gp.GetHdc() 'そのデバイスコンテキストを取得
Dim iro As Long = GetPixel(hDC, x, y) 'やっと使える
2007年12月22日
既存アプリのVista対応・改造計画:追加「文字化けの解消」
VB6で作った自作ソフトがVistaで動作上は何の問題もないが、フォントの一部が文字化けしてしまうのに気がついた。運用環境だけでなく、VB6の開発環境でさえそうなる。
「管理者として実行」すれば文字化けしないが、UACダイアログが起動時に毎回表示されるのは煩わしい限りだ。
いろいろ試行錯誤してみると、フォントを標準(規定)の「MS Pゴシック」から「MS ゴシック」にすると文字化けしなくなるのに気が付いた。文字化けしたコントロールを一つ一つ「MS ゴシック」に変更したところ文字化けは解消された。
これが原因かと考えてみるがフォントファイルは「MS Pゴシック」も「MS ゴシック」も一つのファイルでそれ自体に差異があるとは考えられない。また、この調子ですべてのソースを変更するのも面倒だ。
一体何が原因なのか。散々調べ上げた挙句ようやくわかった。
結論はこうだ。
コントロールのフォント指定でCharset=128が無いと文字化けするということだ。
規定の「MS Pゴシック」から「MS ゴシック」に変更すると自動的にCharsetを含む「BeginProperty Font」セクションが追加される。
フォームのソースファイル(.frm)を見るとわかるが、規定フォントの場合この「BeginProperty Font」セクション自体が無い。
つまりコンテナであるフォームのフォントを継承していると考えられる。であればコントロールを一つ一つ変更しなくてもフォームのフォントにCharset=128を追加することで文字化けが解消できるのではと考えたところ大正解。いっぺんに文字化けは解消した。
1.文字化けしている様子。

2.フォームのフォント指定ダイアログを表示して「OK」するだけで「BeginProperty Font」セクションは作成される。

3.「BeginProperty Font」セクション

4.文字化けが解消された様子。
「管理者として実行」すれば文字化けしないが、UACダイアログが起動時に毎回表示されるのは煩わしい限りだ。
いろいろ試行錯誤してみると、フォントを標準(規定)の「MS Pゴシック」から「MS ゴシック」にすると文字化けしなくなるのに気が付いた。文字化けしたコントロールを一つ一つ「MS ゴシック」に変更したところ文字化けは解消された。
これが原因かと考えてみるがフォントファイルは「MS Pゴシック」も「MS ゴシック」も一つのファイルでそれ自体に差異があるとは考えられない。また、この調子ですべてのソースを変更するのも面倒だ。
一体何が原因なのか。散々調べ上げた挙句ようやくわかった。
結論はこうだ。
コントロールのフォント指定でCharset=128が無いと文字化けするということだ。
規定の「MS Pゴシック」から「MS ゴシック」に変更すると自動的にCharsetを含む「BeginProperty Font」セクションが追加される。
フォームのソースファイル(.frm)を見るとわかるが、規定フォントの場合この「BeginProperty Font」セクション自体が無い。
つまりコンテナであるフォームのフォントを継承していると考えられる。であればコントロールを一つ一つ変更しなくてもフォームのフォントにCharset=128を追加することで文字化けが解消できるのではと考えたところ大正解。いっぺんに文字化けは解消した。
1.文字化けしている様子。
2.フォームのフォント指定ダイアログを表示して「OK」するだけで「BeginProperty Font」セクションは作成される。
3.「BeginProperty Font」セクション
4.文字化けが解消された様子。
2007年12月10日
データソースで取得したレコードの件数を知るには
ASP.NETでよく使うGridViewのページング機能では、何ページあるかおおよそ分かっても、全レコード数が幾つあるかは分からない。
そこで全レコード数を取得する必要があるが、そのためだけにデータベースにアクセスするのは避けたい。そこで調べたところ便利な機能があった。
GridViewではSqlDataSourceをバインドしてデータを取得するが、このデータソースのSelectイベントのなかで表示される全レコード数が取得できる。
e.AffectedRows をヘルプで調べると「データベース操作の影響を受けた行の数を取得」とある。
あとは、GridViewのDataBoundイベントのなかで取得した値を表示する処理を追加するだけである。
そこで全レコード数を取得する必要があるが、そのためだけにデータベースにアクセスするのは避けたい。そこで調べたところ便利な機能があった。
GridViewではSqlDataSourceをバインドしてデータを取得するが、このデータソースのSelectイベントのなかで表示される全レコード数が取得できる。
Dim recCount as Long
Protected Sub SqlDataSource1_Selected(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.SqlDataSourceStatusEventArgs)
recCount = e.AffectedRows
End Sub
e.AffectedRows をヘルプで調べると「データベース操作の影響を受けた行の数を取得」とある。
あとは、GridViewのDataBoundイベントのなかで取得した値を表示する処理を追加するだけである。
2007年10月15日
日付型(DateTime)の初期値を判定
VB6まではDate型は8バイトのDouble形式で値が格納されていた。
整数部が日付で小数部が時刻という具合である。
プログラムの中で日付型の変数に値があるかどうか、言い方を変えると使用されたかどうか、を判断するのにその値が0であるかどうかでチェックすることができた。
VB.NET(VB2005)になって仕様が変わってこの方法がそのまま使えなくなった。そこで違いを確認し、初期値(定義直後の値)を確認する方法をまとめた。
以下は日付型の変数にNow関数とDate関数(VB2005はToDay関数)で現在日時と現在日付を取得しそのまま表示させたものにVal関数とCDbl関数で変換を行っている。また変数を定義した直後の値も同様に表示している。VB2005の場合はToOADate関数でVB6のCDbl関数で取得したのと同様の結果が得られる。またToBinary関数ではVB6には無かった100ナノ秒単位までの値を含む64ビットのシリアル値を表示する。このToBinaryをみると定義直後の値が0であることが良く分かる。
・VB6の場合

・VB2005の場合

整数部が日付で小数部が時刻という具合である。
プログラムの中で日付型の変数に値があるかどうか、言い方を変えると使用されたかどうか、を判断するのにその値が0であるかどうかでチェックすることができた。
VB.NET(VB2005)になって仕様が変わってこの方法がそのまま使えなくなった。そこで違いを確認し、初期値(定義直後の値)を確認する方法をまとめた。
以下は日付型の変数にNow関数とDate関数(VB2005はToDay関数)で現在日時と現在日付を取得しそのまま表示させたものにVal関数とCDbl関数で変換を行っている。また変数を定義した直後の値も同様に表示している。VB2005の場合はToOADate関数でVB6のCDbl関数で取得したのと同様の結果が得られる。またToBinary関数ではVB6には無かった100ナノ秒単位までの値を含む64ビットのシリアル値を表示する。このToBinaryをみると定義直後の値が0であることが良く分かる。
・VB6の場合
Dim d1 As Date
d1 = Now
Text1.Text = d1
Label4.Caption = "Val : " & Val(d1) & vbCrLf & "CDbl : " & CDbl(d1)
Text2.Text = Date
Label5.Caption = "Val : " & Val(Date) & vbCrLf & "CDbl : " & CDbl(Date)
Dim d2 As Date
Text3.Text = d2
Label6.Caption = "Val : " & Val(d2) & vbCrLf & "CDbl : " & CDbl(d2)
・VB2005の場合
Dim d1 As DateTime = Now
TextBox1.Text = d1
Label4.Text = "Val : " & Val(d1) & vbCrLf & _
"ToOADate : " & d1.ToOADate & vbCrLf & _
"ToBinary : " & d1.ToBinary
TextBox2.Text = Today
Label5.Text = "Val : " & Val(Today) & vbCrLf & _
"ToOADate : " & Today.ToOADate & vbCrLf & _
"ToBinary : " & Today.ToBinary
Dim d2 As Date
TextBox3.Text = d2
Label6.Text = "Val : " & Val(d2) & vbCrLf & _
"ToOADate : " & d2.ToOADate & vbCrLf & _
"ToBinary : " & d2.ToBinary

