This should work:
Sub test()
Application.ScreenUpdating = False
Dim ws As Worksheet: Set ws = Worksheets("Sheet1") 'Type the sheet where the data is pasted
Dim myRows As Long
Dim myColumns As Long
Dim rng As Range
Dim userInput As String
Dim Outputrng As Range
Dim rowCounter As Long
Dim columnCounter As Long
myColumns = Selection.Columns.Count
userInput = InputBox("Type output cell eg. B10")
If userInput = vbNullString Then Exit Sub
rowCounter = 0
columnCounter = -1
For Each rng In Selection
columnCounter = columnCounter + 1
If columnCounter > myColumns - 1 Then columnCounter = -1
If columnCounter = -1 Then
rowCounter = rowCounter + 1
columnCounter = 0
End If
Set Outputrng = ws.Range(userInput).Offset(columnCounter, rowCounter)
If rng.HasFormula = True Then
rng.Formula = Application.ConvertFormula(rng.Formula, xlA1, xlA1, 1)
End If
rng.Copy
Outputrng.PasteSpecial xlPasteFormulas
Next
Application.ScreenUpdating = True
End Sub
Remember that if your formulas use relative cell references, you might get unexpected results.
Explanation of the code:
myColumns = Selection.Columns.Count
The code snippet above stores the number of columns in the selected area for future use.
userInput = InputBox("Type output cell eg. B10")
If userInput = vbNullString Then Exit Sub
The code snippet above prompts an InputBox
in which the user can write the desired output cell. The output cell is going to be the top-left cell of the transposed data.
The If
statement exits the sub
if the user doesn't type a value.
The For Each rng In Selection
loop goes through each cell in the selected range. The code loops through columns from left to right first, then goes down a row and loops through columns again. The general idea with this loop is to identify the position of the cell and then paste it to the corresponding transposed position.
The columnCounter
and rowCounter
keeps track of the position of the cell. columnCounter = 0
and rowCounter = 0
would be the very first cell to be transposed. This cell is pasted to the output cell specified by the user. columnCounter = 1
and rowCounter = 0
would be the second cell to be transposed. This cell is pasted in the same column, but one row below the output cell.
At the beginning of each loop, the value of columnCounter
is increased by 1
, which can be seen on the line columnCounter = columnCounter + 1
.
When the value of columnCounter
becomes greater than the value of myColumns
the value of columnCounter
is set to -1
. When the value of columnCounter
is -1
the value of rowCounter
is increased by 1
and the value of columnCounter
is reset to 0
. This means that the loop has finished going through the columns in one row and is now moving on to the next row.
All this can be seen in the following code snippet:
If columnCounter > myColumns - 1 Then columnCounter = -1
If columnCounter = -1 Then
rowCounter = rowCounter + 1
columnCounter = 0
End If
Now that the location of the cell is identified we need to paste it to the correct "output range
", which is called Outputrng
in the code. This is done in the following line:
Set Outputrng = ws.Range(userInput).Offset(columnCounter, rowCounter)
The basis for this line is the Range(userInput)
. This is the original output cell specified by the user via the InputBox
. Using .Offset
we can work with a cell relative to the user-specified output cell. Since we need to transpose the original selection, we invert the position of the original cell using columnCounter
and rowCounter
.
Note that columnCounter
is used as the row offset
while rowCounter
is used as the column offset
.
Next we check if the cell contains a formula. If it does, the formula is converted to absolute reference. This is done via the following code lines:
If rng.HasFormula = True Then
rng.Formula = Application.ConvertFormula(rng.Formula, xlA1, xlA1, 1)
End If
Notice that the 1
at the end is what specifies that we want absolute reference. If we want relative reference, just change the 1
to a 4
.
Last step is to paste the original cell to the Outputrng
. To make sure that we paste the formulas as well, we use .PasteSpecial xlPasteFormulas
. If the cell doesn't contain a formula, then the value is pasted. This is done on the following code lines:
rng.Copy
Outputrng.PasteSpecial xlPasteFormulas
Using Next
tells the code to go to the next cell in the selection, which is called rng
in the code.
This might not be the simplest or most elegant approach, but this is how I would do it - and it works! :)