I want to highlight excel sheet cell (Column 'A') of when it does not contain the text like "Verify", "Validate" or "Evaluate" in its content if, the value in corresponding cell of Column 'B' holds the value 'Y'.
When the column 'A' can't contains the words like 'Verify', 'Validate' and 'Evaluate' if the corresponding cell in Column 'B' holds value 'N'. So just need to highlight those discrepancies if its there.
Column 'A': Press Enter and verify this and this...
Column 'B': Y
This is quick example. However, the second formula can be shorted in case that column B cannot be blank. See if this fits ...
EDIT:
Here is VBA example as requested. You will need to save the code into current sheet (example: Sheet1 )...
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim str As String
Dim lCol As Long
Dim oCell As Object
Dim oCellFormat As Object
lCol = Target.Column
If lCol = 1 Or lCol = 2 Then
Set oCell = Cells(Target.Row, 1)
Else
GoTo mExit
End If
str = UCase(oCell.Value)
Set oCellFormat = Cells(oCell.Row, 1)
If (str = "VERIFY" Or str = "VALIDATE" Or str = "EVALUATE") Then
If UCase(Cells(oCell.Row, 2).Value) = "N" Then
oCellFormat.Interior.ColorIndex = 3 'red
ElseIf UCase(Cells(oCell.Row, 2).Value) = "Y" Then
oCellFormat.Interior.ColorIndex = 4 'green
Else
oCellFormat.Interior.ColorIndex = 2 'white
End If
Else
oCellFormat.Interior.ColorIndex = 2 'white
End If
GoTo mExit
Exit Sub
mExit:
Set oCell = Nothing 'free resources
Set oCellFormat = Nothing
End Sub
Related
I need to get the column letter of the first non-blank cell of a range. This range is basically a part of a row like.
Example:
Range = A2:G2
First non blank cell is on F2 cell.
Need to get 'F' and store it in a String variable.
What is the most efficient way to get this?
Thanks
Try this:
Sub columnName()
Dim mainRange As Range, cell As Range, columnName As String
Set mainRange = Range("A2:G2")
'Set mainRange = Selection
For Each cell In mainRange.Cells
If Not IsEmpty(cell.Value) Then
MsgBox Split(cell.Address, "$")(1)
Exit For
End If
Next cell
End Sub
You can get that column letter with a function:
Function firstBlankCol(rg As Range) As String
Dim x
If rg(1) = "" Then
x = rg(1).Address
Else
x = rg(1).End(xlToRight).Offset(0, 1).Address
End If
firstBlankCol = Split(x, "$")(1)
End Function
However, it is simpler, usually, to deal with the column number, and use that for the column argument of the Cells property.
Function firstBlankCol(rg As Range) As Long
Dim x
If rg(1) = "" Then
x = rg(1).Column
Else
x = rg(1).End(xlToRight).Column + 1
End If
firstBlankCol = x
End Function
How can I force user to enter negative number in Excel?
Basically column A can only be "W" or "X". Whenever column A has "W", i want column B to reflect a negative number, even if the user has keyed in a positive number.
"W" in column A corresponds to a negative value in column B
"X" in column B corresponds to a positive value in column B.
Thanks for the help!
No VBA needed. Just use data validation with the following formula
=OR(AND(A1="W",B1<0),AND(A1="X",B1>0))
Image 1: Using data validation W in column A only allows negatives in column B, X in column A only allows positives in column B.
Install the code below in the code module of the worksheet on which you want to control the input. It's a module that already exists in your VB Project. Any module you have to create is the wrong one and won't work. Look for a module with a double name like Sheet1 (Sheet1).
Private Sub Worksheet_Change(ByVal Target As Range)
' 058
Dim Rng As Range
Dim Numb As Variant
Dim NewNumb As Double
' ignore changes to more than one cell (such as pasting)
If Target.CountLarge > 1 Then Exit Sub
' this range starts in A2 and covers all used cells in columns A:B
Set Rng = Range(Cells(2, "A"), Cells(Rows.Count, "A").End(xlUp)) _
.Resize(, 2)
' skip if the changed cell is not within the defiend range
If Not Application.Intersect(Target, Rng) Is Nothing Then
' take no action of the value in column A isn't "X" or "W"
With Target
Numb = Cells(.Row, "B").Value
' take no action if the cell in column B has no value
If Numb Then
If Cells(.Row, "A").Value = "W" Then
NewNumb = Abs(Val(Numb)) * -1
ElseIf Cells(.Row, "A").Value = "X" Then
NewNumb = Abs(Val(Numb))
End If
' prevent changes made from calling this procedure
Application.EnableEvents = False
' don't take action if the value in column A
' was neither X nor W
If Numb And (Numb <> NewNumb) Then _
Cells(.Row, "B").Value = NewNumb
Application.EnableEvents = True
End If
End With
End If
End Sub
The code works on columns A and B. To modify these targets isn't difficult. For now, when a cell in either column is changed the procedure may take action. For the rules by which it will not take action please read the comments in the code. When it does take action it will make sure that any entry in column B is negative if the letter in column A is W and positive when it's X, regardless of what sign the user entered.
A little VBA in your worksheet module will take care of that:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Const SourceColumn As Long = 1
Const TargetColumn As Long = 2
Const NegatorSymbol As String = "W"
Dim SourceRange As Excel.Range
Dim TargetRange As Excel.Range
Dim Sign As Long
Dim TargetValue As Long
If Target.Column = TargetColumn Then
Set SourceRange = Cells(Target.Row, SourceColumn)
If UCase(SourceRange.Value) = NegatorSymbol Then
Sign = -1
Else
Sign = 1
End If
TargetValue = Sign * Abs(Target.Value)
If Target.Value <> TargetValue Then
Target.Value = TargetValue
End If
ElseIf Target.Column = SourceColumn Then
Set TargetRange = Cells(Target.Row, TargetColumn)
If UCase(Target.Value) = NegatorSymbol Then
Sign = -1
Else
Sign = 1
End If
TargetValue = Sign * Abs(TargetRange.Value)
If TargetRange.Value <> TargetValue Then
TargetRange.Value = TargetValue
End If
End If
End Sub
You can set on column B a data validation Custom with this formula:
=OR(AND(A1="W";B1<0);AND(A1<>"W";B1>0))
[EDIT]
I was late to the party...
I'm trying to create a time line via Excel and VBA, having the hours (1-24) listed in the range A1:A24; I created a ComboBox, filled the list with that very range and now I'm trying to link these two, so that if I choose a certain hour in the ComboBox, Excel will display "Test" one cell to the right of that specific cell from the given range (e.g. if I select "8" in the ComboBox, then Excel will display "Test" in B8, since the value of A8 is "8")
This is how far I got with the little knowledge about VBA that I have:
Private Sub Combobox1_Change()
For Each cell In Range("A1:A24")
If cell.Value = Me.ComboBox1.Value Then
cell.Offset(0, 1).Value = "Test"
End If
Next
End Sub
It would be great if someone could help me work this out!
If the list is ordered 1 - 24, simply use
Private Sub ComboBox1_Change()
Dim MyRange As Range
Set MyRange = [A1] ' or wherever your list starts
MyRange(ComboBox1.Value, 2) = "Test" ' address the range object by row, column
End Sub
Be carefull with If cell.Value = Me.ComboBox1.Value Then ... ComboBox1 returns a String, your Cell may contain numbers and the If may not work (at least here this is the case).
A more generalized routine scanning the whole list and not relying on its ascending sort order (you may soon have a list with "Apple", "Banana", "Cherimoya", ...)
Private Sub ComboBox1_Change()
Dim MyRange As Range, Idx As Integer
Set MyRange = [A1] ' or whereever your list starts
Idx = 1
Do While MyRange(Idx, 1) <> "" ' start processing
If Str(MyRange(Idx, 1)) = Str(ComboBox1) Then
If MyRange(Idx, 2) = "" Then ' bonus: do a toggle
MyRange(Idx, 2) = "Test"
Else
MyRange(Idx, 2) = ""
End If
Exit Do ' or not for full list processing
End If
Idx = Idx + 1
Loop
End Sub
Sorry, I have searched but have only found solutions similar to mine that I think should work! I have a button set up in a financial worksheet to hide rows that have value=0 in each of four colums. This is working fine except then I have a seperation row that I also want to hide if a subtotal row itself is hidden. It is hiding that row that I am having problems with:
Private Sub CommandButton1_Click()
'macro hides rows if all four columns contain zero values
'declare and initialize variables
Dim Col1 As String 'stores the column letter for the first column to examine
Col1 = "C"
Dim Col2 As String 'stores the column letter for the second column to examine
Col2 = "D"
Dim Col3 As String 'stores the column letter for the third column to examine
Col3 = "E"
Dim Col4 As String 'stores the column letter for the fourth column to examine
Col4 = "F"
Dim ListBottom As String 'stores the cell reference of the column that is populated for each record
ListBottom = "A65536"
Dim FirstRow As Long 'first row with data to inspect
FirstRow = 3
'declare and initialize system variables
Dim LastRow As Long 'store the last row with data
LastRow = 300 'Range(ListBottom).End(xlUp).Row 'moves up to the last row with data
Application.ScreenUpdating = False
For x = FirstRow To LastRow
If Cells(x, Col1).Value = "0" And Cells(x, Col2).Value = "0" And Cells(x, Col3).Value = "0" And Cells(x, Col4).Value = "0" Then
Cells(x, Col1).EntireRow.Hidden = True
'Expenses section tenant, utilites and maint - hides spacing and underlines if data rows are hidden'
If Cells("C73").Value = 0 And Cells("D73").Value = 0 And Cells("E73").Value = 0 And Cells("F73").Value = 0 Then
Rows("72").EntireRow.Hidden = True
End If
If Rows("82").EntireRow.Hidden = True Then
Rows("81").EntireRow.Hidden = True And Rows("83").EntireRow.Hidden = True
End If
End If
Next x
Application.ScreenUpdating = True
End Sub
The top part hiding the 0 rows works fine, it is in the bottom section that I can't get to work. I have included the two different ways (starting in line 29) I have tried and neither one works.
If there is a more elegant way to do this, I am certainly open to it. Thank you very much for your help!
Don't panic, the solution should be quite simple (and I'll try to provide some "elegance" to your code) :D
Private Sub CommandButton1_Click()
' You don't need to Dim all those variables. Also they were constants not variables :)
' In case you need to declare a constant use "Const x As yourType = value"
Dim ListBottom As String 'stores the cell reference of the column that is populated for each record
Dim FirstRow As Long 'first row with data to inspect
Dim LastRow As Long 'store the last row with data
ListBottom = "A65536" ' You can address the last cell with some commands like .SpecialCells or .End. I strongly suggest googling them up ;)
FirstRow = 3
LastRow = 300 'moves up to the last row with data
Application.ScreenUpdating = False
For x = FirstRow To LastRow
If Cells(x, 3).Value = "0" And Cells(x, 4).Value = "0" And Cells(x, 5).Value = "0" _
And Cells(x, 6).Value = "0" Then ' WARNING: "0" indicates a STRING in which
' you find a Chr 0. When you (like below) say = 0 without the "", it means
' that you're comparing to a NUMERIC value. In this case, it would do good
' storing your values in some variables with a numeric type (Integer, Long,
' Double) or a string and then compare them as fail-safe!
Cells(x, 3).EntireRow.Hidden = True
'Expenses section tenant, utilites and maint - hides spacing and underlines if data rows are hidden'
If Cells("C73").Value = 0 And Cells("D73").Value = 0 And Cells("E73").Value = 0 And Cells("F73").Value = 0 Then
Rows("72").EntireRow.Hidden = True
End If
If Rows("82").EntireRow.Hidden = True Then
Rows("81").EntireRow.Hidden = True ' DANGER: for multiple commands you
' can't simply give "command" AND "command. All things that are between
' "Then" and "End If" are executed sequentially
Rows("83").EntireRow.Hidden = True
End If
End If
Next x
Application.ScreenUpdating = True
End Sub
Didn't test it but should work. I recommend doing some test with those things I said back in the code, they could help you a lot in the future!
What about this?
Private Sub CommandButton1_Click()
'macro hides rows if all four columns contain zero values
'declare and initialize variables
Dim Col1 As String 'stores the column letter for the first column to examine
Col1 = "C"
Dim Col2 As String 'stores the column letter for the second column to examine
Col2 = "D"
Dim Col3 As String 'stores the column letter for the third column to examine
Col3 = "E"
Dim Col4 As String 'stores the column letter for the fourth column to examine
Col4 = "F"
Dim ListBottom As String 'stores the cell reference of the column that is populated for each record
ListBottom = "A65536"
Dim FirstRow As Long 'first row with data to inspect
FirstRow = 3
'declare and initialize system variables
Dim LastRow As Long 'store the last row with data
LastRow = 300 'Range(ListBottom).End(xlUp).Row 'moves up to the last row with data
Application.ScreenUpdating = False
For x = FirstRow To LastRow
If Cells(x, Col1).Value = "0" And Cells(x, Col2).Value = "0" And Cells(x, Col3).Value = "0" And Cells(x, Col4).Value = "0" Then
Cells(x, Col1).EntireRow.Hidden = True
'Expenses section tenant, utilites and maint - hides spacing and underlines if data rows are hidden'
Cells(x+1, Col1).EntireRow.Hidden = True
End If
Next x
Application.ScreenUpdating = True
End Sub
Instead of veryfing if a row is hidden, hide the secondary row at the same time as you hide the main one.
I have a 2D array in the following format. (Unsure how to format this so it appears in a table format. The first and second columns are 1 character each and the 3rd columns is 2 characters)
a 1 aa
a 2 ab
b 1 ba
b 2 bb
c 1 ca
c 2 cb
d 1 da
d 2 db
e 1 ea
e 2 eb
f 1 fa
f 2 fb
I need to first search for "c" in the first column. If that is found, I need to search for "2" in the second and find the corresponding value in the 3rd. In this case, I finally need the value "cb".
Here is what I have so far but it isn't working correctly since I don't see the desired results
Public Sub Readinto_array()
Dim TheArray As Variant
Dim i As Long, j As Long, k As Long
Dim found As Boolean
TheArray = Range("G20:I31").Value
found = False
For i = LBound(TheArray) To UBound(TheArray)
For j = LBound(TheArray, 2) To UBound(TheArray, 2)
MsgBox TheArray(i, j)
If TheArray(i, j) <> "c" Then
Exit For
Else
If StrComp(TheArray(i, j + 1), "2", vbTextCompare) = 0 Then
MsgBox "found"
found = True
Exit For
End If
End If
Next j
If found Then
Exit For
End If
Next i
End Sub
Not sure why you have to loop for the columns since you know there's always 3...
So this seems easier.
Public Sub Readinto_array()
Dim TheArray As Variant
Dim i As Long
TheArray = Range("G20:I31").Value
For i = LBound(TheArray) To UBound(TheArray)
If TheArray(i, 1) = "c" And TheArray(i, 2) = "2" Then
MsgBox (TheArray(i, 3))
End If
Next i
End Sub
Or further simplified using innate excel objects.
Public Sub Readinto_array()
Dim MyRange As Range
Set MyRange = Range("G20:I31")
For Each cell In MyRange
If cell.Value = "c" And Cells(cell.Row, cell.Column + 1) = "2" Then
MsgBox (Cells(cell.Row, cell.Column + 2).Value)
End If
Next
End Sub
You could also do this with a worksheet formula. For example, if E1 contains your column1 value; and B1 your column2 value, try:
G2: =INDEX(ThirdColumn,SUMPRODUCT((FirstColumn=E1)*(SecondColumn=E2)*ROW(ThirdColumn)))
I see a tree like structure and think xml but to keep it simple use a Dictionary...
In the VBA Editor - using the Tools/References menu add a reference to Microsoft Scripting Runtime.
Write a function to create the dictionary:
Public Function LookErUp() As Dictionary
Dim i As Integer
Dim d As Dictionary
Set d = New Dictionary
Dim col1() As Variant
col1 = Array("a", "b", "c", "d", "e", "f")
Dim col2 As Dictionary
For i = 0 To UBound(col1)
Set col2 = New Dictionary
col2.Add 1, col1(i) & "a"
col2.Add 2, col1(i) & "b"
d.Add col1(i), col2
Next
Set LookErUp = d
End Function
You can test using the dictionary the Test procedure:
Public Sub Test()
Dim ld As Dictionary
Set ld = LookErUp
If ld.Exists("c") Then
If ld("c").Exists(2) Then
MsgBox "Found " & ld("c")(2)
End If
End If
End Sub
Try creating a third column where you concatenate the values from three previous columns i.e. in D1 you would have =A1&B1&C1. Next use that in you vlookup or match. If you do not specify exact match then in case having multiple entries for c 1 you would get the first or last one, depending on comparison type used.