C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

コンボボックスの文字色を変更する方法

[トピック内 18 記事 (1 - 18 表示)]  << 0 >>

■100547 / inTopicNo.1)  コンボボックスの文字色を変更する方法
  
□投稿者/ wani (1回)-(2022/09/10(Sat) 10:44:51)

分類:[.NET 全般] 



VB.NETを使用しております。



コンボボックスの文字色を変更したいと考えているのですが

http://dobon.net/vb/dotnet/control/cbownerdraw.html

このページの方法で変更することができました。


しかし、外観(FlatStyle)がStandardではなくFlatに変わってしまいます。

Standardの状態で文字色だけを変更するにはどのようにしたら良いですか?


引用返信 編集キー/
■100548 / inTopicNo.2)  Re[1]: コンボボックスの文字色を変更する方法
□投稿者/ WebSurfer (2558回)-(2022/09/10(Sat) 11:05:05)
No100547 (wani さん) に返信

何を何で作っているか書けませんか?

(例: Windows Forms アプリを Visual Studio 2022 を使ってフレームワークを
.NET Framework 4.8 で作っています)
引用返信 編集キー/
■100549 / inTopicNo.3)  Re[2]: コンボボックスの文字色を変更する方法
□投稿者/ wani (2回)-(2022/09/10(Sat) 11:46:48)
Windows Forms アプリを Visual Studio 2015 を使ってフレームワークを
.NET Framework 4.5 で作っています

引用返信 編集キー/
■100551 / inTopicNo.4)  Re[1]: コンボボックスの文字色を変更する方法
□投稿者/ KOZ (316回)-(2022/09/10(Sat) 22:56:02)
No100547 (wani さん) に返信
> http://dobon.net/vb/dotnet/control/cbownerdraw.html
> このページの方法で変更することができました。
> しかし、外観(FlatStyle)がStandardではなくFlatに変わってしまいます。

Flat ではなく、DropDownList が DropDown と同じような表示になるのではないですか?

> Standardの状態で文字色だけを変更するにはどのようにしたら良いですか?

ComboBox 自身を VisualStyleElement を使って VisualStyleRenderer で背景を描画します。

ComboBox の DropDownButton 部分については、VisualStyleElement に定義があるのですが、他は無いので
https://docs.microsoft.com/en-us/windows/win32/controls/parts-and-states
を参照して、定義します。

描画時には

VisualStyleRenderer.IsBackgroundPartiallyTransparent メソッドで現在の visual スタイル要素の
背景の一部が半透明である (アルファ ブレンドされている) かどうかをチェックし、True なら
VisualStyleRenderer.DrawParentBackground で親の背景を描画します。

VisualStyleRenderer.SetParameters で VisualStyleElement を反映します。

VisualStyleRenderer.DrawBackground で描画します。

という感じになります。

フォーカスを得た状態、マウスがホバーした状態などのステータスにあわせてこれらを描画しなくてはならないので、
はっきりいってメチャメチャ面倒です。

引用返信 編集キー/
■100552 / inTopicNo.5)  Re[2]: コンボボックスの文字色を変更する方法
□投稿者/ wani (3回)-(2022/09/11(Sun) 15:19:15)
No100551 (KOZ さん) に返信

ありがとうございます。

レベルが高すぎて私にはどのように作成したら良いか分かりません。

どうやれば良いかコードをご提示いただけないでしょうか?

引用返信 編集キー/
■100553 / inTopicNo.6)  Re[1]: コンボボックスの文字色を変更する方法
□投稿者/ 魔界の仮面弁士 (3455回)-(2022/09/11(Sun) 19:20:34)
No100547 (wani さん) に返信
> コンボボックスの文字色を変更したいと考えているのですが
> http://dobon.net/vb/dotnet/control/cbownerdraw.html
> このページの方法で変更することができました。

DrawItem イベントにおいて、e.BackColor や e.ForeColor に頼らずに独自の色にする場合は、
その時点の e.State の値を検査する必要がありますね。


No100547 (wani さん) に返信
> しかし、外観(FlatStyle)がStandardではなくFlatに変わってしまいます。

