Can't find a worksheet which exists - excel

I have a worksheet in Excel with the name "Control". I'm receiving a msgbox saying it doesn't exists. After I click on "OK" I get an error of "invalid call of function or procedure and the debugger stops in this function:
Private Sub ClearData(dataSheet As Worksheet)
'On Error Resume Next
'dataSheet.rows(DataRow1 & ":" & dataSheet.rows.Count).SpecialCells(xlCellTypeConstants).ClearContents
Sheets(dataSheet).UsedRange.ClearContents
End Sub
This function is used to clear the worksheet and the code before 'dataSheet.rows(DataRow1 & ":" & dataSheet.rows.Count).SpecialCells(xlCellTypeConstants).ClearContents is commented because is raises error and I decided to modify to the line Sheets(dataSheet).UsedRange.ClearContents but the problem persists.
EDIT ClearData is called with this code:
Public Sub Init(rowNr As Integer, copyMap As CopyActionsMap, dataSheet As Worksheet)
m_configRowNr = rowNr
Set m_dataSheet = dataSheet
m_dataRowNr = FindDataRow
m_dataSheet.Cells(m_configRowNr, 1).Select 'select first cell in config row
If (Not m_initialized) Then Set m_columnCopyConfigs = GetColumnCopyConfigs(copyMap) 'also sets m_count
ClearData (m_dataSheet) 'Clean the existing data Now it says "object doenst support this method or property" after this: Private Sub ClearData(dataSheet As Worksheet) Sheets(dataSheet).Cells.Delete
End Sub

As #tigeravatar has mentioned in the comments below your question, you are trying to use a worksheet object as a string variable.
Try changing your code to
Private Sub ClearData(dataSheet As Worksheet)
'On Error Resume Next
'dataSheet.rows(DataRow1 & ":" & dataSheet.rows.Count).SpecialCells(xlCellTypeConstants).ClearContents
dataSheet.UsedRange.ClearContents
End Sub
If you want to clear the sheet by a specific string name instead, you should change your code to
Private Sub ClearData(dataSheet As String)
'On Error Resume Next
'dataSheet.rows(DataRow1 & ":" & dataSheet.rows.Count).SpecialCells(xlCellTypeConstants).ClearContents
Sheets(dataSheet).UsedRange.ClearContents
End Sub
And you can then clear the sheet named "Test Sheet" by calling
ClearData "Test Sheet"

Related

How to write code to test a cell for specific data, and if that data is present, don't run the macro. If not present, then run macro?

