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

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

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

Re[17]: タブコントロールのタブの文字色"だけ"を変えたい


(過去ログ 179 を表示中)

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

■102507 / inTopicNo.1)  タブコントロールのタブの文字色"だけ"を変えたい
  
□投稿者/ カルミーア (1回)-(2023/11/10(Fri) 12:16:11)

分類:[VB.NET/VB2005 以降] 

初めまして。宜しく御願い致します。

環境は Visual Studio Professional 2015
    Visual Basic 2015
です。

タブコントロールの特定タブの耳の文字だけを太字赤色にしたいと考えています。
背景色はもとのままです。
そこで、以下のコードを書きました。

初期設定(ロード時)
TabControl1.DrawMode = TabDrawMode.OwnerDrawFixed

イベントハンドラ
Private Sub TabControl1_DrawItem(ByVal sender As Object, _
ByVal e As DrawItemEventArgs) _
Handles TabControl1.DrawItem
'対象のTabControlを取得
Dim tab As TabControl = CType(sender, TabControl)
'タブページのテキストを取得
Dim txt As String = tab.TabPages(e.Index).Text

'タブのテキストのブラシとフォントを決定する
Dim foreBsh As Brush
Dim foreFnt As Font
'4番目のタブの耳の文字だけ太字赤色にする
If e.Index = 3 Then
foreBsh = Brushes.Red
foreFnt = New Font("Red", 10, FontStyle.Bold)
Else
foreBsh = Brushes.Black
foreFnt = New Font("Black", 10, FontStyle.Regular)
End If

'StringFormatを作成
Dim sfmt As New StringFormat
sfmt.Alignment = StringAlignment.Center
sfmt.LineAlignment = StringAlignment.Center

'タブ耳の文字の描画
e.Graphics.DrawString(TabControl1.TabPages(e.Index).Text, foreFnt , foreBsh , RectangleF.op_Implicit(e.Bounds), sfmt )
End Sub

このようなコードで確かに文字が太字赤色に変わったのですが、背景がフォームの色に隠れて全てのタブの耳が正常に描画されなくなりました。
タブの耳の背景色は元のまま(グレーのグラデーション)で、一切変えたくないのですが、設定していない(つもり)にもかかわらず勝手に変更されています。

どのようにしたら背景色はデフォルトのままになるのか、御存じの方は御教示お願い致します。

参考【https://dobon.net/vb/dotnet/control/tabownerdraw.html
  【https://teratail.com/questions/194322

引用返信 編集キー/
■102508 / inTopicNo.2)  Re[1]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ KOZ (420回)-(2023/11/10(Fri) 12:39:26)
No102507 (カルミーア さん) に返信
> どのようにしたら背景色はデフォルトのままになるのか、御存じの方は御教示お願い致します。

TabControlを自分でビジュアルスタイルで描画する
https://dobon.net/vb/dotnet/control/tabsidebug.html#paint

が参考になると思います。
引用返信 編集キー/
■102510 / inTopicNo.3)  Re[2]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ KOZ (421回)-(2023/11/10(Fri) 13:40:08)
2023/11/10(Fri) 14:30:53 編集(投稿者)
No102508 (KOZ) に返信

面倒なら TabPage 実際の文字列は Tag プロパティに保存しておいて、Text プロパティはスペースで埋めておいて文字列のみ描画すればいいかも。

Public Class CustomTabControl
    Inherits TabControl

    Public Sub New()
        DoubleBuffered = True
        SetStyle(ControlStyles.UserPaint, False)
    End Sub

    Const WM_PAINT = &HF

    Protected Overrides Sub WndProc(ByRef m As Message)
        Select Case m.Msg
            Case WM_PAINT
                SetStyle(ControlStyles.UserPaint, True)
                MyBase.WndProc(m)
                SetStyle(ControlStyles.UserPaint, False)
            Case Else
                MyBase.WndProc(m)
        End Select
    End Sub

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        Dim hdc = e.Graphics.GetHdc()
        Dim m = Message.Create(Handle, WM_PAINT, hdc, IntPtr.Zero)
        DefWndProc(m)
        e.Graphics.ReleaseHdc()

        ' ここで文字を書く

        MyBase.OnPaint(e)
    End Sub
End Class

引用返信 編集キー/
■102514 / inTopicNo.4)  Re[3]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ カルミーア (2回)-(2023/11/10(Fri) 16:16:14)
No102508 (KOZ さん) に返信