FlatStyle を意図的に Standard に変更したとしても、Flat の見た目になるということでしょうか?
手元の環境では確認できませんでした。
・Win11 21H2 + .NET Framework 4.8.1
・Win11 21H2 + .NET Framework 3.5

FlatStyle の Standard / Flat / Popup の見た目というのは、
.NET / .NET Framework のバージョンや、
実行 OS や VisualStyles テーマによっても異なってくるかと思いますが、
今回の環境はどういう組み合わせでしたか?
https://github.com/dotnet/winforms/issues/7727
https://www.cnblogs.com/leiyongbo/p/12193639.html


No100552 (wani さん) に返信
> ■No100551 (KOZ さん) に返信
> > フォーカスを得た状態、マウスがホバーした状態などのステータスにあわせてこれらを描画しなくてはならないので、
> どうやれば良いかコードをご提示いただけないでしょうか?

たとえばボタン部のホバーに関しては、その時点のマウス位置に応じて描画内容を変化させます。

下記は Flat な ComboBox を作る場合の例なので、そのものずばりでは無いですが、
マウス位置の判定処理を作りこむ際の参考にはなるかと思います。
https://www.codeproject.com/Articles/11338/Flat-ComboBox-with-MS-Office-XP-2003-style-support?

GDI+ リソースの Dispose 処理が漏れていたり、Option Strict Off 前提のソースだったりと、
そのまま丸写しするには、少々難があるソースですが…。


> レベルが高すぎて私にはどのように作成したら良いか分かりません。
手も足も出ないようなら手間がかかりすぎるので、諦めた方が無難でしょう。
引用返信 編集キー/
■100554 / inTopicNo.7)  Re[3]: コンボボックスの文字色を変更する方法
□投稿者/ KOZ (317回)-(2022/09/12(Mon) 02:21:56)
2022/09/12(Mon) 07:27:48 編集(投稿者)
No100552 (wani さん) に返信

わたしの疑問には答えてもらえないんでしょうか?

> レベルが高すぎて私にはどのように作成したら良いか分かりません。
> どうやれば良いかコードをご提示いただけないでしょうか?

CP_BACKGROUND な VisualStyleElement は、作成はできるものの、SetPrameters でセットするとエラーになります。
API を使って直書きしてみたのですが、どうやら、DropDown スタイルのテーマのようです。

DropDownList スタイルの場合、背景はボタンを描画するのが正解のようです。

とりあえず、マウスがホバーしホットな状態の ComboBox を作ってみました。

あとは面倒なのでおまかせします。
状態を検出して VisualStyles.PushButtonState.Hot/CBXSR_HOT の部分を切り替えてください。
テキストの描画位置も要調整。

フォーカスを得たときの点線は、ControlPaint.DrawFocusRectangle メソッドを使って描画できます。
https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.controlpaint.drawfocusrectangle?view=netframework-4.5

