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

VBA Options:
- xlGeneral
- xlLeft
- xlCenter
- xlRight
- xlFill
- xlJustify
- xlCenterAcrossSelection
- xlDistributed
VerticalAlignment Property

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).





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
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 FunctionOn 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.
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.
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