- - PR -
コントロール描画の残像
投稿者 | 投稿内容 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2008-04-23 18:45
初めて質問させて頂きます。
VS2005 C# (.net framework 2.0) で現在 Windows アプリを作成しているのですが、 フォームの内のレイアウトを変更する際に残像が表示されてしまい困っています。 レイアウトは以下の 3 種類があります。 ■ レイアウト A ┌───────────┐ │ │ │ │ │ │ │ @ │ │ │ │ │ │ │ └───────────┘ ■ レイアウト B ┌───┬───────┐ │ │ │ │ @ │ │ │ │ │ ├───┤ A │ │ │ │ │ B │ │ │ │ │ └───┴───────┘ ■ レイアウト C ┌───┬───────┐ │ │ │ │ @ │ A │ │ │ │ ├───┼───────┤ │ │ │ │ B │ C │ │ │ │ └───┴───────┘ 各レイアウト間はユーザ操作 ( クリック等 ) により、以下のように遷移します。 ┌──┐ │ ↓ A─→B C ↑ │ └──┘ ・レイアウトは Panel, UserControl を継承したクラス、 Splitter で作成しています ・各小分けになった番号がふられた部分には DataGridView 、 Label 、 TextBox 、 PictureBox 、 TabControl など複数の子コントロールが載っています ・各小分けになった番号がふられた部分は DockStyle を指定しておりフォームのリサイズに影響を受けます ・各小分けになった番号がふられた部分は境界になっている Splitter の移動によってリサイズの影響を受けます 例えばレイアウト A から B に変更する場合、レイアウト B のAにレイアウト A の@の残像が表示されてしまいます。 コントロールの描画イメージを表示されないところで作成しておき、その処理が完了したタイミングで 画面に表示させたいのですが、 Windows の Control を継承したコントロールを使用して そのようなことができるものなのでしょうか ? ※ DoubleBuffered プロパティが設定可能なものについては true に設定しましたが、残像が表示されてしまいました。 ( DoubleBuffered プロパティが protected なものについてはサブクラスを作成して true に設定しました ) もし、そのような方法があるならば、教えて頂けますでしょうか ? よろしくお願いします。 | ||||||||||||
|
投稿日時: 2008-04-24 07:46
デザイナが自動生成しているコードを見てください。レイアウト変更中は描画を止めたり、配置が終わったことを通知したりしています。それと同じことをすればいいと思います。
| ||||||||||||
|
投稿日時: 2008-04-24 08:48
よくある勘違いですが、DoubleBufferedは子コントロールまで制御しません。 自分の描画だけですので、今回は意味がありません。 重くしてるだけですので、やめたほうがいいでしょう。
WS_EX_COMPOSITEDというのがありませす。 しかし、適用できるケースが限られています。
残像とはなんですか? 表示が更新されずに残ってしまうということですか? それとも一瞬残ってしまっうということですか? | ||||||||||||
|
投稿日時: 2008-04-24 10:46
おそらくですが、レイアウト ロジックを止めても描画関係の再描画漏れは改善されないと思います。
今回問題となっているのはこれから '表示すべき' Control の描画ではなくて、'消えるべき' Control の描画ではないのでしょうか? 問題解決の手法を見誤っておられる気がします。 安直ですが、レイアウト B の (2) に残ってしまったレイアウト A の (1) の領域のみ強制的に再描画すれば解決するのではと思います。 _________________ C# と VB.NET の入門サイト じゃんぬねっと日誌 | ||||||||||||
|
投稿日時: 2008-04-24 16:24
返答ありがとうございます。
私の説明がわかりにくかったと思いますので、以下の場所に簡単なサンプルを作成して置きました。 速い PC ではわかりにくいと思います。 http://cid-5bee01eee94b636f.skydrive.live.com/self.aspx/%e5%85%ac%e9%96%8b/LayoutTest1.zip サンプルではメニューをクリックするたびにレアイアウトが A → B → C と変わります。 例えばレイアウト A から B に変わるときに以下のキャプチャ画像のように http://cid-5bee01eee94b636f.skydrive.live.com/self.aspx/%e5%85%ac%e9%96%8b/capture.png 一瞬見えるのをなんとかしたいということです。 キャプチャ画像をとった PC のスペックは OS : Windows Vista Ultimate CPU : Pentium M 1.4 GHz Memory : 512 MB エクスペリエンスインデックス : 1.0 ※ノート PC です。 すいませんがお知恵をお貸しください、よろしくお願いします。 | ||||||||||||
|
投稿日時: 2008-04-24 18:09
たしかにやってみればすぐわかるでしょうが、 私はネットからダウンロードした署名なしファイルを 自由に実行できる環境にはいません。 また、おそらくほとんどの人がそうでしょう。 きちんと文章で説明したほうがよいと思います。 もしくは、exeを信頼できる証明書で署名したらよいでしょう。
切り替え時に一瞬見えるだけですね? では、どのようなコード、仕組みでレイアウトを切り替えていますか? #いままでの経験上、 #きちんと説明があれば私はその問題を解決できると思います。 | ||||||||||||
|
投稿日時: 2008-04-24 21:19
れい様、回答ありがとうございます。
配慮が足らず申し訳ありませんでした。 引用:-------------------------------------------------------------------------------- 切り替え時に一瞬見えるだけですね? ------------------------------------------------------------------------------------- はい、その通りです。 引用:-------------------------------------------------------------------------------- では、どのようなコード、仕組みでレイアウトを切り替えていますか? ------------------------------------------------------------------------------------- サンプルではメニューをクリックする度に以下のメソッドで Form 内のレイアウトを変更しています。 ======================================================================= private void SetLayout(LayoutType type) { SuspendLayout(); baseLeftPanel.Controls.Clear(); baseRightPanel.Controls.Clear(); basePanel.Controls.Clear(); switch (type) { case LayoutType.A: parts1Panel.Dock = DockStyle.Fill; baseLeftPanel.Controls.Add(parts1Panel); baseLeftPanel.Dock = DockStyle.Fill; basePanel.Controls.Add(baseLeftPanel); break; case LayoutType.B: parts2Panel.Dock = DockStyle.Fill; baseRightPanel.Controls.Add(parts2Panel); parts3Panel.Dock = DockStyle.Fill; baseLeftPanel.Controls.Add(parts3Panel); baseLeftVerticalSplitter.Dock = DockStyle.Top; baseLeftPanel.Controls.Add(baseLeftVerticalSplitter); parts1Panel.Dock = DockStyle.Top; baseLeftPanel.Controls.Add(parts1Panel); baseRightPanel.Dock = DockStyle.Fill; basePanel.Controls.Add(baseRightPanel); baseHorizontalSplitter.Dock = DockStyle.Left; basePanel.Controls.Add(baseHorizontalSplitter); baseLeftPanel.Dock = DockStyle.Left; basePanel.Controls.Add(baseLeftPanel); break; case LayoutType.C: parts4Panel.Dock = DockStyle.Fill; baseRightPanel.Controls.Add(parts4Panel); baseRightVerticalSplitter.Dock = DockStyle.Top; baseRightPanel.Controls.Add(baseRightVerticalSplitter); parts2Panel.Dock = DockStyle.Top; baseRightPanel.Controls.Add(parts2Panel); parts3Panel.Dock = DockStyle.Fill; baseLeftPanel.Controls.Add(parts3Panel); baseLeftVerticalSplitter.Dock = DockStyle.Top; baseLeftPanel.Controls.Add(baseLeftVerticalSplitter); parts1Panel.Dock = DockStyle.Top; baseLeftPanel.Controls.Add(parts1Panel); baseRightPanel.Dock = DockStyle.Fill; basePanel.Controls.Add(baseRightPanel); baseHorizontalSplitter.Dock = DockStyle.Left; basePanel.Controls.Add(baseHorizontalSplitter); baseLeftPanel.Dock = DockStyle.Left; basePanel.Controls.Add(baseLeftPanel); break; default: break; } ResumeLayout(); } ======================================================================= よろしくお願いします。 | ||||||||||||
|
投稿日時: 2008-04-25 09:38
まず、描画やコントロールのレイアウトの仕組みがどうなっているのか、 考えましょう。 また、使うコントロールのメソッドやプロパティは、 軽くでいいので目を通したほうがいいでしょう。 それなりに考えて作られているので、 たいていの場合、やりたいことに適した方法があります。 今回の場合、 まずSusupend/ResumeLayoutの使い方を間違っています。 これらは「子コントロールのレイアウトロジックの停止/再開」です。 描画の停止でもありませんし、 孫まで停止するものでもありません。 コンテナコントロールごとにSuspendする必要があります。 何回LayoutEventが起きているのか見てみるとよいと思います。 おそらく、本来1回でいいところ、2〜3回起きているはずです。 また、無駄にDoubleBufferedを設定してはいけません。 メモリを大量に消費しますので、 なるべくfalseに設定します。 無駄なレイアウトをやめ、 パフォーマンスが改善されないか 試すとよいと思います。
私の環境では、これでチラツキはほとんど気になりません。 さらにチラツキを抑えたいなら、 WS_EX_COMPOSITEDを追加する手があります。 ですが、これはTabPageやListView、ComboBoxなどで 描画に問題が発生する場合があります。 また、メモリも消費します。
コントロールの数を減らし、 適切な方法でレイアウト・描画を行えば それほど問題にならないはずです。 |