Public Class ComboBoxEx
    Inherits ComboBox

    <ThreadStatic>
    Private Shared vsRenderer As VisualStyles.VisualStyleRenderer
    Private Shared dropdownButtonElement As VisualStyles.VisualStyleElement =
                VisualStyles.VisualStyleElement.CreateElement("COMBOBOX", CP_DROPDOWNBUTTONRIGHT, CBXSR_NORMAL)

    Private Const CP_BACKGROUND As Integer = 2
    Private Const CP_TRANSPARENTBACKGROUND As Integer = 3
    Private Const CP_BORDER As Integer = 4
    Private Const CP_READONLY As Integer = 5
    Private Const CP_DROPDOWNBUTTONRIGHT As Integer = 6
    Private Const CP_DROPDOWNBUTTONLEFT As Integer = 7
    Private Const CP_CUEBANNER As Integer = 8

    Private Const CBXSR_NORMAL As Integer = 1
    Private Const CBXSR_HOT As Integer = 2
    Private Const CBXSR_PRESSED As Integer = 3
    Private Const CBXSR_DISABLED As Integer = 4

    Protected Overrides Sub CreateHandle()
        MyBase.CreateHandle()
        Dim bUserPaint As Boolean = Application.RenderWithVisualStyles AndAlso
            DropDownStyle = ComboBoxStyle.DropDownList AndAlso
            FlatStyle = FlatStyle.Standard
        SetStyle(ControlStyles.UserPaint Or
                 ControlStyles.AllPaintingInWmPaint Or
                 ControlStyles.OptimizedDoubleBuffer, bUserPaint)
    End Sub

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        If vsRenderer Is Nothing Then
            vsRenderer = New VisualStyles.VisualStyleRenderer(dropdownButtonElement)
        End If
        If vsRenderer.IsBackgroundPartiallyTransparent() Then
            vsRenderer.DrawParentBackground(e.Graphics, ClientRectangle, Me)
        End If

        Dim cr As Rectangle = ClientRectangle
        Dim face As New Rectangle(-1, -1, cr.Width + 2, cr.Height + 2)
        Dim buttonWidth As Integer = SystemInformation.HorizontalScrollBarArrowWidth
        Dim buttonRect As New Rectangle(cr.Right - buttonWidth - 1, cr.Top, buttonWidth, cr.Height)
        Dim buttonFace As New Rectangle(buttonRect.X + 1, 0, buttonRect.Width - 2, buttonRect.Height - 2)

        ButtonRenderer.DrawButton(e.Graphics, face, VisualStyles.PushButtonState.Hot)
        vsRenderer.SetParameters(dropdownButtonElement.ClassName,
                                 dropdownButtonElement.Part,
                                 CBXSR_HOT)
        vsRenderer.DrawBackground(e.Graphics, buttonRect, buttonFace)
        TextRenderer.DrawText(e.Graphics, Text, Font, cr, ForeColor,
                              TextFormatFlags.Left Or TextFormatFlags.VerticalCenter)
    End Sub

End Class

使い方

Public Class Form1

    Public Sub New()
        InitializeComponent()

        Dim cbo As New ComboBoxEx
        cbo.Size = New Size(100, 20)
        cbo.Items.AddRange(New Object() {"AAA", "BBB", "CCC"})
        cbo.ForeColor = Color.Red
        cbo.DropDownStyle = ComboBoxStyle.DropDownList
        Controls.Add(cbo)
    End Sub

End Class

とまぁ、ここまで書いたんですが、たいていは面倒なのでやめます。とか無応答になっちゃうんですよね(^_^;)

引用返信 編集キー/
■100555 / inTopicNo.8)  Re[2]: コンボボックスの文字色を変更する方法
□投稿者/ wani (4回)-(2022/09/12(Mon) 22:02:13)
>>■No100551 (KOZ さん) に返信

ありがとうございます。

素晴らしいです。

いいところまでは来ています。

後は、

1.ホイールした時にアイテムを変更する
2.アイテム毎に、文字色を変更する
3.マウスがコンボボックス上にない場合には外観を通常のものにする

の三種だと思います。

3.はMouseEnterとMouseLeaveを使えば良いのでしょうか?
1.や2.はどのメソッドを使えば良いでしょうか?

引用返信 編集キー/
■100556 / inTopicNo.9)  Re[3]: コンボボックスの文字色を変更する方法
□投稿者/ KOZ (318回)-(2022/09/12(Mon) 23:00:17)
2022/09/12(Mon) 23:34:09 編集(投稿者)
No100555 (wani さん) に返信
> 1.ホイールした時にアイテムを変更する

OnMouseWheel メソッドを使って変更してください。
e.Delta で上下を判定します。

> 2.アイテム毎に、文字色を変更する

TextRenderer.DrawText の ForeColor を変更してください。
リスト部分は、DOBON さんのコードを流用すれば良いですね。

> 3.マウスがコンボボックス上にない場合には外観を通常のものにする

.NET のソースコードをあさっているときに目にしたロジックを紹介します。

    Private _MouseIsOver As Boolean = False
    Private _MouseIsDown As Boolean = False

    Protected Property MouseIsOver As Boolean
        Get
            Return _MouseIsOver
        End Get
        Set(value As Boolean)
            If _MouseIsOver <> value Then
                _MouseIsOver = value
                Invalidate()
            End If
        End Set
    End Property

    Protected Property MouseIsDown As Boolean
        Get
            Return _MouseIsDown
        End Get
        Set(value As Boolean)
            If _MouseIsDown <> value Then
                _MouseIsDown = value
                Invalidate()
            End If
        End Set
    End Property

    Protected Overrides Sub OnMouseCaptureChanged(e As EventArgs)
        MyBase.OnMouseCaptureChanged(e)
        MouseIsOver = False
        MouseIsDown = False
    End Sub

    Protected Overrides Sub OnMouseLeave(e As EventArgs)
        MyBase.OnMouseLeave(e)
        MouseIsOver = False
    End Sub

    Protected Overrides Sub OnMouseHover(e As EventArgs)
        MyBase.OnMouseHover(e)
        MouseIsOver = True
    End Sub

    Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
        MyBase.OnMouseDown(e)
        MouseIsDown = True
    End Sub

    Protected Overrides Sub OnMouseUp(e As MouseEventArgs)
        MyBase.OnMouseUp(e)
        MouseIsDown = False
    End Sub

OnPaint で MouseIsOver/MouseIsDown プロパティ、標準の Enabled/DroppedDown プロパティを参照して判定できます。

引用返信 編集キー/
■100557 / inTopicNo.10)  Re[4]: コンボボックスの文字色を変更する方法
□投稿者/ wani (5回)-(2022/09/13(Tue) 11:43:49)
ありがとうございます。


        If MouseIsOver = True Then

            ButtonRenderer.DrawButton(e.Graphics, face, VisualStyles.PushButtonState.Hot)

        ElseIf MouseIsDown = True Then

            ButtonRenderer.DrawButton(e.Graphics, face, VisualStyles.PushButtonState.Pressed)

        Else

            ButtonRenderer.DrawButton(e.Graphics, face, VisualStyles.PushButtonState.Normal)

        End If


こんな感じでしょうか?

何となくはできているのですが、
普通のコンボボックスだとマウスホバーしてすぐに外観が変化するのですが、
このカスタムクラスだとなぜか1秒くらい遅延してから外観が変化します。
なぜでしょうか?

また、コンボボックスの右端にある三角形みたいなマークの上は
マウスをホバーしていなくとも常にHotの状態なのですが
どこかで設定する必要がありますでしょうか?

引用返信 編集キー/
■100558 / inTopicNo.11)  Re[5]: コンボボックスの文字色を変更する方法
□投稿者/ KOZ (319回)-(2022/09/13(Tue) 15:03:12)
No100557 (wani さん) に返信
> こんな感じでしょうか?

操作して違和感がないのであればいいんじゃないでしょうか。

> 普通のコンボボックスだとマウスホバーしてすぐに外観が変化するのですが、
> このカスタムクラスだとなぜか1秒くらい遅延してから外観が変化します。

ちょっと違います。
普通のコンボボックスではマウスがコントロールに侵入すると徐々に明るくなっていきますが、
このクラスでは、しばらくしてからスパッと外観が変わります。
その動きを再現するのであれば、ご自分で研究なさってください。

> また、コンボボックスの右端にある三角形みたいなマークの上は
> マウスをホバーしていなくとも常にHotの状態なのですが
> どこかで設定する必要がありますでしょうか?

vsRenderer.SetParameters の3つめの引数(CBXSR_HOT)の部分を変更してください。

引用返信 編集キー/
■100559 / inTopicNo.12)  Re[6]: コンボボックスの文字色を変更する方法
□投稿者/ KOZ (320回)-(2022/09/13(Tue) 16:30:02)
No100558 (KOZ) に返信
> ちょっと違います。
> 普通のコンボボックスではマウスがコントロールに侵入すると徐々に明るくなっていきますが、
> このクラスでは、しばらくしてからスパッと外観が変わります。
> その動きを再現するのであれば、ご自分で研究なさってください。

BeginBufferedAnimation 等の API を使うようです。
.NET には部品が用意されていないようなので、頑張って再現してみてください。

https://www.pg-fl.jp/program/tips/ownanim.htm

引用返信 編集キー/
■100562 / inTopicNo.13)  Re[7]: コンボボックスの文字色を変更する方法
□投稿者/ KOZ (321回)-(2022/09/18(Sun) 11:25:37)
No100559 (KOZ) に返信
> BeginBufferedAnimation 等の API を使うようです。
> .NET には部品が用意されていないようなので、頑張って再現してみてください。

