I'm currently "trying" to setup a grid in Excel where
the user inputs a reference (e.g. HP1 or HP234) and,
I can automatically detect the cell it was entered into and the numeric value in the cell (e.g. HP1 = 1, HP234 = 234).
I have started to play with the code below. In the section msgbox("work") - I'm using just to test code around it. Here I want to return the numeric value in the cell and the cell location so I can put them onto a report.
Any help would be greatly appreciated.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
Dim rngTarget As Range
Set rngTarget = Range("a1:a100")
If Not Intersect(Target, Range("A1:A100")) Is Nothing Then
For Each rng In rngTarget
If InStr(1, prNg, "H") > 0 And InStr(1, rngEachValue, "P") = 0 Then
MsgBox ("works")
End If
Next
End If
End Sub
I found this a nice question so put some work into the answer. I think this will do just what you want! It even works with decimal and thousand separators.
I do admit the NumericalValue function could be created in a different way as well (find the first and the last number and take that mid part of the string.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
Dim rngTarget As Range
Dim varValue As Variant
Set rngTarget = Range("a1:a100")
If Not Intersect(Target, rngTarget) Is Nothing Then
For Each rng In rngTarget
'only check cells that contain an H and a P
If InStr(1, rng, "H") > 0 And InStr(1, rng, "P") > 0 Then
'find the numerical value if any (Empty if not found)
varValue = NumericalValue(rng.Value2)
If Not IsEmpty(varValue) Then
MsgBox "hurray the value of cell " & rng.AddressLocal & " is " & varValue
End If
End If
Next
End If
End Sub
'return the first numerical value found in the cell
Private Function NumericalValue(ByVal strValue As String) As Variant
Dim intChar As Integer
Dim booNumberFound As Boolean
Dim intDecimal As Integer
booNumberFound = False
NumericalValue = Val(strValue)
For intChar = 1 To Len(strValue) Step 1
'if a number found then grow the total numerical value with it
If IsNumeric(Mid(strValue, intChar, 1)) Then
NumericalValue = NumericalValue * IIf(intDecimal = 0, 10, 1) + _
Val(Mid(strValue, intChar, 1)) * 10 ^ -intDecimal
If intDecimal > 0 Then
intDecimal = intDecimal + 1
End If
booNumberFound = True
'if the decimal separator is found then set the decimal switch
ElseIf intDecimal = 0 And booNumberFound = True And Mid(strValue, intChar, 1) = Application.DecimalSeparator Then
intDecimal = 1
'skip the thousand separator to find more numbers
ElseIf booNumberFound = True And Mid(strValue, intChar, 1) = Application.ThousandsSeparator Then
ElseIf booNumberFound = True Then
Exit For
End If
Next intChar
End Function
you're most of the way there, try the below:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
Dim rngTarget As Range
Dim sText As String
Set rngTarget = Range("a1:a100")
If Not Intersect(Target, Range("A1:A100")) Is Nothing Then
For Each rng In rngTarget
If InStr(1, rng.Text, "H") > 0 And InStr(1, rng.Text, "P") > 0 Then
sText = rng.Text
sText = Replace(sText, "H", "")
sText = Replace(sText, "P", "")
Debug.Print rng.Address & " = " & Val(sText)
End If
Next
End If
End Sub
Related
I'm trying to count the number of instances of a cell containing all uppercase characters in a user defined range, I've got some code already which loops through and highlights those uppercase cells correctly, but I'm struggling to apply that logic to VBA's Countif function. Here's the code I've got but its giving a mismatch error:
'count instances of all caps
Dim allcaps As Long
allcaps = Application.CountIf(Range(rngCompany.Cells(1, 1), rngCompany.Cells(Lastrow, 1)), UCase(Range(rngCompany.Cells(1, 1), rngCompany.Cells(Lastrow, 1))))
MsgBox "There are " & allcaps & " uppercase company names to review."
The code which is highlighting the cells correctly is:
'Highlight all caps company names for review
With ws
For i = 2 To Lastrow
' checks if cells in company name col are uppercase
If rngCompany.EntireColumn.Cells(i, 1).Value = UCase(rngCompany.EntireColumn.Cells(i, 1).Value) Then
wbk1.Sheets(1).Rows(i).Interior.ColorIndex = 6 '6: Yellow
Else
End If
Next i
End With
Is there a way to make the countif code work in a similar way within the loop? Thanks.
Here is how you can do it:
Function AllCapsCount(Target As Range) As Long
With Target.Parent
AllCapsCount = .Evaluate("=SUMPRODUCT(--EXACT(" & Target.Address & ",UPPER(" & Target.Address & ")))")
End With
End Function
Tim's suggestion of simply adding a counter within the loop was the simplest solution for me, after a long day I'd overlooked that way forward!
Code example for anyone coming across this in future:
AllCapsCount = 0
With ws
For i = 2 To Lastrow
' checks if cells in company name col are uppercase
If rngCompany.EntireColumn.Cells(i, 1).Value = UCase(rngCompany.EntireColumn.Cells(i, 1).Value) Then
wbk1.Sheets(1).Rows(i).Interior.ColorIndex = 6 '6: Yellow
AllCapsCount = AllCapsCount + 1
Else
End If
Next i
End With
Highlight and Count Cells if UCase but no LCase
Sub TESTgetAllCapsRange()
Dim rngCompany As Range
Set rngCompany = Range("A2:E11")
rngCompany.Interior.Color = xlNone
Dim rng As Range: Set rng = getAllCapsRange(rngCompany)
If Not rng Is Nothing Then
rng.Interior.Color = vbYellow
Dim AllCaps As Long: AllCaps = rng.Cells.CountLarge
If AllCaps > 1 Then
MsgBox "There are " & AllCaps _
& " uppercase company names to review."
Else
MsgBox "There is 1 uppercase company name to review."
End If
Else
MsgBox "There are no uppercase company names to review."
End If
End Sub
Function getAllCapsRange(rng As Range) As Range
If Not rng Is Nothing Then
Dim tRng As Range
Dim aRng As Range
Dim cel As Range
For Each aRng In rng.Areas
For Each cel In aRng.Cells
If Not IsError(cel) Then
If containsUCaseButNoLCase(cel.Value) Then
buildRange tRng, cel
End If
End If
Next cel
Next aRng
If Not tRng Is Nothing Then
Set getAllCapsRange = tRng
End If
End If
End Function
Function containsUCaseButNoLCase(ByVal CheckString As String) As Boolean
' Check if there is an upper case character.
If StrComp(CheckString, LCase(CheckString), vbBinaryCompare) <> 0 Then
' Check if there are no lower case characters.
If StrComp(CheckString, UCase(CheckString), vbBinaryCompare) = 0 Then
containsUCaseButNoLCase = True
End If
End If
End Function
Sub buildRange(ByRef BuiltRange As Range, AddRange As Range)
If Not AddRange Is Nothing Then
If Not BuiltRange Is Nothing Then
Set BuiltRange = Union(BuiltRange, AddRange)
Else
Set BuiltRange = AddRange
End If
End If
End Sub
i want to print value where background yellow is same as cell and background white is [0,0]
for this condition i want to get
[1,9],[0,0],[1,7],[1,6],[0,0],[1,4],[0,0],[1,2],[0,0]
I've written some code
Dim isect As Range
Set isect = Intersect(Target, Me.Range("$B$80:$J$80"))
If Not isect Is Nothing Then
Dim s As String
If Target.Interior.Color = vbYellow Then
s = Target.Value
Else
s = "[0,0]"
End If
Range("D96").Value = s
but it get only one value, what I should do for continuing.
Any help will be appreciated.
Dim isect As Range
Dim aCell As Range
Dim Output As String
Set isect = Intersect(target, Me.Range("$B$80:$J$80"))
If Not isect Is Nothing Then
For Each aCell In isect
If aCell.Interior.Color = vbYellow Then
Output = Output & "," & aCell.Value
Else
Output = Output & "," & "[0,0]"
End If
Next aCell
Range("D96") = Mid(Output, 2)
End If
Is this what you want?
Dependent on Cell Property (Fill Color)
Standard Module Code (e.g. Module1)
Option Explicit
Function getString(SourceRange As Range, _
Optional ByVal FillColor As Long = 0, _
Optional ByVal CriteriaNotMetValue As Variant = Empty, _
Optional ByVal Delimiter As String = ", ") _
As String
If SourceRange Is Nothing Then Exit Function
' Write values of range to array.
Dim Data As Variant
If SourceRange.Rows.Count > 1 Or SourceRange.Columns.Count > 1 Then
Data = SourceRange.Value
Else
ReDim Data(1 To 1, 1 To 1): Data(1, 1) = SourceRange.Value
End If
' Modify values in array.
Dim i As Long, j As Long, Result As String
For i = 1 To UBound(Data)
For j = 1 To UBound(Data, 2)
If SourceRange.Cells(i, j).Interior.Color <> FillColor Then
Data(i, j) = CriteriaNotMetValue
End If
Result = Result & Delimiter & Data(i, j)
Next j
Next i
' Remove redundant Delimiter.
getString = Right(Result, Len(Result) - Len(Delimiter))
End Function
Sheet Code (e.g. Sheet1)
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Const rngAddress As String = "B80:J80"
Const cellAddress As String = "D96"
Const CriteriaNotMetValue As Variant = "[0,0]"
Const FillColor As Long = vbYellow
Const Delimiter As String = ","
If Intersect(Me.Range(rngAddress), Target) Is Nothing Then Exit Sub
On Error GoTo clearError
Application.EnableEvents = False
Dim Result As String
Result = getString(Me.Range(rngAddress), FillColor, CriteriaNotMetValue, Delimiter)
Me.Range(cellAddress).Value = Result
CleanExit:
Application.EnableEvents = True
Exit Sub
clearError:
Debug.Print "Run-time error '" & Err.Number & "': " & Err.Description
On Error GoTo 0
GoTo CleanExit
End Sub
I would like to change the color of a text in a cell in MS Excel like the conditioned formatting. I have different text in one cell, e.g. "WUG-FGT" or "INZL-DRE". I would like to format the cells (all cells in my workshhet), that a defined text like "WUG-FGT" appears red and the other text "INZL-DRE" green, but the text is in the same cell. With "sandard" conditioned formatting I only get the backgroud coloured.
A similar questions is this: How can I change color of text in a cell of MS Excel?
But the difference is that I (actually) don't work with programming. That means that I need a more simple or easy solution to implement this in my excel file.
Is this possible? A solution with VBA would also be possible, I know how to implement them.
here example how you can achieve required results:
Sub test()
Dim cl As Range
Dim sVar1$, sVar2$, pos%
sVar1 = "WUG-FGT"
sVar2 = "INZL-DRE"
For Each cl In Selection
If cl.Value2 Like "*" & sVar1 & "*" Then
pos = InStr(1, cl.Value2, sVar1, vbTextCompare)
cl.Characters(pos, Len(sVar1)).Font.Color = vbRed
End If
If cl.Value2 Like "*" & sVar2 & "*" Then
pos = InStr(1, cl.Value2, sVar2, vbTextCompare)
cl.Characters(pos, Len(sVar2)).Font.Color = vbGreen
End If
Next cl
End Sub
test
UPDATE
Is it possible to count how often the word has been detected. Either to write to total amount to a defined cell or what also would be great, to add the number of counts in brackets behind the word with an control variable? So in your example: A2: "WUG-FGT(1)", A4: "WUG-FGT(2)", A5: "WUG-FGT(3)"
Yes, but you should update the cell before colorizing, otherwise whole cell font will be colorized by the first char's color (e.g. cell contains both keywords and first is red, and second is green, after update whole cell font will be red). See updated code and test bellow:
Sub test_upd()
Dim cl As Range, sVar1$, sVar2$, pos%, cnt1%, cnt2%
Dim bVar1 As Boolean, bVar2 As Boolean
sVar1 = "WUG-FGT": cnt1 = 0
sVar2 = "INZL-DRE": cnt2 = 0
For Each cl In Selection
'string value should be updated before colorize
If cl.Value2 Like "*" & sVar1 & "*" Then
bVar1 = True
cnt1 = cnt1 + 1
cl.Value2 = Replace(cl.Value, sVar1, sVar1 & "(" & cnt1 & ")")
End If
If cl.Value2 Like "*" & sVar2 & "*" Then
bVar2 = True
cnt2 = cnt2 + 1
cl.Value2 = Replace(cl.Value, sVar2, sVar2 & "(" & cnt2 & ")")
End If
pos = InStr(1, cl.Value2, sVar1, vbTextCompare)
If bVar1 Then cl.Characters(pos, Len(sVar1)).Font.Color = vbRed
pos = InStr(1, cl.Value2, sVar2, vbTextCompare)
If bVar2 Then cl.Characters(pos, Len(sVar2)).Font.Color = vbGreen
bVar1 = False: bVar2 = False
Next cl
End Sub
test
Change Format of Parts of Values in Cells
Links
Workbook Download
Image
The Code
'*******************************************************************************
Sub CFF(Range As Range, SearchString As String, _
Optional ColorIndex As Long = -4105, _
Optional OccurrenceFirst0All1 As Long = 1, _
Optional Case1In0Sensitive As Long = 1)
' ColorIndex
' 3 for Red
' 10 for Green
' OccurrenceFirst0All1
' 0 - Only First Occurrence of SearchString in cell of Range.
' 1 (Default) - All occurrences of SearchString in cell of Range.
' Case1In0Sensitive
' 0 - Case-sensitive i.e. aaa <> AaA <> AAA
' 1 (Default) - Case-INsensitive i.e. aaa = AaA = AAA
Const cBold As Boolean = False ' Enable Bold (True) for ColorIndex <> -4105
Dim i As Long ' Row Counter
Dim j As Long ' Column Counter
Dim rngCell As Range ' Current Cell Range
Dim lngStart As Long ' Current Start Position
Dim lngChars As Long ' Number of characters (Length) of SearchString
' Assign Length of SearchString to variable.
lngChars = Len(SearchString)
' In Range.
With Range
' Loop through rows of Range.
For i = .Row To .Row + .Rows.Count - 1
' Loop through columns of Range.
For j = .Column To .Column + .Columns.Count - 1
' Assign current cell range to variable.
Set rngCell = .Cells(i, j)
' Calculate the position of the first occurrence
' of SearchString in value of current cell range.
lngStart = InStr(1, rngCell, SearchString, Case1In0Sensitive)
If lngStart > 0 Then ' SearchString IS found.
If OccurrenceFirst0All1 = 0 Then ' FIRST occurrence only.
GoSub ChangeFontFormat
Else ' ALL occurrences.
Do
GoSub ChangeFontFormat
lngStart = lngStart + lngChars
lngStart = InStr(lngStart, rngCell, SearchString, _
Case1In0Sensitive)
Loop Until lngStart = 0
End If
'Else ' SearchString NOT found.
End If
Next
Next
End With
Exit Sub
ChangeFontFormat:
' Font Formatting Options
With rngCell.Characters(lngStart, lngChars).Font
' Change font color.
.ColorIndex = ColorIndex
' Enable Bold for ColorIndex <> -4105
If cBold Then
If .ColorIndex = -4105 Then ' -4105 = xlAutomatic
.Bold = False
Else
.Bold = True
End If
End If
End With
Return
End Sub
'*******************************************************************************
Real Used Range (RUR)
'*******************************************************************************
' Purpose: Returns the Real Used Range of a worksheet.
' Returns: Range Object or "Nothing".
'*******************************************************************************
Function RUR(Optional NotActiveSheet As Worksheet) As Range
Dim objWs As Worksheet
If Not NotActiveSheet Is Nothing Then
Set objWs = NotActiveSheet
Else
Set objWs = ActiveSheet
End If
If objWs Is Nothing Then Exit Function
Dim HLP As Range ' Cells Range
Dim FUR As Long ' First Used Row Number
Dim FUC As Long ' First Used Column Number
Dim LUR As Long ' Last Used Row Number
Dim LUC As Long ' Last Used Column Number
With objWs.Cells
Set HLP = .Cells(.Cells.Count)
Set RUR = .Find("*", HLP, xlFormulas, xlWhole, xlByRows)
If Not RUR Is Nothing Then
FUR = RUR.Row
FUC = .Find("*", HLP, , , xlByColumns).Column
LUR = .Find("*", , , , xlByRows, xlPrevious).Row
LUC = .Find("*", , , , xlByColumns, xlPrevious).Column
Set RUR = .Cells(FUR, FUC) _
.Resize(LUR - FUR + 1, LUC - FUC + 1)
End If
End With
End Function
'*******************************************************************************
Usage
The following code if used with the Change1Reset0 argument set to 1, will change the format in each occurrence of the desired strings in a case-INsensitive search.
'*******************************************************************************
Sub ChangeStringFormat(Optional Change1Reset0 As Long = 0)
Const cSheet As Variant = "Sheet1"
Const cStringList As String = "WUG-FGT,INZL-DRE"
Const cColorIndexList As String = "3,10" ' 3-Red, 10-Green
' Note: More strings can be added to cStringList but then there have to be
' added more ColorIndex values to cColorIndexList i.e. the number of
' elements in cStringList has to be equal to the number of elements
' in cColorIndexList.
Dim rng As Range ' Range
Dim vntS As Variant ' String Array
Dim vntC As Variant ' Color IndexArray
Dim i As Long ' Array Elements Counter
Set rng = RUR(ThisWorkbook.Worksheets(cSheet))
If Not rng Is Nothing Then
vntS = Split(cStringList, ",")
If Change1Reset0 = 1 Then
vntC = Split(cColorIndexList, ",")
' Loop through elements of String (ColorIndex) Array
For i = 0 To UBound(vntS)
' Change Font Format.
CFF rng, CStr(Trim(vntS(i))), CLng(Trim(vntC(i)))
Next
Else
For i = 0 To UBound(vntS)
' Reset Font Format.
CFF rng, CStr(Trim(vntS(i)))
Next
End If
End If
End Sub
'*******************************************************************************
The previous codes should all be in a standard module e.g. Module1.
CommandButtons
The following code should be in the sheet window where the commandbuttons are created, e.g. Sheet1.
Option Explicit
Private Sub cmdChange_Click()
ChangeStringFormat 1
End Sub
Private Sub cmdReset_Click()
ChangeStringFormat ' or ChangeStringFormat 0
End Sub
Try:
Option Explicit
Sub test()
Dim rng As Range, cell As Range
Dim StartPosWUG As Long, StartPosINL As Long
With ThisWorkbook.Worksheets("Sheet1")
Set rng = .UsedRange
For Each cell In rng
StartPosWUG = InStr(1, cell, "WUG-FGT")
StartPosINL = InStr(1, cell, "INZL-DRE")
If StartPosWUG > 0 Then
With cell.Characters(Start:=StartPosWUG, Length:=Len("WUG-FGT")).Font
.Color = vbRed
End With
End If
If StartPosINL > 0 Then
With cell.Characters(Start:=StartPosINL, Length:=Len("INZL-DRE")).Font
.Color = vbGreen
End With
End If
Next
End With
End Sub
I have a macro that works perfectly but only if the range has a 1 in the first cell such as the following: Range("E1:E12"). If I want to change the range to Range("E2:E13") it doesn’t paste to the correct cell. The uploaded Excel sheet is the current macro that works but I need to change the range to different cells.
Sub Part()
Dim SearchRange As Range, _
DashPair As Variant, _
PairParts As Variant, _
SearchVal As Variant, _
FoundPos As Variant, _
NextCol As Long
Set SearchRange = Range("E1:E12")
For Each DashPair In Range("B30, F30, J30")
Err.Clear
NextCol = 1
If DashPair.Value <> "" Then
PairParts = Split(DashPair, "-")
If PairParts(1) = "15" Then
SearchVal = DashPair.Offset(RowOffset:=1).Value
On Error Resume Next
Set FoundPos = SearchRange.Find(SearchVal, LookAt:=xlWhole)
If Not FoundPos Is Nothing Then
FoundPos = FoundPos.Row
' find first empty column right of E
While SearchRange(FoundPos).Offset(ColumnOffset:=NextCol).Value <> ""
NextCol = NextCol + 1
Wend
PairParts(1) = PairParts(1) + 1
PairParts = Join(PairParts, "-")
With SearchRange(FoundPos).Offset(ColumnOffset:=NextCol)
.NumberFormat = "#"
.Value = "" & PairParts & ""
End With
DashPair.Resize(ColumnSize:=3).ClearContents
End If
End If '15 found
End If
Next DashPair
End Sub
excel image
Cleaned up the code a little: your issue is with the following: FoundPos = FoundPos.Row as SearchRange(FoundPos) will return the index cell not the cell in the same row
i.e. E2:E15 => E2 is row 2, but SearchRange(2) is E3
* Edit *
Altered next empty cell selection protocol; previous one didn't work as expected
Sub Part()
Dim ws As Worksheet: Set ws = ActiveSheet
Dim Cell As Range, Target As Range, arr As Variant
With ws
Dim SearchRange As Range: Set SearchRange = .Range("E1:E12")
For Each Cell In .Range("B30, F30, J30")
If Cell <> "" Then
arr = Split(Cell, "-")
If UBound(arr) > 0 And arr(1) = "15" Then
On Error Resume Next
Set Target = SearchRange.Find(Cell.Offset(1, 0), LookAt:=xlWhole)
On Error GoTo 0
If Not Target Is Nothing Then
Do While Target <> ""
Set Target = Target.Offset(0, 1)
Loop
With Target
arr(1) = "16"
.NumberFormat = "#"
.value = Join(arr, "-")
Debug.Print Join(arr, "-")
End With
.Range(Cell, Cell.Offset(0, 2)).ClearContents
End If
End If
End If
Next Cell
End With
End Sub
I want to create comments to a range of cells. The comments should contain the values of another range of cells.
Here is what I have so far:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim sResult As String
If Union(Target, Range("A18")).Address = Target.Address Then
Application.EnableEvents = False
Application.ScreenUpdating = False
sResult = "Maximal " & Target.Value
With Range("I6")
.ClearComments
.AddComment
.Comment.Text Text:=sResult
End With
Application.EnableEvents = True
Application.ScreenUpdating = True
End If
End Sub
This works for one cell. I need this for a range of cells. For example, let's say I need the values of cells A1:F20 in comments of cells A21:F40. I do not want to copy the same Sub as many times.
It should do you the job if you replace
With Range("I6")
.ClearComments
.AddComment
.Comment.Text Text:=sResult
End With
with
For Each cell In Range("A1", "F20").Cells
Dim V As Range
Set V = cell.Offset(20, 0)
With cell
.ClearComments
If Not IsEmpty(V) Then
.AddComment V.Value
End If
End With
Next
This will basically ignore all empty cells.
Output:
My code:
Sub TEST()
For Each cell In Range("A1", "F20").Cells
Dim V As Range
Set V = cell.Offset(20, 0)
With cell
.ClearComments
If Not IsEmpty(V) Then
.AddComment V.Value
End If
End With
Next
End Sub
I made some adaptions to your advices, thanks a lot, this solved my problem:
Private Sub Worksheet_Change(ByVal target As Range)
Dim src As Range: Set src = Worksheets("maxleft").Range("C2:K11")
Dim tar As Range: Set tar = Range("I6:Q15")
For i = 0 To tar.Rows.Count - 1
For j = 0 To tar.Columns.Count - 1
Dim sResult As String
sResult = "Maximal " & Worksheets("maxleft").Cells(src.Row + i, src.Column + j)
With Cells(tar.Row + i, tar.Column + j)
.ClearComments
.AddComment
.Comment.Text Text:=sResult
End With
Next j
Next i
End Sub
From your question I understand that you want to select a range of cells (e.g. "A1:A5"), then select another range of cells (e.g. "B6:B10") and the respective values of the first selected Range should be placed as comments in the secon selected Range. Is this correct?
The following code checks if 2 ranges with an equal length are selected and copies the values of the first selected range as comments to the second selected range:
Private Sub Worksheet_SelectionChange(ByVal target As Range)
If InStr(target.Address, ",") Then
Dim selected_range() As String
selected_range = Split(target.Address, ",")
If Range(selected_range(0)).Rows.Count = Range(selected_range(1)).Rows.Count Then
Dim src As Range: Set src = Range(selected_range(0))
Dim tar As Range: Set tar = Range(selected_range(1))
For i = 0 To src.Rows.Count - 1
Dim sResult As String
sResult = "Maximal " & Cells(src.Row + i, src.Column)
With Cells(tar.Row + i, tar.Column)
.ClearComments
.AddComment
.Comment.Text Text:=sResult
End With
Next i
End If
End If
End Sub