お世話になります。VB.NETについてお聞きします。
今回初めてTabControlを配置したフォームを作成することになりまして、
メインとなるTabControlにTabPageが3ページあり、その3ページの
それぞれのページにもTabControl(TabPageは2〜3)が配置されている
といった見た目なんですが…その他にも盛り沢山なフォームみたいなので
現在選択中のページを分かりやすくするため "タブの部分" だけを
太字なり…色変更なり…反転表示なり…
なにかしら強調することができないかと思っています。
なにか良い方法はあれば助言いただけないでしょうか?よろしくお願いします。
自分で描画するしか方法がないのかな。
タブに貼り付けるイメージを動的に切り替えるだけで
良いと思われます。
回答ありがとうございます。
回答内容の意味をきちんと理解できなくて大変申し訳ないのですが…
>自分で描画する
や
>タブに貼り付けるイメージを動的に切り替える
は、フォームデザインやコード上でのプロパティ操作とかではなく
何か別の手法なんでしょうか?
質問後にSelectedIndexChangedイベントのタイミングでSelectedTabの
プロパティ(BackColorとかFontとか…)を変えてみたりしてみましたが
TabPage内に対してであって"タブ部分"自体には変化はなく結局見当違い
だったようなので
何か別の手法なのでしょうか?と思った次第です。
>自分で描画する
Graphics オブジェクトを使って自分でお絵描きする。
[VB.NET]では中級者レベルの基本テクニックです。
例えば文字なら↓で。四角の背景色塗りつぶしとかも必要ですね。
[VB.NET]
With Me.TabControl1
Dim wGraphics As System.Drawing.Graphics = Graphics.FromHwnd(.Handle)
Dim wTextBrush As New System.Drawing.SolidBrush(.ForeColor)
Dim wFont As New Font("MS UI Gothic", 9.75D, FontStyle.Bold)
wGraphics.DrawString("あああ", wFont, wTextBrush, 7, 5)
End With
>タブに貼り付けるイメージを動的に切り替える
正確には分からないけど、BackgroundImage だと TabPage の
コンテナ部分だけ変わって、TabControl の耳のところが
変わらないから…微妙に大きさを調整した PictureBox とか
Label を重ねておいてタブの切り替えにあわせて表示・非表示
を切り替えるとかでそれっぽく見える…んー、どうだろう。
>>タブに貼り付けるイメージを動的に切り替える
>は、フォームデザインやコード上でのプロパティ操作とかではなく
>何か別の手法なんでしょうか?
ImageListに画像を登録しておいて、TabPageのImageIndexを
設定するだけかな。
先ほどはちょっと忙しかったので詳しく書けませんでしたが、
ツールボックスの中から、ImageListをドラッグしてFormに
貼り付けます。(実際はFormの下の部分に張り付きます)
貼り付けられたImageListのプロパティの中からImagesコレクション
を選んで、任意の画像ファイルを幾つか登録します。
次にTabContlorのImageListプロパティにImageListの名前をセットします。
続いてイメージを表示したいTabContlor上のTabPageのImageIndexプロパティをクリックすると
登録した画像が幾つか表示されるので、表示したい画像を選択します。
動的に変えたい場合は、
TabControl1.TabPages(1).ImageIndex = 3
の様に変えたいTabPagesのImageIndexをImageListに登録されたImageの
indexにセットすればそのIndexを持つ画像がセットされます。
このへんはTreeViewコントロールやListViewコントロールもみな同じです。
もちろん画像はタブ(耳)の部分だけに表示されます。
特攻隊長まるるうさん、我龍院忠太さん、回答ありがとうございます。
前にこの掲示板を利用させていただいた際にも回答を付けてもらった
記憶がありますが、いつも丁寧な回答恐れ入ります。
現在、アドバイスを参考に色々テストしています。
稚拙なコードで大変恥ずかしいのですが…
>自分で描画する
With Me.TabControl1
Dim wGraphics As System.Drawing.Graphics = Graphics.FromHwnd(.Handle)
Dim wRectBrush As New System.Drawing.SolidBrush(SystemColors.ActiveCaption)
Dim wTextBrush As New System.Drawing.SolidBrush(SystemColors.ActiveCaptionText)
Dim wFont As New Font("MS UI Gothic", 9.75D, FontStyle.Regular)
Dim wRect As System.Drawing.Rectangle
Dim wPoint As System.Drawing.PointF
If .SelectedIndex = 0 Then
wRect = New System.Drawing.Rectangle(4, 4, 58, 13)
wPoint = New System.Drawing.PointF(3, 3)
ElseIf .SelectedIndex = 1 Then
wRect = New System.Drawing.Rectangle(66, 4, 58, 13)
wPoint = New System.Drawing.PointF(65, 3)
ElseIf .SelectedIndex = 2 Then
wRect = New System.Drawing.Rectangle(128, 4, 58, 13)
wPoint = New System.Drawing.PointF(127, 3)
End If
wGraphics.FillRectangle(wRectBrush, wRect)
wGraphics.DrawString(.TabPages(.SelectedIndex).Text, wFont, wTextBrush, wPoint)
End With
>タブに貼り付けるイメージを動的に切り替える
With TabControl1
Dim i As Integer
'
For i = 0 To .TabPages.Count - 1
If i = .SelectedIndex Then
.TabPages(.SelectedIndex).ImageIndex = .SelectedIndex
Else
.TabPages(i).ImageIndex = -1
End If
Next
End With
※どちらもTabControl1.SelectedIndexChangedに記述しています。
せっかくの丁寧な回答を正しく理解できていないのかもしれませんが
>自分で描画する
の方は、とりあえずタイトルバーのように青系に白字を目標に
作ってみました。動作的にはきれいに動いてくれますが例えば
TabPage内のTextBoxなどフォーカスが移動した時に表示が元に
戻ってしまうのですが、青系に白字の状態を保持するには何か
足りないのでしょうか?
>タブに貼り付けるイメージを動的に切り替える
の方は、ほぼアドバイス通りに作成してみましたが貼り付けた
イメージの微妙な位置やサイズなどが・・・。あと任意の画像ファイル
とゆうのは、どういった物を登録しておけば良いか悩み中です。
可能かは分かりませんが、塗りつぶした四角みたいなのを貼り付けて
タブのTextはそのまま透けて見えるとか…なんでしょうか?
度々の手取り足取りな質問になってきてますが、よろしくお願いします。
長文ですいません
>自分で描画する
>の方は、とりあえずタイトルバーのように青系に白字を目標に
>作ってみました。動作的にはきれいに動いてくれますが例えば
>TabPage内のTextBoxなどフォーカスが移動した時に表示が元に
>戻ってしまうのですが、青系に白字の状態を保持するには何か
>足りないのでしょうか?
面倒な方法を提示してごめんね。
描画する部分をサブルーチンにして呼び出す方法しか思いつきません。
追記
サブクラス化すればいいかも知れない。
サブクラス化とは
http://www.int21.co.jp/pcdn/vb/noriolib/vbmag/9802/subc/
を参考に
順調そうですね(^^)。
では、新しいキーワードを知って新しい問題にぶつかった時は、
原点に戻って調べ直すことを覚えて下さい。
今回の場合、過去ログ検索『Graphics』とか…。
ずばりな説明が引っ掛からなかったので書いておきます。
ユーザは意識しないけど、フォーム(やその上のコントロール)は
あらゆる場面で再描画処理を行ってます。他の Window と
重なったあと、最小化されたあとetc...Control.Paint イベントに
ついてヘルプを読んで下さい。再描画処理が走ったとき、
フォーム(やその上のコントロール)はコードでお絵描きした
情報を知りません。自分の本来の描画処理をして終わりです。
だから消えてしまうのです。
主な手法は2つ知ってます。
王道は、描画したいコントロールごと『継承』して『Paintメソッド
をオーバーライド』する方法。
[DOBON.NET DataGridのセルに画像を表示する]
http://dobon.net/vb/dotnet/datagrid/drawimage.html
ちょっと大掛かり。覚えて損は無いけど知識レベル必要。
Paintメソッドがコントロールの外に公開されてないときに有効。
[VB.NET]では
>サブクラス化
よりこちらを先に調べて下さい。
もうひとつは再描画系のイベントでお絵描き処理を呼び出す
方法。nameless さんの
>描画する部分をサブルーチンにして呼び出す方法
です。
今回は TabControl1.Paint イベントに結び付けられるみたい
だよ。TabControl.DrawItem イベントってのもある?これは
調べないと分かりませんねぇ。
>Paintメソッドがコントロールの外に公開されてないときに有効。
なんかヘン。書き直し。
メソッドじゃない、イベント。そもそもコントロールの時点で
System.Windows.Forms.Control クラスを継承してるから
Paint イベントあるはずじゃん?
動的に変更されるコントロールで有効です。
に変える!。
しかし TabControl には自動でイベントのコードを書いて
くれるコンボボックスに出てこない TabPage は出てくるのに…(怒)
…自分で書いてみる…
……… Handles TabControl1.Paint
なんだあるじゃん。でもこーゆーパターン前にもあったなぁ。
メンバに出てこないからなんで?って調べたら使わないほうがいい…って。
[TabControl.Paint イベント]ヘルプより抜粋。(オンラインヘルプ版は無し?)
>このメンバは、.NET Framework インフラストラクチャのサポートを
>目的としています。独自に作成したコード内で直接使用することは
>できません。
Σ(‾□‾)ダミーっすか???
>動的に変更されるコントロールで有効です。
もーだめー。動的って変更されるってことじゃん。
フォームに動的にコントロールを追加したり、
グリッド系コントロールみたいにセル数が
変わったりするときにいちいちイベント設定って
めんどいから、『継承』ってのが有効になるん
ですよって事が言いたかったのー。
特攻隊長まるるうさん、namelessさん回答ありがとうございます。
>面倒な方法を提示してごめんね。
いえ全然気にしてないですよ。自分達のレベルだとかなり苦労しますが
その分うまくいった時なんかは、かなり楽しいですよね。
特攻隊長まるるうさんのレスでかなり納得(なるほど〜)した事もあり
『Graphics』とか『Paint』など調べてみました。で、
>TabControl.DrawItem イベントってのもある?これは
>調べないと分かりませんねぇ。
を試してみることにしました。
With Me.TabControl1
'<FillRectangleテスト>-------------------------------------------------
'境界四角形
'Dim wRect As System.Drawing.Rectangle = e.Bounds
Dim x, y, w, h As Integer
x = e.Bounds.X + 3
y = e.Bounds.Y + 3
w = e.Bounds.Width - 6
h = e.Bounds.Height - 6
Dim wRect As New System.Drawing.Rectangle(x, y, w, h)
'カラー
Dim wRectBrush As System.Drawing.SolidBrush
If e.State = DrawItemState.Selected Then
wRectBrush = New System.Drawing.SolidBrush(SystemColors.ActiveCaption)
Else
wRectBrush = New System.Drawing.SolidBrush(SystemColors.Control)
End If
'四角形描画(塗りつぶし)
e.Graphics.FillRectangle(wRectBrush, wRect)
'<DrawStringテスト>----------------------------------------------------
'文字列
'Dim wText As String = DirectCast(sender, TabControl).Text
Dim wText() As String = New String(2) {"TabPage1", "TabPage2", "TabPage3"}
'形式
'Dim wFont As New Font("MS UI Gothic", 9.75D, FontStyle.Regular)
Dim wFont As Font = DirectCast(sender, TabControl).Font
'カラー
Dim wTextBrush As System.Drawing.SolidBrush
If e.State = DrawItemState.Selected Then
wTextBrush = New System.Drawing.SolidBrush(SystemColors.ActiveCaptionText)
Else
wTextBrush = New System.Drawing.SolidBrush(SystemColors.ControlText)
End If
'座標
Dim wPoint() As PointF = {New PointF(4, 4), New PointF(66, 4), New PointF(128, 4)}
'文字列描画
e.Graphics.DrawString(wText(e.Index), wFont, wTextBrush, wPoint(e.Index))
End With
DrawModeをOwnerDrawFixedにしてなかったり、悪戦苦闘しましたが
なんとか目標の動作はできてるようです。イベントデータなども結構
勉強になりました。Validatingのe.Cancelくらいなら何度か使った
ことはあったんですけど。
あとは、上記w系変数の取得や設定の部分で結構苦労したので
もう少し見直してちょっとは見栄えの良いコードになればと作業中です。
↑コメント行削除しないで、貼っちゃいました。すいません。
長々とお手数おかけしましたが、今回の作成フォームの画面動作制御が
無事に終わりました。もちろんタブの描画処理も施してあります。
なんとか今週中に終わってよかったです。コードも多少は見栄えよく
まとまったと思います。
時間の合間をみて、"動的に切り替え"をもう少し勉強して
その後は"王道"の方にも挑戦できればと思ってます。
色々と本当にありがとうございました。
ツイート | ![]() |