Excel macro adjust cell height - vba

My script moves data to excel template. Codewords is changed for relevant info.
All works well if TPLNR and AUFNR is filled. The cell is two rows in height. But if i leave AUFNR or TPLNR blank - cell height not ajusted. This is macro used to fill and adjust every row in table.
Sub Mac1()
'
' Mac1
'
Dim i As Integer
i = 12
'
Do While Range("L" & i).Value <> "THE END"
If Range("L" & i).Value = "M" Then
...
ElseIf Range("L" & i).Value = "T" Then
Range("A" & i & ":D" & i).Select
With Selection
.HorizontalAlignment = xlCenter
.Orientation = 0
.WrapText = True
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = True
End With
Selection.Merge
With Selection
.HorizontalAlignment = xlLeft
.VerticalAlignment = xlBottom
.WrapText = True
.Orientation = 0
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = True
End With
Selection.Font.Italic = True
End If
i = i + 1
Loop
Call AutoFitMergedCellRowHeight
Columns("L:L").Select
Selection.Delete Shift:=xlToLeft
End Sub
Sub AutoFitMergedCellRowHeight()
Dim CurrentRowHeight As Single, MergedCellRgWidth As Single
Dim CurrCell As Range
Dim ActiveCellWidth As Single, PossNewRowHeight As Single
Dim StartCell As Range, c As Range, MergeRng As Range, Cell As Range
Dim a() As String, isect As Range, i
'Take a note of current active cell
Set StartCell = ActiveCell
'Create an array of merged cell addresses that have wrapped text
For Each c In ActiveSheet.UsedRange
If c.MergeCells Then
With c.MergeArea
If .Rows.Count = 1 And .WrapText = True Then
If MergeRng Is Nothing Then
Set MergeRng = c.MergeArea
ReDim a(0)
a(0) = c.MergeArea.Address
Else
Set isect = Intersect(c, MergeRng)
If isect Is Nothing Then
Set MergeRng = Union(MergeRng, c.MergeArea)
ReDim Preserve a(UBound(a) + 1)
a(UBound(a)) = c.MergeArea.Address
End If
End If
End If
End With
End If
Next c
Application.ScreenUpdating = False
'Loop thru merged cells
For i = 0 To UBound(a)
Range(a(i)).Select
With ActiveCell.MergeArea
If .Rows.Count = 1 And .WrapText = True Then
'Application.ScreenUpdating = False
CurrentRowHeight = .RowHeight
ActiveCellWidth = ActiveCell.ColumnWidth
For Each CurrCell In Selection
MergedCellRgWidth = CurrCell.ColumnWidth + MergedCellRgWidth
Next
.MergeCells = False
.Cells(1).ColumnWidth = MergedCellRgWidth
.EntireRow.AutoFit
PossNewRowHeight = .RowHeight
.Cells(1).ColumnWidth = ActiveCellWidth
.MergeCells = True
.RowHeight = IIf(CurrentRowHeight > PossNewRowHeight, _
CurrentRowHeight, PossNewRowHeight)
End If
End With
MergedCellRgWidth = 0
Next i
StartCell.Select
Application.ScreenUpdating = True
'Clean up
Set CurrCell = Nothing
Set StartCell = Nothing
Set c = Nothing
Set MergeRng = Nothing
Set Cell = Nothing
End Sub
What could i do to get rows after 12 to look like it intended to? With 1x height.

Making the rows equal size is quite a standard VBA task.
Just try to put this logic away from your code. The only 3 things you should know is the starting row, the ending row and the size. Thus, you may be able to do it quite well. In the code below change the parameters of Call AllRowsAreEqual(4, 10, 35) in order to make it work for you.
Option Explicit
Sub AllRowsAreEqual(lngStartRow As Long, lngEndRow As Long, lngSize)
Dim lngCounter As Long
For lngCounter = lngStartRow To lngEndRow
Cells(lngCounter, 1).RowHeight = lngSize
'Debug.Print lngCounter
Next lngCounter
End Sub
Public Sub Main()
Call AllRowsAreEqual(4, 10, 35)
End Sub

Related

vba Sort by multiple criteria and copy values to another sheet