時間を割いて御回答を頂きまして誠にありがとう御座いました。


> ■No102507 (カルミーア さん) に返信
>>どのようにしたら背景色はデフォルトのままになるのか、御存じの方は御教示お願い致します。
>
> TabControlを自分でビジュアルスタイルで描画する
> https://dobon.net/vb/dotnet/control/tabsidebug.html#paint
>
> が参考になると思います。

こちらせっかく御紹介頂き申し訳ないですが、面倒というよりも目的と剥離しているような気がしました。
タブの回転などは全く不要で、必要な部分が何なのかがよくわからない状況です。
加えてこちらのサンプルは色をべた塗しておりますが、私が求めるものはデフォルトと同じグレーのグラデーション色です。
グレーのグラデーション色に設定しているものをご提示頂けると大変ありがたいです。

>
> 面倒なら TabPage 実際の文字列は Tag プロパティに保存しておいて、Text プロパティはスペースで埋めておいて文字列のみ描画すればいいかも。
>

ソースコードを提示してくださってありがとうございます。
ただ、私の要求が正直こんなに手の込んだものになるとは思わず、かなり難航しています。
特に

>
> ' ここで文字を書く
>

の部分も文字の書き方については、いろいろ設定しないといけない所や(ご提示くださったサイトのボトムのTEXT描画の箇所ですよね)
ビットマップ形式のファイルが必要?みたいですが、そうなってくると開発陣や顧客に相談しないといけなくなります。
自分としては背景は何ら変わらないという事でもっと手軽にできるかと思っていたのですが、描画の部分を社内で詰める必要があります。
限られた工数制限もあり、この件はちょっと相談の為に保留とすることに致します。

お手数おかけしてすみません。
どうも色々御教示頂きありがとう御座いました。
引用返信 編集キー/
■102517 / inTopicNo.5)  Re[4]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ KOZ (423回)-(2023/11/10(Fri) 17:52:46)
No102514 (カルミーア さん) に返信

>>TabControlを自分でビジュアルスタイルで描画する
>>https://dobon.net/vb/dotnet/control/tabsidebug.html#paint
>>が参考になると思います。
> こちらせっかく御紹介頂き申し訳ないですが、面倒というよりも目的と剥離しているような気がしました。
> タブの回転などは全く不要で、必要な部分が何なのかがよくわからない状況です。

コピペして文字を描いているところだけ修正すればいいんですが・・・

> 加えてこちらのサンプルは色をべた塗しておりますが、私が求めるものはデフォルトと同じグレーのグラデーション色です。
> グレーのグラデーション色に設定しているものをご提示頂けると大変ありがたいです。

コピペして実行してみました?

>>面倒なら TabPage 実際の文字列は Tag プロパティに保存しておいて、Text プロパティはスペースで埋めておいて文字列のみ描画すればいいかも。
> ソースコードを提示してくださってありがとうございます。
> ただ、私の要求が正直こんなに手の込んだものになるとは思わず、かなり難航しています。
> ビットマップ形式のファイルが必要?みたいですが、そうなってくると開発陣や顧客に相談しないといけなくなります。

ファイルは不要です。耳の位置は上固定でいいなら簡単です。
TabPage の Tag プロパティに表示する文字、Text プロパティには相応の空白を設定してください。

Public Class CustomTabControl
    Inherits TabControl

    Public Sub New()
        DoubleBuffered = True
        ResizeRedraw = True
        SetStyle(ControlStyles.UserPaint, False)
    End Sub

    Const WM_PAINT = &HF

    Protected Overrides Sub WndProc(ByRef m As Message)
        Select Case m.Msg
            Case WM_PAINT
                SetStyle(ControlStyles.UserPaint, True)
                MyBase.WndProc(m)
                SetStyle(ControlStyles.UserPaint, False)
            Case Else
                MyBase.WndProc(m)
        End Select
    End Sub

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        Dim hdc = e.Graphics.GetHdc()
        Dim m = Message.Create(Handle, WM_PAINT, hdc, IntPtr.Zero)
        DefWndProc(m)
        e.Graphics.ReleaseHdc()
        For i As Integer = 0 To TabPages.Count - 1
            Dim page As TabPage = TabPages(i)
            Dim rect As Rectangle = GetTabRect(i)
            Dim tabColor As Color
            Dim tabFont As Font
            Dim needDispose As Boolean = False
            If i = SelectedIndex Then
                tabColor = Color.Red
                tabFont = New Font(Font.FontFamily, Font.Size, FontStyle.Bold)
                needDispose = True
            Else
                tabColor = ForeColor
                tabFont = Font
            End If
            TextRenderer.DrawText(e.Graphics, CStr(page.Tag),
                                  tabFont, rect, tabColor,
                                  TextFormatFlags.HorizontalCenter Or TextFormatFlags.VerticalCenter)
            If needDispose Then
                tabFont.Dispose()
            End If
        Next
        MyBase.OnPaint(e)
    End Sub

