none
Como bloquear um ComboBox para edição sem deixá-lo na escuridão?

    問題

  •  

    Não achei nada no forum que esclarecesse minha dúvida.

     

    No VB.net

     

    Não achei uma propriedade que bloqueasse a edição de um ComboBox em meu formulário.

     

    Esse controle mostra uma coluna de uma tabela (sql).

    Meu programa checa a que grupo de usuários o fulano pertence e se ele pertencer a um que não tenha permissão de edição desse campo, o programa coloca o controle como ComboBox.Enabled=false. Até ai tubo bem.

     

    MAS TUDO FICA CINZA E NÃO CONSIGO MUDAR A COR DO TEXTO. FICA HORRÍVEL!

     

    Nos TextBox é mole. Coloco a propridade do controle como: TextBox.ReadOnly=True e tudo resolvido.

     

    Como posso travar meu ComboBox e ao mesmo tempo deixá-lo "Bonitinho"?

     

    Bobrigado

    2008年11月22日 21:18

解答

  • Você teria que estender o controle e adicionar a funcionalidade, controlando o desenho do controle etc.

    Um jeito um pouco mais simples, mas que também necessita da estensão do controle, é adicionar um painel transparente à frente do controle para que não seja possível clicá-lo e impedir que o controle ganhe o foco com o teclado. Não é difícil. Algo assim:


    Option Strict On
    Option Explicit On

    Imports System
    Imports System.Drawing
    Imports System.Windows.Forms

    Public Class ComboBoxEx
        Inherits ComboBox

        Private Const WM_NCHITTEST As Integer = &H84
        Private Const WS_EX_TRANSPARENT As Integer = &H20
        Private _panel As PanelEx = Nothing
        Private _readOnly As Boolean = False

        Public Property [ReadOnly]() As Boolean
            Get
                Return _readOnly
            End Get
            Set(ByVal Value As Boolean)
                _readOnly = Value

                If _readOnly Then
                    Call Desabilitar()
                Else
                    Call Habilitar()
                End If
            End Set
        End Property

        Private Sub Desabilitar()
            _panel = New PanelEx()

            _panel.Width = Me.Width
            _panel.Height = Me.Height
            _panel.Left = 0
            _panel.Top = 0
            _panel.BringToFront()

            Me.Controls.Add(_panel)
            Me.TabStop = False ' Impede que o controle ganhe o foco com o TAB.
            ' Garante que nenhum caractere esteja selecionado.
            If Me.DropDownStyle = ComboBoxStyle.DropDown Then Me.Select(00)
            Me.Invalidate() ' Redesenha.
        End Sub

        Private Sub Habilitar()
            If _panel IsNot Nothing Then
                Me.Controls.Remove(_panel)
                _panel = Nothing
                Me.TabStop = True ' Permite que o controle ganhe o foco com o TAB.
                ' Garante que nenhum caractere esteja selecionado.
                If Me.DropDownStyle = ComboBoxStyle.DropDown Then Me.Select(00)
                Me.Invalidate()   ' Redesenha.
            End If
        End Sub

        Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
            ' Impede que algum tipo de interação do mouse com o
            ' controle realce o botão.
            If (m.Msg = WM_NCHITTEST) AndAlso _readOnly Then
                Return
            End If
            MyBase.WndProc(m)
        End Sub

        Private Class PanelEx
            Inherits Panel


            ' Retorna o painel com estilo transparente.
            Protected Overloads Overrides ReadOnly Property CreateParams() As CreateParams
                Get
                    Dim cp As CreateParams = MyBase.CreateParams
                    cp.ExStyle = cp.ExStyle Or WS_EX_TRANSPARENT
                    Return cp
                End Get
            End Property

            Protected Overrides Sub OnPaintBackground(ByVal e As System.Windows.Forms.PaintEventArgs)
                ' Não faz nada.
            End Sub

            Protected Overloads Overrides Sub OnPaint(ByVal e As PaintEventArgs)
                Dim b As New SolidBrush(Color.Transparent)

                e.Graphics.FillRectangle(b, New Rectangle(00Me.Width, Me.Height))

                ' Desenha um botão de ComboBox sobre o painel exatamente sobre o botão do ComBox pai.
                ' O botão do ComboBox tem a mesma largura da barra de rolagem vertical, assim obtemos a largura dele com VerticalScrollBarWidth.
                If ComboBoxRenderer.IsSupported Then ' Se estamos usando Visual Styles.
                    ComboBoxRenderer.DrawDropDownButton(e.Graphics, _
                                     New Rectangle(Me.Width - SystemInformation.VerticalScrollBarWidth - SystemInformation.Border3DSize.Width, _
                                     SystemInformation.Border3DSize.Height, _
                                     SystemInformation.VerticalScrollBarWidth, _
                                     (Me.Height - SystemInformation.Border3DSize.Height) - SystemInformation.Border3DSize.Height), _
                                     VisualStyles.ComboBoxState.Disabled)
                Else  ' Se não estamos usando Visual Styles.
                    ControlPaint.DrawComboButton(e.Graphics, _
                                 New Rectangle(Me.Width - SystemInformation.VerticalScrollBarWidth - SystemInformation.Border3DSize.Width, _
                                 SystemInformation.Border3DSize.Height, _
                                 SystemInformation.VerticalScrollBarWidth, _
                                 (Me.Height - SystemInformation.Border3DSize.Height) - SystemInformation.Border3DSize.Height), _
                                 ButtonState.Inactive)
                End If
            End Sub
        End Class
    End Class


    Para haver ao menos alguma indicação de que o controle está desabilitado eu desenho um botão de ComboBox desabilitado sobre o painel gerado. O estilo do botão é feito para corresponder ao estilo padrão do Combo (FlatStyle = Standard). Para outro estilos você teria que adicionar mais código para simular os estilos exatamente.

    Para usar a funcionalidade criada ajuste a propriedade ReadOnly do ComboBox estendido (como num TextBox).
    2008年11月23日 19:33

所有回覆

  • Você teria que estender o controle e adicionar a funcionalidade, controlando o desenho do controle etc.

    Um jeito um pouco mais simples, mas que também necessita da estensão do controle, é adicionar um painel transparente à frente do controle para que não seja possível clicá-lo e impedir que o controle ganhe o foco com o teclado. Não é difícil. Algo assim:


    Option Strict On
    Option Explicit On

    Imports System
    Imports System.Drawing
    Imports System.Windows.Forms

    Public Class ComboBoxEx
        Inherits ComboBox

        Private Const WM_NCHITTEST As Integer = &H84
        Private Const WS_EX_TRANSPARENT As Integer = &H20
        Private _panel As PanelEx = Nothing
        Private _readOnly As Boolean = False

        Public Property [ReadOnly]() As Boolean
            Get
                Return _readOnly
            End Get
            Set(ByVal Value As Boolean)
                _readOnly = Value

                If _readOnly Then
                    Call Desabilitar()
                Else
                    Call Habilitar()
                End If
            End Set
        End Property

        Private Sub Desabilitar()
            _panel = New PanelEx()

            _panel.Width = Me.Width
            _panel.Height = Me.Height
            _panel.Left = 0
            _panel.Top = 0
            _panel.BringToFront()

            Me.Controls.Add(_panel)
            Me.TabStop = False ' Impede que o controle ganhe o foco com o TAB.
            ' Garante que nenhum caractere esteja selecionado.
            If Me.DropDownStyle = ComboBoxStyle.DropDown Then Me.Select(00)
            Me.Invalidate() ' Redesenha.
        End Sub

        Private Sub Habilitar()
            If _panel IsNot Nothing Then
                Me.Controls.Remove(_panel)
                _panel = Nothing
                Me.TabStop = True ' Permite que o controle ganhe o foco com o TAB.
                ' Garante que nenhum caractere esteja selecionado.
                If Me.DropDownStyle = ComboBoxStyle.DropDown Then Me.Select(00)
                Me.Invalidate()   ' Redesenha.
            End If
        End Sub

        Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
            ' Impede que algum tipo de interação do mouse com o
            ' controle realce o botão.
            If (m.Msg = WM_NCHITTEST) AndAlso _readOnly Then
                Return
            End If
            MyBase.WndProc(m)
        End Sub

        Private Class PanelEx
            Inherits Panel


            ' Retorna o painel com estilo transparente.
            Protected Overloads Overrides ReadOnly Property CreateParams() As CreateParams
                Get
                    Dim cp As CreateParams = MyBase.CreateParams
                    cp.ExStyle = cp.ExStyle Or WS_EX_TRANSPARENT
                    Return cp
                End Get
            End Property

            Protected Overrides Sub OnPaintBackground(ByVal e As System.Windows.Forms.PaintEventArgs)
                ' Não faz nada.
            End Sub

            Protected Overloads Overrides Sub OnPaint(ByVal e As PaintEventArgs)
                Dim b As New SolidBrush(Color.Transparent)

                e.Graphics.FillRectangle(b, New Rectangle(00Me.Width, Me.Height))

                ' Desenha um botão de ComboBox sobre o painel exatamente sobre o botão do ComBox pai.
                ' O botão do ComboBox tem a mesma largura da barra de rolagem vertical, assim obtemos a largura dele com VerticalScrollBarWidth.
                If ComboBoxRenderer.IsSupported Then ' Se estamos usando Visual Styles.
                    ComboBoxRenderer.DrawDropDownButton(e.Graphics, _
                                     New Rectangle(Me.Width - SystemInformation.VerticalScrollBarWidth - SystemInformation.Border3DSize.Width, _
                                     SystemInformation.Border3DSize.Height, _
                                     SystemInformation.VerticalScrollBarWidth, _
                                     (Me.Height - SystemInformation.Border3DSize.Height) - SystemInformation.Border3DSize.Height), _
                                     VisualStyles.ComboBoxState.Disabled)
                Else  ' Se não estamos usando Visual Styles.
                    ControlPaint.DrawComboButton(e.Graphics, _
                                 New Rectangle(Me.Width - SystemInformation.VerticalScrollBarWidth - SystemInformation.Border3DSize.Width, _
                                 SystemInformation.Border3DSize.Height, _
                                 SystemInformation.VerticalScrollBarWidth, _
                                 (Me.Height - SystemInformation.Border3DSize.Height) - SystemInformation.Border3DSize.Height), _
                                 ButtonState.Inactive)
                End If
            End Sub
        End Class
    End Class


    Para haver ao menos alguma indicação de que o controle está desabilitado eu desenho um botão de ComboBox desabilitado sobre o painel gerado. O estilo do botão é feito para corresponder ao estilo padrão do Combo (FlatStyle = Standard). Para outro estilos você teria que adicionar mais código para simular os estilos exatamente.

    Para usar a funcionalidade criada ajuste a propriedade ReadOnly do ComboBox estendido (como num TextBox).
    2008年11月23日 19:33
  • Angus... Obrigado.

    Vou Tentar.

     

    "Mas que é difícil...É!"

    A Microsoft devia ter pensado nisso.

     

    Abraço.

     

    2008年11月24日 22:41
  •  Utilizando no evento KeyPress de sua combo o comando

    e.Handled = True

    vc consegue travar o teclado para que nada seja digitado


    vc pode tentar ajustar esta rotina para o programa definir a propriedade de e.Handled para 'True' ou 'False' dependendo do usuário

    Abraço!

    2009年2月16日 20:11
  • Há ainda mais uma opção;

    Para ninguém digitar nada na combobox, além de configurar a propriedade descrita acíma como true para o evento KeyPress e KeyDown, você ainda pode configurar no evendo Dropdown da combo a propriedade height =1 e depois para destrancar é só voltar o valor original. Exemplo:

    No evento DropDown da combo você verifica se o valor da propriedade é maior que 1, e se for, com uma variável stática guarda este valor:

    Static

     

    lAltura As Long

     

    If ComboBox1.DropDownHeight > 1 Then

    lAltura = ComboBox1.DropDownHeight

     

    End If

     

    If mbLiberar = False Then

    ComboBox1.DropDownHeight = 1

     

    Else

    ComboBox1.DropDownHeight = lAltura

     

    End If

    2011年3月11日 15:09
  • Muito simples

    Muda o evento DropDownList para DropDownList.

    2012年2月25日 17:59
  •   Acho que a melhor solução é colocar o Combobox como DropDownList nas propriedades e Enabled=False. :D

    2012年8月14日 17:55