I'm setting up a new macro to assign comments on a range of Cells with information from another range of cells. I Keep getting an
"Object Required" error.
I ran the code on a more simple workbook and it worked great. When I adapted for new column, sheet, row names and different ranges I ran into the error.
Dim rngCell As Range
Dim strComment As String, strConsolidated As String, strPERSON As String, strConcat As String
Dim arrConcat() As String
Dim lngPos As Long
Dim WIPDATA As Worksheet
Dim Display As Worksheet
Set WIPDATA = Worksheets("WIPDATA")
Set Display = Worksheets("Display")
For Each rngCell In WIPDATA.Range("I2:I278")
strConcat = strConcat & rngCell & rngCell.Offset(0, -7) & "||"
Next rngCell
arrConcat = Split(strConcat, "||")
For Each rngCell In Display.Range("D3:F23")
If rngCell.Value >= 0 Then
strConsolidated = Right(Display.Cells(rngCell.Row, 1).Value, 1)
strPERSON = Display.Cells(1, rngCell.Column).Value
For lngPos = 0 To UBound(arrConcat)
If LCase$(strConsolidated & strPERSON) = LCase$(arrConcat(lngPos)) Then
With WIPDATA
strComment = strComment & Chr(10) _
& "W/O " & .Range("B" & lngPos + 2).Value & Chr(10) _
& "OP# " & .Range("F" & lngPos + 2).Value & Chr(10) _
& "Qty " & .Range("I" & lngPos + 2).Value
End With
End If
Next lngPos
rngCell.ClearComments
If Len(strComment) > 0 Then
rngCell.AddComment (Right(strComment, Len(strComment) - 1))
rngCell.Comment.Shape.TextFrame.AutoSize = True
End If
strComment = vbNullString
End If
Next rngCell
End Sub
If it goes right, Notes are added to each cell in the range with corresponding data from the following sheet.
This is solved: Get a
Run-time error '424' Object Required
And it takes me to line 5. For Each rngCell In WIPDATA.Range("I2:I278")
Now I get notes applied to "E" and "F" But they aren't grabbing any values from the second sheet. Pictures updated to show latest.
Please Keep in mind that I'm mainly adapting already written code. Still very much learning and teaching myself at that.
Hopefully I was able to recreate your dataset properly. Assuming that you want to match Display sheet, Person (row 2) & Consolidated number (column C), with WIPDATA, Person (column A) & Consolidated number (column P), then you would need to use the following code:
Sub foo()
Dim rngCell As Range
Dim strComment As String, strConsolidated As String, strPERSON As String, strConcat As String
Dim arrConcat() As String
Dim lngPos As Long
Dim WIPDATA As Worksheet
Dim Display As Worksheet
Set WIPDATA = Worksheets("WIPDATA")
Set Display = Worksheets("Display")
For Each rngCell In WIPDATA.Range("A2:A278")
strConcat = strConcat & rngCell.Offset(0, 15) & rngCell & "||"
Next rngCell
arrConcat = Split(strConcat, "||")
For Each rngCell In Display.Range("D3:F23")
If rngCell.Value >= 0 Then
strConsolidated = Display.Cells(rngCell.Row, 3).Value
strPERSON = Display.Cells(2, rngCell.Column).Value
For lngPos = 0 To UBound(arrConcat)
If LCase$(strConsolidated & strPERSON) = LCase$(arrConcat(lngPos)) Then
With WIPDATA
strComment = strComment & Chr(10) _
& "W/O " & .Range("B" & lngPos + 2).Value & Chr(10) _
& "OP# " & .Range("F" & lngPos + 2).Value & Chr(10) _
& "Qty " & .Range("I" & lngPos + 2).Value
End With
End If
Next lngPos
rngCell.ClearComments
If Len(strComment) Then
rngCell.AddComment (Right(strComment, Len(strComment) - 1))
rngCell.Comment.Shape.TextFrame.AutoSize = True
End If
strComment = vbNullString
End If
Next rngCell
End Sub
Display sheet on my side displays two comments (yellow & orange colours):
WIPDATA setup (sorry, I was being lazy and I only copied part of your table!):
I created only 3 scenarios where Person & Consolidated match between both sheets, but hopefully you will be able to see that yellow & orange coloured rows are properly being copied into Display sheet comments.
Give it a try and let me know if you need any further help.
Related
I have data like this in different cells in column F: 3RG-1S,22,45YM+1W,32VC,23
How can I do to once I click on a cell in column F, in this case, rows 3, 22, 45, 32 and 23 get painted in yellow?
Please help, I've been trying to do this, but I don't know how to use those formulas within VBA
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim celda As Range
Dim rowvalue As Integer
Dim column As Integer
Dim comas As Integer
Dim positioncoma As Integer
Dim newpositioncoma As Integer
Dim contenidocelda As String
Dim i As Long
Dim NumberOfHits As Long
Dim e As Integer
If ActiveCell.value <> "" Then
Range("A1:F500").Interior.ColorIndex = xlNone
Set celda = ActiveCell
column = ActiveCell.column
If column = 6 Then 'Only works when clicking cells in column F
For i = 1 To Len(celda)
If Mid(celda, i, 1) = "," Then
NumberOfHits = NumberOfHits + 1
End If
Next
comas = NumberOfHits 'Gets the number of commas in the selected cell
positioncoma = 0 'counter in zero
If comas <> 0 Then 'Loop to find the first numbers for each value within commas and paint those rows in yellow
For e = 1 To comas
newpositioncoma = "=IFERROR(FIND(" & Chr(34) & "," & Chr(34) & "," & celda & "," & positioncoma & "+1),LEN(" & celda & "))"
contenidocelda = "=MID(" & celda & "," & positioncoma & "+1," & newpositioncoma & "-" & positioncoma & "-1)"
rowvalue = "=LEFT(" & contenidocelda & ", MATCH(FALSE, ISNUMBER(MID(" & contenidocelda & ", ROW(INDIRECT(" & Chr(34) & "1:" & Chr(34) & "&LEN(" & contenidocelda & ")+1)), 1) *1), 0) -1)"
Range("A" & rowvalue & ":F" & rowvalue).Interior.ColorIndex = 36
positioncoma = newpositioncoma
Next e
Else
rowvalue = "=LEFT(celda,MATCH(FALSE,ISNUMBER(MID(celda,ROW(INDIRECT(" & Chr(34) & "1:" & Chr(34) & "&LEN(celda)+1)),1)*1),0)-1)"
End If
Else
Range("A1:F500").Interior.ColorIndex = xlNone 'unpaint cells once click somewhere else
End If
Else
Range("A1:F500").Interior.ColorIndex = xlNone 'unpaint cells if ActiveCell is empty
End If
End Sub
At the moment I'm using the following code that highlights cells but only when I have a simple number as a value. I can't find a way to get the numbers 3, 22, 45, 32 and 23 from a string like this: 3RG-1S,22,45YM+1W,32VC,23.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim rowvalue As Integer
Range("A4:xz90").Interior.ColorIndex = xlNone
If ActiveCell.column = 6 Then
rowvalue = ActiveCell.Row
Range("A" & rowvalue & ":xz" & rowvalue).Interior.ColorIndex = 19
If VarType(ActiveCell.Value) = 5 Then
rowvalue = ActiveCell.Value
Range("A" & rowvalue & ":xz" & rowvalue).Interior.ColorIndex = 35
End If
End If
End Sub
Example of my worksheet and result when I click cell F69
Dim v As Variant
Dim iRow As Long
Range("A1:F500").Interior.ColorIndex = xlNone
For Each v In Split(Range("f1"), ",")
iRow = Val(v)
If iRow > 0 Then
Range(Cells(iRow, "A"), Cells(iRow, "F")).Interior.Color = vbYellow
End If
Next
I have a workbook and macro to calculate sum from multiple worksheets and put it to the master sheet. Below is my current macro which works fine. But I need to add one more additional condition to SUM. I think this can be done by using sumif. I have attached my workbook below explaining about my current outcome and expected outcome.
Sub GetSums()
Dim lngCol As Long, wsName As Range
With Sheets("Master")
If .[C3] <> "" Then .Range("C3", .[B3].End(2)) = ""
For Each wsName In .Range("C2", .[B2].End(2))
lngCol = Sheets(wsName.Value).Rows(1).Find("My Text").Column
wsName.Offset(1).Value = _
Evaluate("Sum('" & wsName.Value & "'!" & Cells(3, lngCol + 1).Address & ":" & _
Sheets(wsName.Value).Cells(Rows.Count, lngCol + 1).End(3).Address & ")")
Next wsName
End With
End Sub
Master Sheet
Sheet1
Sheet2
This is how it would look using Sumifs:
Sub GetSums()
Dim lngCol As Long, wsName As Range
With Sheets("Master")
If .[C3] <> "" Then .Range("C3", .[B3].End(2)) = ""
For Each wsName In .Range("C2", .[B2].End(2))
lngCol = Sheets(wsName.Value).Rows(1).Find("My Text").Column
wsName.Offset(1).Value = _
Evaluate("Sumifs('" & wsName.Value & "'!" & Cells(3, lngCol + 1).Address & ":" & _
Sheets(wsName.Value).Cells(Rows.Count, lngCol + 1).End(3).Address & ",'" & _
wsName.Value & "'!" & Cells(3, 2).Address & ":" & _
Sheets(wsName.Value).Cells(Rows.Count, 2).End(3).Address & "," & _
"""ABC"")")
Next wsName
End With
End Sub
BTW I would normally use End(xlToRight) and End(xlUp) rather than End(2) and End(3) ...
I have a data entry form that let's users enter the data into specific cells. What i want is a way to track changes to the cell values. When the data entered initially through the entry form, i don't want that information to be tracked. However, if the user tries to change/edit the data that was entered then i want to add a comment to show the initial value and the amended one as well.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim singlecell As Range
If Target.Cells.CountLarge > 1000 Then Exit Sub
For Each singlecell In Target
If singlecell.Comment Is Nothing Then
singlecell.AddComment Now & " - " & singlecell.Value & " - " & Environ("UserName")
Else
singlecell.Comment.Text _
vbNewLine & Now & " - " & singlecell.Value & " - " & Environ("UserName") _
, Len(singlecell.Comment.Text) + 1 _
, False
End If
singlecell.Comment.Shape.TextFrame.AutoSize = True
Next singlecell
End Sub
The code i tried adds a comment when the information from the entry form is submitted. However I don't need the comment to show just yet, I only want it when the user changes the initial cell value.
you can use a helper array to temporary store all of current cell comments and get the sensitive text out of the last recorded comment to compare with current cell content
Private Sub Worksheet_Change(ByVal Target As Range)
Dim singleCell As Range
Dim commentsArray As Variant 'array to hold all singleCell comments
Dim oldText As String ' string to hold last comment sensitive content
If Target.Cells.CountLarge > 1000 Then Exit Sub
For Each singleCell In Target
If singleCell.Comment Is Nothing Then
singleCell.AddComment Now & " - " & singleCell.Value & " - " & Environ("UserName")
Else
commentsArray = Split(singleCell.Comment.Text, vbNewLine) ' fill the array with current singleCell comments
oldText = CStr(Split(commentsArray(UBound(commentsArray)), " - ")(1)) ' extract last recorded comment sensitive text
'update comment if current cell value differs from last recorded comment sensitive text
If oldText <> CStr(singleCell.Value2) Then _
singleCell.Comment.Text _
vbNewLine & Now & " - " & singleCell.Value & " - " & Environ("UserName") _
, Len(singleCell.Comment.Text) + 1 _
, False
End If
singleCell.Comment.Shape.TextFrame.AutoSize = True
Next
End Sub
Copy and create the same table in same sheet, have it hidden ,
Sub CopyCurrentTable()
Application.ScreenUpdating = False
With shtMapping
.Range("E4:G1000").ClearContents 'which value to which value you are copying
.Range("B4:D" & GetLastRow(shtMapping, "B", 4)).Copy ' starting postion
.Range("E4").PasteSpecial xlPasteAll
Application.CutCopyMode = False
End With
End Sub
Sub LogAuditTrail()
Dim colOld As Collection
Dim colNew As Collection
Dim objNew As ClsMapping
Dim objOld As ClsMapping
Set colOld = getMappingData("E")
Set colNew = getMappingData("B")
Dim sTS As String
sTS = Format(Now, "dd-mmm-yyy hh:mm:ss")
For Each objNew In colNew
'Detect Items Changed
If ItemIsInCollection(colOld, objNew.getKey) Then
Set objOld = colOld(objNew.getKey)
If objNew.isDifferent(objOld) Then
Call PlotToAudit(objNew, objOld, sTS, "Change")
End If
Else
'Detect Items Added
Set objOld = New ClsMapping
Call PlotToAudit(objNew, objOld, sTS, "New")
End If
Next objNew
'Detect Items removed
For Each objOld In colOld
If Not ItemIsInCollection(colNew, objOld.getKey) Then
Set objNew = New ClsMapping
Call PlotToAudit(objNew, objOld, sTS, "Removed")
End If
Next objOld
End Sub
Sub PlotToAudit(obj1 As ClsMapping, obj2 As ClsMapping, sTS As String, sType As String)
Dim lRow As Long
lRow = shtAudit.Range("B1048576").End(xlUp).Row
If lRow = 3 Then
lRow = 5
ElseIf lRow = 1048576 Then
MsgBox "Audit sheet is full. Contact Support." & vbNewLine & "No audit trail will be saved", vbCritical, "ERROR"
Exit Sub
Else
lRow = lRow + 1
End If
With shtAudit
.Unprotect g_sPassword
.Range("B" & lRow).value = Application.UserName & "(" & Environ("USERNAME") & ")"
.Range("C" & lRow).value = sTS
.Range("D" & lRow).value = sType
Select Case sType
Case "Removed"
.Range("E" & lRow).value = ""
.Range("F" & lRow).value = ""
.Range("G" & lRow).value = ""
.Range("H" & lRow).value = obj2.FundCode
.Range("I" & lRow).value = obj2.Subs
.Range("J" & lRow).value = obj2.Reds
Case "New"
.Range("E" & lRow).value = obj1.FundCode
.Range("F" & lRow).value = obj1.Subs
.Range("G" & lRow).value = obj1.Reds
.Range("H" & lRow).value = ""
.Range("I" & lRow).value = ""
.Range("J" & lRow).value = ""
Case "Change"
.Range("E" & lRow).value = obj1.FundCode
.Range("F" & lRow).value = obj1.Subs
.Range("G" & lRow).value = obj1.Reds
.Range("H" & lRow).value = obj2.FundCode
.Range("I" & lRow).value = obj2.Subs
.Range("J" & lRow).value = obj2.Reds
End Select
With .Range("B" & lRow & ":J" & lRow)
.Interior.Color = vbWhite
.Borders.LineStyle = xlContinuou
End With
.Protect g_sPassword
End With
End Sub
I want to run a macro that will assign multiple cell values from one sheet as a comment in cells on another sheet, based on range and value.
So in Sheet1, I want to select range B1:D4, then for each cell, if => 0, add the corresponding comment from Sheet2 containing serial number, operation, and quantity.
edit
EDIT2
Sub COMMENTS()
'
' COMMENTS Macro
Dim rngCell As Range
Dim strComment, strStep, strObject As String, strConcat As String
Dim varMatch As Variant
Dim arrConcat() As String
For Each rngCell In Sheet2.Range("E2:E30")
strConcat = strConcat & rngCell & rngCell.Offset(0, -4) & "||"
Next rngCell
arrConcat = Split(strConcat, "||")
For Each rngCell In Sheet1.Range("B2:D5")
If rngCell > 0 Then
strStep = Right(Sheet1.Cells(rngCell.Row, 1).Value, 1)
strObject = Sheet1.Cells(1, rngCell.Column).Value
varMatch = Application.Match(strStep & strObject, arrConcat, 0)
If Not IsError(varMatch) Then
With Sheet2
strComment = "Serial number: " & .Range("B" & varMatch + 1).Value & Chr(10) _
& "Operation: " & .Range("C" & varMatch + 1).Value & Chr(10) _
& "Quantity: " & .Range("D" & varMatch + 1).Value
End With
rngCell.AddComment (strComment)
End If
End If
Next rngCell
End Sub
Give it a try:
Sub COMMENTS()
Dim rngCell As Range
Dim strComment, strStep, strObject As String, strConcat As String
Dim varMatch As Variant
Dim arrConcat() As String
For Each rngCell In Sheet2.Range("E2:E9")
strConcat = strConcat & rngCell & rngCell.Offset(0, -4) & "||"
Next rngCell
arrConcat = Split(strConcat, "||")
For Each rngCell In Sheet1.Range("B2:D5")
If rngCell > 0 Then
strStep = Right(Sheet1.Cells(rngCell.Row, 1).Value, 1)
strObject = Sheet1.Cells(1, rngCell.Column).Value
varMatch = Application.Match(strStep & strObject, arrConcat, 0)
If Not IsError(varMatch) Then
With Sheet2
strComment = "Serial number: " & .Range("B" & varMatch + 1).Value & Chr(10) _
& "Operation: " & .Range("C" & varMatch + 1).Value & Chr(10) _
& "Quantity: " & .Range("D" & varMatch + 1).Value
End With
rngCell.AddComment (strComment)
End If
End If
Next rngCell
End Sub
Result:
Note that there is no combination of "Step 4" and "y" present in Sheet2, that is why 4 in cell C5 does not show any comment. The code will also fail if there is already a comment added to a given cell (this can be also future-proofed).
Edit:
In case there is more than one match in Sheet2:
Sub COMMENTS()
Dim rngCell As Range
Dim strComment As String, strStep As String, strObject As String, strConcat As String
Dim arrConcat() As String
Dim lngPos As Long
For Each rngCell In Sheet2.Range("E2:E13")
strConcat = strConcat & rngCell & rngCell.Offset(0, -4) & "||"
Next rngCell
arrConcat = Split(strConcat, "||")
For Each rngCell In Sheet1.Range("B2:D5")
If rngCell.Value >= 0 Then
strStep = Right(Sheet1.Cells(rngCell.Row, 1).Value, 1)
strObject = Sheet1.Cells(1, rngCell.Column).Value
For lngPos = 0 To UBound(arrConcat)
If LCase$(strStep & strObject) = LCase$(arrConcat(lngPos)) Then
With Sheet2
strComment = strComment & Chr(10) _
& "Serial number: " & .Range("B" & lngPos + 2).Value & Chr(10) _
& "Operation: " & .Range("C" & lngPos + 2).Value & Chr(10) _
& "Quantity: " & .Range("D" & lngPos + 2).Value
End With
End If
Next lngPos
rngCell.ClearComments
If Len(strComment) Then
rngCell.AddComment (Right(strComment, Len(strComment) - 1))
rngCell.Comment.Shape.TextFrame.AutoSize = True
End If
strComment = vbNullString
End If
Next rngCell
End Sub
I have several columns that I need to concatenante, while the text styling for one column is kept intact and each column is concatenated in a new line (carriage return).
Col A text in bold, Col B text normal, Col C = concatenated col A content in bold + carriage return + col B content.
Using Concatenate formula in combination with CHAR(10) works but obviously the text styling isn't kept. VBA seems to be the way to go but I'm a total newbie at it.
I found the following code that does the concatenation, kees the styling but for the life of me I cant figure how to include a carriage return with vbCrLf in a string.
Sub MergeFormatCell()
Dim xSRg As Range
Dim xDRg As Range
Dim xRgEachRow As Range
Dim xRgEach As Range
Dim xRgVal As String
Dim I As Integer
Dim xRgLen As Integer
Dim xSRgRows As Integer
Dim xAddress As String
On Error Resume Next
xAddress = ActiveWindow.RangeSelection.Address
Set xSRg = Application.InputBox("Select cell columns to concatenate:", "Concatenate in Excel", xAddress, , , , , 8)
If xSRg Is Nothing Then Exit Sub
xSRgRows = xSRg.Rows.Count
Set xDRg = Application.InputBox("Select cells to output the result:", "Concatenate in Excel", , , , , , 8)
If xDRg Is Nothing Then Exit Sub
Set xDRg = xDRg(1)
For I = 1 To xSRgRows
xRgLen = 1
With xDRg.Offset(I - 1)
.Value = vbNullString
.ClearFormats
Set xRgEachRow = xSRg(1).Offset(I - 1).Resize(1, xSRg.Columns.Count)
For Each xRgEach In xRgEachRow
.Value = .Value & Trim(xRgEach.Value) & " "
Next
For Each xRgEach In xRgEachRow
xRgVal = xRgEach.Value
With .Characters(xRgLen, Len(Trim(xRgVal))).Font
.Name = xRgEach.Font.Name
.FontStyle = xRgEach.Font.FontStyle
.Size = xRgEach.Font.Size
.Strikethrough = xRgEach.Font.Strikethrough
.Superscript = xRgEach.Font.Superscript
.Subscript = xRgEach.Font.Subscript
.OutlineFont = xRgEach.Font.OutlineFont
.Shadow = xRgEach.Font.Shadow
.Underline = xRgEach.Font.Underline
.ColorIndex = xRgEach.Font.ColorIndex
End With
xRgLen = xRgLen + Len(Trim(xRgVal)) + 1
Next
End With
Next I
End Sub
The interest of the above code is that it allows the user to specify via an input box the cells range to concatenate and where to output the results.
Anyone can give me a hand and modify it so each new column goes in a new line after concatenation?
If you got a simplier solution I'm all for it as long as it works.
p.s. I'm running Excel 2013 if that matters.
This below code does not copy formatting, but it is concatenate both columns and bold the value appears in column A.
Option Explicit
Sub test()
Dim LastRow As Long, Row As Long
With ThisWorkbook.Worksheets("Sheet1")
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
For Row = 1 To LastRow
With .Range("C" & Row)
.Value = ThisWorkbook.Worksheets("Sheet1").Range("A" & Row).Value & vbNewLine & ThisWorkbook.Worksheets("Sheet1").Range("B" & Row).Value
.Characters(1, Len(ThisWorkbook.Worksheets("Sheet1").Range("A" & Row).Value)).Font.FontStyle = "Bold"
End With
Next Row
End With
End Sub
EDITED VERSION:
Option Explicit
Sub test()
Dim LastRow As Long, Row As Long
Dim strA As String, strB As String, strC As String, strD As String, strE As String, strF As String
With ThisWorkbook.Worksheets("Sheet1")
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
For Row = 1 To LastRow
strA = .Range("A" & Row).Value
strB = .Range("B" & Row).Value
strC = .Range("C" & Row).Value
strD = .Range("D" & Row).Value
strE = .Range("E" & Row).Value
strF = .Range("F" & Row).Value
With .Range("G" & Row)
.Value = strA & vbNewLine & strB & vbNewLine & strC & vbNewLine & strD & vbNewLine & strE & vbNewLine & strF
.Characters(1, Len(strA)).Font.FontStyle = "Bold"
.Characters((Len(strA) + Len(strB) + 5), Len(strC)).Font.FontStyle = "Bold"
.Characters((Len(strA) + Len(strB) + Len(strC) + Len(strD) + 9), Len(strE)).Font.FontStyle = "Bold"
End With
Next Row
End With
End Sub