Locking cell based on value on other cell - vba

Please find the below code. I am not sure where am I going wrong in my code.
My purpose is to check the value in D44 cell(drop down list) and based on the value lock/unlock D45 cell.
Values in D44 are NO,13 fracto,18 fracto,Any Other Fracto"
User should be able to edit the cell D45 only if the D44 cell value is set to "Any Other Fracto".
Sub TheSelectCase()
Select Case Range("D44").Value
Case "Any Other Fracto"
Range("D45").Locked = False
Range("D45").Activate
Case = "NO"
Range("D45").Locked = True
Range("D45").Clear
Case <> "NO" Or "Any Other Fracto"
Range("D45").Locked = True
End Select
End Sub

Unless the dropdown is an ActiveX control, you'll need to do this via Worksheet_Change event handler, and also, you only have two cases: 1) A case where user is allowed to edit ("Any other fracto") and 2) any other value in which the user is not allowed to edit.
Assuming you're using a Validation List, do this in the worksheet's Worksheet_Change event:
Private Sub Worksheet_Change(ByVal Target As Range)
'Exit on any other cell
If Intersect(Target, Range("D44")) Is Nothing Then Exit Sub
Application.EnableEvents = False
Dim inputCell As Range
Set inputCell = Range("D45")
Select Case Trim(LCase(Target.Value))
Case "any other fracto"
inputCell.Locked = False
inputCell.Activate
Case Else
'This handles **ANY** other value in the dropdown
inputCell.Locked = True
InputCell.Clear
End Select
Application.EnableEvents = True
End Sub

Related

How to hide cell rows in Excel

Thanks in advance for your help. I have been working on this for a few days now and have tried a few different options. What I need done is to hide specific rows of an excel sheet based on the contents of an active X dropdown. I have indexed the dropdown to a cell and every time the user changes the dropdown selection, the indexed cell contains their selection as either text or number (whichever makes it easiest to code - I've been trying both). I want to keep the code as close to how it is at the moment if possible. I'm sure there are shorter/ more convenient methods, but I just want this over. I think the issue is that when the user selects a new option from the dropdown, the macro isnt refreshing and showing ALL rows again before it begins to hide the new rows. As a result, I just end up with a whole bunch of hidden rows based on what was originally selected. I hope that makes sense.
See the code below for what I've already tried. I also tried this one too, but had the same issue (that the macro wasnt refreshing and showing ALL rows before applying another Hide function)
Private Sub Worksheet_Change(ByVal Target As Range)
ActiveSheet.Activate
If Not Application.Intersect(Range("U13"), Range(Target.Address)) Is Nothing Then
Select Case Target.Value
Case Is = "Brand Health": Rows("19:39").EntireRow.Hidden = True
Rows("40:60").EntireRow.Hidden = False
Case Is = "Brand Imagery": Rows("38:60").EntireRow.Hidden = True
Rows("61:81").EntireRow.Hidden = False
Case Is = "NPS": Rows("30:82").EntireRow.Hidden = True
Rows("83:102").EntireRow.Hidden = False
Case Is = "Talent": Rows("35:103").EntireRow.Hidden = True
Rows("104:126").EntireRow.Hidden = False
Case Is = "Shows": Rows("37:127").EntireRow.Hidden = True
Rows("128:148").EntireRow.Hidden = False
End Select
End If
End Sub
Private Sub Worksheet_Change(ByVal Target`enter code here` As Range)
Sheets("Brand Tracking Dashboard").Rows("1:1000").EntireRow.Hidden = False ' Move this to the top
If Target.Address = ("$U$13") And Target.Value = 1 Then
Sheets("Brand Tracking Dashboard").Rows("19:39").EntireRow.Hidden = True
Sheets("Brand Tracking Dashboard").Rows("59:1000").EntireRow.Hidden = True
ElseIf Target.Address = ("$u$13") And Target.Value = 2 Then
Sheets("Brand Tracking Dashboard").Rows("43:63").EntireRow.Hidden = True
Sheets("Brand Tracking Dashboard").Rows("80:1000").EntireRow.Hidden = True
ElseIf Target.Address = ("$u$13") And Target.Value = 3 Then
Sheets("Brand Tracking Dashboard").Rows("32:84").EntireRow.Hidden = True
Sheets("Brand Tracking Dashboard").Rows("101:1000").EntireRow.Hidden = True
ElseIf Target.Address = ("$u$13") And Target.Value = 4 Then
Sheets("Brand Tracking Dashboard").Rows("37:106").EntireRow.Hidden = True
Sheets("Brand Tracking Dashboard").Rows("121:1000").EntireRow.Hidden = True
ElseIf Target.Address = ("$u$13") And Target.Value = 5 Then
Sheets("Brand Tracking Dashboard").Rows("37:129").EntireRow.Hidden = True
Sheets("Brand Tracking Dashboard").Rows("145:1000").EntireRow.Hidden = True
End If
End Sub
What should happen is that after the user makes a selection, I guess the logic should be that the sheet is told to show ALL rows before applying the hide line command.
You are almost there - your guess was right. You just need to unhide all the rows before you hide the right ones based on the selection.
The first sub you posted is trying to do some unhiding, but it's only unhiding a few rows - and as you can't control what order the user selects the values in, it's probably trying to unhide the wrong ones. (Work through what happens if a user selects "Brand Health" followed by "Shows").
Try this:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ws As Worksheet
On Error GoTo errHandler
Application.ScreenUpdating = False
Set ws = Target.Worksheet
If Not Application.Intersect(ws.Range("U13"), Range(Target.Address)) Is Nothing Then
ws.Rows("19:148").Hidden = False 'edit this to include all the rows that could be hidden
Select Case Range("U13").Value
Case Is = "Brand Health"
ws.Rows("19:39").Hidden = True
Case Is = "Brand Imagery"
ws.Rows("38:60").Hidden = True
Case Is = "NPS"
ws.Rows("30:82").Hidden = True
Case Is = "Talent"
ws.Rows("35:103").Hidden = True
Case Is = "Shows"
ws.Rows("37:127").Hidden = True
End Select
End If
Application.ScreenUpdating = True
Exit Sub
errHandler:
Application.ScreenUpdating = True
End Sub
I've made a few other improvements:
ActiveSheet.Activate wasn't doing anything
You shouldn't rely on a particular sheet being the active one - what if the user changes it halfway through your macro? So I get the right worksheet at the start and use that throughout (make sure we are always working on the correct sheet)
Target could be a range of cells; you are only interested in the value of U13 so make that the condition for the Select Case
it's neater and faster to turn off screen updating - making sure it always gets turned on afterwards (even if there's an error).
Rows("xx:yy") returns whole rows so there's no need for EntireRow