I am trying to test a cell for specific data. If it contains that data, I do not want my code to run (because that would leave my worksheet and workbook Unprotected). If the cell contains data that does not match the test specifics, then I want the code to run. My code is to unprotect the active workbook, then unprotect the active worksheet, then fill the value of cell N41 as the "sheet name", then protect the active worksheet, then protect the active workbook. I want to add the test to the top of the code to avoid security failures.
The data that I want to test the cell for is:
The cell does not contain more than 31 characters (including spaces between charaters)
The cell does not contain any of the following characters: \ / : ? * [ or ]
The cell is not blank (empty)
If any of the above data/characters are in the cell I want the code to not run and leave my password protection in place for both the protected worksheet and protected workbook.
If the cell contains less than 31 characters (including spaces), does not contain any of the unwanted characters, and has at least 1 character in it (not a blank cell) then I want the code to run. Any help would be greatly appreciated.
Private Sub CommandButton16_Click()
ThisWorkbook.Unprotect Password:="Password1"
ActiveSheet.Unprotect Password:="Password2"
ActiveSheet.Name = Range("N41").Value
ActiveSheet.Protect Password:="Password2"
ThisWorkbook.Protect Password:="Password1"
End Sub
I guess the real question is "How to check if some value is the correct name for a worksheet?" in order to minimize the period when the document is not protected, and to eliminate an error when renaming.
From the full list of naming conventions we can learn two additional rules. The name shouldn't be "History" and it shouldn't begin or end with an apostrophe '. Also, there shouldn't be other sheets with that name.
In my opinion, the easiest way to accomplish the main task is to wrap renaming with On Error statements.
Private Sub CommandButton_Click()
Const BookPass = "Password1"
Const SheetPass = "Password2"
Dim NewName as String
Dim ErrCode&, ErrDesc$, ErrMessage$
NewName = Range("N41").Value
With ThisWorkbook
.Unprotect BookPass
With ActiveSheet
.Unprotect SheetPass
On Error Resume Next
' ------ Main Part -------
.Name = NewName
' ------------------------
ErrCode = Err.Number
ErrDesc = Err.Description
On Error GoTo 0
.Protect SheetPass
End With
.Protect BookPass
End With
If ErrCode <> 0 Then
ErrMessage = "NewName=" & NewName & vbNewLine & _
"Error=" & ErrCode & vbNewLine & _
"Description: " & ErrDesc
MsgBox ErrMessage, vbCritical
End If
End Sub
p.s. I suppose, this code will be placed in the worksheet object module. In this case, it is better to replace ActiveSheet with Me for readability.
If you are prepared to weaken the Workbook protection, you can add use this code when protecting the Workbook.
Your code can then change the sheet name without unprotecting the WorkBook, but so can your users.
ActiveWorkbook.Protect Password:="Password1", Structure:=False
The WorkSheet can be protected to allow changes from your code but not by your users.
This way you protect the WorkSheet and never have to unprotect it.
ActiveSheet.Protect Password:="Password2", UserInterfaceOnly:=True
In your code, you can set a boolean value to true if a test passes and exit the sub with a custom message if a test fails. Then test the boolean value and if it is true, unprotect the Workbook, make the update and reprotect the Workbook.
Option Explicit
Private Sub ProtectAll()
ActiveWorkbook.Protect Password:="Password1"
' ActiveWorkbook.Protect Password:="Password1", Structure:=False
'Optional: Allow changes to sheet names and order, not ideal
'but allows you to not have to protect and unprotect the workbook
ActiveSheet.Protect Password:="Password2", UserInterfaceOnly:=True
'Allow changes to the active worksheet by VBA code, remains protected via the UI
End Sub
Private Sub UnprotectAll()
ActiveSheet.Unprotect Password:="Password2"
ThisWorkbook.Unprotect Password:="Password1"
End Sub
Private Sub ProtectWB()
ActiveWorkbook.Protect Password:="Password1"
End Sub
Private Sub UnprotectWB()
ThisWorkbook.Unprotect Password:="Password1"
End Sub
Private Sub Change()
Dim CellValue As String
Dim OKtoChange As Boolean
Dim ErrorMessage As String
CellValue = vbNullString
OKtoChange = False
CellValue = ActiveSheet.Range("N41").Value
If Len(CellValue) < 32 Then
OKtoChange = True
Else
ErrorMessage = "The WorkSheet name is more than 31 characters."
GoTo ErrorHandler
End If
'Other tests here to set the OKtoChange variable based on results
'If any test fails the code exits
If OKtoChange = True Then
Call UnprotectWB
ActiveSheet.Name = CellValue
Call ProtectWB
End If
Exit Sub
ErrorHandler:
MsgBox "Invalid name for the WorkSheet" & vbLf & ErrorMessage, vbCritical, "Invalid name"
End Sub

How to handle blank/Invalid data for RefEdit control in VBA userform

