שתף באמצעות


VB.Net Combobox Text Alignment

Question

Saturday, February 13, 2016 10:29 AM

Hi There 

Is There A Way For Combobox To Center Align Its Text 

Regards

All replies (6)

Saturday, February 13, 2016 10:49 AM ✅Answered

Hello,

See the answer here. In short center align is not supported, you need to use a custom ComboBox.

Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
VB Forums - moderator


Saturday, February 13, 2016 11:54 AM ✅Answered

 Just to add,  the example at the link provided by  Kareninstructor will work good if you want to have your ComboBox.DropDownStyle set to DropDownList so that you can not type anything into the ComboBox.  However,  if you want the DropDownStyle set to the standard DropDown style so the user can type in the combobox then below is an example of creating a small combobox class that does that.

Imports System.Runtime.InteropServices

Public Class ComboBoxEx
    Inherits ComboBox

    Protected Overrides Sub OnHandleCreated(ByVal e As System.EventArgs)
        MyBase.OnHandleCreated(e)
        CenterText()
    End Sub

    Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs)
        CenterText()
        MyBase.OnTextChanged(e)
    End Sub

    Private Sub CenterText()
        If Not Me.DropDownStyle = ComboBoxStyle.DropDownList Then
            Dim hEdit As IntPtr = Apis.FindWindowExW(Me.Handle, IntPtr.Zero, "Edit", Nothing)
            If Not hEdit = IntPtr.Zero Then
                Dim textWidth As Integer = TextRenderer.MeasureText(Me.Text, Me.Font).Width
                Dim rct As Apis.RECT
                Apis.GetWindowRect(hEdit, rct)
                Dim leftMargin As Integer = (rct.Width - textWidth) \ 2
                Apis.SendMessageW(hEdit, Apis.EM_SETMARGINS, Apis.EC_LEFTMARGIN, leftMargin)
            End If
        End If
    End Sub
End Class


Public Class Apis
    <StructLayout(LayoutKind.Sequential)> _
    Public Structure RECT
        Public left, top, right, bottom As Integer
        Public ReadOnly Property Width As Integer
            Get
                Return (Me.right - Me.left)
            End Get
        End Property
    End Structure

    Public Const EM_SETMARGINS As Integer = &HD3
    Public Const EC_LEFTMARGIN As Integer = &H1

    <DllImport("user32.dll", EntryPoint:="FindWindowExW")> _
    Public Shared Function FindWindowExW(ByVal hWndParent As IntPtr, ByVal hWndChildAfter As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszClass As String, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszWindow As String) As IntPtr
    End Function

    <DllImport("user32.dll", EntryPoint:="GetWindowRect")> _
    Public Shared Function GetWindowRect(ByVal hWnd As IntPtr, ByRef lpRect As RECT) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    <DllImport("user32.dll", EntryPoint:="SendMessageW")> _
    Public Shared Function SendMessageW(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As UInteger, ByVal lParam As Integer) As Integer
    End Function
End Class

If you say it can`t be done then i`ll try it


Wednesday, March 20, 2019 2:56 AM

Hi Dear

The Above Code works for Center, but How can it be modify to Align Right Rather than Center? Please help Me


Friday, April 5, 2019 8:08 PM

Hi Dear

The Above Code works for Center, but How can it be modify to Align Right Rather than Center? Please help Me

 You can simply remove the  \ 2  from the end of the line in the CenterText Sub,  the line below. 

Dim leftMargin As Integer = (rct.Width - textWidth) \ 2

 

 Or if you are interested,  you could modify the sub so that you can pass a Left, Center, or Right horizontal alignment to it like the below example.  Notice I added a TextAlign property to the ComboBoxEx class which can be used to set the text alignment.

Imports System.Runtime.InteropServices

Public Class Form1
    Private Sub RadioButton1_CheckedChanged(sender As Object, e As EventArgs) Handles RadioButton1.CheckedChanged, RadioButton2.CheckedChanged, RadioButton3.CheckedChanged
        Select Case True
            Case RadioButton1.Checked
                ComboBoxEx1.TextAlign = HorizontalAlignment.Left
            Case RadioButton2.Checked
                ComboBoxEx1.TextAlign = HorizontalAlignment.Center
            Case RadioButton3.Checked
                ComboBoxEx1.TextAlign = HorizontalAlignment.Right
        End Select
    End Sub
End Class


Public Class ComboBoxEx
    Inherits ComboBox

    Private _TextAlign As HorizontalAlignment = HorizontalAlignment.Left
    Public Property TextAlign As HorizontalAlignment
        Get
            Return _TextAlign
        End Get
        Set(value As HorizontalAlignment)
            If value <> _TextAlign Then
                _TextAlign = value
                SetTextAlignment(_TextAlign)
            End If
        End Set
    End Property

    Protected Overrides Sub OnHandleCreated(ByVal e As EventArgs)
        MyBase.OnHandleCreated(e)
        SetTextAlignment(TextAlign)
    End Sub

    Protected Overrides Sub OnTextChanged(ByVal e As EventArgs)
        SetTextAlignment(TextAlign)
        MyBase.OnTextChanged(e)
    End Sub

    Private Sub SetTextAlignment(alignment As HorizontalAlignment)
        If Not Me.DropDownStyle = ComboBoxStyle.DropDownList Then
            Dim hEdit As IntPtr = Apis.FindWindowExW(Me.Handle, IntPtr.Zero, "Edit", Nothing)
            If Not hEdit = IntPtr.Zero Then
                Dim textWidth As Integer = TextRenderer.MeasureText(Me.Text, Me.Font).Width
                Dim rct As Apis.RECT
                Apis.GetWindowRect(hEdit, rct)
                Dim leftMargin As Integer = 0 '0 would be the Left alignment
                If alignment = HorizontalAlignment.Center Then
                    leftMargin = (rct.Width - textWidth) \ 2
                ElseIf alignment = HorizontalAlignment.Right Then
                    leftMargin = (rct.Width - textWidth)
                End If
                Apis.SendMessageW(hEdit, Apis.EM_SETMARGINS, Apis.EC_LEFTMARGIN, leftMargin)
            End If
        End If
    End Sub
End Class


Public Class Apis
    <StructLayout(LayoutKind.Sequential)>
    Public Structure RECT
        Public left, top, right, bottom As Integer
        Public ReadOnly Property Width As Integer
            Get
                Return (Me.right - Me.left)
            End Get
        End Property
    End Structure

    Public Const EM_SETMARGINS As Integer = &HD3
    Public Const EC_LEFTMARGIN As Integer = &H1

    <DllImport("user32.dll", EntryPoint:="FindWindowExW")>
    Public Shared Function FindWindowExW(ByVal hWndParent As IntPtr, ByVal hWndChildAfter As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszClass As String, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszWindow As String) As IntPtr
    End Function

    <DllImport("user32.dll", EntryPoint:="GetWindowRect")>
    Public Shared Function GetWindowRect(ByVal hWnd As IntPtr, ByRef lpRect As RECT) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    <DllImport("user32.dll", EntryPoint:="SendMessageW")>
    Public Shared Function SendMessageW(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As UInteger, ByVal lParam As Integer) As Integer
    End Function
End Class

 

 Here is the example I posted above...

If you say it can`t be done then i`ll try it


Friday, April 5, 2019 8:49 PM | 1 vote

The Above Code works for Center, but How can it be modify to Align Right Rather than Center? Please help Me

For DropDown ComboBoxes, you can also just set the ES_RIGHT style to the Edit control 


Friday, April 5, 2019 11:24 PM

For DropDown ComboBoxes, you can also just set the ES_RIGHT style to the Edit control 

 Yes that will work too.  8)

 Just to let others know,  it seems that you can only set the ES_LEFT, ES_CENTER, and ES_RIGHT styles just once when the control is created but,  can not change them after that unless you dispose and then recreate a new ComboBox with the new style.  Not sure if that was of any concern or not though.

 So,  if you plan on keeping the text right aligned all the time,  this works.  This example can be tested in a Form with 3 standard ComboBox controls on it.  Again,  they must all have their DropDownStyle property set to DropDown.

 It may also be worth noting that the msdn documents recommend using the GetWindowLongPtr and SetWindowLongPtr functions to make your app compatible with 32 and 64 bit windows versions.

 Also,  I did not include the constant for the ES_LEFT style because,  that is the default style and would not need to be set.

Imports System.Runtime.InteropServices

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        SetComboBoxTextAlignment(ComboBox2, ES_CENTER)
        SetComboBoxTextAlignment(ComboBox3, ES_RIGHT)
    End Sub

    Private Sub SetComboBoxTextAlignment(cbx As ComboBox, txtalign As Integer)
        Dim hEdit As IntPtr = FindWindowExW(cbx.Handle, IntPtr.Zero, "EDIT", Nothing)
        Dim Style As Integer = GetWindowLongW(hEdit, GWL_STYLE)
        SetWindowLongW(hEdit, GWL_STYLE, Style Or txtalign)
    End Sub

    Const ES_CENTER As Integer = &H1
    Const ES_RIGHT As Integer = &H2
    Const GWL_STYLE As Integer = -16

    <DllImport("user32.dll", EntryPoint:="GetWindowLongW")>
    Public Shared Function GetWindowLongW(ByVal hWnd As IntPtr, ByVal nIndex As Integer) As Integer
    End Function

    <DllImport("user32.dll", EntryPoint:="SetWindowLongW")>
    Public Shared Function SetWindowLongW(ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As Integer) As Integer
    End Function

    <DllImport("user32.dll", EntryPoint:="FindWindowExW")>
    Public Shared Function FindWindowExW(ByVal hWndParent As IntPtr, ByVal hWndChildAfter As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszClass As String, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszWindow As String) As IntPtr
    End Function
End Class

 

 

If you say it can`t be done then i`ll try it