Hello again guys I have another tough problem for you, well may not be tough for you but it is for me. So I have one sheet with all of my data and I would like to sort by the first 3 conditions (Reject, Other, & year) Would be nice to be able to pick months too. Once the data is filtered I have it copied and sorted on another sheet so I can do some other functions and generate a table showing amount of times the vendor was rejected. There may be a simpler way to do this but currently this is the way I slapped together. If you have any other suggestions I would like to hear them.Code fails at the year sort. I keep getting all of the data from the other sheet
''Generates defect list
Sub Make_Defect_List_Yearly()
Const REJECTED_COL = 8 'Column H (DISPOSITIO)
Const DATE_COL = 13
Dim shAD As Worksheet, shVP As Worksheet
Dim adRng As Range, vpRng As Range, headers() As Variant
Dim rng As Range, cel As Range, fCell As Range, lCell As Range
Dim flg As Byte, LastRow As Long, flag As Boolean, i
Set shAD = Worksheets("AllData")
Set shVP = Worksheets("VendorProblems")
lr = shAD.Cells(Rows.Count, 1).End(xlUp).Row
Sheets("VendorProblems").UsedRange.ClearContents
'Copy VendorProblems to shVP --------------------------
Application.ScreenUpdating = False
shAD.AutoFilterMode = False
With shAD.UsedRange
Set adRng = FilterWS(.Columns(DATE_COL), "2017")
If Not adRng Is Nothing Then
If .Cells.CountLarge > 2 Then
Set vpRng = shVP.Cells(shVP.UsedRange.Rows.Count + 1, 1)
.Offset(1).Resize(.Rows.Count - 1, .Columns.Count).Copy vpRng
End If
End If
End With
With shAD.UsedRange
Set adRng = FilterWS(.Columns(REJECTED_COL), "Reject")
If Not adRng Is Nothing Then
If .Cells.CountLarge > 2 Then
Set vpRng = shVP.Cells(shVP.UsedRange.Rows.Count + 1, 1)
.Offset(1).Resize(.Rows.Count - 1, .Columns.Count).Copy vpRng
End If
End If
End With
With shAD.UsedRange
Set adRng = FilterWS(.Columns(REJECTED_COL), "Other")
If Not adRng Is Nothing Then
If .Cells.CountLarge > 2 Then
Set vpRng = shVP.Cells(shVP.UsedRange.Rows.Count + 1, 1)
.Offset(1).Resize(.Rows.Count - 1, .Columns.Count).Copy vpRng
End If
End If
End With
shAD.AutoFilterMode = False
'shVP.UsedRange.RemoveDuplicates Columns:=1, Header:=xlNo
'Sort shVP ----------------------------------------------------
Set vpRng = shVP.UsedRange.Columns(11)
With shVP.Sort
.SortFields.Clear
.SetRange shVP.UsedRange
.SortFields.Add Key:=vpRng, SortOn:=xlSortOnValues, Order:=xlAscending
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.Apply
End With
'Remove blanks from shVP --------------------------------------
With shVP.UsedRange
shVP.AutoFilterMode = False
If Len(shVP.Cells(1)) = 0 Then shVP.Cells(1) = "Header": flg = 1
Set vpRng = FilterWS(shVP.UsedRange.Columns(11), "=")
If Not vpRng Is Nothing Then
Set vpRng = shVP.UsedRange.Columns(2).SpecialCells(xlCellTypeVisible)
If .Cells.Count > 1 Then .SpecialCells(xlCellTypeVisible).EntireRow.Delete
End If
If flg = 1 Then shVP.Cells(1).EntireRow.Delete
shVP.AutoFilterMode = False
End With
Application.ScreenUpdating = True
'Copys qty recieved to amnt rejected if amt rejected is blank
With shVP
lr = .Cells(.Rows.Count, "A").End(xlUp).Row
For Each cel In .Range("G2:G" & lr) 'loop through each cell in Column
If (cel.Value) = "" Then 'check Command Name
Set fCell = cel.Offset(0, -3) 'set first cell to be copied in fCell
Set lCell = cel.Offset(0, 0)
lCell = fCell
End If
Next cel
End With
'Sorts data alphabetically by vendor
Application.ScreenUpdating = True
shVP.Activate
Cells.Select
Range("A:P").Activate 'old line a118
With Selection
.HorizontalAlignment = xlGeneral
.WrapText = False
.AddIndent = False
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = False
End With
shVP.Range("A1").Select
' Array of header labels
headers() = Array("Warehouse", "Inspection Type", "ItemID", "QtyReceived", "UOM", "Sample::Sample", "DefectFound", _
"Disposition", "PurchOrder", "DISTRIBUTOR", "Manufacturer", "Remarks", "Date", "Cost", "RejectCat", "Date")
' Row to insert
shVP.Activate
Range("A1").EntireRow.Insert
With shVP
For i = LBound(headers()) To UBound(headers())
.Cells(1, 1 + i).Value = headers(i)
Next i
.Rows(1).Font.Bold = True
End With
End Sub

