DOBON.NET DOBON.NETプログラミング掲示板過去ログ

ComboBoxのTooltipについて

環境/言語:[XP VB.NET2003 .NET Framework1.1]
分類:[.NET]

いつも参考させていただいています。AREXと申します。
ComboBoxのドロップダウン部の一行毎に違うTooltipを表示させたいのですが、
ドロップダウン部でのマウスカーソル位置や選択行を拾うことすら出来ずにいます。
どなたかご存知でしたらご教授お願いします。
興味があったので調べてみました。

 コンボボックスのドロップダウンリストで選択項目が変更されると、 WM_CTLCOLORLISTBOX メッセージが送信されるようです。これを処理することで選択に応じた内容を表示することができるでしょう。
 ただ、ドロップダウンリスト表示中はコンボボックスを対象に Tooltip.SetToolTip していても、ツールチップが表示されないようです。ドロップダウンリストのウィンドウハンドルは取得できますけど ( Control.FromHandle しても ) Control オブジェクトとしては扱えませんし、もしかすると過去ログにある『メニューへツールチップを表示する。』※ と同様、ツールチップを CreateWindowEx しないと上手くいかないかも知れません(未検証)。

※ http://dobon.net/vb/bbs/log3-1/263.html


 ところでツールチップを表示させようとしている目的は何なのでしょうか?
 もしドロップダウンリストの表示幅が問題になっているのであれば、以下の内容が参考になりそうです。
#恐らく違う目的なのでしょうけど一応。

拡張 ComboBox の作成
http://www.microsoft.com/japan/msdn/net/winforms/bettercombobox.asp
深山さん情報ありがとうございます。
お礼が遅れてしまって申し訳ありません。
表示の目的はドロップダウン部にメッセージのタイトルを表示させ、
ツールチップにメッセージの内容を表示させようと思っています。

教えていただいた情報を元に自分なりにやって見ましたが、
バルーンツールチップであれば最前面に表示されるのですが、
標準ツールチップをドロップダウン部より前面に表示する方法が見つかりませんでした。
どなたかご存知でしたらご教授お願いします。

文字制限に引っかかるので2回に分けてコードを貼ります。

ソースコード1/2--

Imports System.Runtime.InteropServices

Public Class Form1
Inherits System.Windows.Forms.Form

<DllImport("user32.dll")> _
Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

End Function

#Region " Windows フォーム デザイナで生成されたコード "

Public Sub New()
MyBase.New()

' この呼び出しは Windows フォーム デザイナで必要です。
InitializeComponent()

' InitializeComponent() 呼び出しの後に初期化を追加します。

End Sub

' Form は、コンポーネント一覧に後処理を実行するために dispose をオーバーライドします。
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub

' Windows フォーム デザイナで必要です。
Private components As System.ComponentModel.IContainer

' メモ : 以下のプロシージャは、Windows フォーム デザイナで必要です。
'Windows フォーム デザイナを使って変更してください。
' コード エディタを使って変更しないでください。
Friend WithEvents ComboBoxEX1 As WindowsApplicationCombotest.Form1.ComboBoxEX
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
Me.components = New System.ComponentModel.Container
Me.ComboBoxEX1 = New WindowsApplicationCombotest.Form1.ComboBoxEX(Me.components)
Me.SuspendLayout()
'
'ComboBoxEX1
'
Me.ComboBoxEX1.Items.AddRange(New Object() {"test1", "test2", "test3", "test4", "test5"})
Me.ComboBoxEX1.Location = New System.Drawing.Point(0, 0)
Me.ComboBoxEX1.Name = "ComboBoxEX1"
Me.ComboBoxEX1.Size = New System.Drawing.Size(121, 20)
Me.ComboBoxEX1.TabIndex = 1
Me.ComboBoxEX1.Text = "ComboBoxEX1"
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 12)
Me.ClientSize = New System.Drawing.Size(292, 273)
Me.Controls.Add(Me.ComboBoxEX1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)

End Sub