End Class


引用返信 編集キー/
■102519 / inTopicNo.6)  Re[5]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ カルミーア (3回)-(2023/11/11(Sat) 11:41:47)
2023/11/11(Sat) 12:02:24 編集(投稿者)

No102517 (KOZ さん) に返信


私の悩みを気にかけてくださってありがとう御座います。

>
> コピペして文字を描いているところだけ修正すればいいんですが・・・
>

すみません、今は試せないのですが試したときに報告します。

>
> コピペして実行してみました?
>

一応試してみまして、始め「Strict がONの場合はどうちゃらこうちゃら〜〜」
が出てまして、上記を直している間に「ここで文字を書く」の部分のリンク先のサイトの【'Bottomの時はTextを描画する】
の箇所で「あれ、ビットマップが必要か?」って気づき、そこからは実行していませんでした。

>
> ファイルは不要です。耳の位置は上固定でいいなら簡単です。
> TabPage の Tag プロパティに表示する文字、Text プロパティには相応の空白を設定してください。
>

次の機会に新しく記載下さったコードをぜひ試したいと思います。
ご丁寧な対応ありがとう御座います。
引用返信 編集キー/
■102520 / inTopicNo.7)  Re[6]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ KOZ (424回)-(2023/11/11(Sat) 12:17:43)
No102519 (カルミーア さん) に返信
>>コピペして実行してみました?
> 一応試してみまして、始め「Strict がONの場合はどうちゃらこうちゃら〜〜」
> が出てまして、上記を直している間に「ここで文字を書く」の部分のリンク先のサイトの【'Bottomの時はTextを描画する】
> の箇所で「あれ、ビットマップが必要か?」って気づき、そこからは実行していませんでした。

実行したわけではないんですね。

>> 加えてこちらのサンプルは色をべた塗しておりますが、私が求めるものはデフォルトと同じグレーのグラデーション色です。
>> グレーのグラデーション色に設定しているものをご提示頂けると大変ありがたいです。

手元には Windows 10 しかなく、フラットに描画されてしまうので確認できないんですが、
紹介したサンプルはテーマを使って描画しているのでべた塗りにはならないはずです。
引用返信 編集キー/
■102538 / inTopicNo.8)  Re[7]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ カルミーア (4回)-(2023/11/15(Wed) 00:18:16)
2023/11/15(Wed) 01:16:19 編集(投稿者)

No102520 (KOZ さん) に返信

お待たせしました。
色々とありがとう御座います。

>
> 実行したわけではないんですね。
>

>
> 手元には Windows 10 しかなく、フラットに描画されてしまうので確認できないんですが、
> 紹介したサンプルはテーマを使って描画しているのでべた塗りにはならないはずです。

すみません、結論として上記は設計の検討により廃案(タブの文字の色を変えない)という事でまとまりました。
今までご助言いただきましたがこのような結果になり、誠にお騒がせしました。

文字の色は簡単に変わりはしましたが背景が変わってしまうという事で、私も設計のメンバー(や顧客先)も
背景はそのままでいいので、コードを2〜3行追加して、タブのプロパティを何か変えれば解決するのではないかと読んでいましたが
ここまで手が込んだものになると、たかが文字色を変えるだけなのに工数もステップ数も膨れ上がって割に合わないと判断しての事でした。

なお、実際に手を入れることはなくなりましたが、気になるのでプライベートで新しくフォームを生成して試してみたところ、耳の文字自体が出ませんでした。
プロパティの箇所でTEXTを省いてTAGに移せばいいだけですよね。。。?

