I'm working with a sub which calls an input box to copy selected cells from a sheet and paste them into a multicolumn listbox. I've finally got everything working correctly, except the error 424 when the user cancels the inputbox. I've read through countless help threads regarding this error and have found nothing that seems to be able to handle the error for me. I'm hoping that someone out there can tell me if something is wrong with the code below (aside from 12 million exit sub attempts to stop the error), or possibly give me an idea of another area (Declarations, Initialization, Activate?) that I should be checking. Any ideas are appreciated, thanks.
Private Sub CopyItemsBtn_Click()
Dim x As Integer
Dim rSelected As Range, c As Range
Dim wb
Dim lrows As Long, lcols As Long
x = ProformaToolForm.ItemsLB.ListCount
'Prompt user to select cells for formula
On Error GoTo cleanup
wb = Application.GetOpenFilename(filefilter:="Excel Files,*.xl*;*.xm*")
If wb <> False Then
Workbooks.Open wb
End If
Set rSelected = Application.InputBox(Prompt:= _
"Select cells to copy", _
Title:="Transfer Selection", Type:=8)
If Err.Number = 424 Then
Debug.Print "Canceled"
Exit Sub
ElseIf Err.Number <> 0 Then
Debug.Print "unexpected error"
Exit Sub
End If
If rSelected.Rows.Count < 1 Or rSelected.Columns.Count < 1 Then
Exit Sub
End If
Err.Clear
On Error GoTo 0
'Only run if cells were selected and cancel button was not pressed
If Not rSelected Is Nothing Then
For Each c In rSelected
With ProformaToolForm.ItemsLB
.AddItem
.List = rSelected.Cells.Value
End With
Next
Else
Exit Sub
End If
cleanup: Exit Sub
End Sub
After some cleanup, here's my attempt with Tim's code:
Private Sub CopyItemsBtn_Click()
Dim rSelected As Range, c As Range
Dim wb
wb = Application.GetOpenFilename(filefilter:="Excel Files,*.xl*;*.xm*")
If wb <> False Then
Workbooks.Open wb
End If
'Prompt user to select cells for formula
On Error Resume Next
Set rSelected = Application.InputBox(Prompt:= _
"Select cells to copy", _
Title:="Transfer Selection", Type:=8)
On Error GoTo 0
If rSelected Is Nothing Then
MsgBox "no range selected", vbCritical
Exit Sub
End If
For Each c In rSelected
With ProformaToolForm.ItemsLB
.AddItem
.List = rSelected.Cells.Value
End With
Next
End Sub
Here's how I'd tend to do this:
Private Sub CopyItemsBtn_Click()
Dim rSelected As Range
On Error Resume Next
Set rSelected = Application.InputBox(Prompt:= _
"Select cells to copy", _
Title:="Transfer Selection", Type:=8)
On Error GoTo 0
If rSelected Is Nothing Then
MsgBox "no range selected!", vbCritical
Exit Sub
End If
'continue with rSelected
End Sub
Found a solution, from Dirk's final post here. For anyone interested, here is the working code:
Private Sub CopyItemsBtn_Click()
Dim rSelected As Range
Dim wb
Dim MyCol As New Collection
wb = Application.GetOpenFilename(filefilter:="Excel Files,*.xl*;*.xm*")
If wb <> False Then
Workbooks.Open wb
End If
MyCol.Add Application.InputBox(Prompt:= _
"Select cells to copy", _
Title:="Transfer Selection", Type:=8)
If TypeOf MyCol(1) Is Range Then Set MyRange = MyCol(1)
Set MyCol = New Collection
If rSelected Is Nothing Then
MsgBox "no range selected", vbCritical
Exit Sub
End If
ProformaToolForm.ItemsLB.List = rSelected.Value
End Sub
Related
I'm currently trying to detect duplicated sheet name using "CheckSheet" function. And I want to call this function to run in "Add Sheet" to prevent users from creating duplicate sheet names. However, I ran into error "Compile Error: Expected function or variable" and still not succeeding in solving the problem. Kindly enlighten me where I am doing it wrong and feel free to point out if there are any weakness and better optimization to my code. Thanks in advance.
Option Explicit
Public sheetName As Variant
Public cS As Variant
Sub CheckSheet(cS) 'To check duplicate sheet name - used in AddSheet function.
Dim wS As Worksheet
Dim wsName As String
wsName = wS(sheetName)
On Error GoTo 0
If wS Is Nothing Then
cS = False
Exit Sub
End Sub
Sub AddSheet()
Dim cSheet As Variant
cSheet = CheckSheet(cS).Value
On Error Resume Next
sheetName = Application.InputBox(prompt:="New Sheet Name", Left:=(Application.Width / 2), Top:=(Application.Height / 2), Title:="Add Sheet", Type:=2)
If sheetName = "" Then
MsgBox "Sheet name cannot be empty!"
Exit Sub
ElseIf cSheet = False Then
MsgBox "Duplicate Name! Please try again!"
Exit Sub
Else
Application.ScreenUpdating = False
Sheets.Add(After:=Sheets(Sheets.Count)).Name = sheetName
MsgBox """" & sheetName & """ was successfully created!"
Sheets("Sheet1").Activate
End If
End Sub
Two things.
1. Your code can be simplified. You do not need a function to check if a worksheet exists.
Option Explicit
Sub AddSheet()
Dim sh As Object
Dim sheetName As Variant
'~~> Accept user input
sheetName = Application.InputBox(prompt:="New Sheet Name", _
Left:=(Application.Width / 2), _
Top:=(Application.Height / 2), _
Title:="Add Sheet", Type:=2)
'~~> User presses cancel
If sheetName = False Then Exit Sub
'~~> Check if the sheet name is empty
If sheetName = "" Then
MsgBox "Sheet name cannot be empty!"
Exit Sub
End If
'~~> Check if the sheet exists
On Error Resume Next
Set sh = ThisWorkbook.Sheets(sheetName)
On Error GoTo 0
If Not sh Is Nothing Then
MsgBox "Duplicate Name! Please try again!"
Exit Sub
End If
'~~> Create the worksheet
With ThisWorkbook
.Sheets.Add(After:=.Sheets(.Sheets.Count)).Name = sheetName
MsgBox """" & sheetName & """ was successfully created!"
End With
End Sub
2. Even if you want to use a function, your code has lot of errors. (One of them is pointed out by #braX above.
Is this what you are trying?
Option Explicit
Sub AddSheet()
Dim sheetName As Variant
'~~> Accept user input
sheetName = Application.InputBox(prompt:="New Sheet Name", _
Left:=(Application.Width / 2), _
Top:=(Application.Height / 2), _
Title:="Add Sheet", Type:=2)
'~~> User presses cancel
If sheetName = False Then Exit Sub
'~~> Check if the sheet name is empty
If sheetName = "" Then
MsgBox "Sheet name cannot be empty!"
Exit Sub
End If
'~~> Check if the sheet exists
If DoesSheetExists(CStr(sheetName)) = True Then
MsgBox "Duplicate Name! Please try again!"
Exit Sub
End If
'~~> Create the worksheet
With ThisWorkbook
.Sheets.Add(After:=.Sheets(.Sheets.Count)).Name = sheetName
MsgBox """" & sheetName & """ was successfully created!"
End With
End Sub
'~~> Function to check if sheet exists
Private Function DoesSheetExists(wsName As String) As Boolean
Dim sh As Object
'~~> Check if the sheet exists
On Error Resume Next
Set sh = ThisWorkbook.Sheets(wsName)
On Error GoTo 0
If Not sh Is Nothing Then DoesSheetExists = True
End Function
so i used this code
Set Rng = Sheets("COA").Range("i11:i39")
On Error Resume Next
Set VisibleCells = Rng.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not VisibleCells Is Nothing Then
For Each aCell In VisibleCells
Select Case aCell.DisplayFormat.Interior.Color
Case vbRed
MsgBox "Terdapat data outspek. Periksa kembali!", vbCritical + vbOKOnly, ""
'Show Excel and resize the UserForm2
Application.Visible = True
Me.Height = 405
Me.Width = 730.5
SaveButton.Enabled = False
Case 16777215
Unload UserForm2
'Gets the name of the currently visible worksheet
Filename = "COA" & Sheets("COA").Range("B1")
'Puts the worksheet into its own workbook
ThisWorkbook.ActiveSheet.Copy
'Saves the workbook
ActiveWorkbook.SaveAs Filename
'Closes the newly created workbook so you are still looking at the original workbook
ActiveWorkbook.Close
End Select
Next aCell
End If
If there is a red cell then it will return to the userform. cell I17 is not red, but why is it automatically saved in .xls format? even though if there is a red cell, it cannot be saved in .xls format and must return to the userform. can you guys help me?
Suggest something like this:
Option Explicit
Sub Tester()
Dim rng As Range, Filename As String
Set rng = ThisWorkbook.Sheets("COA").Range("I11:I39")
If HasVisibleRedCell(rng) Then 'call the function to check the range...
MsgBox "Terdapat data outspek. Periksa kembali!", vbCritical + vbOKOnly, ""
Application.Visible = True
Me.Height = 405
Me.Width = 730.5
Me.SaveButton.Enabled = False
Else
Unload UserForm2 'Me?
Filename = "COA" & ThisWorkbook.Sheets("COA").Range("B1")
ThisWorkbook.ActiveSheet.Copy
ActiveWorkbook.SaveAs Filename '<<< should use a full path here...
ActiveWorkbook.Close False
End If
End Sub
'Does the range `rng` contain at least one visible red-filled cell?
Function HasVisibleRedCell(rng As Range) As Boolean
Dim VisibleCells As Range, c As Range
On Error Resume Next
Set VisibleCells = rng.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not VisibleCells Is Nothing Then 'any visible cells?
For Each c In VisibleCells 'check each cell fill
If c.DisplayFormat.Interior.Color = vbRed Then
HasVisibleRedCell = True 'found one
Exit Function 'no need to check further
End If
Next c
End If
'if got here then by default returns False...
End Function
I am trying to change the pivot filter using vba based on a cell.
I get error Application-defined or Object Error on my second line of code.
Sub RefreshPivots()
Sheets("Details").PivotTables("PivotTable1").PivotCache.Refresh
Sheets("Details").PivotTables("PivotTable2").PivotCache.Refresh
temp = Sheets("Input").Range("H2")
Sheets("Details").PivotTables("PivotTable1").PivotFields("Period").PivotFilters.Add Type:=xlCaptionEquals, Value1:=temp
End Sub
I am trying to switch to a date that I have in Sheets("Input").Range("H2") So if I have Sept 10/20 in this cell, I want the pivot to update to that.
Does anyone know what I am doing wrong?
Thanks.
Pivot Fields:
Pivot source data, maybe this format could be why?
filterDate value based on Christians Code:
First of all I think the Period field must be under the Rows section of the PivotTable Fields pane (alone or among other fields - order doesn't matter):
Then you would need to replace this:
temp = Sheets("Input").Range("H2")
Sheets("Details").PivotTables("PivotTable1").PivotFields("Period").PivotFilters.Add Type:=xlCaptionEquals, Value1:=temp
with this:
With Sheets("Details").PivotTables("PivotTable1").PivotFields("Period")
.ClearAllFilters
.PivotFilters.Add Type:=xlSpecificDate, Value1:=Sheets("Input").Range("H2").Value2
End With
You might want to do some checks before running your code because sheet names can change as well as pivot table names and so on. Also instead of Sheets maybe use ThisWorkbook.Worksheets. This way you are not reffering to the ActiveWorkbook but to the Workbook where the code is running.
EDIT
Here's code that does some checks like mentioned above:
Option Explicit
Sub RefreshPivots()
Dim pivTable1 As PivotTable
Dim pivTable2 As PivotTable
Set pivTable1 = GetPivotTable(ThisWorkbook, "Details", "PivotTable1")
If pivTable1 Is Nothing Then
'Do Something. Maybe Exit or display a MsgBox
End If
pivTable1.PivotCache.Refresh
Set pivTable2 = GetPivotTable(ThisWorkbook, "Details", "PivotTable2")
If pivTable2 Is Nothing Then
'Do Something. Maybe Exit or display a MsgBox
End If
pivTable2.PivotCache.Refresh
Dim periodField As PivotField
On Error Resume Next
Set periodField = pivTable1.PivotFields("Period")
On Error GoTo 0
If periodField Is Nothing Then
'Do Something. Maybe Exit or display a MsgBox
End If
On Error GoTo 0
Dim filterDate As Variant
On Error Resume Next
filterDate = ThisWorkbook.Worksheets("Inputs").Range("H2").Value2
If Err.Number <> 0 Then
'Do Something. Maybe Exit or display a MsgBox
Else
Select Case VarType(filterDate)
Case vbDouble
'Maybe check if serial number is valid
Case vbString
filterDate = CDbl(CDate(filterDate))
Case Else
'Maybe show a MsgBox
Exit Sub
End Select
End If
On Error GoTo 0
With periodField
.ClearAllFilters
.PivotFilters.Add Type:=xlSpecificDate, Value1:=filterDate
End With
End Sub
Private Function GetPivotTable(ByVal sourceBook As Workbook _
, ByVal wSheetName As String _
, ByVal pivotName As String _
) As PivotTable
On Error Resume Next
Set GetPivotTable = sourceBook.Worksheets(wSheetName).PivotTables(pivotName)
On Error GoTo 0
End Function
EDIT 2
I've simplified the filter date check and added some code instead of the "Maybe" comments:
Sub RefreshPivots()
Dim pivTable1 As PivotTable
Dim pivTable2 As PivotTable
Set pivTable1 = GetPivotTable(ThisWorkbook, "Details", "PivotTable1")
If pivTable1 Is Nothing Then
MsgBox "Missing Pivot Table", vbInformation, "Cancelled"
Exit Sub
End If
pivTable1.PivotCache.Refresh
Set pivTable2 = GetPivotTable(ThisWorkbook, "Details", "PivotTable2")
If pivTable2 Is Nothing Then
MsgBox "Missing Pivot Table", vbInformation, "Cancelled"
Exit Sub
End If
pivTable2.PivotCache.Refresh
Dim periodField As PivotField
On Error Resume Next
Set periodField = pivTable1.PivotFields("Period")
On Error GoTo 0
If periodField Is Nothing Then
MsgBox "Missing Pivot Field", vbInformation, "Cancelled"
Exit Sub
End If
On Error GoTo 0
'Maybe check if date is within a certain range
' If filterDate < minDate Or filterDate > maxDate Then
' MsgBox "Invalid Date", vbInformation, "Cancelled"
' Exit Sub
' End If
Dim filterDate As Variant
On Error Resume Next
filterDate = ThisWorkbook.Worksheets("Inputs").Range("H2").Value2
If VarType(filterDate) = vbString Then filterDate = CDbl(CDate(filterDate))
If Err.Number <> 0 Or VarType(filterDate) <> vbDouble Then
MsgBox "Missing/Invalid Filter Date", vbInformation, "Cancelled"
Err.Clear
Exit Sub
End If
On Error GoTo 0
With periodField
.ClearAllFilters
.PivotFilters.Add Type:=xlSpecificDate, Value1:=filterDate
End With
End Sub
EDIT 3
Based on updated question:
Option Explicit
Sub RefreshPivots()
Dim pivTable1 As PivotTable
Dim pivTable2 As PivotTable
Set pivTable1 = GetPivotTable(ThisWorkbook, "Details", "PivotTable1")
If pivTable1 Is Nothing Then
MsgBox "Missing Pivot Table", vbInformation, "Cancelled"
Exit Sub
End If
pivTable1.PivotCache.Refresh
Set pivTable2 = GetPivotTable(ThisWorkbook, "Details", "PivotTable2")
If pivTable2 Is Nothing Then
MsgBox "Missing Pivot Table", vbInformation, "Cancelled"
Exit Sub
End If
pivTable2.PivotCache.Refresh
Dim periodField As PivotField
On Error Resume Next
Set periodField = pivTable1.PivotFields("Period")
On Error GoTo 0
If periodField Is Nothing Then
MsgBox "Missing Pivot Field", vbInformation, "Cancelled"
Exit Sub
End If
periodField.ClearAllFilters
'Maybe check if date is within a certain range
' If filterDate < minDate Or filterDate > maxDate Then
' MsgBox "Invalid Date", vbInformation, "Cancelled"
' Exit Sub
' End If
Dim filterDate As Variant
On Error Resume Next
filterDate = ThisWorkbook.Worksheets("Inputs").Range("H2").Value2
If Err.Number <> 0 Then
Err.Clear
MsgBox "Missing Filter Date", vbInformation, "Cancelled"
Exit Sub
End If
'Try String first
If VarType(filterDate) = vbString Then
periodField.PivotFilters.Add Type:=xlCaptionEquals, Value1:=filterDate
If Err.Number = 0 Then Exit Sub
filterDate = CDbl(CDate(filterDate))
Err.Clear
End If
If VarType(filterDate) <> vbDouble Then
MsgBox "Invalid Filter Date", vbInformation, "Cancelled"
Exit Sub
End If
'Try Date (as Double data type)
periodField.PivotFilters.Add Type:=xlSpecificDate, Value1:=filterDate
If Err.Number <> 0 Then
Err.Clear
MsgBox "Could not apply filter", vbInformation, "Cancelled"
Exit Sub
End If
End Sub
Private Function GetPivotTable(ByVal sourceBook As Workbook _
, ByVal wSheetName As String _
, ByVal pivotName As String _
) As PivotTable
On Error Resume Next
Set GetPivotTable = sourceBook.Worksheets(wSheetName).PivotTables(pivotName)
On Error GoTo 0
End Function
The filter items in the pivot table are characters, not values. Therefore, under the condition that the cell format type is the same as the field format type of the pivot table, you must obtain the character, not the cell value(range("h2").Text not range("h2").value).
Sub RefreshPivots()
Dim Ws As Worksheet
Dim PT As PivotTable
Dim PF As PivotField
Dim Temp As String
Temp = Sheets("Input").Range("H2").Text '<~~ it is string not value
Set Ws = Sheets("Details")
Set PT = Ws.PivotTables("PivotTable1")
Set PF = PT.PivotFields("Period")
PT.PivotCache.Refresh
PF.ClearAllFilters
'*** if your source type is date
'PF.PivotFilters.Add Type:=xlSpecificDate, Value1:=Temp
'but your source data type is string
PF.PivotFilters.Add Type:=xlCaptionEquals, Value1:=Temp
End Sub
I have a code which deletes a value from a locked sheet. Whenever I run the code, Error message
Delete method of Range class failed
is displayed. How do I prompt the user with a message such as first unprotect the sheet?
Sub DeleteRow()
Dim rng As Range
On Error Resume Next
With Selection.Cells(1)
Set rng = Intersect(.EntireRow, ActiveCell.ListObject.DataBodyRange)
On Error GoTo 0
If rng Is Nothing Then
MsgBox "Please select a valid table cell.", vbCritical
Else
rng.delete xlShiftUp
End If
End With
End Sub
This will Work:
Activesheet.ProtectContents will tell you if a sheet is protected or not.
Sub DeleteRow()
Dim rng As Range
On Error Resume Next
If ActiveSheet.ProtectContents = False Then
With Selection.Cells(1)
Set rng = Intersect(.EntireRow, ActiveCell.ListObject.DataBodyRange)
On Error GoTo 0
If rng Is Nothing Then
MsgBox "Please select a valid table cell.", vbCritical
Else
rng.Delete xlShiftUp
End If
End With
Else: MsgBox "Unprotect the Sheet First!"
End If
End Sub
I have a code to filter data and copy to new worksheet. I have an issue where if the sheet being created already exists then it will jump to error handling and stop not continue with remaining 'next'. If i move the 'Next' after the error handling it will only loop if there is and error. Is there a way I can have both?
Sub SortDataAll()
' Sort Data All
If (Workbooks("Fakturagrunnlag All_1.xlsm").Sheets("All Focal Point Data").AutoFilterMode And Workbooks("Fakturagrunnlag All_1.xlsm").Sheets("All Focal Point Data").FilterMode) _
Or Workbooks("Fakturagrunnlag All_1.xlsm").Sheets("All Focal Point Data").FilterMode Then
Workbooks("Fakturagrunnlag All_1.xlsm").Sheets("All Focal Point Data").ShowAllData
End If
'~~> Set filter of main data
Dim rRange As Range
Dim rCell As Range
Set rRange = Worksheets("Front Page").Range("A7:A21")
For Each rCell In rRange
MsgBox "Setting filter for " & rCell
Dim rList As String
rList = rCell & "List"
MsgBox "The list for filter is" & rList
' can remove after
Worksheets("All Focal Point Data").Activate
Dim v As Variant
v = Application.WorksheetFunction.Transpose(Range(rList).Value)
Range("A:BC").AutoFilter Field:=54, Criteria1:=v, Operator:=xlFilterValues
Selection.AutoFilter Field:=54, Criteria1:=v, Operator:=xlFilterValues
MsgBox "Check data is filtered"
'~~> Create new sheet and paste data
On Error Resume Next
With ThisWorkbook
.Sheets.Add(After:=.Sheets(.Sheets.Count)).Name = rCell
End With
If Err Then GoTo ErrorJump
Err.clear
Worksheets("All Focal Point Data").Range("A1:BC5000").Copy Worksheets(rCell).Range("A1").Paste
Columns("BB:BB").Delete Shift:=xlToLeft
Next rCell
Exit Sub
ErrorJump:
MsgBox "Sheet already exists":
Application.DisplayAlerts = False
ActiveWindow.SelectedSheets.Delete
Application.DisplayAlerts = True
'Worksheets("Front Page").Activate
'Range("A1").Select
Next rCell
End Sub
I've used a method where you simply try to use the worksheet and let error control create the worksheet if an error is thrown.
In this, if the abc worksheet exists, it is used. If it doesn't exist, it is created then used.
sub testws()
dim wsn as string
wsn = "abc"
on error goto make_ws
with worksheets(wsn)
on error goto 0
...
end with
exit sub
make_ws:
with worksheets.add
.name = wsn
end with
resume
end sub