#End Region

Dim ToolTipEX1 As New WindowsApplicationCombotest.Form1.ToolTipEX

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'ToolTipEX1.Style = ToolTipEX.ttStyleEnum.TTBalloon
ToolTipEX1.Style = ToolTipEX.ttStyleEnum.TTStandard

ToolTipEX1.CreateToolTip(Me.ComboBoxEX1.Handle.ToInt32)
End Sub

Private Sub ComboBoxEX1_SelectListChange(ByVal sender As Object, ByVal e As SelectEventArgs) Handles ComboBoxEX1.SelectListChange
If ToolTipEX1.Visible = True Then
ToolTipEX1.Hide()
End If
ToolTipEX1.TipText = e.selectstring
ToolTipEX1.Show(ComboBoxEX1.Width / 2, ComboBoxEX1.Height + 10, Me.ComboBoxEX1.Handle.ToInt32)
End Sub

Private Sub Form1_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Closed
ToolTipEX1.Destroy()
ToolTipEX1 = Nothing
End Sub

Private Sub ComboBoxEX1_DropDownClose(ByVal sender As Object, ByVal e As System.EventArgs) Handles ComboBoxEX1.DropDownClose
If ToolTipEX1.Visible = True Then
ToolTipEX1.Hide()
End If
End Sub

#Region "ComboBoxEX"
Public Class ComboBoxEX
Inherits System.Windows.Forms.ComboBox


#Region " コンポーネント デザイナで生成されたコード "

Public Sub New(ByVal Container As System.ComponentModel.IContainer)
MyClass.New()

'Windows.Forms クラス作成デザイナのサポートに必要です。
Container.Add(Me)
End Sub

Public Sub New()
MyBase.New()

' この呼び出しは、コンポーネント デザイナで必要です。
InitializeComponent()

' InitializeComponent() 呼び出しの後に初期化を追加します。

End Sub

'Component は、コンポーネント一覧に後処理を実行するために dispose をオーバーライドします。
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub

' コンポーネント デザイナで必要です。
Private components As System.ComponentModel.IContainer

' メモ : 以下のプロシージャはコンポーネント デザイナで必要です。
' コンポーネント デザイナを使って変更してください。
' コード エディタを使って変更しないでください。
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
components = New System.ComponentModel.Container
End Sub

#End Region

Private Const WM_USER As Integer = &H400
Private Const WM_COMMAND As Integer = &H111
Private Const WM_CTLCOLORLISTBOX As Integer = &H134

Private Const OCM__BASE As Integer = WM_USER + &H1C00
Private Const OCM_COMMAND As Integer = OCM__BASE + WM_COMMAND

Private Const CBN_CLOSEUP As Integer = 8

Private Const CB_GETCURSEL As Integer = &H147
Private Const CB_GETDROPPEDSTATE As Integer = &H157

Public Delegate Sub SelectEventhandler(ByVal sender As Object, ByVal e As SelectEventArgs)
Public Event SelectListChange As SelectEventhandler

Public Event DropDownClose As EventHandler


Protected Overrides Sub RefreshItem(ByVal index As Integer)

End Sub

Protected Overrides Sub SetItemsCore(ByVal items As System.Collections.IList)

End Sub

Private Function HIWORD(ByVal value As Integer) As Short
Return CShort(New System.Drawing.Point(value).Y)
End Function

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If (m.Msg = OCM_COMMAND) Then
Dim code As Integer = HIWORD(m.WParam.ToInt32)
If code = CBN_CLOSEUP Then
RaiseEvent DropDownClose(Me, New EventArgs)
End If
ElseIf (m.Msg = WM_CTLCOLORLISTBOX) Then

Dim ds As Long
ds = SendMessage(Me.Handle, CB_GETDROPPEDSTATE, 0, 0)
If ds = 1 Then
Dim Mye As SelectEventArgs = New SelectEventArgs
Mye.selectindex = SendMessage(Me.Handle, CB_GETCURSEL, 0, 0)

If (Mye.selectindex <> -1) Then
Mye.hwnd = m.LParam
Mye.selectstring = Me.SelectedItem.ToString
RaiseEvent SelectListChange(Me, Mye)
End If

End If
End If

MyBase.WndProc(m)
End Sub
End Class
#End Region
ソースコード2/3 2つでも無理なので3つにします--

#Region "ToolTipEX"
Public Class ToolTipEX

Private Declare Sub InitCommonControls Lib "comctl32.dll" ()
Private Declare Function CreateWindowEx Lib "user32.dll" Alias "CreateWindowExA" ( _
ByVal dwExStyle As Integer, _
ByVal lpClassName As String, _
ByVal lpWindowName As String, _
ByVal dwStyle As Integer, _
ByVal X As Integer, _
ByVal Y As Integer, _
ByVal nWidth As Integer, _
ByVal nHeight As Integer, _
ByVal hWndParent As Integer, _
ByVal hMenu As Integer, _
ByVal hInstance As Integer, _
ByRef lpParam As Integer) As Integer

Private Declare Function SendMessageBT Lib "user32.dll" Alias "SendMessageA" ( _
ByVal hwnd As Integer, _
ByVal wMsg As Integer, _
ByVal wParam As Integer, _
ByRef lParam As TOOLINFO) As Integer

Private Declare Function SendMessageStr Lib "user32.dll" Alias "SendMessageA" ( _
ByVal hwnd As Integer, _
ByVal wMsg As Integer, _
ByVal wParam As Integer, _
ByVal lParam As String) As Integer

Private Declare Function SendMessageLong Lib "user32.dll" Alias "SendMessageA" ( _
ByVal hwnd As Integer, _
ByVal wMsg As Integer, _
ByVal wParam As Integer, _
ByVal lParam As Integer) As Integer

Private Declare Function DestroyWindow Lib "user32.dll" ( _
ByVal hwnd As Integer) As Integer

Private Declare Function ClientToScreen Lib "user32.dll" ( _
ByVal hwnd As Integer, _
ByRef lpPoint As POINTAPI) As Integer

Private Const HWND_TOP As Long = 0
Private Const HWND_BOTTM As Long = 1
Private Const HWND_TOPMOST As Long = -1
Private Const HWND_NOTOPMOST As Long = -2

Private Const SWP_NOSIZE As Integer = &H1
Private Const SWP_NOMOVE As Integer = &H2
Private Const SWP_NOACTIVATE As Integer = &H10
Private Const SWP_SHOWWINDOW As Integer = &H40

'Windows API Constants
Private Const WM_USER As Short = &H400S
Private Const WM_SETFONT = &H30
Private Const CW_USEDEFAULT As Integer = &H80000000

'Windows API Types
Private Structure RECT
Dim left_Renamed As Integer
Dim top As Integer
Dim right_Renamed As Integer
Dim bottom As Integer
End Structure

Private Structure POINTAPI
Dim X As Integer
Dim Y As Integer
End Structure

'Tooltip Window Constants
Private Const TTS_NOPREFIX As Short = &H2S
Private Const TTF_TRANSPARENT As Short = &H100S
Private Const TTF_CENTERTIP As Short = &H2S
Private Const TTM_ADDTOOLA As Integer = (WM_USER + 4)
Private Const TTM_ACTIVATE As Integer = WM_USER + 1
Private Const TTM_UPDATETIPTEXTA As Integer = (WM_USER + 12)
Private Const TTM_SETMAXTIPWIDTH As Integer = (WM_USER + 24)
Private Const TTM_SETTIPBKCOLOR As Integer = (WM_USER + 19)
Private Const TTM_SETTIPTEXTCOLOR As Integer = (WM_USER + 20)
Private Const TTM_SETTITLE As Integer = (WM_USER + 32)
Private Const TTS_BALLOON As Short = &H40S
Private Const TTS_ALWAYSTIP As Short = &H1S
Private Const TTF_SUBCLASS As Short = &H10S
Private Const TTF_TRACK As Short = &H20S
Private Const TTF_IDISHWND As Short = &H1S
Private Const TTM_SETDELAYTIME As Integer = (WM_USER + 3)
Private Const TTDT_AUTOPOP As Short = 2
Private Const TTDT_INITIAL As Short = 3
Private Const TTM_TRACKACTIVATE As Integer = WM_USER + 17
Private Const TTM_TRACKPOSITION As Integer = WM_USER + 18
Private Const WS_POPUP As Integer = &H80000000
Private Const WS_EX_TOPMOST As Integer = &H8