引用返信 編集キー/
■102539 / inTopicNo.9)  Re[8]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ 魔界の仮面弁士 (3709回)-(2023/11/15(Wed) 00:42:38)
No102538 (カルミーア さん) に返信
> なお、実際に手を入れることはなくなりましたが、気になるのでプライベートで新しくフォームを生成して試してみたところ、耳の文字自体が出ませんでした。
> プロパティの箇所でTEXTを省いてTAGに移せばいいだけですよね。。。?

デザイン時と実行時のいずれも表示されませんか?

(1) CustomTabControl1.Tag ではなく、その中の TabPage1.Tag にセットしていますか?

(2) デザイン時は、先に Tag プロパティに文字をセットしてから Text プロパティに空白を入れてみてください。
 Text プロパティには変更通知があるものの、Tag プロパティには変更通知機構が無いため、
 後から Tag だけを編集しても、ただちに画面に反映されないためです。
 もしも実行時にプログラムから Tag を書き換える場合は、Tag を編集した直後に
 Invalidate メソッドを呼び出して、再描画を促すようにします。

 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
  TabPage2.Tag = "新しい見出し"
  CustomTabControl1.Invalidate()
 End Sub
引用返信 編集キー/
■102540 / inTopicNo.10)  Re[8]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ KOZ (428回)-(2023/11/15(Wed) 09:54:22)
No102538 (カルミーア さん) に返信
> 文字の色は簡単に変わりはしましたが背景が変わってしまうという事で、私も設計のメンバー(や顧客先)も

私が紹介したサンプルを動かしたうえで背景が変わるという結論になったということですか?
そうであるならば、Windows 7 のころ、これを参考にコンポーネントを作っており、対処法を考えなくてはならないので教えていただきたいんですが・・・

> なお、実際に手を入れることはなくなりましたが、気になるのでプライベートで新しくフォームを生成して試してみたところ、耳の文字自体が出ませんでした。
> プロパティの箇所でTEXTを省いてTAGに移せばいいだけですよね。。。?

この辺は弁士さんのレスを参考にしてください。
デザイン時でもタブをきりかえれば出てくるんですけどね。
引用返信 編集キー/
■102547 / inTopicNo.11)  Re[9]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ カルミーア (5回)-(2023/11/16(Thu) 01:52:21)
2023/11/16(Thu) 03:35:01 編集(投稿者)

No102539 (魔界の仮面弁士 さん) に返信

ご協力頂きましてありがとう御座います。


> デザイン時と実行時のいずれも表示されませんか?
>

デザインはTEXTが空白なので、表示はされないですね。
実行時も同じでした。

> (1) CustomTabControl1.Tag ではなく、その中の TabPage1.Tag にセットしていますか?
>

タブコントロールではないと思います。
タブコントロールは1つしかないですので、全部のタブ耳の文字列は入れられない筈ですので。

> (2) デザイン時は、先に Tag プロパティに文字をセットしてから Text プロパティに空白を入れてみてください。
>  Text プロパティには変更通知があるものの、Tag プロパティには変更通知機構が無いため、
>  後から Tag だけを編集しても、ただちに画面に反映されないためです。
>  もしも実行時にプログラムから Tag を書き換える場合は、Tag を編集した直後に
>  Invalidate メソッドを呼び出して、再描画を促すようにします。

事情で本日は試せませんでしたので、後日試させて頂きます。ありがとう御座いました。
引用返信 編集キー/
■102548 / inTopicNo.12)  Re[9]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ カルミーア (6回)-(2023/11/16(Thu) 02:01:21)
No102540 (KOZ さん) に返信

返信ありがとう御座います。

>>文字の色は簡単に変わりはしましたが背景が変わってしまうという事で、私も設計のメンバー(や顧客先)も
>
> 私が紹介したサンプルを動かしたうえで背景が変わるという結論になったということですか?
> そうであるならば、Windows 7 のころ、これを参考にコンポーネントを作っており、対処法を考えなくてはならないので教えていただきたいんですが・・・

時系列にお話ししますと、KOZ様の1回目の投稿の通りやっても上手くいかず
ビットマップどうこうの所で職場に相談したという次第です。
KOZ様の2回目のソースの投稿を試す前に廃案になったという結果ですので、私が間違えずにやってできなかったという事ではないです。
おそらくできると思っていますが、それ程の労力がかかるならば文字色は変えなくていいと言う結論です。
開発では他にも色々課題はありますので、そちらの製造を優先となりました。(課題が終わって余裕が出来たら再度提案の可能性は有り)

>>なお、実際に手を入れることはなくなりましたが、気になるのでプライベートで新しくフォームを生成して試してみたところ、耳の文字自体が出ませんでした。
>>プロパティの箇所でTEXTを省いてTAGに移せばいいだけですよね。。。?
>
> この辺は弁士さんのレスを参考にしてください。
> デザイン時でもタブをきりかえれば出てくるんですけどね。

ありがとう御座います。おそらく私が間違えていると思っていますが、都合で本日は試せませんでした。
後日結果を報告致します。
引用返信 編集キー/
■102568 / inTopicNo.13)  Re[9]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ カルミーア (7回)-(2023/11/19(Sun) 01:13:39)
No102540 (KOZ さん) に返信
No102539 (魔界の仮面弁士 さん) に返信

お待たせしました。実行結果は残念ながらうまくいきませんでした。
(1) デザインの時点で文字列が表示されていない(TEXTを空白にしているため)
(2) 実行しても文字列は空白のままです。色以前に表示がされておりません
(3) ブレイクをWndProcやOnPaintに設置したが。止まってくれていない(何が間違っているか謎)
※示して頂いたソースコードはコピペしましたが、すべての行は理解していません

ここで、開発環境を調べてみたのですが、OSはWINDOWS 7 Ultimate SP1
であることが分かりました。
もしかしてこのOSだと実現できない可能性もあります。(後出しですみません)
フレームワークは4.8で試しました。

それから感じたことは、自分が最初に提示させて戴いたリンク先
https://dobon.net/vb/dotnet/control/tabownerdraw.html
を、ひょっとしたら1行変えるだけでうまくいくのではないかと思うのですが、如何でしょうか。
コードの以下の部分
*****
'タブのテキストと背景を描画するためのブラシを決定する
Dim foreBrush, backBrush As Brush
If (e.State And DrawItemState.Selected) = DrawItemState.Selected Then
'選択されているタブのテキストを赤、背景を青とする
foreBrush = Brushes.Red
backBrush = Brushes.Blue '←これをデフォルト同じ白に変更する(White)
Else
'選択されていないタブのテキストは灰色、背景を白とする
foreBrush = Brushes.Gray
backBrush = Brushes.White '←これをデフォルト同じグレーのグラデーションに変更する(???)
End If
*****
最初はバックを変えたくないのでバックブラシは設定していませんでしたが、
この?の部分さえわかれば変更箇所は1行で済むと思うのですがどうでしょうか。
もしかしてグラデーションのブラシの値って設定することができないのでしょうか...?

何度もお聞きして大変お手数お掛け致します。宜しく御願いします。
引用返信 編集キー/
■102573 / inTopicNo.14)  Re[10]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ 魔界の仮面弁士 (3714回)-(2023/11/19(Sun) 02:58:23)
No102568 (カルミーア さん) に返信
> お待たせしました。実行結果は残念ながらうまくいきませんでした。
No102510 / No102517 のコードのことですよね。


> (2) 実行しても文字列は空白のままです。色以前に表示がされておりません
(確認1)
DrawMode プロパティは、(OwnerDrawFixed モードではなく) Normal のままになっているでしょうか。


> (3)ブレイクをWndProcやOnPaintに設置したが。止まってくれていない(何が間違っているか謎)
> ※示して頂いたソースコードはコピペしましたが、すべての行は理解していません
(確認2)
Class CustomTabControl の WndProc や OnPaint ではなく、誤って
Class Form1 の WndProc や OnPaint にブレークポイントを貼っていないでしょうか。

(確認3)
Form 上に貼ってあるコントロールの型 (≠コントロールの名前)が、
KOZ さんの CustomTabControl ではなく、TabControl のままになっていないでしょうか。


> 開発環境を調べてみたのですが、OSはWINDOWS 7 Ultimate SP1
> であることが分かりました。
今回、そこは関係ないですね。
OS が XP でも Vista でも 7 でも、OnPaint は発生するはず。


もう一度、手順を確認させてください。
動作確認のため、既存プロジェクトではなく、新規プロジェクトで動作を確認します。

(1) 新規プロジェクトを作成した後、新しく CustomTabControl.vb というファイルを追加し、
 そこに No102517 のコードをそのまま貼り付ける。

(2) そのままビルドすると、ツールボックスに CustomTabControl が追加されるので
 それを Form1 に貼り付ける。コントロール名は既定の CustomTabControl1 のままで OK。