I am using a Excel VBA userform to change the font case as below picture. When RefEdit control have correct Range, then it is working fine. But if I click "Apply" button keeping RefEdit blank/ only Space/ any word(invalid Range), Userform disappear without showing any error notification.
For Uppercase code:-
Sub UpperCaseFont()
For Each x In Range(CaseRefEdit.Value)
If Not IsEmpty(x.Value) Then
x.Value = UCase(x.Value)
End If
Next
MsgBox "Done"
End Sub
LowerCase code:-
Sub LowerCaseFont()
For Each x In Range(CaseRefEdit.Value)
If Not IsEmpty(x.Value) Then
x.Value = LCase(x.Value)
End If
Next
MsgBox "Done"
End Sub
Propercase code:-
Sub ProperCaseFont()
For Each x In Range(CaseRefEdit.Value)
If Not IsEmpty(x.Value) Then
x.Value = WorksheetFunction.Proper(x.Value)
End If
Next
End Sub
CommandButton code:-
Private Sub CaseApplyCommandButton_Click()
If UpperCase = True Then Call UpperCaseFont
If LowerCase = True Then Call LowerCaseFont
If ProperCase = True Then Call ProperCaseFont
For that reason, I have tried to modified as below, But still i am facing the problem that if RefEdit is blank and I click on "Apply" button then userform disappear and also found that other all userform start unknown problem to initialize.
Private Sub CaseApplyCommandButton_Click()
'Font Case
Dim Rng As Range
On Error Resume Next
Set Rng = Range(Me.CaseRefEdit.Value)
MsgBox Rng
On Error GoTo 0
If Rng Is Nothing Then
MsgBox "Select the Cells to change the case"
Else
If UpperCase = True Then Call UpperCaseFont
If LowerCase = True Then Call LowerCaseFont
If ProperCase = True Then Call ProperCaseFont
End If
End Sub
I have found that problem is started when I add below code:-
Private Sub CaseRefEdit_Exit(ByVal Cancel As MSForms.ReturnBoolean)
Range(CaseRefEdit.Value).Select
End Sub
As per my understanding when RefEdit is not giving any range for input any number or word or keeping blank, then userform disappear. Any solution for this?
On the second question.
The [if IsError (range ("Hello") then ...] expression first evaluates the range ("Hello"), and if it is invalid, an error occurs before calling the function. Therefore, it is better to pass the address of the range to the IsError function, and calculate the range inside the function and determine its correctness.
Function IsError(addr As String) As Boolean
Dim rng As Range
On Error Resume Next
Set rng = Range(addr)
IsError = rng Is Nothing
End Function
Sub test1()
If IsError("%$%W34") Then
Debug.Print "Range is invalid"
Else
Debug.Print "Range is correct"
End If
End Sub
my problem is solved as below. Thanks #Алексей Р.
Private Sub CaseRefEdit_Exit(ByVal Cancel As MSForms.ReturnBoolean)
On error resume next
Range(CaseRefEdit.Value).Select
End Sub
Anyone know, how to check Range("etc")/ Range(123) is valid or not? Like-
If IsError(range("etc")) then
...
else
....
end if
You may use On Error statement, for example:
Function testRNG(addr As String) As Range ' returns correct Range object or Nothing otherwise
' initially testRNG = Nothing
On Error Resume Next
Set testRNG = Range(addr) ' if the address is correct, testRNG returns Range, otherwise an error occurs, the expression is not evaluated and testRNG remains Nothing
End Function
Sub foo()
Dim addr As String
addr = "W12"
Set Rng = testRNG(addr)
If Rng Is Nothing Then
Debug.Print "Address " & addr & " is wrong"
Else
Debug.Print "Range " & Rng.Address & " is correct"
End If
End Sub

How do i fix "Run-time error '1004'" when setting validation on a UserInterfaceOnly protected sheet with VBA?

I am getting a "Run-time error '1004': Aplication-defined or object-defined error" when I try to set the validation on a cell using VBA. The sheet is protected using the UserInterFaceOnly flag set to true.
I tried moving the specific functions/subs to a blank workbook to see if the error repeated itself, and also without protection to see if it would still work. The problem was the same, and the code works if the sheet isn't protected. I googled the problem and found the link below suggests there's a character limit on the validation string but even restricting it to 200 chars didn't solve the problem.
https://answers.microsoft.com/en-us/msoffice/forum/all/what-is-limit-of-the-number-of-entries-in-excel/9ce4a909-8b03-428f-94a4-1b13433aa399
'pasting this code into a blank workbook, running ps and then running test should reproduce the problem
'set specific protection with pw
Sub ps()
ThisWorkbook.Worksheets("Sheet1").Unprotect Password:="secret"
ThisWorkbook.Worksheets("Sheet1").Protect Password:="secret", UserInterFaceOnly:=True
End Sub
'general protection sub
Public Sub protectSht(ws As Worksheet, pass As String)
ws.Protect Password:=pass, UserInterFaceOnly:=True
End Sub
'set validation on cells
Sub setValidation(rng As Range, lst As Collection)
Dim tmpstr As String
Dim loopVar As Variant
For Each loopVar In lst
tmpstr = Trim(loopVar) & ", " & tmpstr
Next loopVar
If lst.Count = 0 Then
rng.Validation.Delete
Else
With rng.Validation
.Delete
.Add xlValidateList, AlertStyle:=xlValidAlertStop, _
Operator:=xlBetween, Formula1:=tmpstr
End With
End If
End Sub
'test function reproducing error
'run this on a sheet that's protected using ps
Sub test()
Dim tst As New Collection
tst.Add "hello"
tst.Add "bye"
tst.Add "etc"
setValidation ThisWorkbook.Sheets(1).Range("B1:B5"), tst
End Sub
This should set the validation on the cells but regardless of whether they're locked or not it fails to do so. instead, it gives "Run-time error '1004': Aplication-defined or object-defined error" .

SpecialCells(xlCellTypeFormulas, xlErrors) returns expected results only when the macro is run independently

I am creating a macro that checks for errors in formulas for each sheet in a workbook. The macro runs when the BeforeSave hook is triggered and prompts the user decide if they still want to save when an error is found.
Public Sub errorCheck()
On Error Resume Next
Application.StatusBar = "Running: formulaErrorCheck"
Dim ws As Worksheet
Dim errors As range
Dim r As range
For Each ws In Worksheets
Set errors = Nothing
Set errors = ws.UsedRange.SpecialCells(xlCellTypeFormulas, xlErrors).cells
If Not (errors Is Nothing) Then
For Each r In errors
If IsError(r.Value) = True Then
Select Case r.Value
Case CVErr(xlErrValue), CVErr(xlErrDiv0), CVErr(xlErrName), CVErr(xlErrRef)
If MsgBox("Excel Sheet " + ws.name + " contains a reference error in cell " + r.Address(False, False) + ". Save anyway?", vbYesNo, "") = vbNo Then
Application.GoTo Reference:=r
GoTo quit_checking
End If
End Select
End If
Next
End If
Next
quit_checking:
Application.StatusBar = False
End Sub
Code in the Class Module that detects events:
OptionExplicit
Private WIthEvents App As Application
Private Sub App_WorkbookBeforeSave(ByVal wb As Workbook, ByVal SaveAsUI As Boolean, Cancel As Boolean)
Book_BeforeSave SaveAsUI, Cancel
End Sub
Public Sub Book_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
Call errorCheck
End Sub
The issue that I'm having is that
Set errors = ws.UsedRange.SpecialCells(xlCellTypeFormulas, xlErrors).cells
returns the expected cells when I run the macro independently. However when the macro is called from the BeforeSave hook, it returns the entire used range. I thought maybe it was an issue with the reference to the workbook, but the worksheets are still iterated through as expected. I've tried removing On Error Resume Next to make sure there wasn't actually an error being thrown. I'm at a loss as to what the difference could be.

Excel Error Handling for range object

I'm working on an Excel user form where the user can input a range. For example, they can put in "B5" and "B20".
I'm trying to do error handling to prevent the user from putting in an incorrect range. For Example, "asdf" and "fdsa".
The following code fails:
Private Sub cmdSend_Click()
Dim beginTerm As String
Dim endTerm As String
beginTerm = TermsBegin.Text
endTerm = TermsEnd.Text
If (IsError(Worksheets("Account Information").Range(beginTerm + ":" + endTerm)) = True) Then
MsgBox "Cell Range is invalid."
Exit Sub
End If
End Sub
I also tried the following:
Private Sub cmdSend_Click()
Dim beginTerm As String
Dim endTerm As String
beginTerm = TermsBegin.Text
endTerm = TermsEnd.Text
Dim myRange As Range
myRange = Worksheets("Account Information").Range(beginTerm + ":" + endTerm)
On Error GoTo ErrHandler
On Error GoTo 0
'other code ...
ErrHandler:
MsgBox "Cell Range is invalid."
Exit Sub
End Sub
My question is how can I handle the case that it fails?
Thanks!
You have to put
On Error GoTo ErrHandler
before the line that could throw the error.
If you need to get a range from a user, I would recommend using Application.InputBox with a Type = 8. This allows the user to select a range from the worksheet.
Check this out:
http://www.ozgrid.com/VBA/inputbox.htm
Also, if you are using a userform, you can also add a command button that will call the Application.InputBox to allow a user to select a range.
Quick example:
Private Sub CommandButton1_Click()
Dim r As Range
On Error Resume Next
Set r = Application.InputBox(Prompt:= _
"Please select a range with your Mouse to be bolded.", _
Title:="SPECIFY RANGE", Type:=8)
If Not r Is Nothing Then MsgBox r.Address
On Error GoTo 0
End Sub

Resources