Private Const TOOLTIPS_CLASSA As String = "tooltips_class32"

''Tooltip Window Types
Private Structure TOOLINFO
Dim lSize As Integer
Dim lFlags As Integer
Dim hwnd As Integer
Dim lId As Integer
Dim lpRect As RECT
Dim hInstance As Integer
Dim lpStr As String
Dim lParam As Integer
End Structure

Public Enum ttStyleEnum
TTStandard
TTBalloon
End Enum

'local variable(s) to hold property value(s)
Private m_Style As ttStyleEnum
Private m_TipText As String
Private m_PopupOnDemand As Boolean

Private m_Visible As Boolean

'private data
Private m_lTTHwnd As Integer ' hwnd of the tooltip
Private m_TipFont As Font
Private m_lParentHwnd As Integer ' hwnd of the window the tooltip attached to
Private ti As TOOLINFO

Public Sub New()
MyBase.New()
InitCommonControls()

m_PopupOnDemand = False
End Sub
Protected Overrides Sub Finalize()
Destroy()
MyBase.Finalize()
End Sub

'//////////////////////////////////////////////////////
Public Property TipText() As String
Get
Return m_TipText
End Get
Set(ByVal Value As String)
m_TipText = Value
ti.lpStr = Value
If m_lTTHwnd <> 0 Then
SendMessageBT(m_lTTHwnd, TTM_UPDATETIPTEXTA, 0, ti)
End If
End Set
End Property

'//////////////////////////////////////////////////////
Public Property PopupOnDemand() As Boolean
Get
Return m_PopupOnDemand
End Get
Set(ByVal Value As Boolean)
m_PopupOnDemand = Value
'If m_lTTHwnd <> 0 Then
'End If
End Set
End Property

'//////////////////////////////////////////////////////
Public Property Style() As ttStyleEnum
Get
Style = m_Style
End Get
Set(ByVal Value As ttStyleEnum)
m_Style = Value
End Set
End Property

'//////////////////////////////////////////////////////
Public ReadOnly Property Visible() As Boolean
Get
Visible = m_Visible
End Get
End Property
ソースコード3/3--
'X and Y are in Pixel so dont send vbTwips value
Public Sub Show(Optional ByRef X As Integer = 0, Optional ByRef Y As Integer = 0, Optional ByRef hWndClient As Integer = 0)

Dim pt As POINTAPI
Dim ptTip As Integer
Dim ret As Integer

With pt
.X = X
.Y = Y
End With

ret = ClientToScreen(hWndClient, pt)

ptTip = pt.Y * &H10000
ptTip = ptTip + pt.X

' These two messages will set the position of the tooltip:
ret = SendMessageLong(m_lTTHwnd, TTM_TRACKPOSITION, 0, ptTip)
ret = SendMessageBT(m_lTTHwnd, TTM_TRACKACTIVATE, True, ti)

m_Visible = True
End Sub

Public Sub Hide()
Dim ret As Integer
Dim udtToolinfo As TOOLINFO
udtToolinfo.lSize = Len(udtToolinfo)
udtToolinfo.lFlags = TTF_TRACK
udtToolinfo.hwnd = m_lParentHwnd
udtToolinfo.lId = 1
ret = SendMessageBT(m_lTTHwnd, TTM_TRACKACTIVATE, 0, udtToolinfo)

m_Visible = False
End Sub