(3) 複数のタブそれぞれの Text に空白文字を入れてタブ幅を決めてから、
 それぞれのタブの Tag に文字列をセットする。

(4) アクティブなタブのみ、文字色が赤になれば成功。


> backBrush = Brushes.Blue '←これをデフォルト同じ白に変更する(White)
デフォルト色が白とは限りません。
スタイルは実行環境によって異なっており、単色なこともあれば、グラデーションがかかることもありえます。
https://atmarkit.itmedia.co.jp/fdotnet/dotnettips/234winxpstyle/winxpstyle.html

> backBrush = Brushes.White '←これをデフォルト同じグレーのグラデーションに変更する(???)
OS が用意した既定のスタイルで描画するための物が、先に紹介されていた TabRenderer ですね。
ただ、大仰になりすぎるので今回は採用しにくいかと。
https://dobon.net/vb/dotnet/graphics/drawvisualcontrol.html

既定のグラデーションに拘らないのであれば、 LinearGradientBrush や PathGradientBrush を使うことはできます。
https://dobon.net/vb/dotnet/graphics/lineargradientbrush.html

> この?の部分さえわかれば変更箇所は1行で済むと思うのですがどうでしょうか。
少なくとも 1 行では無理でしょう。たとえば LinearGradientBrush を使う場合、
標準の Brushes.何某 と違って「自分で新たに作成したリソース」なので、
利用後には Using なり Dispose なりで処分する義務が生じます。

背景はそのままで文字だけを差し替えるというのであれば、
コントロールを作成する側としては、 No102517 の方が、実装としては単純かと思います。
その分、コントロールを利用する側の手間が少し増えますけれどね(Text に空白をセットするなど)。
引用返信 編集キー/
■102580 / inTopicNo.15)  Re[11]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ カルミーア (8回)-(2023/11/20(Mon) 01:20:26)
No102573 (魔界の仮面弁士 さん) に返信

何度もお教え下さり、ありがとう御座います。

> もう一度、手順を確認させてください。
> 動作確認のため、既存プロジェクトではなく、新規プロジェクトで動作を確認します。

手順を丁寧に示してくださり有難いです。
後日試せるときに試したいと思います。助かります。

> 背景はそのままで文字だけを差し替えるというのであれば、
> コントロールを作成する側としては、 No102517 の方が、実装としては単純かと思います。

承知しました。
それでは仰る通り、KOZ様の御提示されたコードを中心に組み込むように致します。
引用返信 編集キー/
■102597 / inTopicNo.16)  Re[11]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ カルミーア (9回)-(2023/11/24(Fri) 01:36:10)
No102540 (KOZ さん) に返信
No102573 (魔界の仮面弁士 さん) に返信

だいぶ遅くなりました。
ようやく祭日に少し試してみました

再びまっさらな状態から、お示し下さった手順通りにやったらうまくいきました。
どうもありがとう御座います。
それまでできなかった要因としては、既存の作成済みのタブコントロールを無理くりカスタムに変更しようとしていたのが原因のようです。
ありがとう御座いました。

ただ懸念点は、いまからその納品用の本番で用いるタブコントロールからカスタムコントロールへの差し替えの手間が出てくるところですね
サイズや位置など、果たしてすべての部品をコピペしてうまくいくのかどうかというところが課題だと思います。
その辺、現場で相談してみます。

重ね重ねKOZ様と魔界の仮面弁士様に感謝の意を申し上げます。
(※特に御意見がないようでしたら週末に解決済みに致します)
引用返信 編集キー/
■102603 / inTopicNo.17)  Re[12]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ 魔界の仮面弁士 (3717回)-(2023/11/24(Fri) 15:17:02)
No102597 (カルミーア さん) に返信
> ようやく祭日に少し試してみました
祭日ではなく、祝日ですよね?


> それまでできなかった要因としては、既存の作成済みのタブコントロールを無理くりカスタムに変更しようとしていたのが原因のようです。
> ありがとう御座いました。
何も描画されなかったのなら、OwnerDrawFixed モードに設定されていた可能性が最も高いです。


> サイズや位置など、果たしてすべての部品をコピペしてうまくいくのかどうかというところが課題だと思います。
> その辺、現場で相談してみます。
Text を Tag で置き換える実装になっているので、少し手直しは必要ですね。

