Home > ソフト談話所 > メイン画面と設定画面を兼用するのも考えものです

メイン画面と設定画面を兼用するのも考えものです

2009/03/10
私が簡易的に作成したソフトは1画面で済むように作ることがあります。

1画面アプリケーションの利用手順はこんな感じです。

・ソフトを起動するとメイン画面が表示される
・1画面ですべての操作ができます
・メイン画面で設定更新もでき、変更があれば保存ボタンがクリックできるようになります

今回は、この形式のソフトに起こった設定変更についてのトラブル解決メモです。

[つづく]
[つづき] 通常は設定画面を1画面作っていますが、それなりに手間がかかって面倒です。 そこで、メイン画面に設定項目を作ってあげるわけです。 こうすると余分に作る手間が省けて、一見よさそうに見えます。 実際、用途によってはメイン画面だけで十分使えます。 今回、このメイン画面でListViewコントロールのイベントでとても面倒なことに遭遇したので、メモしておきます。 事の発端は、AutoLogGetterというログダウンロードソフトへの機能追加のテスト中に起こりました。 (AutoLogGetterは当初簡易的な機能を想定していたので1画面アプリです) 公開中のバージョン(V1.10以下)はダウンロード先が2個という制限があって不便なため、新バージョンでは、 好きなだけダウンロード先を登録できるようにしようとしています。 登録したダウンロード先をListViewに表示してListViewコントロールのCheckBoxesプロパティをTrueにして、 チェックボックスを表示し、チェックするとダウンロード先が有効になるという使い方を想定しています。 プログラムの機能追加がひととおり終わり、テストしていて「チェックボックス」について不具合を発見。 アプリケーションを表示させたり最小化する時に、「設定保存」ボタンがクリックできるようになってしまうのです。 設定変更した時は「設定保存」ボタンがクリックできるので構わないのですが、設定画面を表示させた だけでこのようになるのはおかしいです。 「設定保存」ボタンをクリックできるようにしているのは、ListViewに変更があった時のプログラムです。 設定の変更はしていないし、一体どうしてなんだろう。 早速、調査を開始しました。 まず、「設定保存」ボタンがクリックできるようになるのは、ListViewのItemCheckedイベントを拾ってチェックが変更された時です。テストしてみると、このイベントはマウスでチェックのON/OFFを切り替えなくても実は発生することがわかりました。 ListViewコントロールを表示したり、非表示にしたりする時に、ListViewのチェックが入っているItem毎にItemCheckedイベントが発生します。 (補足:ListViewコントロールは初めて表示された時にItemCheckedイベントが発生するので、それについては内部フラグで対処することにしています。ここでの問題点はアプリケーションが表示されたり、最小化した時もItemCheckedイベントが呼ばれてしまうことです) [イベントの発生パターン] ——————————————————————————————— (前提条件)ListView1の1つ目(Indexは0始まり)にチェックが入っているものとします。 ListView1.ItemCheckedイベントで呼び出されるコードの一部 > Private Sub ListView1_ItemChecked(ByVal sender As Object, ByVal e As System.Windows.Forms.ItemCheckedEventArgs) Handles ListView1.ItemChecked > Dim idx As Integer = e.Item.Index() > Dim chk As Boolean = ListView1.Items(idx).Checked [フォーム非表示→表示] (1)chk = False (2)chk = True (1)(2)の順番で連続してイベントが呼び出されます。 Items(0).CheckedはTrueをセット済みなので、そもそもItemCheckedイベントが発生することは想定していませんでした。 [フォーム表示→非表示] (1)chk = False (2)chk = True (1)(2)の順番で連続してイベントが呼び出されます。 Items(0).CheckedはTrueをセット済みなので、そもそもItemCheckedイベントが発生することは想定していませんでした。 —————————————————– ちなみに、ListView1.Items(0)にチェックがついていない場合は、上記のイベント呼び出しが発生しません。 そのため問題は起こりません。 ListViewコントロールの仕様のようなので、何とか対処方法を考えてみました。 1つ手っ取り早い方法を思い付きました。 まず、ListView1.VisibleがFalseになっている時はイベントを無視すること。これで非表示になった時の問題は解消します。 残りはListViewが表示される時、ListView1.Visible=Trueになっている時の状況認識です。 これは表示されたことがあるかどうかフラグをもたせるのが簡単でしょう。 初期表示の時にフラグを持たせているので、非表示(Me.Resizeイベントまたはメニューから最小化を選択)にするタイミングでフラグをFalseにしてあげればいいでしょう。コードを追加して試してみると、このやり方で希望どおりうまく動作します。 しかし、この方法はあまりエレガントではないです。 もう少し読みやすくわかりやすい方法はないものでしょうか。 根本的な原因を考えてみると、この問題は常時インスタンス化しているメイン・設定兼用フォームの 表示・非表示を切り替える時に発生しています。 (補足1:TabControlコントロールのタブシートにListViewコントロールを貼り付けて、タブを切り替えても この問題は発生しません、アプリケーション自体の表示・非表示の状態を変更した時にのみ発生します) (補足2:ListViewコントロールが初めて表示される時も表示・非表示の切り替えと同様にItemCheckedイベントが 発生します(ListView1.Visible=Trueです)、ListViewコントロールにItemを増やしただけではItemCheckedイベント は発生しません。初回表示を認識できるようフラグを持たせることで対応できます) 設定だけを行うフォームを作ってListViewを付け、ShowDialogで呼び出せば、この問題はクリアできそうです。 (アプリケーションはデスクトップ表示にすると最小化されてしまうので、本当は非表示のことを考える必要があり、 思ったほど単純ではありません) 設定を保存してもしなくても、設定画面を閉じたらフォームは破棄しますので、インスタンス化の時にだけItemChecked イベントを考慮すればよくなります。 設定用のフォームを新規に作る必要がありますが、ItemCheckedイベントの特殊処理を(あまり)書かなくて済むため、 メンテナンスの観点からも意味があるかなと思います。 しかしながら、設定項目が多かったら改めて作るかどうかは考えますね。 今回は、項目数も多くなっていたので、あまりエレガントではない方法で対処しました(^^;)。 .NET使いの人なら普通に読めるコードだと思うので、今回は妥協します。 (時間が十分あり、コストを掛けられるならフォームの新規作成したいところです。 実際には時間は有限だし、コストはかけられないのです・・・・) 次回のソフト作りの時は、簡易ソフトであっても設定画面をどうするか少し考えてから始めたいと思います。