Public Function CreateToolTip(ByVal ParentHwnd As Integer) As Boolean
Dim lWinStyle As Integer
If m_lTTHwnd <> 0 Then
DestroyWindow(m_lTTHwnd)
End If
m_lParentHwnd = ParentHwnd

'create baloon style if desired
If m_Style = ttStyleEnum.TTBalloon Then
lWinStyle = lWinStyle Or TTS_BALLOON
End If

m_lTTHwnd = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASSA, 0, lWinStyle, 0, 0, 0, 0, m_lParentHwnd, 0, 0, 0)

'now set our tooltip info structure
With ti
'NOTE: dont incude TTF_SUBCLASS for on demand
' if we want it centered, then set that flag
If m_PopupOnDemand = False Then
.lFlags = TTF_SUBCLASS Or TTF_IDISHWND
Else
.lFlags = TTF_IDISHWND Or TTF_TRACK Or TTF_TRANSPARENT
End If

'set the hwnd prop to our parent control's hwnd
.hwnd = m_lParentHwnd
.lId = m_lParentHwnd '0
.hInstance = 0 'VB6.GetHInstance.ToInt32
.lpStr = m_TipText
'.lpRect = lpRect
.lSize = Len(ti)
End With

Dim a As Integer

''add the tooltip structure
a = SendMessageBT(m_lTTHwnd, TTM_ADDTOOLA, 0, ti)

End Function

Public Sub Destroy()
If m_lTTHwnd <> 0 Then
DestroyWindow(m_lTTHwnd)
End If
End Sub
End Class
#End Region

#Region "SelectEventArgs"
'追加イベント用
Public Class SelectEventArgs
Inherits EventArgs

Public selectindex As Long
Public selectstring As String
Public hwnd As IntPtr

End Class
#End Region

End Class
えーっと‥‥(汗)

 まず、コードを投稿するときは図表モードにすることをオススメしておきます。インデントが崩れると非常に見辛いですよね?
 それから、文字数が多いとそれだけ細部まで目を通す人間が減る可能性が高くなると思いますよ。『デザイナで生成されたコード』や使用していない定数、プロパティなど、 ( 動作確認する上で ) 不要な箇所は整理したほうが見通しが良くなるでしょう。
#私は読む気がしなかった口です(^_^;)

 もしそのまま実行してもらうことを意図しているのでしたら、プロジェクトファイル一式をアップしたほうが良かったのではないでしょうか? もしくは、新規プロジェクトにコピペで動かせるよう、名前空間まで意識した構成にしておくか。


 前置きが長くなりました。本題に入ります。

> バルーンツールチップであれば最前面に表示されるのですが、
> 標準ツールチップをドロップダウン部より前面に表示する方法が見つかりませんでした。

 確認しました。
 最初、ツールチップの親ウィンドウにコンボボックスを指定しているのが原因かと思ったのですが‥‥どうやら違うようですね。親ウィンドウをドロップダウンリストに変更しても、動作は変わりませんでした。
 Spy++ で調べたところ、どちらの場合も何故かデスクトップが親ウィンドウになっていました。 CreateWindowEx でアプリケーションインスタンスを指定していないのが原因かも知れません(未調査)

 取り敢えず−すっきりしませんが−、親ウィンドウを指定せずに作成すれば回避できるようです。こちらではそれでツールチップが最前面に表示されるのを確認できましたけど、どうでしょうか?
深山さんご教授ありがとうございます。
あまり注意事項を読まずに書き込みしてしまいました、今後気をつけます。

教えていただいた方法でツールチップを最前面に表示させることができましたが、
親ウィンドウを指定しないで作成しても問題ないのでしょうか?

もう一つ教えていただきたいことがあります。
上のソースではツールチップの表示タイミングをリスト描画が発生した時としているので
すが、これだとマウスカーソルをドロップダウンリスト外に移動させ、
再びドロップダウンリスト上に移動させた場合、ツールチップが表示されません。

