tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板)
VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板)
[ツリー表示へ]  [ワード検索]  [Home]

タイトル TopIndexの実装
投稿日: 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

- 関連一覧ツリー をクリックするとツリー全体を一括表示します)

古いスレッドにレスはつけられません。