実行時に「If TabControl1.SelectedTab.Text = "カルミーア" Then」のような処理があった場合、
「If TryCast(TabControl1.SelectedTab.Tag, String) = "カルミーア" Then」などとする必要がありますし、
また、既存タブを空白文字で補っているので、プロポーショナル フォントの場合は
TabPage にセットする空白文字数について調整が必要かもしれません。

一方 TabControl 側に関しては、デザイナーで編集するよりも、
デザイン時コードを直接書き換えた方が手っ取り早いかと思います。

具体的には、フォーム名.designer.vb ファイルを編集して、
"System.Windows.Forms.TabControl" や "TabControl" と書かれた 型名を
"CustomTabControl" に置き換えていく、という感じで。
引用返信 編集キー/
■102604 / inTopicNo.18)  Re[12]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ KOZ (430回)-(2023/11/24(Fri) 18:26:04)
2023/11/25(Sat) 01:05:12 編集(投稿者)
No102597 (カルミーア さん) に返信

※ 弁士さんの報告を元に修正しています。

Tab プロパティ使わないバージョンを作ってみました。
テキストをセットする際、TCITEM.pszText を同等幅のスペースに置き換えます。
Image は考慮していませんので、使っている場合は描画位置を調整してください。

Option Strict On
Imports System.Runtime.InteropServices

Public Class CustomTabControl
    Inherits TabControl

    Public Sub New()
        DoubleBuffered = True
        ResizeRedraw = True
        SetStyle(ControlStyles.UserPaint, False)
    End Sub

    Protected Overrides Sub WndProc(ByRef m As Message)
        Select Case m.Msg
            Case WM_PAINT
                SetStyle(ControlStyles.UserPaint, True)
                MyBase.WndProc(m)
                SetStyle(ControlStyles.UserPaint, False)
            Case TCM_SETITEMA, TCM_SETITEMW
                ReplaceTcItem(m)
            Case TCM_INSERTITEMA, TCM_INSERTITEMW
                ReplaceTcItem(m)
            Case Else
                MyBase.WndProc(m)
        End Select
    End Sub

    Private Sub ReplaceTcItem(ByRef m As Message)
        Dim item As TCITEM = Marshal.PtrToStructure(Of TCITEM)(m.LParam)
        Dim adSpace As String = AdjustSpace(item.pszText)
        item.pszText = Marshal.StringToCoTaskMemAuto(adSpace)
        item.cchTextMax = adSpace.Length
        Dim lParam As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(item))
        Try
            Marshal.StructureToPtr(item, lParam, False)
            Dim newMessage As Message = Message.Create(m.HWnd, m.Msg, m.WParam, lParam)
            MyBase.DefWndProc(newMessage)
            m.Result = newMessage.Result         '※この行を追加 
        Finally
            Marshal.FreeCoTaskMem(item.pszText)
            Marshal.FreeCoTaskMem(lParam)
        End Try
    End Sub

    Private Function AdjustSpace(pszText As IntPtr) As String
        Using g As Graphics = CreateGraphics()
            Dim prevText As String = Marshal.PtrToStringAuto(pszText)
            Dim nLen As Integer = prevText.Length
            Dim nWidth As Integer = TextRenderer.MeasureText(prevText, Font).Width
            Do
                Dim tmpStr As New String(" "c, nLen)
                If TextRenderer.MeasureText(tmpStr, Font).Width >= nWidth Then
                    Return New String(" "c, nLen + 1)
                End If
                nLen += 1
            Loop
        End Using
    End Function

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        Dim hdc As IntPtr = e.Graphics.GetHdc()
        Dim m As Message = Message.Create(Handle, WM_PAINT, hdc, IntPtr.Zero)
        DefWndProc(m)
        e.Graphics.ReleaseHdc()
        For i As Integer = 0 To TabPages.Count - 1
            Dim page As TabPage = TabPages(i)
            Dim rect As Rectangle = GetTabRect(i)
            Dim tabColor As Color
            Dim tabFont As Font
            Dim flags As TextFormatFlags = TextFormatFlags.HorizontalCenter Or TextFormatFlags.VerticalCenter
            Dim needDispose As Boolean = False
            If i = SelectedIndex Then
                tabColor = Color.Red
                tabFont = New Font(Font.FontFamily, Font.Size, FontStyle.Bold)
                needDispose = True
                rect.Y -= 1
            Else
                tabColor = ForeColor
                tabFont = Font
                rect.Y += 1
            End If
            TextRenderer.DrawText(e.Graphics, page.Text,
                                  tabFont, rect, tabColor, flags)
            If needDispose Then
                tabFont.Dispose()
            End If
        Next
        MyBase.OnPaint(e)
    End Sub

    Private Const WM_PAINT As Integer = &HF
    Private Const TCM_FIRST As Integer = &H1300
    Private Const TCM_SETITEMA As Integer = TCM_FIRST + 6
    Private Const TCM_SETITEMW As Integer = TCM_FIRST + 61
    Private Const TCM_INSERTITEMA As Integer = TCM_FIRST + 7
    Private Const TCM_INSERTITEMW As Integer = TCM_FIRST + 62

    <StructLayout(LayoutKind.Sequential)>
    Private Structure TCITEM
        Public mask As Integer
        Public dwState As Integer
        Public dwStateMask As Integer
        Public pszText As IntPtr
        Public cchTextMax As Integer
        Public iImage As Integer
        Public lParam As IntPtr
    End Structure