Excel VBA: Merging a range inside a loop

I want to merge that repeating Chapters into just one cell by Chapter.
Here is how my code does the looping.
Dim label As Control
Dim itm As Object
For ctr = 1 To InfoForm.Chapter.ListCount - 1
For Each label In InfoForm.Controls
If TypeName(label) = "Label" Then
With ActiveSheet
i = i + 1
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row + IIf(i = 1, 1, 0)
lastColumn = .Cells(i, .Columns.Count).End(xlToLeft).Column
If label <> "Chapter" Then
.Cells(lastColumn, i).Value = "Chapter " & ctr
.Cells(lastRow, i).Value = label.Caption
End If
End With
End If
Next
Next
I've tried merging it like this
.Range(Cells(1, lastColumn), Cells(1,i)).Merge
But it merges all the repeating chapters into one cell instead
Expected Result:
My method is bellow
Dim label As Control
Dim itm As Object
For ctr = 1 To InfoForm.Chapter.ListCount - 1
For Each label In InfoForm.Controls
If TypeName(label) = "Label" Then
With ActiveSheet
i = i + 1
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row + IIf(i = 1, 1, 0)
lastColumn = .Cells(i, .Columns.Count).End(xlToLeft).Column
If label <> "Chapter" Then
.Cells(lastColumn, i).Value = "Chapter " & ctr
.Cells(lastRow, i).Value = label.Caption
End If
End With
End If
Next
Next
'this is merge method
Dim rngDB As Range, rng As Range, n As Integer
Application.DisplayAlerts = False
Set rngDB = Range("a1", Cells(1, Columns.Count).End(xlToLeft))
For Each rng In rngDB
If rng <> "" Then
n = WorksheetFunction.CountIf(rngDB, rng)
rng.Resize(1, n).Merge
rng.HorizontalAlignment = xlCenter
End If
Next rng
Application.DisplayAlerts = True
How about this?
With ActiveSheet
firstCol = 1
lastCol = .Cells(1, .Cells.Columns.Count).End(xlToLeft).Column
For i = 1 To lastCol
If .Cells(1, i) = "" Then GoTo NextCol 'skip blank cell
If firstCol = 0 And .Cells(1, i) <> "" Then firstCol = i 'set first column
If .Cells(1, i) = .Cells(1, i + 1) Then
LastColDup = i 'remember last duplicate column
Else
Application.DisplayAlerts = False
With .Range(Cells(1, firstCol), Cells(1, LastColDup + 1))
.Merge
.HorizontalAlignment = xlCenter
End With
Application.DisplayAlerts = True
firstCol = 0
LastColDup = 0
End If
NextCol:
Next i
End With
If you know the ranges before hand then you could adjust the code below. I've created this by recording a macro and then disabling/enabling alerts as appropriate. I've included a function to convert integer column values to alph equivalents.The MainLoop Intcol1 and intcol2 would be values that you would provide based on the input from the original Form.
Sub MainLoop()
Dim StrMycol_1 As String
Dim StrMycol_2 As String
Dim intcol1 As Integer
Dim intcol2 As Integer
intcol1 = 5: intcol2 = 7
StrMycol_1 = WColNm(intcol1) ' mycell.column is numeric. Function returns integer
StrMycol_2 = WColNm(intcol2) ' mycell.column is numeric. Function returns integer
'
do_merge_centre StrMycol_1, StrMycol_2
End Sub
Sub do_merge_centre(col1, col2)
Range(col1 + "1:" + col2 + "1").Select
Application.DisplayAlerts = False
With Selection
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlBottom
.WrapText = False
.Orientation = 0
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = False
End With
Selection.Merge
Application.DisplayAlerts = True
End Sub
'
Public Function WColNm(ColNum) As String
WColNm = Split(Cells(1, ColNum).Address, "$")(1)
End Function

VBA Macros behaves differently depending on selected cell

