none
TextBoxを自分で描画する際、一般的なビジュアルスタイルで描画されない RRS feed

  • 質問

  • 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

    のようなソフトも試してみたのですが、結局テキストボックスだけ同じようにシンプルな描画となってしまいました。

    何か解決策があるのでしょうか?よろしくおねがいします。

    2012年6月12日 9:22

回答

  • やってみましたが、やはり求めている結果になりません・・・

    こんな感じ?

    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
    2012年6月12日 13:13
  • > 調べた限り .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
    2012年6月14日 10:18

すべての返信

  • 私は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/

    2012年6月12日 10:27
  • やってみましたが、やはり求めている結果になりません・・・
    2012年6月12日 12:16
  • やってみましたが、やはり求めている結果になりません・・・

    こんな感じ?

    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
    2012年6月12日 13:13
  • どこまで求めているのでしょうか。
    単に静止している画像として描くのであれば、kyano30 さんのコードで実現できそうです。

    もし、マウスをホバーさせたときのほんのり色が変わるまで再現しようとすると、かなり大変だと思われます。
    .NET が用意している要素だけで足りないかもしれません

    2012年6月12日 13:32
    モデレータ
  • 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 追記
    2012年6月12日 14:40
  • 目的が見えないので見当違いかもしれませんが、
    TextBoxを継承したカスタムコントロールでは要件を満たせないのですか?

    というか、要件によっては普通にTextBoxを配置して、
    ReadOnly = true, BackColor = System.Drawing.SystemColors.Window
    とすれば良い話とすら思うのですが・・・

    あらためて見当違いだったらすいません。

    2012年6月14日 1:27
  • > 調べた限り .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
    2012年6月14日 10:18
  • みなさま、ありがとうございました。

    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 少し追記
    2012年6月14日 11:44
  • コンポーネント化されてはいませんが、標準の HotKey コントロールではダメなんでしょうか? 適当なショートカットのプロパティを開いて「ショートカットキー」という欄に使われているやつです。

    http://msdn.microsoft.com/en-us/library/windows/desktop/bb775233(v=vs.85).aspx

    2012年6月14日 13:37
  • 前はそれをつかっていたのですが、EverNoteのオプションダイアログにあるコントロールがWindowsキーも入れられてクリアボタンなんかもあっていい感じだなーと思ったので作り始めました。

    こんなに苦戦するとは思ってなかったのでプログラミングは奥が深いなーと改めて感じてます。

    2012年6月15日 11:52