Excel VBA Hide different columns depending on different cell values in another sheet, in real time

I've got a workbook with 5 sheets: Sheet1, Sheet2, Sheet3, Sheet4, Sheet5. The first sheet: "Sheet" has a cell: "C3" with a drop down menu with 4 different options: Opt1, Opt2, Opt3, Opt4.
Depending on what is selected in this drop down menu, I'd like different columns to be hidden in the various sheets - in real time. And if nothing is entered, I'd like no columns hidden.
I've entered the below code which partly works but I think there's an issue because I've selected overlapping columns to hide - not completely sure.
Additionally, I'd like to work in hiding particular rows as well as the column below, depending on what different option you select in the drop down menu.
Also, I'll replicate hiding the same columns across all Sheets1-5.
Private Sub Worksheet_Change(ByVal Target As Range)
If Range("C3").Value = "Opt1" Then
Sheets("Sheet1").Columns("G:L").EntireColumn.Hidden = True
Sheets("Sheet1").Columns("N:T").EntireColumn.Hidden = True
Else
Sheets("Sheet1").Columns("G:L").EntireColumn.Hidden = False
Sheets("Sheet1").Columns("N:T").EntireColumn.Hidden = False
End If
If Range("C3").Value = "Opt2" Then
Sheets("Sheet1").Columns("B:F").EntireColumn.Hidden = True
Sheets("Sheet1").Columns("N:T").EntireColumn.Hidden = True
Else
Sheets("Sheet1").Columns("B:F").EntireColumn.Hidden = False
Sheets("Sheet1").Columns("N:T").EntireColumn.Hidden = False
End If
If Range("C3").Value = "Opt3" Then
Sheets("Sheet1").Columns("B:M").EntireColumn.Hidden = True
Else
Sheets("Sheet1").Columns("B:M").EntireColumn.Hidden = False
End If
If Range("C3").Value = "Opt4" Then
Sheets("Sheet1").Columns("B:AB").EntireColumn.Hidden = True
Else
Sheets("Sheet1").Columns("B:AB").EntireColumn.Hidden = False
End If
End Sub
Following on from my comment. You can define the entire range of columns as a variable e.g. entireRange and set this to unhidden at the start of each worksheet change.
Add fully qualified references to the ranges i.e. ThisWorkbook.Sheets("Sheet1") or ws (as a variable shown below).
As everything is unhidden at start Else is not needed for each If statement. This is probably where confusion arises.
Change to a Select case statement as you are testing the value of a single cell against different expected values.
Combine your separate line column ranges that you are hiding into one line statements e.g.
Sheets("Sheet1").Columns("G:L").EntireColumn.Hidden = True
Sheets("Sheet1").Columns("N:T").EntireColumn.Hidden = True
Becomes:
ws.Range("G:L,N:T").EntireColumn.Hidden = True
You code would then look like the following:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim wb As Workbook
Dim ws As Worksheet
Dim entireRange As Range
Set wb = ThisWorkbook
Set ws = wb.Sheets("Sheet1")
Set entireRange = ws.Columns("B:AB")
entireRange.EntireColumn.Hidden = False
Select Case ws.Range("C3") 'Test the value of C3
Case "Opt1"
ws.Range("G:L,N:T").EntireColumn.Hidden = True
Case "Opt2"
ws.Range("B:F,N:T").EntireColumn.Hidden = True
Case "Opt3"
ws.Range("B:M").EntireColumn.Hidden = True
Case "Opt4"
entireRange.Hidden = True
End Select
End Sub
This will be easier to debug in terms of where things are being hidden or unhidden.
I have rewritten your code to make it easy to read and edit. My goal was to make the code as short as possible. I changed your if statement into a Select Case. It's more elegant and I think it's faster, but don't take my word for it.
The problem that had to be tackled was that if I select Opt1 and then select Opt2, the columns from Opt1 would still be hidden. So before the code hides anything, it automatically unhides all the columns in the range B:AB.
I added the Case Else to unhide all columns if you entered anything but Opt1, Opt2, Opt3 or Opt4. This could easily be changed into a MsgBox that warns the user that the entered value is incorrect. You can remove this line if you have limited the choice for the users already.
The Code:
Private Sub Worksheet_Change(ByVal Target As Range)
' Unhide Columns
Worksheets("Sheet1").Range("B:AB").EntireColumn.Hidden = False
Select Case Worksheets("Sheet1").Range("C3").Value
Case "Opt1"
Worksheets("Sheet1").Range("G:L,N:T").EntireColumn.Hidden = True
Case "Opt2"
Worksheets("Sheet1").Range("B:F,N:T").EntireColumn.Hidden = True
Case "Opt3"
Worksheets("Sheet1").Range("B:M").EntireColumn.Hidden = True
Case "Opt4"
Worksheets("Sheet1").Range("B:AB").EntireColumn.Hidden = True
' If anything else is entered, the columns will be unhidden.
Case Else
Worksheets("Sheet1").Range("B:AB").EntireColumn.Hidden = False
End Select
End Sub

Why wont the code below execute when a cell is double clicked on?

The code below ran earlier but will not execute when a cell is double clicked.
Private Sub Worksheet_DoubleClick(ByVal Target As range, Cancel As Boolean)
If Target.Font.Bold = False Then
Target.Font.Bold = True
Target.Font.Color = vbRed
Else
Target.Font.Bold = False
Target.Font.Color = 1
End If
End Sub
Not an answer to why it's not working (#Mat's Mug and #Scott Craner beat me to that again), but a shortened version of the code.
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
With Target.Font
.Bold = Not .Bold
.Color = Choose(Abs(CLng(.Bold)) + 1, 1, vbRed)
End With
End Sub
Ok, not as easy to follow as the original but here's what it's doing:
Target.Font.Bold is either TRUE or FALSE, so Not .Bold will return the opposite.
Bold = TRUE so Not Bold = FALSE
Abs(CLng(.Bold)) + 1
Again, .Bold is either TRUE or FALSE. Numerically TRUE = -1, FALSE = 0.
CLNG(.Bold) will return -1 or 0.
ABS(CLNG(.Bold)) will return 1 or 0.
Abs(CLng(.Bold)) + 1 will return 1 or 2 - which is used in the CHOOSE command to return vbRed or 1.
DO NOT type any of these signatures manually!
Use the code pane dropdowns instead:
Select Worksheet from the left dropdown, and pick an event to handle in the right dropdown; the VBE will generate a method stub with the proper signature for you.
Typing them out manually off the top of your head can (and does!) result with handlers that end up never being called, or worse, that are called, but are given parameter values in the wrong arguments, e.g. if UserForm_QueryClose is typed up manually with inverted parameters (the handler has 2 Integer parameters, so you need to remember the exact order.. otherwise you assign Cancel and the form understands that you assigned CloseMode)
If you're not seeing Worksheet in the left dropdown, then you're not in a worksheet's code-behind module. Worksheet events can only be handled in a worksheet module.
In a Workbook module (i.e. ThisWorkbook) you can handle the SheetBeforeDoubleClick event to handle a double-click on any worksheet in the workbook:
Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean)
End Sub

unhiding rows based on cell value for data entry - refresh error

I've set up a worksheet that will allow the user to select preset options from a data validation list in a cell (B23). The user's selection off this one cell will then trigger certain rows to be unhidden, guiding the user to input data into only the appropriate rows. The VBA code I am using for unhiding the appropriate rows works fine, EXCEPT for the fact that whenever a user enters data into one of the unhidden rows, all the rows will hide. The user then needs to reselect their option from the initial data validation list (cell B23) to unhide the appropriate rows again. The value they enter is entered and saved in the cell, but they need to reselect their initial choice between each data entry step, which is annoying and what I'd like to fix.
I suspect that:
1)the VBA code I hobbled together doesn't account for the fact that users will be entering data into rows that are hidden / will be triggered to unhide, and/or
2) the crux of the problem is refreshing the cell with the data validation list (B23) that triggers which rows to be unhidden. I unfortunately have no idea how to do this.
Any help would be very much appreciated!!
My VBA code to hide rows is below.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim allRows As Range
Set allRows = Rows("27:64")
allRows.Hidden = True
If Not Intersect(Target, Range("B23")) Is Nothing Then
If Target.Value = "A1" Then
Rows("27:31").Hidden = False
ElseIf (Target.Value = "A10-A-S" Or Target.Value = "A10-A-P" Or Target.Value = "A10-A-T") Then
Rows("32:36").Hidden = False
ElseIf (Target.Value = "A10-B-S" Or Target.Value = "A10-B-P" Or Target.Value = "A10-B-T") Then
Rows("37:44").Hidden = False
ElseIf (Target.Value = "E19S" Or Target.Value = "E19P" Or Target.Value = "E19T") Then
Rows("46:54").Hidden = False
ElseIf (Target.Value = "E20S" Or Target.Value = "E20P" Or Target.Value = "E20T") Then
Rows("56:64").Hidden = False
End If
End If
End Sub
You're right that as soon as anyone changes anything on the worksheet, the Worksheet_Change event will fire and hide those rows.
A simple option would probably be to wrap that code around a check that the change was triggered by your dropdown:
With Target
If .Count = 1 Then
If .Row = 23 And .Column = 2 Then ' Assumes your list result is B23?
allRows.Hidden = True
' do your other checks and updates here...
End If
End If
End With
You should check if the target is B23 and if not Exit Sub. Maybe Something like this.
If Intersect(Target, Range("B23")) Is Nothing Then
Exit Sub
End If

Excel VBA Case not recognizing value of cell

Im trying to use VBA to hide/show a group of rows on a separate sheet within the same workbook named Invoice
To do this, on the InputForm sheet, there is a cell (N14) which uses =ISBLANK(D53) to check if D53 contains anything and obviously returns TRUE/FALSE
From this im trying to run an If Statement in VBA to hide/show rows based on whether the cell N14 contains TRUE/FALSE
The code i've tried works ok if i manually type TRUE/FALSE but not if it is automatically entered by the formula.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address(False, False) = "N14" Then
Select Case Target.Value
Case "TRUE": Sheets("Invoice").Rows("57:123").Hidden = True:
Case "FALSE": Sheets("Invoice").Rows("57:123").Hidden = False:
End Select
End If
End Sub
The format of Cell N14 is "Text"
As I mentioned in comments, Worksheet_Change doesn't fires when result of your formula changes. It fires only if you change value of cell itself. You should look into Worksheet_Calculate event instead:
Private Sub Worksheet_Calculate()
Application.EnableEvents = False
Sheets("Invoice").Rows("57:123").Hidden = Range("N14").Value
Application.EnableEvents = True
End Sub