I'm making a simple subtraction between two cells that contain dates in order to obtain the period. Every client, in Data_p worksheet, Range ("4"), will have all the order dates in the respective column. So the subtraction will be between the second date and the first, and so on, and the result will be pasted in Data_p_mgnt. This function will have to be executed until there're no more dates for each client.
I have the following code, but I don't know why it won't stop when it finds and Empty cell in Data_p. Any insight will be appreciated.
Sub Prueba_Data_p_mgnt()
Sheets("Data_p_mgnt").Select
Range("B5").Select 'Starts in cell B5
Do Until IsEmpty(Worksheets("Data_p").Range("B5")) 'Checks if cells in Data_p are Empty or Blank
ActiveCell.FormulaR1C1 = "=Data_p!R[1]C-Data_p!RC" 'Makes the subtraction between cells
ActiveCell.Offset(1, 0).Range("A1").Select 'Moves down for paste the next period
Loop 'Loop until there's an Empty cell in Data_p
'Then should move to next client to the right and repeat until there are no more clients in row 4
End Sub
I believe this is what you are trying to do:
Sub Prueba_Data_p_mgnt()
Dim wsMgnt As Worksheet
Dim wsData As Worksheet
Dim rowNo As Long
Dim colNo As Long
Set wsMgnt = Worksheets("Data_p_mgnt")
Set wsData = Worksheets("Data_p")
colNo = 2
Do Until IsEmpty(wsData.Cells(4, colNo)) 'Checks if cells in Data_p are Empty or Blank
rowNo = 5
Do Until IsEmpty(wsData.Cells(rowNo, colNo)) 'Checks if cells in Data_p are Empty or Blank
'Alternatively, to avoid subtracting the last non-blank cell from a blank cell
'Do Until IsEmpty(wsData.Cells(rowNo + 1, colNo)) 'Checks if cells in Data_p are Empty or Blank
wsMgnt.Cells(rowNo, colNo).FormulaR1C1 = "=Data_p!R[1]C-Data_p!RC" 'Makes the subtraction between cells
'Alternatively, if you would rather have values than formulae
'wsMgnt.Cells(rowNo, colNo).Value = wsData.Cells(rowNo + 1, colNo).Value - wsData.Cells(rowNo, colNo).Value
rowNo = rowNo + 1 'Moves down for paste the next period
Loop 'Loop until there's an Empty cell in Data_p
colNo = colNo + 1 'Then should move to next client to the right and repeat until there are no more clients in row 4
Loop
End Sub
This should, I hope, do the trick:
Sub Prueba_Data_p_mgnt()
Dim dataWS As Worksheet
Dim rng As Range
Set dataWS = Sheets("Data_p_mgnt")
Set rng = dataWS.Range("B5") ' what's this? You never use data_p_mgnt cell B5?
For i = 5 To 100 ' Change 100 to whatever you need
If Not IsEmpty(Worksheets("Data_p").Range("b" & i)) Then 'Checks if cells in Data_p are Empty or Blank
Worksheets("Data_p").Range("b" & i).FormulaR1C1 = "=Data_p!R[1]C-Data_p!RC" 'Makes the subtraction between cells
End If 'Loop until there's an Empty cell in Data_p
Next i
End Sub
But looking at your code, I don't know what you plan on doing with B5 on the Data_p_mgnt sheet.
Related
This question already has answers here:
Return background color of selected cell
(5 answers)
Closed 4 years ago.
I'm fairly new to VBA and I've been struggling over this problem for a couple weeks.
Every time a name has passed a training, the corresponding name/training title cell is filled with the date, and the background is filled in yellow RGB(255,255,0). When IN training they are filled with a yellow background and no date. (There are also some that are red or grey for out of date, but I think I have already worked those out.)
The end goal is to have a separate output sheet within the same file. This sheet will only contain the necessary Training Titles at the top, and all of the names under it if they are the blank yellow cells (No date + yellow). Eventually I would like to be able to email this list to certain people, but I think there are enough resources to figure that out myself.
Currently, I have code to find the max/min of the column/rows, and code that deletes all cells containing dates. My plan was to have it scan the remaining cells for any that were yellow, then paste the training titles/names on a new sheet, but I cannot figure out how to that in VBA.
I'm sure there has to be an easier way to do this as it is several hundred columns wide and rows long.
Thanks for any input!
EDIT: This is the code I am currently using. This scans the range of name vs training and clears the cell data if it is any other color than yellow, or if it is yellow with a date.
I attached an image to help explain more clearly. The important cells are the ones that are yellow with no date. From those cells I need to paste the Training Title in Row 1, and the Name of the person in Column A on a new sheet in the way you can see in the picture.
Sub ClearCellMacro()
Dim myLastCell As Range
Dim cell As Range
Application.ScreenUpdating = False
'Find last cell
Set myLastCell = Range("C4").SpecialCells(xlLastCell)
'Make sure last cell is outside of first row and column (or else exit)
If myLastCell.Row = 1 Or myLastCell.Column = 1 Then Exit Sub
'Loop through entire range removing cell contents if value is not numeric
For Each cell In Range("C4:" & myLastCell.Address)
If Not IsNumeric(cell) Then cell.Clear
Next cell
For Each cell In Range("C4:" & myLastCell.Address)
If cell.Interior.Color <> RGB(255, 255, 0) Then cell.Clear
Next cell
Application.ScreenUpdating = True
MsgBox "Non-Yellow + Blank Cells Removed."
End Sub
This will not clear the non-numeric cells. I am assuming that is already done.
Any cell that is blank and highlighted yellow will be moved to a table on Sheet2 with corresponding name.
You need to update the 3rd and 4th line of code to reflect your actual sheet names (make sure to leave the quotes of course). Sheet1 reflects your "starting sheet" in photo and Sheet2 reflects your desired output.
This is dynamic by rows and columns. Last row (lRow) is determined by Column A and last column (lCol) is determined by Row 1. Photo of the starting point and output produced by the below macro.
Option Explicit
Sub TestMe()
Dim ws1 As Worksheet: Set ws1 = ThisWorkbook.Sheets("Sheet1")
Dim ws2 As Worksheet: Set ws2 = ThisWorkbook.Sheets("Sheet2")
Dim lCol As Long: lCol = ws1.Cells(1, ws1.Columns.Count).End(xlToLeft).Column
Dim lRow As Long: lRow = ws1.Range("A" & ws1.Rows.Count).End(xlUp).Row
Dim myRange As Range, myCell As Range, myUnion As Range
Dim i as Long
For i = 3 To lCol 'Open column loop
Set myRange = ws1.Range(ws1.Cells(4, i), ws1.Cells(lRow, i))
For Each myCell In myRange 'Open row loop
If myCell = "" And myCell.Interior.Color = 65535 Then
If myUnion Is Nothing Then
Set myUnion = myCell.Offset(0, -i + 1)
Else
Set myUnion = Union(myUnion, myCell.Offset(0, -i + 1))
End If
End If
Next myCell 'Next Row
If Not myUnion Is Nothing Then 'This will need some updating to dynamically paste in first available column
ws2.Cells(1, i - 2).Value = ws1.Cells(1, i).Value
myUnion.Copy
ws2.Cells(2, i - 2).PasteSpecial xlPasteValues
Set myUnion = Nothing
End If
Next i 'Next Column
End Sub
I have a sheet (Sheet3) within a workbook that I would like to write VBA to hide multiple rows based on cell value in multiple ranges. The VBA would have to run through two different steps; the first would be if the first cell within the specified range is blank then hide the entire range (except range 1 since the first cell would never be blank). The second step would be if the first cell in range is not blank, then hide rows in that range that are blank. Here are the specifics:
Range 1
A11:A60 - Hide rows that are blank in range
Range 2
A71:A120 - If cell A71 is blank, Hide A71:A120. Otherwise hide all rows that are blank in range A71:A120.
Range 3
A131:A180 - If cell A131 is blank, Hide A131:A180. Otherwise hide all rows that are blank in range A131:A180.
Range 4
A191:A240 - If cell A191 is blank, Hide A191:A240. Otherwise hide all rows that are blank in range A191:A240.
Range 5
A251:A300 - If cell A251 is blank, Hide A251:A300. Otherwise hide all rows that are blank in range A251:A300.
Public Sub HideRowsSummary()
Dim wsMySheet As Worksheet
Dim lngMyRow As Long, unionRng As Range
Application.ScreenUpdating = False
For Each wsMySheet In ThisWorkbook.Sheets
Select Case wsMySheet.Name
Case Is = Sheet3
.Range("A11:A60", "A71:A120", "A131:A180", "A191:A240", "A251:A300").EntireRow.Hidden = False
For lngMyRow = 11 To 60
If Len(.Range("A" & lngMyRow)) = 0 Then
If Not unionRng Is Nothing Then
Set unionRng = Union(unionRng, .Range("A" & lngMyRow))
Else
Set unionRng = .Range("A" & lngMyRow)
End If
End If
Next lngMyRow
End With
End Select
If Not unionRng Is Nothing Then unionRng.EntireRow.Hidden = True
Set unionRng = Nothing
Next wsMySheet
Application.ScreenUpdating = True
End Sub
In your question #2, 3, 4, 5 all follow similar logic.
The first i loop tackles #1. The next portion of the code tackles #2. You can simply copy/paste the bottom portion and change your test values to complete your ask.
Option Explicit
Sub HideMe()
Dim i As Integer
With ThisWorkbook.Sheets("Sheet3")
For i = 11 To 60
.Range("A" & i).EntireRow.Hidden = .Range("A" & i) = vbNullString
Next i
'Repeat this portion for you other ranges that follow the same rules
If .Range("A" & 71) = vbNullString Then
.Range("A71:A120").EntireRow.Hidden = True
Else
For i = 72 To 120
.Range("A" & i).EntireRow.Hidden = .Range("A" & i) = vbNullString
Next i
End If
End With
End Sub
This can be improved by
A) Use For Each loop instead of For i loop
B) Instead of hiding rows one by one, add them to a collection of rows as a (Union) and hide the Union all at once
top part of the worksheet
very new to VBA and I'm trying to develop a macro to do some formatting. I have a variable amount of data (row wise, columns are the same) in my worksheet. After the last row of data, there are a bunch of blank white rows, and at the very bottom is a grey-shaded row. I want to hide all of the blank white rows in the middle, so that the grey-shaded row is then right under my last row with data in it.
Here is the code I have so far (note: Column I is the last column). Any help would be greatly appreciated. Right now, I am getting a "type mismatch" error for the "BeforeFinalRow = finalRow - 1" part, but I'm sure there's a lot more that's wrong with this code. Thanks in advance!
Sub hide_rows()
Dim BelowUsedData As Long
BelowUsedData = Cells(Rows.Count, 2).End(xlUp).Row + 1
Dim RowBelowUsedData As Range
RowBelowUsedData = Range("A" & BelowUsedData, "I" & BelowUsedData)
Range("A1").Select
Selection.End(xlDown).Select
Dim finalRow As Range
finalRow = Range(Selection, Selection.End(xlToRight))
Dim BeforeFinalRow As Long
BeforeFinalRow = finalRow - 1
Rng = Range(Cells(RowBelowUsedData, "A"), Cells(BeforeFinalRow, "I")).Select
Selection.EntireRow.Hidden = True
End Sub
You could simplify this and hard code your bottom border cell into the code (Just change the value of BottomBorder in code)
Option Explicit
Sub Test()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim LRow As Long, BottomBorder As Long
LRow = ws.Range("B" & ws.Rows.Count).End(xlUp).Offset(1).Row
BottomBorder = 1006 'Change this if your bottom border changes
ws.Range(ws.Cells(LRow, 1), ws.Cells(BottomBorder, 1)).EntireRow.Hidden = True
End Sub
Another option is to use a WorkSheet_Change Event. This will only work if you are inputting data in one entry (row) at a time.
To implement: Hide all unused rows with the exception of 1! So if your last used cell is B4, hide B6 down to BottomBorder which will leave B5 as a white blank row where your next entry will go. Then paste the below code in the worksheet in VBE. Every time an entry is made in your blank row (B5) here, the macro will insert a new row keeping your current format.
This is dynamic so it will also look at the next blank row (After B5, B6 will be your new target row)
Private Sub Worksheet_Change(ByVal Target As Range)
Dim LRow As Long
LRow = Range("B" & Rows.Count).End(xlUp).Offset(1).Row
Application.EnableEvents = False
If Target.Row = LRow - 1 And Target.Column = 2 Then
Range("A" & LRow + 1).EntireRow.Insert (xlShiftUp)
End If
Application.EnableEvents = True
End Sub
On the photo it looks like the rows are not hidden but grey. The below code will find where the color changes and hide those white rows between the last row with data and the first grey cell:
Sub hide_rows()
Dim rngData As Range
Dim rngFirstCelltoHide As Range
Dim rngLastWhite As Range
Set rngData = Range("B1").CurrentRegion
Set rngFirstCelltoHide = rngData.Cells(rngData.Rows.Count, 1).Offset(1, 0)
Set rngLastWhite = rngFirstCelltoHide
Do Until rngLastWhite.Interior.Color <> rngLastWhite.Offset(1, 0).Interior.Color
Set rngLastWhite = rngLastWhite.Offset(1, 0)
Loop
Range(rngFirstCelltoHide, rngLastWhite).EntireRow.Hidden = True
End Sub
finalRow is a range object. That is why you get 'type error' when you subtract 1 from it. Declare the variable as long and assign row number to it as follows:
finalRow = Range(Selection, Selection.End(xlToRight)).Row
I hope you can help. I have a piece of code below, and its working somewhat. I just need it to do more.
It currently looks along the first row from A1 to H1. If it finds a blank cell then it copies the cell value to the left of the blank cell, then pastes this value into the blank cell and then moves along.
As the range can change from day to day A1 to H1 will not suffice. I now need the code to look along the first row, until it finds the last cell with data in it then look for the blanks and start the copy and paste process.
I also need the code to then add a 2 to the pasted cell so that I can perform a pivot and differentiate between the copied cells and the pasted.
I have provided a picture below for better understanding. The end result should be that cell B2 contains the text 24 - Company: Hier 2 and E2 contains the text 07 - Product: Family Hier 2
My code is below and as always any and all help is greatly appreciated.
Pic 1
MY CODE
Public Sub BorderForNonEmpty()
Dim myRange As Range
Set myRange = Sheet1.Range("A1:H1")
For Each MyCell In myRange
If MyCell.Text = "" Then
MyCell.Offset(0, -1).Select
ActiveCell.Copy
ActiveCell.Offset(0, 1).PasteSpecial (xlPasteAll)
End If
Next
End Sub
Try the code below - the comments indicate what each important line is doing:
Option Explicit
Sub FillInHeaders()
Dim ws As Worksheet
Dim lngRowWithHeaders As Long
Dim rngHeader As Range
Dim rngCell As Range
' get a reference to your worksheet
Set ws = ThisWorkbook.Worksheets("SHeet1")
' set the row that the headers are on
lngRowWithHeaders = 2
' get the range from A1 to ??1 where ?? is last column
Set rngHeader = ws.Cells(lngRowWithHeaders, 1) _
.Resize(1, ws.Cells(lngRowWithHeaders, ws.Columns.Count) _
.End(xlToLeft).Column)
' iterate the range and look for blanks
For Each rngCell In rngHeader
' if blank then ...
If IsEmpty(rngCell.Value) Then
' get cell value from left and a 2
rngCell.Value = rngCell.Offset(0, -1).Value & "2"
End If
Next rngCell
End Sub
I am trying to change the background colour of certain cells in sheet 1 based on the same set of values in the sheet 2.
I want it to search the values in sheet 2 to sheet 1, if the values are same then the colour should change according to whatever color code we give. Below are screenshots of sheet1 (green) where I want to apply formatting and other is sheet2 is where I give input
I have got this code below, but it is selecting the cells in which data is not available also, please explain.
Option Explicit
Public Sub tmpSO()
Dim cell As Range
For Each cell In Sheet1.Range("A1:B10")
If cell.Value2 <> Sheet2.Cells(cell.Row, cell.Column).Value2 Then
cell.Interior.Color = vbRed
End If
Next cell
End Sub
#Peh , please check the below screenshot for how exactly my out put should look like in sheet1 based on the values in sheet2.
Output (Sheet1)
Input (Sheet2)
Your code is working fine. In sheet 1 it colors every cell of Range("A1:B10") that is different from sheet 2. If you don't want empty cells of sheet 1 to be colored you need to check for empty cells too.
Option Explicit
Public Sub tmpSO()
Dim cell As Range
For Each cell In Sheet1.Range("A1:B10")
If cell.Value2 <> Sheet2.Cells(cell.Row, cell.Column).Value2 And _
cell.Value2 <> vbNullString Then
cell.Interior.Color = vbRed
End If
Next cell
End Sub
Update for the updated question:
Therefore you will need a second loop. The first loop loops through the cells you want to format, the second loop loops through the input values and compares them to every cell of the first loop.
Option Explicit
Public Sub tmpSO()
Dim iCell As Range, jCell As Range
Dim FormatRange As Range
Set FormatRange = Sheet1.Range("A1:H11") 'the range you want to format
Dim InputRange As Range
Set InputRange = Sheet2.Range("B4:B10") 'the range where your input values are
For Each iCell In FormatRange
For Each jCell In InputRange
If iCell.Value2 = Sheet2.Cells(jCell.Row, jCell.Column).Value2 And _
iCell.Value2 <> vbNullString Then 'compare cell with all input values but left out empty cells
iCell.Interior.Color = vbRed
Exit For ' we can abort compairing with other input values if one is found.
End If
Next jCell
Next iCell
End Sub