これを解決するためにドロップダウンリスト上でのマウスの操作
(MouseEnter、MouseMove等)を検出したいのですが、
ご存知のかたご教授お願いします。
2005/05/25(Wed) 11:33:04 編集(投稿者)
2005/05/21(Sat) 18:58:01 編集(投稿者)

> あまり注意事項を読まずに書き込みしてしまいました、今後気をつけます。

 気に掛けて頂いてありがとうございます(^^)
#ただ、先の私の発言は『注意事項』とかでなく『提案』のつもりだったのですけど(^_^;;;)


> 親ウィンドウを指定しないで作成しても問題ないのでしょうか?

 詳しいわけではないので認識に誤りがあるかも知れませんが‥‥

 LPSTR_TEXTCALLBACK のように通知メッセージを送るようにするものを使用しているわけではないようですし、そのことが直接問題になることはないと思います。親ウィンドウのないツールチップは普通に使われているようですし。
#勿論、責任を持って DestroyWindow しなくてはなりません。
#今更ですけど、 ToolTp クラスもしくは NativeWindow クラスを継承した作りにしておいたほうが良かったのかも?<すみません。 ToolTipEX クラスは ToolTip クラスを継承してるものと思い込んでましたm(__)m
#(追記2)‥‥って、 ToolTip クラスは継承できないんですね(汗) ボケボケでごめんなさいm(__)m

> これを解決するためにドロップダウンリスト上でのマウスの操作
> (MouseEnter、MouseMove等)を検出したいのですが、

 ウィンドウのサブクラス化を行えばメッセージを扱うことができます。
 私は昔ながらの SetWindowLong API を用いる方法しか使ったことがありませんけど、こういう場合 .NET 開発では NativeWindow から継承したクラスで WndProc メソッドをオーバーライドするのが一般的(?)なようです。

 少し手法が異なりますが、ドロップダウンリストを扱ってるサンプルを見かけましたので紹介しておきます。参考になるでしょうか?

Hacking the Combo Box to give it horizontal scrolling
http://www.codeproject.com/cs/combobox/ComboHack.asp


(追記)
 きちんと目を通していませんが、次のようなやり取りを見掛けました。これはそのものズバリかも?

ToolTip for ListBox-/ComboBox-Items
http://www.aewnet.com/nntp/id-43661.html
深山さん何度もありがとうございます。
教えていただいた情報を元にさっそくNativeWindowクラスを継承させ、
マウス検出とタイマーによるディレイを実装してみました。

> #勿論、責任を持って DestroyWindow しなくてはなりません。
APIやハンドルに関する知識が浅いので、開放し忘れがあるかもしれません。
よろしければ指摘していただけないでしょうか。

>  きちんと目を通していませんが、次のようなやり取りを見掛けました。これはそのものズバリかも?
>
> ToolTip for ListBox-/ComboBox-Items
> http://www.aewnet.com/nntp/id-43661.html
どうやらそのものズバリみたいなのですが、
作者の方が誤って削除してしまったみたいですw
今はVB6版のツールチップクラスのみががダウンロード可能になっています。

ソースをアップしてみました
http://dobon.net/cgi-bin/up/files/002.lzh

ツールチップクラスは以下のサイトを参考にしています。
http://www.experts-exchange.com/Programming/Programming_Languages/Dot_Net/VB_DOT_NET/Q_21313776.html
> APIやハンドルに関する知識が浅いので、開放し忘れがあるかもしれません。
> よろしければ指摘していただけないでしょうか。

 先程も申し上げた通り、私も詳しくはありません。ですのでそういった指摘はできないのですけれど、少し気になった点がありましたので触れさせて頂きますね。


> 教えていただいた情報を元にさっそくNativeWindowクラスを継承させ、

 ごめんなさい。言葉足らずでしたね(汗)

 継承させたらという話をしたのは、そうすることでアンマネージドな部分を減らすことができる ( って言い方すると語弊があるのかなぁ? ) からです。 CreateWindowEx / DestroyWindow API ではなく CreateHandle / DestroyHandle メソッドを用いるようにしたほうが良かろうと。
