タイトル | : TopIndexの実装 |
記事No | : 9430 |
投稿日 | : 2009/10/04(Sun) 18:29 |
投稿者 | : ダンボ |
たくボン@10年ぶり さん、どうもありがとうございます。 事情があって返信も遅れてすみません。
> どうやらComboBoxの構造を理解されていないようですね。 > ComboBoxのDropDownの部分の矩形は、どのように描画されているかわかっていますか? > API使うのが嫌ならこのような仕様にすべきではありません。
「DropDownの部分の矩形は独立したWindowだからComboBoxのメンバーとしては 一般提供されていない。やりたければAPIで処理できるのだからAPIを厭うべきでない」 ということをおっしゃっているのでしょうか?
.NetFrameworkでは、非常に多くのクラスが用意されておりVB6時代のAPI Hellから 抜け出せたんだと感激しました。ひょっとしたら.NetFrameworkでは(現バージョンでは 無理としても)一切APIを直接コールする必要が無くなる、それも.NetFrameworkの 目標の一つと勝手に解釈しておりました。
.NetFramework2.0ではAPI使用で行くしか無いようですので、下記のコードでなんとか 動作確認をとれるところまで来ました。しかしバグがありました!!(いや、知っては いたんですがTopIndexを足せば済むだけと後回しにしていました) ところが、VB2005ではComboBoxのTopIndexがサポートされなくなりました。 http://msdn.microsoft.com/ja-jp/library/cxh2w9wf%28VS.80%29.aspx
ということで、TopIndexをなんとか実装しようと考えている最中なのですが よいアイデアが浮かびません。
Public Class ExComboBox Inherits ComboBox Private Shared ScreenIndex As Integer = -1 Public Sub New() InitializeComponent() '呼び出しの後で初期化を追加します。 Me.components = New System.ComponentModel.Container() End Sub <System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)> _ Private Structure ComboBoxInfo Public Size As Integer Public RectItem As System.Drawing.Rectangle Public RectButton As System.Drawing.Rectangle Public ButtonState As Integer Public ComboBoxHandle As System.IntPtr Public EditBoxHandle As System.IntPtr Public ListBoxHandle As System.IntPtr End Structure <System.Runtime.InteropServices.DllImport("USER32.DLL")> _ Private Shared Function GetComboBoxInfo( _ ByVal hWndCombo As System.IntPtr, _ ByRef pcbi As ComboBoxInfo) As Boolean End Function Protected Overrides Sub OnHandleCreated(ByVal e As System.EventArgs) Dim cbinfo As New ComboBoxInfo() cbinfo.Size = System.Runtime.InteropServices.Marshal.SizeOf(cbinfo) If Not GetComboBoxInfo(Me.Handle, cbinfo) Then Return If cbinfo.ListBoxHandle.Equals(System.IntPtr.Zero) Then Return DropdownList = New ListBoxWindow(Me) DropdownList.AssignHandle(cbinfo.ListBoxHandle) End Sub Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing = True Then If Not Me.components Is Nothing Then Me.components.Dispose() End If End If MyBase.Dispose(disposing) End Sub <System.Runtime.InteropServices.DllImport("USER32.DLL")> _ Private Shared Function GetWindowInfo( _ ByVal hwnd As System.IntPtr, _ ByRef info As WINDOWINFO) As Boolean End Function Structure WINDOWINFO Dim cbSize As UInt32 Dim rcWindow As Rectangle Dim rcClient As Rectangle Dim dwStyle As UInt32 Dim dwExStyle As UInt32 Dim dwWindowStatus As UInt32 Dim cxWindowBorders As UInt32 Dim cyWindowBorders As UInt32 Dim atomWindowType As UInt16 Dim wCreatorVersion As UInt16 End Structure
Private WithEvents DropdownList As ListBoxWindow Public Class ListBoxWindow Inherits System.Windows.Forms.NativeWindow Public Event MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Private Parent As ComboBox Public Sub New(ByVal parentComboBox As ComboBox) Parent = parentComboBox AddHandler parentComboBox.HandleDestroyed, AddressOf Me.OnHandleDestroyed End Sub Private Sub OnHandleDestroyed(ByVal sender As Object, ByVal e As System.EventArgs) Me.ReleaseHandle() End Sub Public Function PointToIndex(ByVal Y As Integer) As Integer Return CInt(Fix(Y \ Parent.ItemHeight)) End Function <System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand)> _ Protected Overrides Sub WndProc(ByRef m As Message) Const WM_RBUTTONDOWN As Integer = &H204 Const WM_MOUSEMOVE As Integer = &H200 Dim info As New WINDOWINFO Select Case m.Msg Case WM_MOUSEMOVE If ScreenIndex < 0 Then MyBase.WndProc(m) Case WM_RBUTTONDOWN info.cbSize = Convert.ToUInt32(System.Runtime.InteropServices.Marshal.SizeOf(info)) Dim b As Boolean = GetWindowInfo(m.HWnd, info) Dim X As Integer = info.rcWindow.X + LOWORD(m.LParam) Dim Y As Integer = info.rcWindow.Y + HIWORD(m.LParam) Dim i As Integer = PointToIndex(HIWORD(m.LParam)) Parent.SelectedIndex = i Dim e As New System.Windows.Forms.MouseEventArgs(Windows.Forms.MouseButtons.Right, 1, X, Y, i) RaiseEvent MouseDown(Me, e) MyBase.WndProc(m) Case Else MyBase.WndProc(m) End Select End Sub Private Function LOWORD(ByVal value As IntPtr) As Integer Return CInt((value.ToInt32 And &HFFFF&)) End Function Private Function HIWORD(ByVal value As IntPtr) As Integer Return (value.ToInt32 And &HFFFF0000%) \ &H10000% End Function End Class
Private Sub DropdownList_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles DropdownList.MouseDown Dim X As Integer = e.X Dim Y As Integer = e.Y ScreenIndex = e.Delta SubMenu.Show(X, Y) End Sub
Private Sub SubMenu_Remove_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SubMenu_Remove.Click Me.Items.RemoveAt(ScreenIndex) ScreenIndex = -1 End Sub Private Sub SubMenu_Rename_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SubMenu_Rename.Click Me.Items.Insert(ScreenIndex, Me.Items(ScreenIndex).ToString & "XXX") Me.Items.RemoveAt(ScreenIndex) ScreenIndex = -1 End Sub End Class
|