I have an AutoFitMergedCellRowHeight subroutine that takes a merged cell as an argument and then fixes its height so that all the text will be visible. The FixAll sub is activated when a button is pressed.
The problem is it's behavior is unstable. When a cell is selected that is in the same column as the merged cell (column 4) the height is one size (smaller, but the text is 100% visible); when a cell is selected outside that column but inside a table nothing happens; when a cell is selected outside the table the height is fixed but get too big.
Why is this happening? I can't see anything related to a selected cell in the sub.
Sub FitAll()
AutoFitMergedCellRowHeight (Cells(3, 4))
End Sub
Sub AutoFitMergedCellRowHeight(cell As Range)
Dim CurrentRowHeight As Single, MergedCellRgWidth As Single
Dim CurrCell As Range
Dim ActiveCellWidth As Single, PossNewRowHeight As Single
If cell.MergeCells Then
With cell.MergeArea
.WrapText = True
If .Rows.Count = 1 Then
cell = cell.MergeArea.Cells(1, 1)
MsgBox (cell.Row & "and" & cell.Column)
Application.ScreenUpdating = False
CurrentRowHeight = .RowHeight
ActiveCellWidth = cell.ColumnWidth
For Each CurrCell In Selection
MergedCellRgWidth = CurrCell.ColumnWidth +
MergedCellRgWidth
Next
.MergeCells = False
.Cells(1).ColumnWidth = MergedCellRgWidth
.EntireRow.AutoFit
PossNewRowHeight = .RowHeight
.Cells(1).ColumnWidth = ActiveCellWidth
.MergeCells = True
.RowHeight = IIf(CurrentRowHeight > PossNewRowHeight, _
CurrentRowHeight, PossNewRowHeight)
End If
End With
End If
End Sub
EDIT: I compare my results also to the same sub that doesn't use an argument but rather a selected cell. The results differ thought even after applying the changes CLR suggested..
Sub AutoFitMergedActiveCellRowHeight()
Dim CurrentRowHeight As Single, MergedCellRgWidth As Single
Dim CurrCell As Range
Dim ActiveCellWidth As Single, PossNewRowHeight As Single
If ActiveCell.MergeCells Then
With ActiveCell.MergeArea
.WrapText = True
If .Rows.Count = 1 Then
Application.ScreenUpdating = False
CurrentRowHeight = .RowHeight
ActiveCellWidth = ActiveCell.ColumnWidth
For Each CurrCell In Selection
MergedCellRgWidth = CurrCell.ColumnWidth + MergedCellRgWidth
Next
.MergeCells = False
.Cells(1).ColumnWidth = MergedCellRgWidth
.EntireRow.AutoFit
PossNewRowHeight = .RowHeight
.Cells(1).ColumnWidth = ActiveCellWidth
.MergeCells = True
.RowHeight = IIf(CurrentRowHeight > PossNewRowHeight, _
CurrentRowHeight, PossNewRowHeight)
End If
End With
End If
'MsgBox ("DONE")
MsgBox (ActiveCell.Row & "and" & ActiveCell.Column)
End Sub
For Each CurrCell In Selection is looking at selected cell, not cell passed in parameter.
I think you want to replace:
For Each CurrCell In Selection
MergedCellRgWidth = CurrCell.ColumnWidth + MergedCellRgWidth
Next
with something like:
For Each CurrCell In cell.MergeArea
MergedCellRgWidth = CurrCell.ColumnWidth + MergedCellRgWidth
Next

Unmerge and paste cells down with vba

I am facing the problem to proecess a report I got into a useful structured excel model.
My problem is that cells in this report are merged and now I would like to unmerge them to process the information much easier.
I tried to record something using the macro recorder, but I am unsure how to automate it on every cell in the sheet.
I would like to let the output look like that:
This is the part I recorded:
Sub Macro1()
Range("A2:A3").Select
With Selection
.HorizontalAlignment = xlGeneral
.WrapText = False
.Orientation = 0
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = True
End With
Selection.UnMerge
Range("A2").Select
Selection.AutoFill Destination:=Range("A2:A3")
Range("A2:A3").Select
End Sub
Any suggestions how to rewrite this macro to do the merging and pasting automatically?
Appreciate your replies!
UPDATE
I tried to use the selection, however, I am currently facing the problem of not knowing how to get next cell:
Sub split()
'
'Dim C As Double
'Dim R As Double
Dim Rng As Range
'select cells
Set Rng = Selection
'C = Rng
'R = 10
For Each cell In Rng
'starts in row 2 and A -> cell 2,1 is the first cell or A2
cell.Select
With Selection
.HorizontalAlignment = xlGeneral
.VerticalAlignment = xlBottom
.WrapText = False
.Orientation = 0
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = True
End With
Selection.UnMerge
'Cells(R + 1, C) = Cells(R, C)
If cell.Value = "" Then MsgBox ("Finished splitting and copying!"): End
' If C = 7 Then C = 0: R = R + 2
Next cell
End Sub
Sub Macro1()
NbRows = Sheets("Feuil1").UsedRange.Rows.Count - 1
NbCols = 9 ' If it doesn't change
Range("A2:I11").Copy Destination:= _
Range("K2")
Range("K:S").MergeCells = False ' remove merge
For i = 2 To NbRows ' Number of rows
For j = 11 To NbCols + NbCols ' Number of cols
If Cells(i, j) = "" Then
Cells(i, j) = Cells(i - 1, j).Value
End If
Next j
Next i
End Sub
My code copy-paste the datas from the first table to the cell "K2" (as in your example). Then, you remove the merge that will left some blanks. What you want to do is if cells(i , 1) is empty, then you just use the data from above (cells(i-1, 1))
if the data you want to change is on columns a to g and your are starting from row 2 and assuming all of the cell are not empty
try this code:
Sub split()
'
Dim C As Double
Dim R As Double
C = 1
R = 2
For C = 1 To 7
Cells(R, C).Select
With Selection
.HorizontalAlignment = xlGeneral
.VerticalAlignment = xlBottom
.WrapText = False
.Orientation = 0
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = True
End With
Selection.UnMerge
Cells(R + 1, C) = Cells(R, C)
If Cells(R, C).Value = "" Then MsgBox ("PROJECT ENDED"): End
If C = 7 Then C = 0: R = R + 2
Next C
End Sub
Please save your data before running the macro. You cannot undo.