#だから継承しただけでは何も変わりないという‥‥(^_^;)

 ただ後になって、継承クラスではなくラッパクラスのほうが適切だったかも知れないと思うようになりました。メッセージ処理をするわけではない ( = WndProc メソッドをオーバーライドする必要がない ) のですもの。< ToolTipEx クラス
#参考にはならないかも知れませんけど、こちらで作成したものをアップしました。よろしければご覧になってください。※
http://dobon.net/cgi-bin/up/files/003.zip


> ToolTipTimer クラス

 このクラスが
> タイマーによるディレイ
に相当するのですよね。この役割は ComboBoxEx 内にいるものが負うべきではないでしょうか?
 ツールチップに表示する内容をイベントで設定できるようになってるのは良いと思うのですけど、表示するタイミングはコントロール側で制御してるほうが自然に感じます。
#いや、大きなお世話でしょうけど(汗)

 それから、 Dispose メソッドを実装するのであれば、 IDisposable インタフェースを Implements してガイドラインに沿う形にしたほうが良いのではないでしょうか?
#この辺りもきちんと理解してるわけではないのですが‥‥(///)

#あ、 DropDwonList クラスについても同様です。


> ComboBoxEx クラス

 上述した内容と被りますけど、このクラスの機能は『ドロップダウンリストにツールチップを表示する』というものですよね? ツールチップをメンバとして持ち、表示/非表示の制御は自身で行うようにしたほうが良いと思いますよ。<やっぱり大きなお世話

 もう一つ、こちらは仕様に関して。
 ツールチップを表示した後、矢印キー操作によってドロップダウンリストの選択を変化させると、マウスカーソルの位置とツールチップの内容が対応しなくなってしまいます。これは構わないのでしょうか?
#そういう仕様で作成されているのでしょうけれど、念のため確認です。


 以上です。‥‥って、あんまり実のある内容になってないですね(汗)



※補足
・ ( TTM_TRACKACTIVATE を使用してないので ) AREXさんのものとは挙動が異なります。
・いくつか不具合を抱えてます。
・どうでもいいところに凝ってたりします。<気にしないでください :D
深山さんサンプル参考にさせて頂きました。
見たことのないテクニック満載でいまだに全部把握できたわけでは無いのですが、

> '' MouseMove イベントをテスト
> 'Private Sub _dropDownList_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles _dropDownList.MouseMove
> ' '_listToolTip.Activate = True
> ' '_listToolTip.Text = String.Format("{0}, {1}", e.X, e.Y)
> ' 'If Me.rect Then
> ' Debug.WriteLine(e.X.ToString & ":" & e.Y.ToString)
> 'End Sub

のコードがコメントアウトされている個所は使わないほうがいいのでしょうか?
自分のサンプルではマウス検知するのに一々SendMessageしていたので改良したいと思っていました。


>  もう一つ、こちらは仕様に関して。
>  ツールチップを表示した後、矢印キー操作によってドロップダウンリストの選択を変化させると、マウスカーソルの位置とツールチップの内容が対応しなくなってしまいます。これは構わないのでしょうか?
> #そういう仕様で作成されているのでしょうけれど、念のため確認です。

実はその辺の細かい仕様はまだ考えていませんw。
当初はツールチップが表示できるかどうか自体不明な状況でしたので。

ですが調べてみるとWindows2000のエクスプローラーではカーソルのあるアイテムのツールチップが、
WindowsXPのエクスプローラーでは選択中のアイテムのツールチップが表示されているようですので
これもプロパティ等によって切り替えれるようにするのが一番いいのかもしれませんね。
> コメントアウトされている個所は使わないほうがいいのでしょうか?

 使っても問題はないと思います。
 必要になるかな?と思って実装したものの自分では使わなくって。削除するのは簡単なので、取り敢えず残してあるといったところです。コメント化してあるのは存在が埋もれないように、という意図でした。
#‥‥あ、「いくつか不具合を」と書いてたから(汗)
# MouseEnter / MouseLeave イベントはなんちゃってな作りですけど、 MouseMove イベントは大丈夫‥‥のはず。ドロップダウンリストが表示中はずっと発生する ( キャプチャされてるので ) という点だけお気を付けくださいませ。

> ですが調べてみるとWindows2000のエクスプローラーではカーソルのあるアイテムのツールチップが、
> WindowsXPのエクスプローラーでは選択中のアイテムのツールチップが表示されているようですので

 エクスプローラというと‥‥ツリービューやリストビューの部分ですか?
 OS によって挙動が異なるとは気付きませんでした。マウスカーソル位置のものではないツールチップが表示されることもあるのですね。勉強になりました。
#あれ、でも手元の XP ではそうなってないような‥‥ Home Edition だから? それとも何か勘違いしてるのかなぁ(ーー;)
>  エクスプローラというと‥‥ツリービューやリストビューの部分ですか?
>  OS によって挙動が異なるとは気付きませんでした。マウスカーソル位置のものではないツールチップが表示されることもあるのですね。勉強になりました。
> #あれ、でも手元の XP ではそうなってないような‥‥ Home Edition だから? それとも何か勘違いしてるのかなぁ(ーー;)

自分が調べたのはエクスプローラーの右側の窓(リストビュー?)の方です。
操作は
1.ファイルをクリック
2.そのままツールチップが表示されるまでマウス停止
3.ツールチップが表示されたらキーボードの上キーで他ファイルを選択
4.そのままツールチップが表示されるまでマウス停止
この操作だとWindows2000だとマウスカーソルがあるファイルのツールチップが
マウスカーソルの下辺りに表示されますが、WindowsXP Proだとキー操作により
選択されたアイテムの下辺りに選択されたアイテムのツールチップが表示されます。
エクスプローラの設定によっても違うのかもしれませんね。
> 自分が調べたのはエクスプローラーの右側の窓(リストビュー?)の方です。

 はい。リストビューですね。

> 操作は
> 1.ファイルをクリック
> 2.そのままツールチップが表示されるまでマウス停止
> 3.ツールチップが表示されたらキーボードの上キーで他ファイルを選択
> 4.そのままツールチップが表示されるまでマウス停止

 ごめんなさい。やっぱり勘違いしていましたm(__)m
#キーボード操作で、って話の続きだということを理解してなかったみたいで‥‥(///)

 ですので
> エクスプローラの設定によっても違うのかもしれませんね。
ということではなさそうです(^_^;)


 改めて試したところ、こちらでも同じように動作しました。
 で少し観察してみたのですが、(マウス操作の有無に関わらず)キーボード操作でリストの選択が変更されると、トラッキングツールチップが表示されるようです。
 マウス操作で表示されるツールチップは普通のものでしたから、二種類のツールチップを使い分けている‥‥ということになるのでしょうか。<これまで意識したことありませんでしたけれど、凝った作りになってるのかも?

 No11141 の時点ではまだ仕様を確定されてないとのことでしたけれど、もし同様の動作をさせようと思ったら少し大変そうですね。
>  改めて試したところ、こちらでも同じように動作しました。
>  で少し観察してみたのですが、(マウス操作の有無に関わらず)キーボード操作でリストの選択が変更されると、トラッキングツールチップが表示されるようです。
>  マウス操作で表示されるツールチップは普通のものでしたから、二種類のツールチップを使い分けている‥‥ということになるのでしょうか。<これまで意識したことありませんでしたけれど、凝った作りになってるのかも?
>
>  No11141 の時点ではまだ仕様を確定されてないとのことでしたけれど、もし同様の動作をさせようと思ったら少し大変そうですね。

おそらくそこまで細かい動作は必要なさそうな雰囲気になってきましたw。
当初考えていたより大変でしたが、必要な動作は実現できました。
深山さんご教授ありがとうございました。また何かありましたらよろしくお願いします。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板