i am new to VBA and i can´t really understand, how to solve the following problem:
I have an excel spreadsheet, representing balance sheet of the company:
A. Assets
1. Intangible assets YES
1.1. AB 12
1.2. ABC 0
1.3. ABCD 3
2. Tangible assets NO
2.1. B 0
2.2. BC 0
2.3. BCD 0
I have a dropdown menu (YES/NO). YES, if there are number in a subgroup and No if sugroup is empty. So that Intangible assets would be YES and Tangible assets would be NO.
I need a macro, which will hide rows, if there is No in dropdown menu. In our case rows 2.1. - 2.3. must be hidden. Is there a possible solution to this problem?
As far as I understood, one can use this code:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$C$1" Then
If Range("C1").Value = "Yes" Then
Rows("2:4").EntireRow.Hidden = False
ElseIf Range("C1").Value = "No" Then
Rows("2:4").EntireRow.Hidden = True
End If
End If
End Sub
This code is only for rows 2-4, how can I extend it?
EDIT:
Is it possible to extend the last piece of code, so that it will hide rows then NO, and bring them back if YES. Something like:
If Not RowsToHide Then
RowsToHide.EntireRow.Hidden = False
If RowsToHide Then
RowsToHide.EntireRow.Hidden = True
End If
End If
End Sub
?
Using the same data in your screenshot:
Add a header line (we need one line above the data for the formula to work)
Add a helper column in column D and insert the following formula into D2 (and copy it down)
=IF(C2="YES","show",IF(C2="NO","show",IF(C1="NO","hide",D1)))
Then use AutoFilter to filter by show in column D
Image 1: How to filter the helper column D by 'show'.
With VBA you would need to loop through all data rows and check if you are in a NO subrow or not:
Option Explicit
Public Sub HideSubRowsWithNo()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1") 'define your sheet here
Dim LastRow As Long 'get last used row in column A
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim NoArea As Boolean
Dim RowsToHide As Range
Dim iRow As Long
For iRow = 1 To LastRow 'loop through all data rows
If ws.Cells(iRow, "C").Value = "NO" Then 'check if row has NO in column C (note this is case sensitive)
NoArea = True 'mark that we are in a NO subrow
ElseIf ws.Cells(iRow, "C").Value = "YES" Then
NoArea = False 'mark that we are NOT in a NO subrow
ElseIf ws.Cells(iRow, "C").Value = vbNullString Then 'if column c is empty
If NoArea Then 'check if we are in a NO subrow
If RowsToHide Is Nothing Then
Set RowsToHide = ws.Rows(iRow)
Else
Set RowsToHide = Union(RowsToHide, ws.Rows(iRow))
End If
End If
End If
Next iRow
If Not RowsToHide Is Nothing Then
RowsToHide.Select 'just to show which rows would be hidden for production use the line below to hide the rows
'RowsToHide.EntireRow.Hidden = True
End If
End Sub
Sub HideNo()
Dim y As Integer
Dim hide As Integer
Dim lstrow As Integer
lstrow = ActiveSheet.UsedRange.Rows.Count
hide = 1
For y = 2 To lstrow
If Range("C" & y).Value = "NO" Then
hide = 0
ElseIf Range("C" & y).Value = "YES" Then
hide = 1
End If
If hide = 1 Then
Rows(y).EntireRow.Hidden = False
ElseIf hide = 0 Then
Rows(y).EntireRow.Hidden = True
End If
Next y
End Sub
This should do what you were asking for You'd need to run the macro after you had your data filled in.
Related
I've made a For Each loop that'll keep data depending upon some criteria's, but I do not know how to format it so if a cell in column A contain exactly 8 numeric digits, then it'll keep the row.
Example:
Cell A289 Contains: 04245468 ← Keep this row
Cell A978 Contains: 04513 ← Delete this row
So far I have the following by using the left function within my code:
Sub CleanUpSheet1()
Dim RowA As Range
'hides any popups
Application.DisplayAlerts = False
'Deletes all blanks up to row 15,0000
Range("a2:A15000").Select
Selection.SpecialCells(xlCellTypeBlanks).EntireRow.Delete
For Each RowA In Range("A2:A" & ActiveSheet.UsedRange.Rows.Count)
If Left(RowA.Value, 5) <> "issue" And Right(RowA.Value, 4) <> "-000" And RowA.Value <> 0 Then
RowA.EntireRow.Delete
End If
Next
're-enables popups
Application.DisplayAlerts = True
End Sub
If it's just a matter of numbers you can transform the cell value into a string (RowA.Text or maybe Cstr(RowA.Value) and then test on the lenght :
if len(cstr(RowA.Value)) = 8 ???
(or len(RowA.Text))
Tell me if I havn't understood your question.
Had to reformat this a lot.
Sub CleanUpSelect1()
Dim RowA As Range
Dim cRng As Range
Dim iCounter As Long
Set RowA = Sheet1.Range("A2:A" & Sheets("Sheet1").UsedRange.Rows.Count)
iCounter = 1
Do
Set cRng = RowA(iCounter, 1) 'Loop rows
If CStr(cRng.Value2) = vbNullString Then
cRng.EntireRow.Delete
Else
If Not KeepRow(cRng.Value2) Then
cRng.EntireRow.Delete 'Delete row
Else
iCounter = iCounter + 1 'Advance
End If
End If
Loop While iCounter <= RowA.Rows.Count 'Stop after loop all rows
End Sub
Private Function KeepRow(RowValue As String) As Boolean
KeepRow = (RowValue Like "########" Or RowValue Like "issue#" Or RowValue Like "######-###")
End Function
But it works.
I have a worksheet with 3 rows and 7 columns (A1:G3).
A and B columns have 6 checkboxes (A1:B3). Boxes in columns A & B are linked to columns C & D respectively. Cells in columns E & F are just replicating columns C & D respectively (live E1 cell is =C1 and F3 cell is =D3).
I want to put a timestamp in cell G for each row when a checkbox is ticked or unticked by using Worksheet_Calculate event in VBA for that sheet.
My code works when used for just 1 row.
Private Sub Worksheet_calculate()
Dim cbX1 As Range
Set cbX1 = Range("A1:F1")
If Not Intersect(cbX1, Range("A1:F1")) Is Nothing Then
Range("G1").Value = Now()
End If
End Sub
I want to combine the code for 3 rows.
Here are 2 variations:
1st one:
Private Sub Worksheet_calculate()
Dim cbX1 As Range
Dim cbX2 As Range
Dim cbX3 As Range
Set cbX1 = Range("A1:F1")
Set cbX2 = Range("A2:F2")
Set cbX3 = Range("A3:F2")
If Not Intersect(cbX1, Range("A1:F1")) Is Nothing Then
Range("G1").Value = Now()
ElseIf Intersect(cbX2, Range("A2:F2")) Is Nothing Then
Range("G2").Value = Now()
ElseIf Intersect(cbX3, Range("A3:F3")) Is Nothing Then
Range("G3").Value = Now()
End If
End Sub
When I combine them with ElseIf like in the code above, a timestamp gets put in only G1, no matter if I tick B1 or C2.
2nd one:
Private Sub Worksheet_calculate()
Dim cbX1 As Range
Dim cbX2 As Range
Dim cbX3 As Range
Set cbX1 = Range("A1:F1")
If Not Intersect(cbX1, Range("A1:F1")) Is Nothing Then
Range("G1").Value = Now()
End If
Set cbX2 = Range("A2:F2")
If Not Intersect(cbX2, Range("A2:F2")) Is Nothing Then
Range("G2").Value = Now()
End If
Set cbX3 = Range("A3:F2")
If Not Intersect(cbX3, Range("A3:F3")) Is Nothing Then
Range("G3").Value = Now()
End If
End Sub
When I combine them by ending each one with End If and start a new If, timestamp gets put in all of the G1, G2 and G3 cells, even if I tick just one of the boxes.
You seem to be confusing Worksheet_Calculate with Worksheet_Change and using Intersect as if one of the arguments was Target (which Worksheet_Calculate does not have).
Intersect(cbX1, Range("A1:F1")) is always not nothing because you are comparing six apples to the same six apples. You might as well ask 'Is 1,2,3,4,5,6 the same as 1,2,3,4,5,6?'.
You need a method of recording the values of your range of formulas from one calculation cycle to the next. Some use a public variable declared outside the Worksheet_calculate sub procedure; personally I prefer a Static variant array declared within the Worksheet_calculate sub.
The problem with these is initial values but this can be accomplished since workbooks undergo a calculation cycle when opened. However, it is not going to register Now in column G the first time you run through a calculation cycle; you already have the workbook open when you paste in the code and it needs one calculation cycle to 'seed' the array containing the previous calculation cycle's values.
Option Explicit
Private Sub Worksheet_Calculate()
Static vals As Variant
If IsEmpty(vals) Then 'could also be IsArray(vals)
vals = Range(Cells(1, "A"), Cells(3, "F")).Value2
Else
Dim i As Long, j As Long
With Range(Cells(1, "A"), Cells(3, "F"))
For i = LBound(vals, 1) To UBound(vals, 1)
For j = LBound(vals, 2) To UBound(vals, 2)
If .Cells(i, j).Value2 <> vals(i, j) Then
Application.EnableEvents = False
.Cells(i, "G") = Now
Application.EnableEvents = True
vals(i, j) = .Cells(i, j).Value2
End If
Next j
Next i
End With
End If
End Sub
I'm currently looking for a code to improve my Dashboard. Actually, I need to know how to use a loop in a column X who will affect a column Y (cell on the same line).
To give you an example:
Column A: I have all Production Order (no empty cell)
Column B: Cost of goods Sold (Sometimes blank but doesn't matter)
I actually pull information from SAP so my Column B is not in "Currency".
The action should be:
If A+i is not empty, then value of B+i becomes "Currency".
It's also for me to get a "generic" code that I could use with other things.
This is my current code...
Sub LoopTest()
' Select cell A2, *first line of data*.
Range("A2").Select
' Set Do loop to stop when an empty cell is reached.
Do Until IsEmpty(ActiveCell)
ActiveCell.Offset(0, 1).Style = "Currency"
ActiveCell.Offset(1, 0).Select
Loop
End Sub
Another example, getting Last Row, in case your data contains any blank rows.
Sub UpdateColumns()
Dim wks As Worksheet
Dim lastRow As Long
Dim r As Long
Set wks = ActiveSheet
lastRow = ActiveSheet.Cells.SpecialCells(xlLastCell).Row
For r = 2 To lastRow
If wks.Cells(r, 1) <> "" Then
wks.Cells(r, 2).NumberFormat = "$#,##0.00"
End If
Next r
End Sub
I can see I was a little slower than the others, but if you want some more inspiration, heer is a super simple solution (as in easy to understand as well)
Sub FormatAsCurrency()
'Dim and set row counter
Dim r As Long
r = 1
'Loop all rows, until "A" is blank
Do While (Cells(r, "A").Value <> "")
'Format as currency, if not blank'
If (Cells(r, "B").Value <> "") Then
Cells(r, "B").Style = "Currency"
End If
'Increment row
r = r + 1
Loop
End Sub
Try the following:
Sub calcColumnB()
Dim strLength As Integer
Dim i As Long
For i = 1 To Rows.Count
columnAContents = Cells(i, 1).Value
strLength = Len(columnAContents)
If strLength > 0 Then
Cells(i, 2).NumberFormat = "$#,##0.00"
End If
Next i
End Sub
Explanation--
What the above code does is for each cell in Column B, so long as content in column A is not empty, it sets the format to a currency with 2 decimal places
EDIT:
Did not need to loop
Here's a really simply one, that I tried to comment - but the formatting got messed up. It simply reads column 1 (A) for content. If column 1 (A) is not empty it updates column 2 (B) as a currency. Changing active cells makes VBA more complicated than it needs to be (in my opinion)
Sub LoopTest()
Dim row As Integer
row = 1
While Not IsEmpty(Cells(row, 1))
Cells(row, 2).Style = "Currency"
row = row + 1
Wend
End Sub
I am trying to highlight the max value in each row of data to determine what year it falls in. Is there a simple way to apply it to the whole spreadsheet? The only way I can do it right now is by using the Format Painter on each individual row... which is not efficient with 800+ rows of data.
Using Conditional Formatting - Top N Items
Here is a tiny macro - you need to copy it to a module in VBA Project. Once there, put a cursor in the macro and press F5 :)
1) it works for rows from 1 to 800 (change it if you need it somewhere else)
2) it works on Sheet1
Sub ManyConditions()
Dim iRow As Integer
For iRow = 1 To 800
With Sheet1
With .Range(.Cells(iRow, 1), .Cells(iRow, 10)).FormatConditions.AddTop10
.TopBottom = xlTop10Top
.Rank = 1
.Percent = False
.Interior.PatternColorIndex = xlAutomatic
.Interior.Color = 13551615
.StopIfTrue = False
End With
End With
Next
End Sub
The following VBA code could do the trick (updated version):
Sub Mark_max_value_in_every_row()
Dim rngArea As Range
Set rngArea = ThisWorkbook.Sheets("Sheet1").UsedRange
Dim rngRow As Range
Dim iRow As Long
For iRow = 2 To rngArea.Rows.Count
Set rngRow = rngArea.Range(Cells(iRow, 1), Cells(iRow, rngArea.Columns.Count))
With rngRow.FormatConditions.AddTop10
.Rank = 1
.Interior.Color = 49407
End With
Next
End Sub
I assume that your first row of the table is headers, therefore you see iRow beginning to count from 2.
I am having some trouble detecting the value in a cell with a dropdown list.
When I am running the below code, it only gives me the value 0 in column I. Column H contains a number of Dropdown lists (made by data validation), which value can either be Yes or No:
Sub DropDownlistValue()
Dim Holidays As Worksheet
Dim Checkbox_RowCount As Long
Dim HolidayCount As Long
Set Holidays = ThisWorkbook.Sheets("Visning")
Checkbox_RowCount = Holidays.Cells(Holidays.Rows.Count, "H").End(xlUp).Row
For HolidayCount = 2 To Checkbox_RowCount
If Not IsEmpty(Holidays.Range("H" & HolidayCount)) Then
Holidays.Activate
Holidays.Range("H" & HolidayCount).Select
If ActiveCell = "YES" Then
ActiveCell.Offset(0, 1) = 1
Else
ActiveCell.Offset(0, 1) = 0
End If
End If
Next HolidayCount
End Sub
Thanks in advance.
What you possibly need is the change in this line:
If ActiveCell = "YES" Then
into
If Ucase(ActiveCell) = "YES" Then
One more tip- move this line:
Holidays.Activate
before/outside your loop.