VBA Creating Sheets, error handeling - vba

I am using the code below, to copy a hidden worksheet and copy it, rename is and fill in certain fields on two sheets.
I have done it like this, as i need to copy the layout and formatting of the hidden sheet.
The problem I am having, is that when i click the create button, if the sheet already exits, it completely crashes Excel, I have tried to add error handling but everything i have tried to check if the sheet exists doesn't work and still crashes Excel.
Have have separated the code that is un-hides the template sheet, copys it, renames the new sheet, and then re-hides the template.
What I would like it to do, is check the entered sheet name from TextBox5, and check is the sheet exists, if it does the display a message box, saying sheet already exists, if the sheet does not exist them carry on with the code as normal.
If really appreciate all the help and support i have already received, and thank all of you for the help you can provide with this.
Private Sub CommandButton3_Click()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = wb.Sheets("Template")
Dim newws As Worksheet, sh As Worksheet, newname
Dim query As Long, xst As Boolean, info As String
Dim NextRow As Long, myCCName As Variant, lastRow2 As Long, lastRow As Long
'Contract Name
Dim Contact As String, name As String, name2 As String, SpacePos As Integer
Dim answer As Integer
With Application
.ScreenUpdating = False
.EnableEvents = False
.CutCopyMode = False
End With
lastRow2 = Sheets("Payment Form").Range("A18:A34").End(xlDown).Row
lastRow = Sheets("Payment Form").Range("U36:U53").End(xlDown).Row
'Contract Name
Set contract = Sheets("Payment Form").Range("C9")
SpacePos = InStr(contract, "- ")
name = Left(contract, SpacePos)
name2 = Right(contract, Len(contract) - Len(name))
'
retry:
xst = False
newname = Me.TextBox5.Value
myCCName = Me.TextBox4.Value
If newname = "" Then
MsgBox "You have not entered a CC Code Number. Please enter CC Code Number!", vbExclamation, "An Error Occured"
Exit Sub
End If
If myCCName = "" Then
MsgBox "You have not entered a CC Code Name. Please enter CC Code Name!", vbExclamation, "An Error Occured"
Exit Sub
End If
For Each sh In wb.Sheets
If sh.name = newname Then
xst = True: Exit For
End If
Next
If Len(newname) = 0 Or xst = True Then
info = "Sheet name is invalid. Please retry."
GoTo retry
End If
Sheets("Template").Visible = True
ws.Copy before:=Sheets("Details"): Set newws = ActiveSheet: newws.name = newname
Sheets("Template").Visible = False
With ActiveWorkbook.Sheets("Payment Form").Activate
For Each cell In Columns(1).Range("A18:A34").Cells
If Len(cell) = 0 Then cell.Select: Exit For
Next cell
ActiveCell.Value = newname & " " & "-" & name2 & ":" & " " & myCCName
End With
With ActiveWorkbook.Sheets(newname).Activate
ActiveWorkbook.Sheets(newname).Range("D4") = Sheets("Payment Form").Range("a18:a34").End(xlDown).Value
ActiveWorkbook.Sheets(newname).Range("D6") = Sheets("Payment Form").Range("L11").Value
ActiveWorkbook.Sheets(newname).Range("D8") = Sheets("Payment Form").Range("C9").Value
ActiveWorkbook.Sheets(newname).Range("D10") = Sheets("Payment Form").Range("C11").Value
End With
ActiveWorkbook.Sheets("Payment Form").Activate
With ActiveWorkbook.Sheets("Payment Form")
Range("J" & lastRow2 + 1) = 0
Range("L" & lastRow2 + 1).Formula = "=N" & lastRow2 + 1 & "-J" & lastRow2 + 1 & ""
Range("N" & lastRow2 + 1).Formula = "='" & newname & "'!L20"
Range("U" & lastRow + 1) = newname & ":" & " "
Range("V" & lastRow + 1).Formula = "='" & newname & "'!I21"
Range("W" & lastRow + 1).Formula = "='" & newname & "'!L23"
Range("X" & lastRow + 1).Formula = "='" & newname & "'!K21"
End With
answer = MsgBox("Would you like to create another sheet?", vbYesNo + vbQuestion, "New Sheet")
If answer = vbYes Then
Else
Unload Me
End If
With Application
.ScreenUpdating = True
.EnableEvents = True
.CutCopyMode = True
End With
Me.TextBox4.Value = ""
Me.TextBox5.Value = ""
End Sub

