トップ回答者
TextBoxを自分で描画する際、一般的なビジュアルスタイルで描画されない

質問
-
Windows7 64bit
Visual Studio 2010 C# Express
WinForms
現在コントロールを作成しており、見た目をTextBoxと同じにしたいと考えています。
そこでVisualStyleRendererを使いました。(実際にはVisualスタイルが無効な時にControlPaintで描画するようになっています)
private void Form1_Paint(object sender, PaintEventArgs e) { VisualStyleRenderer render = new VisualStyleRenderer(VisualStyleElement.TextBox.TextEdit.Normal); render.DrawBackground(e.Graphics, new Rectangle(10, 20, 120, 20)); }
しかし、こうすると灰色の線で囲われたスタイルになってしまい、通常のTextBoxと同じになりません。
HotやFocusedなども試しましたが、どれもかわらず、通常のような角丸になったりふちに影がついたりということはありませんでした。
ほかのボタンやチェックボックスなどはWindows7の一般的なスタイルで表示されます。
コードに問題があるのかと思い、Cで書いてみたり、
Add XP Visual Style Support to OWNERDRAW Controls - TheCodeProject
のようなソフトも試してみたのですが、結局テキストボックスだけ同じようにシンプルな描画となってしまいました。
何か解決策があるのでしょうか?よろしくおねがいします。
回答
-
やってみましたが、やはり求めている結果になりません・・・
こんな感じ?
private void Form1_Paint(object sender, PaintEventArgs e) { VisualStyleRenderer render = new VisualStyleRenderer("EDIT", 6, 1); render.DrawBackground(e.Graphics, new Rectangle(10, 20, 120, 20)); }
で、お求めの描画になりましたか?
- 回答としてマーク tinq 2012年6月14日 11:54
-
> 調べた限り .NET の VisualStyle 機能は XP までの機能のようで、今回例示した
> 指定は XP では動かない可能性があります。書かれている定数は VisualStyle の拡張の AeroStyle で追加されているものなので、XP では動かないですね。
Windows Vista/7 などで Windows Aero を有効にしている場合に採用される描画形式です。どのような描画パーツが追加されているかは、Windows SDK 7.0 以上に付属する Include/AeroStyle.xml を参照されるとよいでしょう。(Visual Studio と一緒にインストールされていると思います)
また、提示されている定数等については同 Include/vsstyle.h や Windows SDK のリファレンスから参照することができます。ざっとみたところ、AeroStyle で 99 個ほどの描画パーツが追加されていますので、VisualStyle 時代のパーツで描画すると差異がでるものがそれだけあるということでしょうか。
AeroStyle の定数は、VisualStyleElement.Create を使用して名前をつけておくと使いやすくなるかもしれません。
/// <summary>スクロールバーなしのテキストボックス</summary> private static class EditBorder_NoScroll { // import from AeroStyle.xml & vsstyle.h (include Windows SDK v7.0 or later) public static VisualStyleElement Normal = VisualStyleElement.CreateElement("EDIT", 6, 1); public static VisualStyleElement Hot = VisualStyleElement.CreateElement("EDIT", 6, 2); public static VisualStyleElement Focused = VisualStyleElement.CreateElement("EDIT", 6, 3); public static VisualStyleElement Disabled = VisualStyleElement.CreateElement("EDIT", 6, 4); }
すでに ControlPaint との切り替えも実装されているとのことですので、Windows Aero が有効な場合は AeroStyle、Visual Style は有効だが Windows Aero が無効な場合は VisualStyle、Visual Style が無効なら ControlPaint というかんじですね。
そして、自作のコントロールの描画で、このEditBorder_NoScrollをレンダリングするには、ちょっと工夫がいります。というのは、このレンダリングパーツは名前に Border があるようにコントロールのクライアント領域の外側に描画があるためです。
このため、Control.OnPaint を override して描画する際に、与えられた e.Graphics の外側にも描画しないと、標準の TextBox と比較して一回り小さくなったり、文字が境界線に重なってしまって読めなかったりします。コントロール自身を一回り大きくしておけばよいのですが…そうするとヒットテスト領域が標準の TextBox より広くなったり、AeroStyle 以外の描画を行う場合に小さく描画する必要がでちゃうのですよね。
- 回答としてマーク tinq 2012年6月14日 11:54
すべての返信
-
私はTextBoxRenderer.DrawTextBoxを使いました。
VisualStyles.TextBoxState textBoxState = 0; if (!Enabled) { textBoxState = VisualStyles.TextBoxState.Disabled; } else if (Focused) { textBoxState = VisualStyles.TextBoxState.Hot; } else { textBoxState = VisualStyles.TextBoxState.Normal; } TextBoxRenderer.DrawTextBox(e.Graphics, ClientRectangle, textBoxState);
http://systemartlaboratory.com/
-
やってみましたが、やはり求めている結果になりません・・・
こんな感じ?
private void Form1_Paint(object sender, PaintEventArgs e) { VisualStyleRenderer render = new VisualStyleRenderer("EDIT", 6, 1); render.DrawBackground(e.Graphics, new Rectangle(10, 20, 120, 20)); }
で、お求めの描画になりましたか?
- 回答としてマーク tinq 2012年6月14日 11:54
-
どこまで求めているのでしょうか。
単に静止している画像として描くのであれば、kyano30 さんのコードで実現できそうです。もし、マウスをホバーさせたときのほんのり色が変わるまで再現しようとすると、かなり大変だと思われます。
.NET が用意している要素だけで足りないかもしれません。 -
Azulean さんの言われるとおり、ホバー時の描画等の変更をするとなると定義されてないので問題ですね。
定義値が組合せで変になってるし・・・。
とはいえ VisualStyleRenderer は VisualStyle API のラッパーという事なので再現できないということもないはずですが・・・。
せっかくなので利用しそうな定義値を一部紹介しておきます。
Part
EP_EDITBORDER_NOSCROLL = 6
State
EPSN_NORMAL = 1,
EPSN_HOT = 2,
EPSN_FOCUSED = 3,
EPSN_DISABLED = 4,ホバー時に HOT 、フォーカス時に FOCUSED 、無効時に DISABLED で描画するとよいはず・・・・。
-----------------------------------------------------------------------------------
調べた限り .NET の VisualStyle 機能は XP までの機能のようで、今回例示した指定は XP では動かない可能性があります。
標準で使える TextBox の描画機能は XP 用のテキストボックスなのではないでしょうか?
恐らくテキストボックスは Vista 以降で Parts 変更して実装されたのでしょう。
後、ホバー時にほんのり色を変えるというアニメーション描画機能は Vista 以降の機能なので API による実装でないと再現できないようです。
思ったよりは簡単そうですが、そこまでして同一表示を求めるのは無駄に思えますね。
- 編集済み kyano30 2012年6月12日 22:09 追記
-
> 調べた限り .NET の VisualStyle 機能は XP までの機能のようで、今回例示した
> 指定は XP では動かない可能性があります。書かれている定数は VisualStyle の拡張の AeroStyle で追加されているものなので、XP では動かないですね。
Windows Vista/7 などで Windows Aero を有効にしている場合に採用される描画形式です。どのような描画パーツが追加されているかは、Windows SDK 7.0 以上に付属する Include/AeroStyle.xml を参照されるとよいでしょう。(Visual Studio と一緒にインストールされていると思います)
また、提示されている定数等については同 Include/vsstyle.h や Windows SDK のリファレンスから参照することができます。ざっとみたところ、AeroStyle で 99 個ほどの描画パーツが追加されていますので、VisualStyle 時代のパーツで描画すると差異がでるものがそれだけあるということでしょうか。
AeroStyle の定数は、VisualStyleElement.Create を使用して名前をつけておくと使いやすくなるかもしれません。
/// <summary>スクロールバーなしのテキストボックス</summary> private static class EditBorder_NoScroll { // import from AeroStyle.xml & vsstyle.h (include Windows SDK v7.0 or later) public static VisualStyleElement Normal = VisualStyleElement.CreateElement("EDIT", 6, 1); public static VisualStyleElement Hot = VisualStyleElement.CreateElement("EDIT", 6, 2); public static VisualStyleElement Focused = VisualStyleElement.CreateElement("EDIT", 6, 3); public static VisualStyleElement Disabled = VisualStyleElement.CreateElement("EDIT", 6, 4); }
すでに ControlPaint との切り替えも実装されているとのことですので、Windows Aero が有効な場合は AeroStyle、Visual Style は有効だが Windows Aero が無効な場合は VisualStyle、Visual Style が無効なら ControlPaint というかんじですね。
そして、自作のコントロールの描画で、このEditBorder_NoScrollをレンダリングするには、ちょっと工夫がいります。というのは、このレンダリングパーツは名前に Border があるようにコントロールのクライアント領域の外側に描画があるためです。
このため、Control.OnPaint を override して描画する際に、与えられた e.Graphics の外側にも描画しないと、標準の TextBox と比較して一回り小さくなったり、文字が境界線に重なってしまって読めなかったりします。コントロール自身を一回り大きくしておけばよいのですが…そうするとヒットテスト領域が標準の TextBox より広くなったり、AeroStyle 以外の描画を行う場合に小さく描画する必要がでちゃうのですよね。
- 回答としてマーク tinq 2012年6月14日 11:54
-
みなさま、ありがとうございました。
Vista以降のスタイルで描画することができました。
CreateElementでPartをEP_EDITBORDER_NOSCROL以降にしないといけなかったのですね。
Cでもtmschema.hではEP_EDITTEXTとEP_CARETしか宣言されず、vsstyle.hのなかを見ないと見つからないという・・・
とりえあず、アニメーションまでは求めないでおこうと思います。
>TextBoxを継承したカスタムコントロールでは要件を満たせないのですか?
作っているのはショートカットを入力するようなコントロールです。
たしかTextBoxだとコンテキストメニューを完全に消せなかったなー、見た目がTextBoxなだけで機能も違うわけだし、継承するべきではないかなーとおもってControlを継承して作り始めてしまった状態です。
先ほど改めて調べてみたところ、
TextBoxで右クリックしてもコンテキストメニューが表示されないようにする - Dobon.NET
にShortcutsEnabledをtrueにすると表示されなくなるという情報を見つけ、やっぱりTextBoxの継承に変えようかと迷っています・・・
XPや細かい仕様まで検討するとそっちのほうが簡単でしっかりできそうな気がしてきました。
- 編集済み tinq 2012年6月14日 11:54 少し追記
-
コンポーネント化されてはいませんが、標準の HotKey コントロールではダメなんでしょうか? 適当なショートカットのプロパティを開いて「ショートカットキー」という欄に使われているやつです。
http://msdn.microsoft.com/en-us/library/windows/desktop/bb775233(v=vs.85).aspx