CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 12 of 12
  1. #1
    Join Date
    Dec 2003
    Location
    Northern Ireland
    Posts
    1,362

    How to disable ComboBox / ListBox Items

    Greets guys,

    I need to extend a combobox to disable some listitems (i.e splits - "----------").

    I reckon some APIs will be involved, and it could get complicated. That'll not put me off though.

    If anyone with usefull info on the subject could post it, I'd really appreciate it.

    Thanks
    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning. - Rich Cook


    0100 1101 0110 1001 0110 0011 0110 1000 0110 0001 0110 0101 0110 1100 0010 0000 0100 0101 0110 1100 0110 1100 0110 0101 0111 0010

  2. #2
    Join Date
    Jul 2001
    Location
    Sunny South Africa
    Posts
    11,283

    Re: How to disable ComboBox / ListBox Items

    Hey buddy!

    I'm really not sure if there is a definite way to do that, if I'm wrong ( which I doubt, I apolgise )

    I did some thinking. Let me explain.
    Why not show a visible cue to the user that a certain item is selectable and a certain item is not selectable. For example, an item which contains your split ( "-----" ) will not be selectable, so, what I did in my example here is to make all items which is equals to "-----" red, and all normal items black. Another thing to be considered is some logic about what to do if an item "-----" is selected. You can perhaps cancel all the neceassary things / exit the sub, or whatever. In my example, I just reset the Selected index to 0.

    Here is my code :
    Code:
    'Add one combobox to the form
    Public Class Form1
        Private ComboItemArr() As String = {"One", "-----", "Two", "-----", _
        "Three", "-----", "Four", "-----", "Five", "-----"} 'Array for combobox
    
        Protected Sub Combobox1_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles ComboBox1.DrawItem
    
            If e.Index < 0 Then
                e.DrawBackground()
                e.DrawFocusRectangle()
                Exit Sub
            End If
    
            Dim EnabledColor As Color = Color.White
            ' get a square using the bounds height
            Dim SizeRect As Rectangle = New Rectangle(2, e.Bounds.Top + 2, e.Bounds.Width, e.Bounds.Height - 2)
    
            Dim ComboBrush As Brush
    
            ' call these methods first
            e.DrawBackground()
            e.DrawFocusRectangle()
    
            ' change brush color if item is selected
            If e.State = Windows.Forms.DrawItemState.Selected Then
                ComboBrush = Brushes.White
            Else
                ComboBrush = Brushes.Black
            End If
    
            For i As Integer = 0 To 9
                If ComboItemArr(e.Index).ToString = "-----" Then
                    e.Graphics.DrawRectangle(New Pen(Color.Red), SizeRect)
                    e.Graphics.FillRectangle(New SolidBrush(Color.White), SizeRect)
                    e.Graphics.DrawString(ComboItemArr(e.Index), ComboBox1.Font, Brushes.Red, e.Bounds.Height + 5, ((e.Bounds.Height - ComboBox1.Font.Height) \ 2) + e.Bounds.Top)
                Else
                    ' draw a rectangle and fill it
                    e.Graphics.DrawRectangle(New Pen(Color.White), SizeRect)
                    e.Graphics.FillRectangle(New SolidBrush(Color.White), SizeRect)
                    e.Graphics.DrawString(ComboItemArr(e.Index), ComboBox1.Font, Brushes.Black, e.Bounds.Height + 5, ((e.Bounds.Height - ComboBox1.Font.Height) \ 2) + e.Bounds.Top)
                End If
    
            Next
    
            ' UNCOMMENT THIS, If you want to draw a border as well
            'SizeRect.Inflate(1, 1)
            'e.Graphics.DrawRectangle(Pens.Green, SizeRect)
    
        End Sub
    
        Protected Sub Combobox1_MeasureItem(ByVal sender As Object, ByVal e As System.Windows.Forms.MeasureItemEventArgs) Handles ComboBox1.MeasureItem
            Dim myRandom As New Random
            e.ItemHeight = myRandom.Next(20, 40)
    
        End Sub
    
        Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            For i As Integer = 0 To 9
                ComboBox1.Items.Add(ComboItemArr(i))
            Next i
        End Sub
    
        Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
            If ComboBox1.Items(ComboBox1.SelectedIndex).ToString = "-----" Then
                ComboBox1.SelectedIndex = 0
                Exit Sub
            Else
                MessageBox.Show(ComboBox1.SelectedItem.ToString())
            End If
    
        End Sub
    End Class
    Because this is an interesting topic, I decided to attach my project as well.

    Have a look at it, maybe it's all you'll need.

    I hope my post was helpful.
    Last edited by HanneSThEGreaT; December 19th, 2008 at 03:18 AM.

  3. #3
    Join Date
    Dec 2003
    Location
    Northern Ireland
    Posts
    1,362

    Re: How to disable ComboBox / ListBox Items

    Hi Hannes,
    Good to see you. I see you got a promotion, well done

    I'm working on a class that inherits the combobox, overrides DrawItem, then check in OnSelectionChangeCommitted whether its my split line or not.

    ps: I started a new job and got a haircut so I guess I need to change my name to just MonkeyMan

    I found this very interesting code by Nasir Chandwale
    Code:
    Imports System.ComponentModelPublic Class MyCombo
        Inherits System.Windows.Forms.ComboBox
    
    #Region "Declaration:Enum"
    
        Enum ListDisplayStyle
            eSystem
            eIcon
            eExtended
        End Enum
    
    #End Region#Region "Declaration:Variables"
    
        Private _ImageList As ImageList
        Private _DropDownListStyle As ListDisplayStyle
        Private _TempText As String
    
    #End Region
    
    #Region " Windows Form Designer generated code "
    
        Public Sub New()
            MyBase.New()
            'This call is required by the Windows Form Designer.
            InitializeComponent()
            DrawMode = DrawMode.OwnerDrawFixed
            'Add any initialization after the InitializeComponent() call
        End Sub
        'UserControl overrides dispose to clean up the component list.
        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
        'Required by the Windows Form Designer
        Private components As System.ComponentModel.IContainer
        'NOTE: The following procedure is required by the Windows Form Designer
        'It can be modified using the Windows Form Designer.
          'Do not modify it using the code editor.
         Private Sub InitializeComponent()
            components = New System.ComponentModel.Container()
        End Sub
    
    #End Region
    
    #Region "Implementation:Properties"
    
         Public Property DropDownListStyle() As ListDisplayStyle
            Get
                Return _DropDownListStyle
            End Get
            Set(ByVal Value As ListDisplayStyle)
                _DropDownListStyle = Value
                Value = Nothing
            End Set
        End Property
    
    #End Region
    
    #Region "Implementation:Methods"
    
        Public Sub AddItem(ByVal ItemText As String, Optional ByVal ItemIcon As Integer = -1, Optional ByVal ItemFont As Font = Nothing)
            If ItemFont Is Nothing Then
                ItemFont = Me.Font
            End If
            MyBase.Items.Add(New ComboItem(ItemText, ItemIcon, ItemFont))
        End Sub
    
    #End Region
    
    #Region "Implementation:Overrides"
    
        Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)
            Dim oComboItem As ComboItem
            Dim iLeft As Integer = e.Bounds.Left
            Dim rctIconRectangle As Rectangle
            Dim colorForeGround As Color
            Dim iTop As Integer = e.Bounds.Top
            Try
                If e.Index = -1 Then Return
                oComboItem = CType(Me.Items(e.Index), ComboItem)
                If oComboItem.Enabled And oComboItem.Text.Substring(0, 1) <> "-" Then
                    e.DrawFocusRectangle()
                    e.DrawBackground()
                    colorForeGround = e.ForeColor
                Else
                    colorForeGround = SystemColors.GrayText
                End If
                If _ImageList.ImageSize.Height > Me.ItemHeight Then
                    rctIconRectangle = New Rectangle(e.Bounds.Left, e.Bounds.Top, Me.ItemHeight, Me.ItemHeight)
                Else
                    rctIconRectangle = New Rectangle(New Point(e.Bounds.Left, e.Bounds.Top), _ImageList.ImageSize)
                End If
                If _DropDownListStyle = ListDisplayStyle.eExtended Then
                    Dim rctBar As Rectangle = rctIconRectangle
                    rctBar.Width += 4
                    rctBar.Height += 4
                    e.Graphics.FillRectangle(New SolidBrush(SystemColors.Control), rctBar)
                    iLeft += rctBar.Width
                    _ImageList.Draw(e.Graphics, (rctBar.Width - rctIconRectangle.Width) / 2, rctIconRectangle.Top + (rctBar.Height - rctIconRectangle.Height) / 2, rctIconRectangle.Width, rctIconRectangle.Height, oComboItem.IconIndex)
                End If
                If _DropDownListStyle = ListDisplayStyle.eIcon Then
                    If oComboItem.IconIndex > -1 Then
                        iLeft += rctIconRectangle.Width
                        _ImageList.Draw(e.Graphics, rctIconRectangle.Left, rctIconRectangle.Top, rctIconRectangle.Width, rctIconRectangle.Height, oComboItem.IconIndex)
                    End If
                End If
                If oComboItem.Text.Substring(0, 1) = "-" Then
                    e.Graphics.DrawLine(New Pen(Me.ForeColor), 0, e.Bounds.Top + CInt(Me.ItemHeight / 2), Me.DropDownWidth, e.Bounds.Top + CInt(Me.ItemHeight / 2))
                Else
                    e.Graphics.DrawString(oComboItem.Text, oComboItem.Font, New SolidBrush(colorForeGround), iLeft, iTop)
                End If
            Catch
                If oComboItem.Text.Substring(0, 1) = "-" Then
                    e.Graphics.DrawLine(New Pen(Me.ForeColor), 0, e.Bounds.Top + CInt(Me.ItemHeight / 2), Me.DropDownWidth, e.Bounds.Top + CInt(Me.ItemHeight / 2))
                Else
                    e.Graphics.DrawString(oComboItem.Text, oComboItem.Font, New SolidBrush(e.ForeColor), iLeft, iTop)
                End If
            End Try
            MyBase.OnDrawItem(e)
            oComboItem = Nothing
            rctIconRectangle = Nothing
        End Sub
        Protected Overrides Sub OnMeasureItem(ByVal e As System.Windows.Forms.MeasureItemEventArgs)
            MyBase.OnMeasureItem(e)
        End Sub
        Protected Overrides Sub OnDropDown(ByVal e As System.EventArgs)
            _TempText = Me.Text
        End Sub
        Protected Overrides Sub OnSelectionChangeCommitted(ByVal e As System.EventArgs)
            MyBase.OnSelectionChangeCommitted(e)
            If Not Me.SelectedItem.Enabled Or SelectedItem.Text.substring(0, 1) = "-" Then
                Me.Text = _TempText
            End If
        End Sub
    
    #End Region
    
    #Region "Definition:Class_ComboItem"
    
        Private Class ComboItem
    
    #Region "Declaration:Variable"
    
            Private _Text As String
            Private _Font As Font
            Private _IconIndex As Integer = -1
            Private _IconFile As String
            Private _Icon As Icon
            Private _Enabled As Boolean = True
    
    #End Region
    
    #Region "Implementation:Properties"
    
            Public Sub New(ByVal ItemText As String, ByVal ItemIconIndex As Integer, ByVal ItemFont As Font)
                _Text = ItemText
                _IconIndex = ItemIconIndex
                _Font = ItemFont
            End Sub
            Public Property Text() As String
                Get
                    Return _Text
                End Get
                Set(ByVal Value As String)
                    _Text = Value
                End Set
            End Property
            Public Property Font() As Font
                Get
                    Return _Font
                End Get
                Set(ByVal Value As Font)
                    _Font = Value
                End Set
            End Property
            Public Property IconIndex() As Integer
                Get
                    Return _IconIndex
                End Get
                Set(ByVal Value As Integer)
                    _IconIndex = Value
                End Set
            End Property
            Public Property IconFile() As String
                Get
                    Return _IconFile
                End Get
                Set(ByVal Value As String)
                    _IconFile = Value
                End Set
            End Property
            Public Property Icon() As Icon
                Get
                    Return _Icon
                End Get
                Set(ByVal Value As Icon)
                    _Icon = Value
                End Set
            End Property
            Public Property Enabled() As Boolean
                Get
                    Return _Enabled
                End Get
                Set(ByVal Value As Boolean)
                    _Enabled = Value
                End Set
            End Property
            Public Overrides Function ToString() As String
                Return _Text
            End Function
    #End Region
        End Class
    #End Region
    End Class
    Your code is also very helpful Hannes. I think now, we could build a super dooper combo, so far hitherto unknown to the people in this area
    Last edited by HairyMonkeyMan; November 27th, 2007 at 11:35 AM.
    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning. - Rich Cook


    0100 1101 0110 1001 0110 0011 0110 1000 0110 0001 0110 0101 0110 1100 0010 0000 0100 0101 0110 1100 0110 1100 0110 0101 0111 0010

  4. #4
    Join Date
    Jun 2004
    Location
    NH
    Posts
    678

    Re: How to disable ComboBox / ListBox Items

    Hey guys I found this topic interesting too.
    I'll try to come up with a general API example.

    Hey Hannes, are you setting the selected index back to 0, or -1?
    I guess it doesn't matter at that point, but I just wanted to be sure of what you are saying.
    Do you simply handle the error if it's -1?
    I'm using version 2008, so maybe it's a little different.

  5. #5
    Join Date
    Jul 2001
    Location
    Sunny South Africa
    Posts
    11,283

    Re: How to disable ComboBox / ListBox Items

    Hey thanx guys, just glad I could help a little
    In my example, I set the SelectedIndex back to 0, but I think best would be to set it to -1, then catch the error & exit the sub. The whole reasoning behind this, is because when someone selects an unwanted item ( which we don't want ), it still gets displayed inside the textbox of the combo, which it mustn't.

    I'll also see what I can come up with ...

  6. #6
    Join Date
    Nov 2007
    Posts
    110

    Re: How to disable ComboBox / ListBox Items

    If I understand your problem correctly, you just need to be able to set items to be disabled so that they are not selectable?

    I had a similar problem a few days ago, so I wrote my own combobox that allows you to do just that. I am planning on writing up an article and submitting it to codeproject.com, but I can send you the .dll for it if you would like. I am about 98% complete (still doing testing and tweaking a few things) but it is quite usable.

  7. #7
    Join Date
    Jun 2004
    Location
    NH
    Posts
    678

    SendMessage CB_ LB_

    Here are some helpful API demos, for generally dealing with the combobox on almost ANY application.
    Since there are many paths of logic possible, I've left it open to the readers to come up with different ideas.
    The ListBox constants start with the prefix LB_ but I've only included CB_ constants here.
    It should be easy to disable a combo item, by placing a crude mouse hook, or message hook, in combination with one or more examples below.

    Code:
    Public Class Form1
        ' Const CB_GETEDITSEL As Int32 = 320 'Combobox
        ' Const CB_LIMITTEXT As Int32 = 321
        ' Const CB_SETEDITSEL As Int32 = 322
        Const CB_ADDSTRING As Int32 = 323
        Const CB_DELETESTRING As Int32 = 324
        ' Const CB_DIR As Int32 = 325
        Const CB_GETCOUNT As Int32 = 326
        Const CB_GETCURSEL As Int32 = 327
        Const CB_GETLBTEXT As Int32 = 328
        Const CB_GETLBTEXTLEN As Int32 = 329
        Const CB_INSERTSTRING As Int32 = 330
        Const CB_RESETCONTENT As Int32 = 331
        Const CB_FINDSTRING As Int32 = 332
        Const CB_SELECTSTRING As Int32 = 333
        Const CB_SETCURSEL As Int32 = 334
        Const CB_SHOWDROPDOWN As Int32 = 335
        'Const CB_GETITEMDATA As Int32 = 336
        'Const CB_SETITEMDATA As Int32 = 337
        'Const CB_GETDROPPEDCONTROLRECT As Int32 = 338
        'Const CB_SETITEMHEIGHT As Int32 = 339
        'Const CB_GETITEMHEIGHT As Int32 = 340
        'Const CB_SETEXTENDEDUI As Int32 = 341
        'Const CB_GETEXTENDEDUI As Int32 = 342
        Const CB_GETDROPPEDSTATE As Int32 = 343
        Const CB_FINDSTRINGEXACT As Int32 = 344
        'Const CB_SETLOCALE As Int32 = 345
        'Const CB_GETLOCALE As Int32 = 346
        'Const CB_GETTOPINDEX As Int32 = 347
        'Const CB_SETTOPINDEX As Int32 = 348
        'Const CB_GETHORIZONTALEXTENT As Int32 = 349
        'Const CB_SETHORIZONTALEXTENT As Int32 = 350
        'Const CB_GETDROPPEDWIDTH As Int32 = 351
        'Const CB_SETDROPPEDWIDTH As Int32 = 352
        'Const CB_INITSTORAGE As Int32 = 354
        'Const CB_MSGMAX As Int32 = 354
        Private Declare Function apiSendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Int32, ByVal wMsg As Int32, ByVal wParam As Int32, ByVal lParam As String) As Int32
        Private Declare Function apiFindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Int32 'Retrieves the handle to the top-level window whose class name and window name match the specified strings. This function does not search child windows.
        Private Declare Function apiFindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Int32, ByVal hWnd2 As Int32, ByVal lpsz1 As String, ByVal lpsz2 As String) As Int32 'The FindWindowEx function retrieves the handle to a window whose class name and window name match the specified strings. The function searches child windows, beginning with the one following the given child window.
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim hwnd As Int32 = apiFindWindow(Nothing, Me.Text)
    
            'You'll need to get the class name of your combobox first to insert below.  Here it is "WindowsForms10.COMBOBOX.app.0.378734a", but this will vary from simply "COMBOBOX".
            Dim cwnd As Int32 = apiFindWindowEx(hwnd, 0, "WindowsForms10.COMBOBOX.app.0.378734a", Nothing)
            ' Dim ewnd As Int32 = apiFindWindowEx(cwnd, 0, "Edit", Nothing) 'The editable window
    
            'simply returns the item count
            MessageBox.Show(apiSendMessage(cwnd, CB_GETCOUNT, 0, Nothing))
    
            'Finds the specified string item(lParam), and returns the item's index. CB_FINDSTRING similar
            'MessageBox.Show(apiSendMessage(cwnd, CB_FINDSTRINGEXACT, 0, "two"))
    
            'Returns the index of the currently selected item by the user
            'MessageBox.Show(apiSendMessage(cwnd, CB_GETCURSEL, 0, Nothing))
    
            'Selects a specified string item position(wParam) > 0, and returns nonzero if success
            'MessageBox.Show(apiSendMessage(cwnd, CB_SETCURSEL, 2, Nothing))
    
            'Selects a specified string item(lParam), and returns it's index
            'MessageBox.Show(apiSendMessage(cwnd, CB_SELECTSTRING, 0, "three"))
    
            'Add a string item at the specified position(wParam), and returns the total item count
            'MessageBox.Show(apiSendMessage(cwnd, CB_ADDSTRING, 0, "New item"))
    
            'inserts a string item at the specified position(wParam) > 0, and returns non zero upon success.
            'MessageBox.Show(apiSendMessage(cwnd, CB_INSERTSTRING, 1, "inserted"))
    
            'deletes a string item at the specified position(wParam), and returns the total item count
            'MessageBox.Show(apiSendMessage(cwnd, CB_DELETESTRING, 0, Nothing))
    
            'returns the index of the specified string item(lParam)
            ' MessageBox.Show(apiSendMessage(cwnd, CB_GETLBTEXT, 0, "two"))
    
            'returns the length of the specified string item position(wParam).
            'MessageBox.Show(apiSendMessage(cwnd, CB_GETLBTEXTLEN, 4, Nothing))
    
            'Drop the combobox down, making it visible to the user, and returns nonzero upon success.
            'apiSendMessage(cwnd, CB_SHOWDROPDOWN, 1, Nothing)
    
            'Drop the combobox down, and see if it's dropped down or not
            'apiSendMessage(cwnd, CB_SHOWDROPDOWN, 1, Nothing)
            'MessageBox.Show(apiSendMessage(cwnd, CB_GETDROPPEDSTATE, 0, Nothing)) 'return nonzero if dropped.
    
            'reset all item content to empty string, returns nonzero if success
            'MessageBox.Show(apiSendMessage(cwnd, CB_RESETCONTENT, 0, Nothing))
    
        End Sub
    End Class
    Here is the project in a zip below:
    Attached Files Attached Files
    Last edited by TT(n); November 29th, 2007 at 01:21 AM.

  8. #8
    Join Date
    Jul 2001
    Location
    Sunny South Africa
    Posts
    11,283

    Re: SendMessage CB_ LB_

    Quote Originally Posted by jshultz
    I had a similar problem a few days ago, so I wrote my own combobox that allows you to do just that. I am planning on writing up an article and submitting it to codeproject.com, but I can send you the .dll for it if you would like. I am about 98% complete (still doing testing and tweaking a few things) but it is quite usable.
    Welcome to the forums!
    Just a note, you can also submit articles to CodeGuru, and an article based on this topic will surely be welcomed
    Here's more details :
    http://www.codeguru.com/edit-article.php

    Quote Originally Posted by TT(n)
    Here are some helpful API demos, for generally dealing with the combobox on almost ANY application.
    Since there are many paths of logic possible, I've left it open to the readers to come up with different ideas.
    The ListBox constants start with the prefix LB_ but I've only included CB_ constants here.
    It should be easy to disable a combo item, by placing a crude mouse hook, or message hook, in combination with one or more examples below.
    Nice finds!!!!
    Let me start playing

  9. #9
    Join Date
    Nov 2007
    Posts
    110

    Re: SendMessage CB_ LB_

    Quote Originally Posted by HanneSThEGreaT
    Welcome to the forums!
    Just a note, you can also submit articles to CodeGuru, and an article based on this topic will surely be welcomed
    Here's more details :
    http://www.codeguru.com/edit-article.php
    Thanks, and thanks =-). I am new to this site, didn't know you could submit articles. I believe I have finished up the project, so I will start writing up the article soon. Probably on lunch today and over the weekend, hopefully i'll be able to get it done by the beginning of next week.

  10. #10
    Join Date
    Jul 2001
    Location
    Sunny South Africa
    Posts
    11,283

    Re: SendMessage CB_ LB_

    That's good news!
    From time to time, we also have competitions for the best articles, where you can win money

  11. #11
    Join Date
    Jul 2011
    Posts
    1

    Re: How to disable ComboBox / ListBox Items

    Quote Originally Posted by HairyMonkeyMan View Post
    Greets guys,

    I need to extend a combobox to disable some listitems (i.e splits - "----------").

    I reckon some APIs will be involved, and it could get complicated. That'll not put me off though.

    If anyone with usefull info on the subject could post it, I'd really appreciate it.

    Thanks

    Combobox.Items(index).IsEnabled = False

  12. #12
    Join Date
    Jul 2008
    Location
    WV
    Posts
    5,362

    Re: How to disable ComboBox / ListBox Items

    The question is over 3 years old, very little chance that the poster is still looking for the answer.
    Always use [code][/code] tags when posting code.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured