My goal is to be able to have a drop down list that hides certain non-contiguous rows in excel based off the name of the individual in the list I create. I have this code which I found off Youtube and was wondering what was wrong with it as it was not working. I am relatively new to VBA
Private Sub Worksheet_Calculate()
Dim Andrew, Robert, Michael As Range
Set Andrew = Range("K30")
Set Robert = Range("K30")
Set Michael= Range ("K30")
Select Case Andrew
Case Is = "Andrew": Rows("8:10").EntireRow.Hidden = True
Rows("11:12").EntireRow.Hidden = False
Rows("13:13").EntireRow.Hidden = True
Rows("14:25").EntireRow.Hidden = False
End Select
Select Case Robert
Case Is = "Robert"
Rows("6:20").EntireRow.Hidden = True
Rows("21:25").EntireRow.Hidden = False
End Select
Select Case Michael
Case Is = "Michael"
Rows("1:5").EntireRow.Hidden = True
Rows("6:25").EntireRow.Hidden = False
End Select
End Sub
I created a dummy test Excel worksheet and inserted your VBA code into a new module. It worked fine for me, albeit is a bit clunky.
Some suggestions to help:
Always set Option Explicit at the top of your module, because this means any undeclared variables and other little things like that get picked up immediately. It's good practice to get into that habit early when starting out with VBA.
Always qualify your .Range statement with the prefix for the specific workbook/worksheet your code needs to work on. This may be why it isn't working for you, but ran fine for me. As it stands, your code will only run on whatever worksheet happens to be active at the time.
You have made this a Private Sub (private subroutine). If you have done the proverbial copy & paste then this subroutine will not show up in your list of macros, which could be another reason you cannot run it. I highly recommend you have a read of this ExcelOffTheGrid article, which breaks down the different types nicely. If you have inserted this into the Worksheet object of your VBA Project, then it may need to be moved into its own Module.
You have assigned three different names (Andrew, Robert, Michael) to the same .Range reference. This shouldn't really be allowed (although weirdly didn't flag an error when I copied your code) because what it is saying is that those text strings - and they could be anything, not just those names - all refer to the same specific cell on your worksheet. This hasn't affected your code, because you don't actually refer to them later on. In your Select Case logical tests you have used double quotes " " around each name, telling VBA it is a string of characters not a variable you have defined.
I would suggest something like this:
COPY & PASTE INTO A NEW MODULE
Option Explicit
'
'
Sub HideRows()
' This macro will hide specific non-contiguous rows based upon criteria in my drop down combo box.
'
Dim wkMyBook As Workbook
Dim wsMainSheet As Worksheet
Dim rName As Range
'
With Application
.ScreenUpdating = False
.EnableEvents = False
.Calculation = xlCalculationManual
End With
Set wkMyBook = ActiveWorkbook
Set wsMainSheet = wkMyBook.Sheets("ENTER SHEET NAME HERE")
Set rName = wsMainSheet.Range("K30")
Select Case rName
Case Is = "Andrew"
wsMainSheet.Rows("8:10").EntireRow.Hidden = True
wsMainSheet.Rows("11:12").EntireRow.Hidden = False
wsMainSheet.Rows("13:13").EntireRow.Hidden = True
wsMainSheet.Rows("14:25").EntireRow.Hidden = False
Case Is = "Robert"
wsMainSheet.Rows("6:20").EntireRow.Hidden = True
wsMainSheet.Rows("21:25").EntireRow.Hidden = False
Case Is = "Michael"
wsMainSheet.Rows("1:5").EntireRow.Hidden = True
wsMainSheet.Rows("6:25").EntireRow.Hidden = False
End Select
With Application
.ScreenUpdating = False
.EnableEvents = False
.Calculation = xlCalculationManual
End With
End Sub
COPY & PASTE INTO THE WORKBOOK OBJECT
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
' This code will run whenever a change is made to your worksheet
If Target.Address = "$K$30" Then
Select Case Target.Value
Case Is = "Andrew", "Robert", "Michael"
Call HideRows
End Select
End If
End Sub
This has bought your ticket, given you the lift, dropped you off right at the door. Now you gotta do that final step to put this together to make it work. Read the article I linked, learn about bit about how VBA is constructed and then next time you should be a bit further along the path before you need a pick up. Good luck!
Drop Down Worksheet Change
When you change a value in a cell via 'drop down', the Worksheet.Change event is triggered.
Copy the first code into the appropriate sheet module e.g. Sheet1.
Copy the second code into a standard module, e.g. Module1.
You do not run anything, it is automatically showing or hiding rows.
Sheet1
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Const RangeAddress As String = "K30"
If Not Intersect(Target, Me.Range(RangeAddress)) Is Nothing Then
manipulateRows Me, Target.Value
End If
End Sub
Module1
Option Explicit
Sub manipulateRows(Sheet As Worksheet, checkString As String)
With Sheet
Select Case checkString
Case "Andrew"
.Rows("8:10").Hidden = True
.Rows(13).Hidden = True
.Rows("11:12").Hidden = False
.Rows("14:25").Hidden = False
Case "Michael"
.Rows("1:5").Hidden = True
.Rows("6:25").Hidden = False
Case "Robert"
.Rows("6:20").Hidden = True
.Rows("21:25").Hidden = False
Case Else ' When DEL is pressed (Empty Cell), shows all rows.
.Rows("1:25").Hidden = False
End Select
End With
End Sub
Related
I have an Excel file that are used by end users, where, in a specific range of cells, if a change is made, a change event macro is triggered.
What I do with this macro is to check if the last action is any type of pasting.
What I need is to, somehow, get in a variable the content the user has copied (clipboard?) and then execute a function or procedure which checks the validy of the data. If it's correct, it will paste the values mantaining the conditional format, and if wrong it will undo the operation and disable the events.
So far, I think I am close to have everything but I am missing the knowledge to get in VBA the clipboard content in a variable.
I would appreciate general feedback as well.
PD: I have stated range(B:B) to keep it simple, in reality I will have a function for each column because the validation changes based (but that's on me,I just need to have 1 correct in order to replicate the logic).
Private Sub Worksheet_Change(ByVal Target As Range)
lastAction = Application.CommandBars("Standard").FindControl(ID:=128).List(1)
If Left(lastAction, 5) = "Paste" Then
If Not Application.Intersect(Target, Range("B:B")) Is Nothing Then
validation (Application.Intersect(Target, Range("B:B")))
End If
Else
End If
End Sub
Function validation(cell) As Boolean
Dim check As Boolean
check = Application.WorksheetFunction.VLookup(cell, MDM.Range("AK2:AK86"), 1, False)
If check = True Then
ActiveSheets.PasteSpecial Paste:=xlPasteAllMergingConditionalFormats
Application.CutCopyMode = False
Else
With Application
.EnableEvents = False
.Undo
End With
Application.EnableEvents = True
End If
End Function
I need to do this validation because if the user paste the value from another excel, it will remove both the conditional formatting and the data validation for that column.
I've used the clsClipboard class described at the following link
http://www.la-solutions.co.uk/content/CONNECT/MVBA/MVBA-Clipboard.htm
Copy the VBA class module code to a file named clsClipboard.cls, then import new Class module into your project.
Usage:
Sub test()
Dim CB As New clsClipboard
Dim myVar As String
CB.SetText "this is a test"
myVar = CB.GetText()
Debug.Print myVar
Set CB = Nothing
End Sub
Very Basic I am sure but I can't figure it out for the life of me.
I have a set of radio buttons that changes the value of cell("L37") between 1 and 2.
I have tried to write the VBA code several different ways without luck. Please advise.
Sub hide_sheet()
If Worksheets("Feedback").Range("L37").Value = 1 Then
Rows("63:93").EntireRow.Hidden = True
Else Worksheets("Feedback").Range("L37").Value = 2 Then
Worksheets("Feedback").Rows("63:93").EntireRow.Hidden = False
End If
End Sub
I had it working perfectly fine via a Macro tied to the radio buttons; however, due to me needing to protect the sheet I needed to change it.
I am using a protect/unprotect VBA code and would like to include it into the code so it won't set off the macro/sheet protected warning.
Here is my protect/unprotect code I am using for everything.
Sub unprotect()
Worksheets("Feedback").unprotect
End Sub
Sub protect()
Worksheets("Feedback").protect , _
AllowFormattingCells:=True, _
AllowFormattingRows:=True
End Sub
Any advice would be greatly appreciated. I Thank You in Advance of your assistance.
Show/Hide Rows
Issues
The Feedback worksheet is not qualified so if the wrong workbook is active, it will fail. To reference the workbook containing this code, you can use ThisWorkbook:
ThisWorkbook.Worksheets("Feedback")...
You are using Rows("63:93") instead of Worksheets("Feedback").Rows("63:93") in the If clause. If the wrong worksheet is active (selected), it will fail.
You are using Else instead of ElseIf.
You can use the With statement to reduce typing as illustrated in the following code.
If you convert the cell value to a string, then if the cell accidentally contains an error value, the code will not fail.
The Code
Sub ShowHideRowsFix()
With ThisWorkbook.Worksheets("Feedback")
.Unprotect
Select Case CStr(.Range("L37").Value)
Case "1"
.Rows("63:93").Hidden = True
Case "2"
.Rows("63:93").Hidden = False
Case Else
End Select
.Protect AllowFormattingCells:=True, AllowFormattingRows:=True
End With
End Sub
An Improvement
To automate this operation (no need for buttons), in the sheet module of the Feedback worksheet identified in the VBE Project explorer window by e.g. Sheet1(FeedBack) (double-click to open), you could use the following code.
Private Sub Worksheet_Change(ByVal Target As Range)
Const CellAddress As String = "L37"
Dim Cell As Range: Set Cell = Me.Range(CellAddress)
If Intersect(Cell, Target) Is Nothing Then Exit Sub
ShowHideRows Cell
End Sub
Sub ShowHideRows(ByVal Cell As Range)
With Cell.Worksheet
.Unprotect
Select Case CStr(Cell.Value)
Case "1"
.Rows("63:93").Hidden = True
Case "2"
.Rows("63:93").Hidden = False
Case Else
End Select
.Protect AllowFormattingCells:=True, AllowFormattingRows:=True
End With
End Sub
I prefer the simplest approach where possible. This is the approach I use to hide columns re-written for your needs.
The following code may exist on the UserForm or in a standard Code Module:
Sub rwControl(ByRef hType As String)
Dim rwVis As Boolean
If hType = "hRW" Then rwVis = True
If hType = "uRW" Then rwVis = False
With ThisWorkbook.Worksheets("Feedback")
.Unprotect
.Rows("63:93").Hidden = rwVis
.Protect
End With
End Sub
You may call this code directly from you RadioButton_Change() Event vy including the following code:
IF RadioButton1.Value = True then 'Assuming the value is 1
rwControl "hRW" 'This hides the Rows
ELSE
rwControl "uRW" 'This unhides the Rows
End If
OR, to keep it really simple:
in your RadioButton_Change() event simply add:
Private Sub RadioButton1 Change()
With ThisWorkBook.Worksheets("Feedback")
.Unprotect
If RadioButton1.Value = True Then
.Rows("63:93").Hidden = True
Else
.Rows("63:93").Hidden = False
End If
.Protect
End With
End Sub
Using this approach negates the need for Worksheet Module Coding and Case Coding and allows you to keep the RadioButtons if you deem them important to the functionality.
I have a macro that hides certain rows when the values in a cell change. However this macro is not running unless you enter the target cell and click on it. I have tried several alternatives but none work for me.
Sheet
Private Sub Worksheet_Change(ByVal Target As Range)
If Range("$b$156").Value = 1 Then Call oculta_4
If Range("$b$156").Value = 2 Then Call oculta_5
If Range("$b$156").Value = 3 Then Call oculta_6
If Range("$b$156").Value = 4 Then Call oculta_7
End Sub
Macro
Sub oculta_4()
Rows("158:176").EntireRow.Hidden = False
Range("$c$158").Select
For Each celda In Range("$c$158:$c$176")
If celda.Value = 0 Then
ActiveCell.EntireRow.Hidden = True
End If
ActiveCell.Offset(1).Select
Next
End Sub
As others have said, to respond to a value changed by a Formula, you need to use Worksheet_Calculate.
As Worksheet_Calculate does not have a Target property, you need to create your own detection of certain cells changing. Use a Static variable to track last value.
You should also declare all your other variables too.
Repeatedly referencing the same cell is slow and makes code more difficult to update. Put it in a variable once, and access that
Select Case avoids the need to use many If's
Don't use Call, it's unnecessary and obsolete.
Adding Application.ScreenUpdating = False will make your code snappy, without flicker
Writing the hidden state of a row takes a lot longer than reading it. So only write it if you need to.
Something like this (put all this code in the code-behind your sheet (that's Hoja1, right?)
Private Sub Worksheet_Calculate()
Static LastValue As Variant
Dim rng As Range
Set rng = Me.Range("B156")
If rng.Value2 <> LastValue Then
LastValue = rng.Value2
Select Case LastValue
Case 1: oculta_4
Case 2: oculta_5
Case 3: oculta_6
Case 4: oculta_7
End Select
End If
End Sub
Sub oculta_4()
Dim celda As Range
Application.ScreenUpdating = False
For Each celda In Me.Range("C158:C176")
With celda.EntireRow
If celda.Value = 0 Then
If Not .Hidden Then .Hidden = True
Else
If .Hidden Then .Hidden = False
End If
End With
Next
Application.ScreenUpdating = True
End Sub
I am using a worksheet change function to give my excel spread sheet the illusion of a search bar with a drop down box containing the results of the text in the search bar.
before I just had the hide rows part of my code which would hide and then unhide some rows in my spread sheet containing the results. that worked fine but the results would sometimes be slow and not always show up until I re calculated them.
so I added calculate to the ranges and this unfortunately slows the whole thing down substantially. Is there a better way to do this?
Private Sub Worksheet_Change(ByVal target As Range)
Application.ScreenUpdating = False
Application.EnableEvents = False
If Range("D11").Value <> "" Then
Dim xlpassword As String
xlpassword = "Perry2012"
ActiveSheet.Unprotect xlpassword
ActiveSheet.EnableCalculation = False
ActiveSheet.EnableCalculation = True
Worksheets("HOME").Range("A1").Calculate
Worksheets("HOME").Range("D33").Calculate
Worksheets("HOME").Range("D32").Calculate
Worksheets("HOME").Range("E33").Calculate
Worksheets("HOME").Range("E32").Calculate
Worksheets("HOME").Range("F33").Calculate
Worksheets("HOME").Range("F32").Calculate
Worksheets("HOME").Range("G33").Calculate
Worksheets("HOME").Range("G32").Calculate
Worksheets("HOME").Range("H33").Calculate
Worksheets("HOME").Range("H32").Calculate
Worksheets("HOME").Range("I33").Calculate
Worksheets("HOME").Range("I32").Calculate
Worksheets("HOME").Range("J33").Calculate
Worksheets("HOME").Range("J32").Calculate
Worksheets("HOME").Range("K33").Calculate
Worksheets("HOME").Range("K32").Calculate
Worksheets("HOME").Range("L33").Calculate
Worksheets("HOME").Range("L32").Calculate
Worksheets("HOME").Range("M33").Calculate
Worksheets("HOME").Range("M32").Calculate
Worksheets("HOME").Range("N33").Calculate
Worksheets("HOME").Range("N32").Calculate
Worksheets("HOME").Range("O33").Calculate
Worksheets("HOME").Range("O32").Calculate
Worksheets("HOME").Range("P33").Calculate
Worksheets("HOME").Range("P32").Calculate
Worksheets("HOME").Range("Q33").Calculate
Worksheets("HOME").Range("Q32").Calculate
Worksheets("HOME").Range("R33").Calculate
Worksheets("HOME").Range("R32").Calculate
Worksheets("HOME").Range("S33").Calculate
Worksheets("HOME").Range("S32").Calculate
Worksheets("HOME").Range("T33").Calculate
Worksheets("HOME").Range("T32").Calculate
Worksheets("HOME").Range("U33").Calculate
Worksheets("HOME").Range("U32").Calculate
Worksheets("HOME").Range("V33").Calculate
Worksheets("HOME").Range("V32").Calculate
Worksheets("HOME").Range("W33").Calculate
Worksheets("HOME").Range("W32").Calculate
Worksheets("HOME").Range("D15").Calculate
Worksheets("HOME").Range("D17").Calculate
Worksheets("HOME").Range("D19").Calculate
Worksheets("HOME").Range("D21").Calculate
Worksheets("HOME").Range("D23").Calculate
Worksheets("HOME").Range("D25").Calculate
Worksheets("HOME").Range("D27").Calculate
Worksheets("HOME").Range("M15").Calculate
Worksheets("HOME").Range("M17").Calculate
Worksheets("HOME").Range("M19").Calculate
Worksheets("HOME").Range("M21").Calculate
Worksheets("HOME").Range("M23").Calculate
Worksheets("HOME").Range("M25").Calculate
Worksheets("HOME").Range("M27").Calculate
Worksheets("HOME").Range("T15").Calculate
Worksheets("HOME").Range("T17").Calculate
Worksheets("HOME").Range("T19").Calculate
Worksheets("HOME").Range("T21").Calculate
Worksheets("HOME").Range("T23").Calculate
Worksheets("HOME").Range("T25").Calculate
Worksheets("HOME").Range("T27").Calculate
Rows("15:28").Hidden = False
Rows("34:36").Hidden = True
Else
Rows("15:28").Hidden = True
Rows("34:36").Hidden = False
ActiveSheet.Protect xlpassword
End If
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Would replacing all those separate lines by just one work:
Application.Calculate
it might be the case that you have some volatile functions heavily used in the workbook(i.e. TODAY()), which I reckon will make all formulas based on them re-calculate on each of those calculation lines in your code
I have en excel file where i have to put validation rule. I have one cell let says "customer Time" where user can enter time but it is customize time. User can enter time like that
23:45
98:20
100:30
User cannot enter string and no special character except colon. I have made one macro and it works perfectly accoriding to customer demand. Here is macro
Public Function isValidTime(myText) As String
Dim regEx
Set regEx = New RegExp 'Regular expression object
regEx.Pattern = "^[0-9]+([:]+[0-9]+)*$" ' Set pattern.
If regEx.test(myText) Then
isValidTime = myText
Else
isValidTime = "Null"
End If
End Function
Note: To test this macro you have to go to VBA ide in Tool then reference and then select microsoft visual basic vbascript 5.5
Now i want to call this at excel. I can call like =IsValidTime("23:43") and getting result but customer is not interested to call this. Customer need a excel where he/she enter the value and value will validate according to above criteria and get the exact value or Null.
I dont know how to fix this task. I have Validated date and time as well from Data and then data validation and set the rule and it works perfect, i need the same way for my this rule as well. Any help will be highly appreciated...
Thanks
Kazmi
You can use the Worksheet_Change event inside the sheet. Inside the VBE, select the sheet and choose Workhseet from the left drop-down and Change from the right.
Enter the following code:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$A$1" Then 'assumes user input cell is A1
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
On Error GoTo ErrTrap
Target.Value = isValidTime(Target.Value)
End If
KeepMoving:
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
Exit Sub
ErrTrap:
MsgBox Err.Number & Err.Description
Resume KeepMoving
End Sub
Public Function isValidTime(myText) As String
Dim regEx
Set regEx = New RegExp 'Regular expression object
regEx.Pattern = "^[0-9]+([:]+[0-9]+)*$" ' Set pattern.
If regEx.test(myText) Then
isValidTime = myText
Else
isValidTime = "Null"
End If
End Function