End Class

引用返信 編集キー/
■102606 / inTopicNo.19)  Re[13]: タブコントロールのタブの文字色"だけ"を変えたい
□投稿者/ 魔界の仮面弁士 (3719回)-(2023/11/24(Fri) 21:41:41)
No102604 (KOZ さん) に返信
> Tab プロパティ使わないバージョンを作ってみました。

おぉ。素晴らしい!

しかし当方環境で試してみたら TabPage を追加したときの動作が何故かおかしいようで。


OnPaint を追ってみると、タブ 3 枚の時点では
 TabPages(0) => 1 枚目のタブを返す
 TabPages(1) => 2 枚目のタブを返す
 TabPages(2) => 3 枚目のタブを返す
が返されていたのに、4 枚目を .TabPages.Add すると、何故か
 TabPages(0) => 4 枚目のタブを返す
 TabPages(1) => 1 枚目のタブを返す
 TabPages(2) => 2 枚目のタブを返す
 TabPages(3) => 3 枚目のタブを返す
という状態になってしまいました。


たとえば、アクティブなタブを【〜】で表すとして。

最初に 3 つのタブがあって、真ん中が選択されている状態にしておいて、
 [ TabPage1 ]【TabPage2】[ TabPage3 ]
この状態で
  TabControl1.TabPages.Add("長い文字列のタブ")
  CustomTabControl1.TabPages.Add("長い文字列のタブ")
を行うと、標準の TabControl は期待通りに
 [ TabPage1 ]【TabPage2】[ TabPage3 ][長い文字列のタブ]
になるのに対し、なぜか CustomTabControl の方は
 [い文字列のタ]【TabPage1】[ TabPage2 ][ TabPage4 ]
になってしまいました。原因は未調査。



>  If i = SelectedIndex Then
>   tabColor = Color.Red
>   tabFont = New Font(Font.FontFamily, Font.Size, FontStyle.Bold)

元質問だと、「選択されたタブの文字色を太字赤色にする」ではなく
「特定タブの耳の文字だけを太字赤色にしたい」なんですよね。


複数(0個以上)のタブを同時に太字赤色にしたいのであれば、
TabControl 側に「太字赤色にしたいタブの番号配列」を持たせておいて、
 <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
 Public ReadOnly Property ColoredTabs As New List(Of Integer)()
赤色判定の部分を
 'If i = SelectedIndex Then
 If ColoredTabs.Contains(i) Then
するとよいかも。
引用返信 編集キー/
■102607 / inTopicNo.20)  Re[14]: タブコントロールのタブの文字色"だけ"を変えたい
 
□投稿者/ KOZ (431回)-(2023/11/24(Fri) 23:38:38)
2023/11/25(Sat) 01:07:46 編集(投稿者)

No102606 (魔界の仮面弁士 さん) に返信

原因がわかったので※を追加しています。

> しかし当方環境で試してみたら TabPage を追加したときの動作が何故かおかしいようで。

あら?なにかおかしいですね。ちょっと見てみます。

※ メッセージを差し替えたとき、Result をちゃんと返してなかったのが原因でした。


> 元質問だと、「選択されたタブの文字色を太字赤色にする」ではなく
> 「特定タブの耳の文字だけを太字赤色にしたい」なんですよね。

おおう、これは勘違いしてました。

引用返信 編集キー/

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -