SearchBox Week, Day 1

It's Searchbox Week on Code For Excel And Outlook Blog! That means that every day this week, I will pick out a search term from the previous day and post some code based on it. I'll do my best to interpret the searcher's intent, and post some VBA code (or maybe a formula) to solve a problem.

So if you've used the searchbox, or plan to, you might see some related code right here very soon.

Let's start with a search from this past weekend. There were a few searches for the word "alignment".

You can use VBA to position text within a cell. The horizontal and vertical options in VBA are almost identical to the options listed in the Format Cells dialog boxes in Excel. For horizontal they are as follows:

HorizontalAlignment Property

horizontal

VBA Options:

  • xlGeneral
  • xlLeft
  • xlCenter
  • xlRight
  • xlFill
  • xlJustify
  • xlCenterAcrossSelection
  • xlDistributed

VerticalAlignment Property

vertical

VBA Options:

  • xlTop
  • xlCenter
  • xlBottom
  • xlJustify
  • xlDistributed

The following sample code sets the horizontal alignment to Left and the vertical alignment to Center for a given worksheet range.

Sub rngAlign()
Dim rng As Excel.Range

Set rng = Range("B1:B10")
With rng
  .HorizontalAlignment = xlLeft
  .VerticalAlignment = xlCenter
End With

  Set rng = Nothing
End Sub

And a slightly more advanced sub that takes a range argument, making the original code a bit more flexible:

Sub rngAlign(rng As Excel.Range)
Dim rRng As Excel.Range

On Error Resume Next
Set rRng = Range(rng)
On Error GoTo 0

If rRng Is Nothing Then GoTo ExitProc

With rRng
  .HorizontalAlignment = xlLeft
  .VerticalAlignment = xlCenter
End With

ExitProc:
Set rRng = Nothing
End Sub

And a function version that returns a True/False value to the calling sub, so you can check the success of the operation:

Function rngAlign(rng As Excel.Range) As Boolean
Dim rRng As Excel.Range

On Error GoTo ErrorExit
Set rRng = Range(rng)

With rRng
  .HorizontalAlignment = xlLeft
  .VerticalAlignment = xlCenter
End With

'assume success
rngAlign = True
GoTo ExitProc

ErrorExit:
rngAlign = False

ExitProc:
Set rRng = Nothing
End Function

And a final version that takes a Range argument, and two strings indicating the horizontal and vertical alignment you want:

Function rngAlign(rng As Excel.Range, Horizontal As String, Vertical As String) As Boolean
Dim rRng As Excel.Range
Dim horiz As Integer, vert As Integer

On Error GoTo ErrorExit
Set rRng = rng

Select Case Horizontal
  Case "General"
    horiz = 1
  Case "Left"
    horiz = -4131
  Case "Center"
    horiz = -4108
  Case "Right"
    horiz = -4152
  Case "Fill"
    horiz = 5
  Case "Justify"
    horiz = -4130
  Case "Center Across Selection"
    horiz = 7
  Case "Distributed"
    horiz = -4117
End Select

Select Case Vertical
  Case "Top"
    vert = -4160
  Case "Center"
    vert = -4108
  Case "Bottom"
    vert = -4107
  Case "Justify"
    vert = -4130
  Case "Distributed"
    vert = -4117
End Select

With rRng
  .HorizontalAlignment = horiz
  .VerticalAlignment = vert
End With

'assume success
rngAlign = True
GoTo ExitProc

ErrorExit:
rngAlign = False

ExitProc:
Set rRng = Nothing
End Function

To use the above function, just pass the appropriate arguments to it. For the last two arguments, use the names from the Format Cells dialog box. Don't use the "(Indent)" portion of the name. If you want to use the "Center Across Selection" option, just pass it that way and the function will automatically remove the spaces. Ex:

Dim bSuccess As Boolean
bSuccess = rngAlign(Range("A1:A10"), "Center", "Top")
If bSuccess Then
  MsgBox "You did it!"
End If

The alignment values are integers, so you can't pass strings directly to them. I converted the constants to their integer values.

Notes:

  • The horizontal alignment value xlGeneral will reset the cell format to its default. So if you have a mix of number-only and letter-only cells in the range you are acting on, and all of the cells were aligned center, the number-only cells will align right and the letter-only cells will align left.
  • In some cases, you won't notice the changes until you change the height or width of the rows or columns (respectively). For example, if you autofit the column and then change the horizontal alignment from xlGeneral to xlCenter you won't notice it until you widen the column (manually or programmatically).

Related Articles:

About JP

I'm just an average guy who writes VBA code for a living. This is my personal blog. Excel and Outlook are my thing, with a sprinkle of Access and Word here and there. Follow this space to learn more about VBA. Keep Reading »

Share This Article:

Share and bookmark this articledelicious buttonfacebook buttonlinkedin buttonstumbleupon buttontwitter button

comment bubble 3 Comments:

  1. Peder Schmedling writes:

    Great post JP, I'm looking forward to get a peak into what people are searching for.

    In order to improve user-friendliness of the rngAlign function I would suggest to enumerate the valid alignment options. This way the programmer using the function would get access the valid options when using the function through intellisense.

    Also I can't see why you need the line

    If rRng Is Nothing Then GoTo ErrorExit

    This problem would be handled by the error handling when the With statement is executed anyway..?

    I took the liberty of formalizing the code a bit to show how I personally would implement a function to provide essentially the same functionality:

    'Enumerate available Vertical alignements
    Public Enum vacVerticalAlignement
        vacTop = xlTop
        vacCenter = xlCenter
        vacBottom = xlBottom
        vacJustify = xlJustify
        vacDistributed = xlDistributed
    End Enum
    
    'Enumerate available Horizontal alignements
    Public Enum hacHorizontalAlignement
        hacGeneral = xlGeneral
        hacLeft = xlLeft
        hacCenter = xlCenter
        hacRight = xlRight
        hacFill = xlFill
        hacJustify = xlJustify
        hacCenterAcrossSelection = xlCenterAcrossSelection
        hacDistributed = xlDistributed
    End Enum
    
    '******************************************************************************
    '* Type      : Function
    '* Purpose   :
    '*  Applies a given alignement (both vertical and horizontal) to a given range.
    '* Parameters:
    '*  [In] rng, the range on which tto apply the alignement options
    '*  [In] hac, vertical alignement option (enumerated value)
    '*  [In] vac, horizontal alignement option (enumerated value)
    '* Return    :
    '*  Boolean, indicating the result of the operation
    '******************************************************************************
    Public Function SetRangeAlignement(ByRef rng As Excel.Range, _
        ByVal hac As hacHorizontalAlignement, ByVal vac As vacVerticalAlignement) _
        As Boolean
        On Error GoTo ExitProc:
    
        'Apply the alignement
        With rng
            .HorizontalAlignment = hac
            .VerticalAlignment = vac
        End With
    
        'Assume success
        SetRangeAlignement = True
    
    ExitProc:
    End Function
    

    On a side note, you may notice the use of Public scope; one should always use the smallest scope necessary, therefore most of my functions are placed in code modules with Option Private Module. This ensures that the functions are available everywhere withing my project but aren't available outside the project (except if I deliberately intend for this). Likewise in object modules I'll use the Friend scope most of the time.

  2. JP writes:

    Peder,

    I did a lot of cutting and pasting while writing the post. I left that in by mistake, and I'll remove it shortly.

    When I test your code I get "User-defined type not defined" — when I pasted the Enum sections into a class module, it worked. It's very clever and I like the approach, although I would have chosen easier to remember names than "hacGeneral". But the Intellisense makes it easier.

  3. Peder Schmedling writes:

    Ok, I see.

    I find it strange that you receive the "User-defined type not defined" message.. This code should work regardless of module type..

    One mistake you may have made is to not keep the Enum section "in the top of the module". If you for example define a function above the Enum section, the compiler will just disregard the Enum definition totally. This is a flaw in VBA, at least in MS office products, if you ask me. The compiler should have come up with some sort of a warning or error. Essentially, keep the Enum section(s) together with module level constant and variable definitions. The probable reason it worked for you when you moved it to a separate class module must be because the Enum is global and was therefore available to the SetRangeAlignement function.

    If this doesn't solve your problem, please let me know.

    As for the naming convention, I try to conform with the Reddick VBA (RVBA) conventions (http://www.xoc.net/standards/default.asp). This is the coding convention we use at work, so normally this is the way I write code.

    Explanation: the naming of the Enum "hacHorizontalAlignement" derives from "Horizontal Alignment Constant". As for the members, for example "hacGeneral", this derives from the name of the parent Enum, "Horizontal Alignment Constant" in conjunction with the suffix "General" describing the member itself (the same logic applies for the vertical alignement Enum). This may seem comprehensive at first, but as you get used to it, it's very helpfull. And as you say, intellisense makes it easier :-)

Comments on this article are closed. Why?

Site last updated: February 9, 2012