There appear to be a few general typos and a few errors with your 'With' statements throughout the code.
I have hopefully tidied up and recoded the function to work, but as it is untested I can't guarantee it will work off the bat.
I have also included the worksheet check function as a separate function
Private Sub CommandButton3_Click()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim wsTemplate As Worksheet: Set wsTemplate = wb.Sheets("Template")
Dim wsPayment As Worksheet: Set wsPayment = wb.Sheets("Payment Form")
Dim wsNew As Worksheet
Dim NewName As String: NewName = Me.TextBox5.Value
Dim CCName As Variant: CCName = Me.TextBox4.Value
If NewName = "" Or CCName = "" Then
MsgBox "CC Code Name or Number missing. Please check details!", vbExclamation, "An Error Occured"
Exit Sub
End If
If WorksheetExists(NewName) Then
MsgBox "Sheet name already exists. Please retry!", vbExclamation, "An Error Occured"
Exit Sub
End If
With Application
.ScreenUpdating = False
.EnableEvents = False
.CutCopyMode = False
End With
Dim lastRow As Long: lastRow = wsPayment.Range("U36:U53").End(xlDown).Row
Dim lastRow2 As Long: lastRow2 = wsPayment.Range("A18:A34").End(xlDown).Row
'Contract Name
Dim Contract As String: Contract = Sheets("Payment Form").Range("C9").Value
Dim SpacePos As Integer: SpacePos = InStr(Contract, "- ")
Dim Name As String: Name = Left(Contract, SpacePos)
Dim Name2 As String: Name2 = Right(Contract, Len(Contract) - Len(Name))
wsTemplate.Visible = True
wsTemplate.Copy before:=Sheets("Details"): Set wsNew = ActiveSheet
wsTemplate.Visible = False
With wsPayment
For Each Cell In .Range("A18:A34")
If Len(Cell) = 0 Then
Cell.Value = NewName & " -" & Name2 & ": " & CCName
Exit For
End If
Next Cell
End With
With wsNew
.Name = NewName
.Range("D4").Value = wsPayment.Range("A18:A34").End(xlDown).Value
.Range("D6").Value = wsPayment.Range("L11").Value
.Range("D8").Value = wsPayment.Range("C9").Value
.Range("D10").Value = wsPayment.Range("C11").Value
End With
With wsPayment
.Range("J" & lastRow2 + 1).Value = 0
.Range("L" & lastRow2 + 1).Formula = "=N" & lastRow2 + 1 & "-J" & lastRow2 + 1 & ""
.Range("N" & lastRow2 + 1).Formula = "='" & NewName & "'!L20"
.Range("U" & lastRow + 1).Value = NewName & ": "
.Range("V" & lastRow + 1).Formula = "='" & NewName & "'!I21"
.Range("W" & lastRow + 1).Formula = "='" & NewName & "'!L23"
.Range("X" & lastRow + 1).Formula = "='" & NewName & "'!K21"
End With
With Application
.ScreenUpdating = True
.EnableEvents = True
.CutCopyMode = True
End With
Dim Answer As Integer: Answer = MsgBox("Would you like to create another sheet?", _
vbYesNo + vbQuestion, "New Sheet")
If Answer = vbNo Then Unload Me
Me.TextBox4.Value = ""
Me.TextBox5.Value = ""
End Sub
Public Function WorksheetExists(ByVal WorksheetName As String) As Boolean
On Error Resume Next
WorksheetExists = (ThisWorkbook.Sheets(WorksheetName).Name <> "")
On Error GoTo 0
End Function

Personally i use the function below to check if a sheet allready exist in the workbook, in which case it returns True:
Public Function doItExist(strSheetName as String) As Boolean
Dim wsTest As Worksheet: Set wsTest = Nothing
On Error Resume Next
Set wsTest = ThisWorkbook.Worksheets(strSheetName)
On Error GoTo 0
If wsTest Is Nothing Then
doExist = False
Else
doExist = True
End If
End Function
I cannot seem to find the original source for the code, but I cannot take credit, it is mearly a modified version of some code I found on either SO, ozgrid or Mrexcel
EDIT:
Taking a closer look at your code, it seems you allready check for the existence of the sheetname in the xst variable. As far as I can see the user is not able to update the sheetname if is invalid, as the retry block will just keep looping?
under retry:
'### This bit essentially does the same as doSheetExist
For Each sh In wb.Sheets
If sh.name = newname Then
xst = True: Exit For
End If
Next
'###
If Len(newname) = 0 Or xst = True Then 'if you go for the doSheetExist, then the xst check is obsolete. Else move the xst check to the elseif and remove the doSheetExist call
info = "Sheet name is invalid. Please retry."
'GoTo retry 'As far as I can tell calling retry would just cause an infinite loop as the user have had no chance to update sheetname
Exit Sub 'let the user update and click the button again
ElseIf doSheetExist(newname) = True Then
info = "Sheet name allready exist. Please specify other sheetname"
Exit Sub
End If

Related

I have a macro program which splits file and protects the sheet but I am unable to put autofilter and sort in the individual workbooks

I have a macro program that parses through a worksheet and creates new work book based on one particular column. In my case new workbooks will be created based on column 3. Also I have written a call function to protect the individual workbooks with a password. Only few columns are editable and the rest of the columns are read only. Now I want to apply auto filter and sort function so that the user can search information based on their need and enter values in the editable cells. However when we protect the sheet autofilter doesn't work. Can you help in adding autofilter function on a protected sheet for each individual workbooks.
Sample code shown for reference.
Sub parse_data()
Dim lr As Long
Dim ws As Worksheet
Dim vcol, i As Integer
Dim icol As Long
Dim myarr As Variant
Dim title As String
Dim titlerow As Integer
vcol = 3
Set ws = Sheets("Sheet1")
lr = ws.Cells(ws.Rows.Count, vcol).End(xlUp).Row
title = "A1:Z1"
titlerow = ws.Range(title).Cells(1).Row
icol = ws.Columns.Count
ws.Cells(1, icol) = "Unique"
For i = 2 To lr
On Error Resume Next
If ws.Cells(i, vcol) <> "" And Application.WorksheetFunction.Match(ws.Cells(i, vcol), ws.Columns(icol), 0) = 0 Then
ws.Cells(ws.Rows.Count, icol).End(xlUp).Offset(1) = ws.Cells(i, vcol)
End If
Next
myarr = Application.WorksheetFunction.Transpose(ws.Columns(icol).SpecialCells(xlCellTypeConstants))
ws.Columns(icol).Clear
For i = 2 To UBound(myarr)
ws.Range(title).AutoFilter field:=vcol, Criteria1:=myarr(i) & ""
If Not Evaluate("=ISREF('" & myarr(i) & "'!A1)") Then
'===================================================================
'~~Sheets.Add(after:=Worksheets(Worksheets.Count)).Name = myarr(i) & ""
Workbooks.Add
ActiveWorkbook.Sheets.Add(0).Name = myarr(i) & ""
'===================================================================
Else
Sheets(myarr(i) & "").Move after:=Worksheets(Worksheets.Count)
End If
'==========================================================================
'~~ws.Range("A" & titlerow & ":A" & lr).EntireRow.Copy Sheets(myarr(i) & "").Range("A1")
'~~Sheets(myarr(i) & "").Columns.AutoFit
ws.Range("A" & titlerow & ":A" & lr).EntireRow.Copy ActiveWorkbook.Sheets("Sheet1").Range("A1")
'mainworkBook.Sheets(1).Range("T2:T1000").Formula = "=SUM(Q2:S2)"
ActiveWorkbook.SaveAs "C:\Macros\Split_Files\" & myarr(i) & ".xlsx"
'=========================================================================
ActiveWorkbook.Close
Next
ws.AutoFilterMode = False
ws.Activate
Call ProtectAll
End Sub
Sub ProtectAll()
Dim wBk As Workbook
Dim sFileSpec As String
Dim sPathSpec As String
Dim sFoundFile As String
Dim mainworkBook As Workbook
Dim ws1 As Worksheet
Dim LastRow As Long
sPathSpec = "C:\Macros\Split_Files\"
sFileSpec = "*.xlsx"
sFoundFile = Dir(sPathSpec & sFileSpec)
Do While sFoundFile <> ""
Set wBk = Workbooks.Open(sPathSpec & sFoundFile)
With wBk
Set mainworkBook = wBk
'mainworkBook.Sheets(1).Unprotect passowrd = "abc"
Set ws1 = mainworkBook.Sheets(1)
LastRow = ws1.Cells(ws1.Rows.Count, "U").End(xlUp).Row
mainworkBook.Sheets(1).Range("U2:U" & LastRow).Formula = "=SUM(R2:T2)"
'mainworkBook.Sheets(1).Range("A:Z").Locked = True
'mainworkBook.Sheets(1).Range("A1:Z1").Locked = False
'mainworkBook.Sheets(1).Range("Q:S").Locked = False
'mainworkBook.Sheets(1).Range("U:U").Locked = False
'mainworkBook.Sheets(1).Range("W:X").Locked = False
mainworkBook.Worksheets("Sheet1").Cells.EntireColumn.AutoFit
'mainworkBook.Sheets(1).Protect passowrd = "abc"
'mainworkBook.Sheets(1).Protect passowrd:="abc", userinterfaceonly:=True
'mainworkBook.Sheets(1).EnableOutlining = True
'mainworkBook.Sheets(1).EnableAutoFilter = True
'mainworkBook.Sheets(1).EnableSelection = xlUnlockedCells
Worksheets(2).Visible = xlSheetHidden
Worksheets(3).Visible = xlSheetHidden
Application.DisplayAlerts = False
wBk.SaveAs Filename:=.FullName
Application.DisplayAlerts = True
End With
Set wBk = Nothing
Workbooks(sFoundFile).Close False
sFoundFile = Dir
Loop
End Sub
Regards,
Linu
In order to sort in a protected sheet you would have to unprotect it and protect it again afterwards.
But you could use the filter function even when the sheet is protected, just not sort.
Here are two little functions I used for on of my projects:
Function protect_sheet(sheetname As String)
If Sheets(sheetname).ProtectContents = False Then
Sheets(sheetname).Protect Password:=Password, DrawingObjects:=True, Contents:=True, Scenarios:=True, AllowSorting:=True, AllowFiltering:=True
End If
End Function
Function unprotect_sheet(sheetname As String)
If Sheets(sheetname).ProtectContents = True Then
Sheets(sheetname).Unprotect Password:=Password
End If
End Function

How do I search through a sheet of data and return MULTIPLE matching results on another sheet?

This is my desired flow:
On "Sheet2" you can select a macro "Search by first name"
You see a popup to enter a name, you enter a name (X) and select ok
It will search the next sheet, "Master", and look for results where first name = X
and finally return these results back on "Sheet2"
Here's a screenshot of the two sheets:
Sheet 2
and
Master
The following VB code means that it only returns 1 result when there should be multiple sometimes:
Sub Searchbyfirstname()
Dim wks As Excel.Worksheet
Dim rCell As Excel.Range
Dim fFirst As String
Dim i As Long
Dim MyVal As String
MyVal = InputBox("Enter the first name of the employees record you need", "Search By First Name", "")
If MyVal = "" Then Exit Sub
Application.ScreenUpdating = False
Application.DisplayAlerts = False
With Cells(5, 1)
.Value = "The below data has been found for " & MyVal & ":"
.EntireColumn.AutoFit
.HorizontalAlignment = xlCenter
End With
i = 2
For Each wks In ActiveWorkbook.Worksheets
If wks.Name <> "List" Then
With wks.Range("B:B")
Set rCell = .Find(MyVal, , , xlWhole, xlByColumns, xlNext, False)
If Not rCell Is Nothing Then
fFirst = rCell.Address
Do
rCell.Hyperlinks.Add Cells(6, 1), "", "'" & wks.Name & "'!" & rCell.Address
wks.Range("A" & rCell.Row & ":Z" & rCell.Row).Copy Destination:=Cells(6, 1)
Set rCell = .FindNext(rCell)
i = i + 3
Loop While Not rCell Is Nothing And rCell.Address <> fFirst
End If
End With
End If
Next wks
Set rCell = Nothing
If i = 2 Then
MsgBox "No record for " & MyVal & " has been found", 64, "No Matches"
Cells(1, 1).Value = ""
End If
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
Any help would be very much appreciated, thanks!
Ok so I am pretty sure I have the answer now that Maertin and chris neilsen pointed out the errors with hardcoding.
I have posted my code again but the points where I have added or changed are not code (didn't know the best way to format this):
Sub Searchbyfirstname()
Dim wks As Excel.Worksheet
Dim rCell As Excel.Range
Dim fFirst As String
Dim i As Long
Dim MyVal As String
MyVal = InputBox("Enter the first name of the employees record you need", "Search By First Name", "")
If MyVal = "" Then Exit Sub
Application.ScreenUpdating = False
Application.DisplayAlerts = False
With Cells(5, 1)
.Value = "The below data has been found for " & MyVal & ":"
.EntireColumn.AutoFit
.HorizontalAlignment = xlCenter
End With
i = 2
For Each wks In ActiveWorkbook.Worksheets
If wks.Name <> "List" Then
With wks.Range("B:B")
Set rCell = .Find(MyVal, , , xlWhole, xlByColumns, xlNext, False)
If Not rCell Is Nothing Then
fFirst = rCell.Address
Dim x As Integer
x = 6
With Sheets("Sheet2")
.Rows(6 & ":" & .Rows.Count).Delete
End With
' for this part I have created the variable x, then I'm assigning this 6 because that's the first row I want to put the data in, then I am saying if there's anything in row 6 or below, delete it
Do
rCell.Hyperlinks.Add Cells(x, 1), "", "'" & wks.Name & "'!" & rCell.Address
'see this and row below, instead of being Cells(6, 1), it is now x and this means it will paste to 6, then if there's another 7 and so on
wks.Range("A" & rCell.Row & ":Z" & rCell.Row).Copy Destination:=Cells(x, 1)
Set rCell = .FindNext(rCell)
i = i + 3
x = x + 1
' Here I am incrementing x by 1 so that if there's another piece of data to paste it will paste in the next row - on first go this would be row 7
Loop While Not rCell Is Nothing And rCell.Address <> fFirst
End If
End With
End If
Next wks
Set rCell = Nothing
If i = 2 Then
MsgBox "No record for " & MyVal & " has been found", 64, "No Matches"
Cells(1, 1).Value = ""
With Sheets("Sheet2")
.Rows(5 & ":" & .Rows.Count).Delete
End With
End If
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub

Export sheet as CSV, add new column with header and insert workbook name in all the cells

I want to create a macro that copies a sheet called "Week" from my workbook, deletes the first row, adds a new column (farthest to the left), assigns it the header "Department" and assigns it a fixed value. The fixed value should be the name of the CSV file. The name can be found on the front page in cell G6. I don't want the fixed value to be copied all the way down in the first column. I want it to be copied until there isn't any value in any of the columns to the right of the first column. Currently I've tried just comparing it to the second column (column B). I get the message:
Run-time error '424':
Object required
and is referring back to:ยจ
If InStr(1, thiswork.Sheets(ActiveSheet.Name).Range("$B$" & X), "") > 0 Then
This is my code:
Sub Export_pb_uge()
Dim MyPath As String
Dim MyFileName As String
MyPath = "C:mypath1"
MyFileName = Sheets("Front_Page").Range("g6").Value
Application.ScreenUpdating = False
Application.DisplayAlerts = False
If Not Right(MyPath, 1) = "\" Then MyPath = MyPath & "\"
If Not Right(MyFileName, 4) = ".csv" Then MyFileName = MyFileName & ".csv"
Sheets("PB_uge").Visible = True
Sheets("PB_uge").Copy
Rows(1).EntireRow.Delete
With target_sheet
Range("A1").EntireColumn.Insert
Range("A1").Value = "Department"
End With
If ThisWorkbook.Sheets(ActiveSheet.Name).FilterMode Then ThisWorkbook.Sheets(ActiveSheet.Name).ShowAllData
lRow = ThisWorkbook.Sheets(ActiveSheet.Name).Cells(Rows.Count, "B").End(xlUp).Row
For X = 1 To lRow
If InStr(1, thiswork.Sheets(ActiveSheet.Name).Range("$B$" & X), "") > 0 Then
target_sheet.Range("$A$" & X) = ActiveSheet.Name
End If
Next
With ActiveWorkbook
.SaveAs Filename:= _
MyPath & MyFileName, _
FileFormat:=xlCSV, _
CreateBackup:=False, _
Local:=True
.Close False
End With
Sheets("Week").Visible = False
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
Well spotted gazzz0x2z, however I would also declare and set target_sheet
Dim target_sheet As Worksheet
Set target_sheet = ActiveSheet ' or for example Sheets("sheet1")
With target_sheet
Range("A1").EntireColumn.Insert
Range("A1").Value = "Department"
End With
If ThisWorkbook.Sheets(ActiveSheet.Name).FilterMode Then ThisWorkbook.Sheets (ActiveSheet.Name).ShowAllData
lRow = ThisWorkbook.Sheets(ActiveSheet.Name).Cells(Rows.Count, "B").End(xlUp).Row
For X = 1 To lRow
If InStr(1, ThisWorkbook.Sheets(ActiveSheet.Name).Range("$B$" & X), "") > 0 Then
target_sheet.Range("$A$" & X) = ActiveSheet.Name
End If
Next
Try :
If InStr(1, ThisWorkbook.Sheets(ActiveSheet.Name).Range("$B$" & X), "") > 0 Then
Seems like, for some reason, you've lost 4 letters.
I found the answer to be:
Sub Export_PB_uge()
Dim pb_uge As Worksheet
Dim myPath As String
Dim MyFileName As String
Dim x As Long
Dim wsCSV As Worksheet
myPath = "C:mypath1"
MyFileName = Sheets("Front_Page").Range("g6").Value
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
If Not Right(myPath, 1) = "\" Then myPath = myPath & "\"
If Not Right(MyFileName, 4) = ".csv" Then MyFileName = MyFileName & ".csv"
With ThisWorkbook.Sheets("PB_uge")
If .FilterMode Then pb_uge.ShowAllData
.Visible = True
.Copy
End With
Set wsCSV = ActiveWorkbook.Sheets(1)
With wsCSV
.Range("A1").EntireRow.Delete
.Range("A1").EntireColumn.Insert
.Range("A1").Value = "Department"
lRow = .Cells(Rows.Count, "C").End(xlUp).Row
.Range("A2:A" & lRow) = ThisWorkbook.Sheets("Front_Page").Range("g6").Value
.Parent.SaveAs Filename:= _
myPath & MyFileName, _
FileFormat:=xlCSV, _
CreateBackup:=False, _
Local:=True
.Parent.Close False
End With
ThisWorkbook.Sheets("PB_uge").Visible = False
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.DisplayAlerts = True
MsgBox "CSV saved at " & myPath & MyFileName, vbInformation
End Sub

Error handling for if sheets exists when copying rows

following my post If cell value matches a UserForm ComboBox column, then copy to sheet.
I have managed to get the code to work to move the check the names and move then to the correct sheets.
The problem i am having is checking if the sheets exists. If it finds a match in the sheet and column 2 in the combobox but there is no sheet for the value then it crashes the code.
Once all the information has been copied to the relevant sheets, i would like it to display a msgbox telling the user how many rows of data have been copied to the respective sheets.
Dim i As Long, j As Long, lastG As Long, strWS As String, rngCPY As Range
With Application
.ScreenUpdating = False
.EnableEvents = False
.CutCopyMode = False
End With
On Error GoTo bm_Close_Out
' find last row
lastG = sheets("Global").Cells(Rows.Count, "Q").End(xlUp).row
For i = 3 To lastG
lookupVal = sheets("Global").Cells(i, "Q") ' value to find
' loop over values in "details"
For j = 0 To Me.ComboBox2.ListCount - 1
currVal = Me.ComboBox2.List(j, 2) ' value to match
If lookupVal = currVal Then
Set rngCPY = sheets("Global").Cells(i, "Q").EntireRow
strWS = Me.ComboBox2.List(j, 1)
On Error GoTo bm_Need_Worksheet '<~~ if the worksheet in the next line does not exist, go make one
With Worksheets(strWS)
rngCPY.Copy
.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Insert shift:=xlDown
End With
End If
Next j
Next i
GoTo bm_Close_Out
bm_Need_Worksheet:
On Error GoTo 0
With Worksheet
Dim wb As Workbook: Set wb = ThisWorkbook
Dim wsTemplate As Worksheet: Set wsTemplate = wb.sheets("Template")
Dim wsPayment As Worksheet: Set wsPayment = wb.sheets("Payment Form")
Dim wsNew As Worksheet
Dim lastRow2 As Long
Dim Contract As String: Contract = sheets("Payment Form").Range("C9").value
Dim SpacePos As Integer: SpacePos = InStr(Contract, "- ")
Dim Name As String: Name = Left(Contract, SpacePos)
Dim Name2 As String: Name2 = Right(Contract, Len(Contract) - Len(Name))
Dim NewName As String: NewName = strWS
Dim CCName As Variant: CCName = Me.ComboBox2.List(j, 0)
Dim lastRow As Long: lastRow = wsPayment.Range("U36:U53").End(xlDown).row
If InStr(1, sheets("Payment Form").Range("A20").value, "THE VAT SHOWN IS YOUR OUTPUT TAX DUE TO CUSTOMS AND EXCISE") > 0 Then
lastRow2 = wsPayment.Range("A23:A39").End(xlDown).row
Else
lastRow2 = wsPayment.Range("A18:A34").End(xlDown).row
End If
wsTemplate.Visible = True
wsTemplate.Copy before:=sheets("Details"): Set wsNew = ActiveSheet
wsTemplate.Visible = False
If InStr(1, sheets("Payment Form").Range("A20").value, "THE VAT SHOWN IS YOUR OUTPUT TAX DUE TO CUSTOMS AND EXCISE") > 0 Then
With wsPayment
For Each cell In .Range("A23:A39")
If Len(cell) = 0 Then
If sheets("Payment Form").Range("A20").value = "Network" Then
cell.value = NewName & " - " & Name2 & ": " & CCName
Else
cell.value = NewName & " - " & Name2 & ": " & CCName
End If
Exit For
End If
Next cell
End With
Else
With wsPayment
For Each cell In .Range("A18:A34")
If Len(cell) = 0 Then
If sheets("Payment Form").Range("A20").value = "Network" Then
cell.value = NewName & " - " & Name2 & ": " & CCName
Else
cell.value = NewName & " - " & Name2 & ": " & CCName
End If
Exit For
End If
Next cell
End With
End If
If InStr(1, sheets("Payment Form").Range("A20").value, "THE VAT SHOWN IS YOUR OUTPUT TAX DUE TO CUSTOMS AND EXCISE") > 0 Then
With wsNew
.Name = NewName
.Range("D4").value = wsPayment.Range("A23:A39").End(xlDown).value
.Range("D6").value = wsPayment.Range("L11").value
.Range("D8").value = wsPayment.Range("C9").value
.Range("D10").value = wsPayment.Range("C11").value
End With
Else
With wsNew
.Name = NewName
.Range("D4").value = wsPayment.Range("A18:A34").End(xlDown).value
.Range("D6").value = wsPayment.Range("L11").value
.Range("D8").value = wsPayment.Range("C9").value
.Range("D10").value = wsPayment.Range("C11").value
End With
End If
wsPayment.Activate
With wsPayment
.Range("J" & lastRow2 + 1).value = 0
.Range("L" & lastRow2 + 1).Formula = "=N" & lastRow2 + 1 & "-J" & lastRow2 + 1 & ""
.Range("N" & lastRow2 + 1).Formula = "='" & NewName & "'!L20"
.Range("U" & lastRow + 1).value = NewName & ": "
.Range("V" & lastRow + 1).Formula = "='" & NewName & "'!I21"
.Range("W" & lastRow + 1).Formula = "='" & NewName & "'!I23"
.Range("X" & lastRow + 1).Formula = "='" & NewName & "'!K21"
End With
End With
On Error GoTo bm_Close_Out
Resume
bm_Close_Out:
With Application
.ScreenUpdating = True
.EnableEvents = True
.CutCopyMode = True
End With
With help from Jeeped I have manage to get the code for copying the rows to the relevant sheets, and if the sheet doesn't exists then it create it. I just need help with problem two above.
Attempting to use a Worksheet Object that does not exist throws an error. If you catch that error and create a worksheet with the name that you are looking for, you can Resume back to the point where the error was thrown and continue your processing.
Private Sub CommandButton7_Click()
Dim i As Long, j As Long, lastG As Long, strWS As String, strMSG As String
dim rngHDR as range, rngCPY aS range
With Application
.ScreenUpdating = False
.EnableEvents = False
.CutCopyMode = False
End With
On Error GoTo bm_Close_Out
' find last row
lastG = Sheets("Global").Cells(Rows.Count, "Q").End(xlUp).Row
For i = 3 To lastG
lookupVal = Sheets("Global").Cells(i, "Q") ' value to find
' loop over values in "details"
For j = 0 To Me.ComboBox2.ListCount - 1
currVal = Me.ComboBox2.List(j, 2) ' value to match
If lookupVal = currVal Then
set rngHDR = Sheets("Global").Cells(1, "Q").EntireRow
set rngCPY = Sheets("Global").Cells(i, "Q").EntireRow
strWS = Me.ComboBox2.List(j, 1)
On Error GoTo bm_Need_Worksheet '<~~ if the worksheet in the next line does not exist, go make one
With WorkSheets(strWS)
rngCPY .copy
.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Insert shift:=xlDown
End With
exit for
End If
Next j
if j >= Me.ComboBox2.ListCount then _
strMSG = strMSG & "Not found: " & lookupVal & chr(10)
Next i
GoTo bm_Close_Out
bm_Need_Worksheet:
On Error GoTo 0
With Worksheets.Add(after:=Sheets(Sheets.Count))
.Name = strWS
'maybe make a header row here; watch out you do not lose your copy
rngHDR.copy destination:=.cells(1, 1)
End With
On Error GoTo bm_Close_Out
Resume
bm_Close_Out:
With Application
.ScreenUpdating = True
.EnableEvents = True
.CutCopyMode = False
End With
debug.print strMSG
'the next is NOT recommended as strMSG could possibly be VERY long
'if cbool(len(strMSG)) then msgbox strMSG
End Sub
There is a question about whether the new worksheet needs a column header label row but that should be fairly easily rectified.
You could use a function like this :
Sub test_atame()
Dim Ws As Worksheet
Set Ws = Sheet_Exists(ThisWorkbook, "Sheet1")
Set Ws = Sheet_Exists(ActiveWorkbook, "Sheet1")
End Sub
Here is the function :
Public Function Sheet_Exists(aWorkBook As Workbook, Sheet_Name As String) As Worksheet
Dim Ws As Worksheet, _
SExistS As Boolean
SExistS = False
For Each Ws In aWorkBook.Sheets
If Ws.Name <> Sheet_Name Then
Else
SExistS = True
Exit For
End If
Next Ws
If SExistS Then
Set Sheet_Exists = aWorkBook.Sheets(Sheet_Name)
Else
Set Sheet_Exists = Nothing
MsgBox "The sheet " & Sheet_Name & " wasn't found in " & aWorkBook.Name & vbCrLf & _
"Break code to check and correct.", vbCritical + vbOKOnly
End If
End Function
Maybe a check like:
Public Function SheetExists(ByVal Book As Workbook, ByVal SheetName As String) As Boolean
On Error Resume Next
Dim wsTest As Worksheet
Set wsTest = Book.Worksheets(SheetName)
If Not wsTest Is Nothing Then SheetExists = True
End Function

Copying Selective Rows from Sheet1 to Sheet2

Hi all I need to selectively copy entire rows from sheet1 to other sheet. As of now I am using checkboxes to select the rows and then copy the selected rows to sheet of user's choice. But I am facing a bizarre error. For sometime the code runs fine, copying exact data to sheets but after some time it copies erroneous values from nowhere. Can you please help me with this? Pasting the code I am using.
Sub Addcheckboxes()
Dim cell, LRow As Single
Dim chkbx As CheckBox
Dim MyLeft, MyTop, MyHeight, MyWidth As Double
Application.ScreenUpdating = False
LRow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
For cell = 2 To LRow
If Cells(cell, "A").Value <> "" Then
MyLeft = Cells(cell, "E").Left
MyTop = Cells(cell, "E").Top
MyHeight = Cells(cell, "E").Height
MyWidth = Cells(cell, "E").Width
ActiveSheet.CheckBoxes.Add(MyLeft, MyTop, MyWidth, MyHeight).Select
With Selection
.Caption = ""
.Value = xlOff
.Display3DShading = False
End With
End If
Next cell
Application.ScreenUpdating = True
End Sub
Sub RemoveCheckboxes()
Dim chkbx As CheckBox
For Each chkbx In ActiveSheet.CheckBoxes
chkbx.Delete
Next
End Sub
Sub CopyRows()
Dim Val As String
Val = InputBox(Prompt:="Sheet name please.", _
Title:="ENTER SHEET NAME", Default:="Sheet Name here")
For Each chkbx In ActiveSheet.CheckBoxes
If chkbx.Value = 1 Then
For r = 1 To Rows.Count
If Cells(r, 1).Top = chkbx.Top Then
With Worksheets(Val)
LRow = .Range("A" & Rows.Count).End(xlUp).Row + 1
.Range("A" & LRow & ":AF" & LRow) = _
Worksheets("Usable_Inv_Data").Range("A" & r & ":AF" & r).Value
End With
Exit For
End If
Next r
End If
Next
End Sub
Normal Copy Output:
Erroneous Copy Output for same values:
Doing a quick comparison of the normal and the erroneous outputs, it looks like some of your cells/columns are not formatted correctly in your destination sheet (where you are "pasting" the values).
For example, your Base Change column in the Normal copy (the value 582.16) is formatted as a General or Number. The same column in the destination sheet is formatted as a date (582.16 converted to a date value in Excel will be 8/4/1901, or 8/4/01, as shown in your screen.
Just make sure the columns are formatted to display the data type you expect. On your destination sheet, select the column, right-click "Format Cells", and then select the appropriate data type.
---EDIT---
To automate the formatting, you would have to copy and paste the values, inclusive of the formats. Your code would change from this:
With Worksheets(Val)
LRow = .Range("A" & Rows.Count).End(xlUp).Row + 1
.Range("A" & LRow & ":AF" & LRow) = _
Worksheets("Usable_Inv_Data").Range("A" & r & ":AF" & r).Value
End With
TO
With Worksheets(Val)
LRow = .Range("A" & Rows.Count).End(xlUp).Row + 1
Worksheets("Usable_Inv_Data").Range("A" & r & ":AF" & r).Copy
.Range("A" & LRow).PasteSpecial (xlPasteValuesAndNumberFormats)
End With
I have added the checkbox with LinkedCell property. This helps to identify the rows when checkbox is checked.
Also i have added a function check_worksheet_exists which will check if the workbook exist.
Sub Addcheckboxes()
Dim cell, LRow As Single
Dim chkbx As CheckBox
Dim MyLeft, MyTop, MyHeight, MyWidth As Double
Application.ScreenUpdating = False
LRow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).row
For cell = 2 To LRow
If Cells(cell, "A").Value <> "" Then
MyLeft = Cells(cell, "E").Left
MyTop = Cells(cell, "E").Top
MyHeight = Cells(cell, "E").Height
MyWidth = Cells(cell, "E").Width
ActiveSheet.CheckBoxes.Add(MyLeft, MyTop, MyWidth, MyHeight).Select
With Selection
.Caption = ""
.Value = xlOff
.Display3DShading = False
.LinkedCell = Cells(cell, "AZ").Address
End With
End If
Next cell
Application.ScreenUpdating = True
End Sub
Sub RemoveCheckboxes()
Dim chkbx As CheckBox
For Each chkbx In ActiveSheet.CheckBoxes
chkbx.Delete
Next
End Sub
Sub CopyRows()
Dim Val As String
Dim row As Long
Val = InputBox(Prompt:="Sheet name please.", Title:="ENTER SHEET NAME", Default:="Sheet Name here")
If check_worksheet_exists(ThisWorkbook, Val, False) = False Then
Exit Sub
End If
For Each chkbx In ActiveSheet.CheckBoxes
If chkbx.Value = 1 Then
row = Range(chkbx.LinkedCell).row
With Worksheets(Val)
LRow = .Range("A" & Rows.Count).End(xlUp).row + 1
.Range("A" & LRow & ":AF" & LRow) = ActiveSheet.Range("A" & row & ":AF" & row).Value
End With
End If
Next
End Sub
Function check_worksheet_exists(tBook As Workbook, ByVal check_sheet As String, Optional no_warning As Boolean = False) As Boolean
On Error Resume Next
Dim wkSht As Worksheet
Set wkSht = tBook.Sheets(check_sheet)
If Not wkSht Is Nothing Then
check_worksheet_exists = True
ElseIf wkSht Is Nothing And no_warning = False Then
MsgBox "'" & check_sheet & "' sheet does not exist", vbCritical, "Error"
End If
On Error GoTo 0
End Function
i cannot immediately see the errors you refer to, unless you are referring to the sequences of hash-signs ###? These just indicate that the columns aren't wide enough.
Worksheets(Val).Range("A1").CurrentRegion.EntireColumn.AutoFit
BTW I don't think Val is a sensible variable name ;)