Merge cells in different ranges

I have the following:
I expect the following:
I am using this code:
Sub merge_cells()
Application.DisplayAlerts = False
Dim r As Integer
Dim mRng As Range
Dim rngArray(1 To 4) As Range
r = Range("A65536").End(xlUp).Row
For myRow = r To 2 Step -1
If Range("A" & myRow).Value = Range("A" & (myRow - 1)).Value Then
For cRow = (myRow - 1) To 1 Step -1
If Range("A" & myRow).Value <> Range("A" & cRow).Value Then
Set rngArray(1) = Range("A" & myRow & ":A" & (cRow + 0))
Set rngArray(2) = Range("B" & myRow & ":B" & (cRow + 0))
Set rngArray(3) = Range("C" & myRow & ":C" & (cRow + 0))
Set rngArray(4) = Range("D" & myRow & ":D" & (cRow + 0))
For i = 1 To 4
Set mRng = rngArray(i)
mRng.Merge
With mRng
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
.WrapText = False
.Orientation = 90
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = True
End With
Next i
myRow = cRow + 2
Exit For
End If
Next cRow
End If
Next myRow
Application.DisplayAlerts = True
End Sub
what I get is:
Question: how to achieve this?
Actually in my original data, the first three columns have data every 88 rows starting from row 3 and the column D should get merged every four rows.
Your code does not distinguish between the different columns in any way. If you know how many rows to merge you can simply search for cells and then do the merge based on column number. Here is one such approach which uses a pair of arrays to track how many rows to merge and then what formatting to apply.
You will need to change the row counts in the array definition. Sounds like you want (87,87,87,3) based on your edit. I did (11,11,11,3) to match your example though. This is the real fix to your code; it uses the Column number to determine how many rows to merge.
I also just typed some values into the spreadsheet and used SpecialCells to get only the cells with values. If your data matches your example, this works fine.
Edit includes unmerging cells first per OP request.
Sub MergeAllBasedOnColumn()
Dim rng_cell As Range
Dim arr_rows As Variant
Dim arr_vert_format As Variant
'change these to the actual number of rows
'one number for each column A, B, C, D
arr_rows = Array(11, 11, 11, 3)
'change these if the formatting is different than example
arr_vert_format = Array(True, True, True, False)
'unmerge previously merged cells
Cells.UnMerge
'get the range of all cells, mine are all values
For Each rng_cell In Range("A:D").SpecialCells(xlCellTypeConstants)
'ignore the header row
If rng_cell.Row > 2 Then
'use column to get offset count
Dim rng_merge As Range
Set rng_merge = Range(rng_cell, rng_cell.Offset(arr_rows(rng_cell.Column - 1)))
'merge cells
rng_merge.Merge
'apply formatting
If arr_vert_format(rng_cell.Column - 1) Then
'format for the rotated text (columns A:C)
With rng_merge
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
.WrapText = False
.Orientation = 90
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
End With
Else
'format for the other cells (column D)
With rng_merge
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
.WrapText = False
End With
End If
End If
Next rng_cell
End Sub
Before
After