再現してみましたが、長くなって投稿できなくなったので、以下参照。

https://github.com/KOZ60/Samples/tree/master/NET/ForeColorComboBox/ForeColorComboBox
引用返信 編集キー/
■100563 / inTopicNo.14)  Re[8]: コンボボックスの文字色を変更する方法
□投稿者/ wani (6回)-(2022/09/18(Sun) 23:17:37)
No100562 (KOZ さん) に返信

ありがとうございます。

ホイールは動作するようになったことを確認できました。

しかし、なぜか私の環境ではマウスをホバーした時に
外観が変わるのはBeginBufferedAnimationを使わなかった時と同じく
タイムラグが発生します。

もしかして、どこかの設定を変更する必要がありますか?

関係ないかも知れませんが、
.NET Framework4.5.2に変更して使用しています。


あと、項目毎に色を変更する方法もご提示いただけると助かります。

引用返信 編集キー/
■100564 / inTopicNo.15)  Re[9]: コンボボックスの文字色を変更する方法
□投稿者/ KOZ (322回)-(2022/09/19(Mon) 04:11:59)
2022/09/19(Mon) 04:25:26 編集(投稿者)

No100563 (wani さん) に返信
> ホイールは動作するようになったことを確認できました。

ホイールに対応するようなコードは書いてません。

> しかし、なぜか私の環境ではマウスをホバーした時に
> 外観が変わるのはBeginBufferedAnimationを使わなかった時と同じく
> タイムラグが発生します。
> もしかして、どこかの設定を変更する必要がありますか?

よくわかりません。
もしかして github のコードの一部をコピペして利用しているんでしょうか?

> あと、項目毎に色を変更する方法もご提示いただけると助かります。

DrawItem イベントで何かやっているんだと思いますが、
OnDrawItem をオーバーライドし、その処理を書いてください。


引用返信 編集キー/
■100565 / inTopicNo.16)  Re[10]: コンボボックスの文字色を変更する方法
□投稿者/ wani (7回)-(2022/09/19(Mon) 10:41:43)
No100564 (KOZ さん) に返信

> よくわかりません。
もしかして github のコードの一部をコピペして利用しているんでしょうか?

いえ、コードを丸ごとダウンロードして使用しております。


> OnDrawItem をオーバーライドし、その処理を書いてください。

私には難しいため、お手本を見せていただけないでしょうか?

引用返信 編集キー/
■100566 / inTopicNo.17)  Re[11]: コンボボックスの文字色を変更する方法
□投稿者/ KOZ (323回)-(2022/09/19(Mon) 13:28:40)
No100565 (wani さん) に返信

ホイールの話はどうなったんでしょう?

> いえ、コードを丸ごとダウンロードして使用しております。

ちょっと見当がつきません。
Form1.vb に通常の ComboBox と ComboBoxEx が張り付けてありますが、
比較して動きが遅いということでしょうか。

>>OnDrawItem をオーバーライドし、その処理を書いてください。
> 私には難しいため、お手本を見せていただけないでしょうか?

http://dobon.net/vb/dotnet/control/cbownerdraw.html
を参考に実現したのではないですか?
どのようなコードを書いたのでしょうか?
ほぼそのまま使えるはずなのですが。


引用返信 編集キー/
■100575 / inTopicNo.18)  Re[12]: コンボボックスの文字色を変更する方法
□投稿者/ radian (95回)-(2022/09/21(Wed) 10:33:13)
2022/09/21(Wed) 10:57:05 編集(投稿者)

> ■No100565 (wani さん) に返信
>>私には難しいため、お手本を見せていただけないでしょうか?

(意訳)
コントロール描画の基本全然理解してないけど、サンプルコード読むのも勉強するのも面倒だから
お前がコード代わりに全部書いてくれ

自力描画の処理を他人に書いて貰った所で、基本理解してないと
その後の保守出来ないと思うけど大丈夫?
参考にしたWebサイトや、書いて貰ったサンプルコード弄りながら
実際に試行錯誤してみて、試してみた結果何がおかしいか、
何が判らなくて先に進めないかを書きましょう。
難しい、だけで何も試していないなら、質問ではなく只の作業の丸投げです。
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