How to finish a sub in VBA? - excel

I Have a Sub Who opens a new workbook, but this new workbook has its Sub that immediately Activates a user form, and the first Sub never ends, so this is my question How Can I finish the first sub?
first Workbook
Private Sub BotonBalanza_Click()
Workbooks.Open Filename:="C:\Users\proc_221\Desktop\Balanza.xlsm", Password:="genesis1969"
End Sub
Second Workbook
Private Sub Workbook_Open()
Application.Visible = False
Seleccion.Show
End Sub
Thank you

My suggestion would be to deactivate the events when opening the workbook in question
Private Sub BotonBalanza_Click()
Application.EnableEvents=False
Workbooks.Open Filename:="C:\Users\proc_221\Desktop\Balanza.xlsm", Password:="genesis1969"
Application.EnableEvents=True
End Sub

Thanks for all; I fixed the error using a delay time on the code.
Sub Mostrar()
Workbooks.Open Filename:="C:\Users\proc_221\Desktop\Balanza.xlsm", Password:="genesis1969"
End Sub
Private Sub BotonBalanza_Click()
Application.OnTime Now + TimeValue("00:00:03"), "Mostrar"
End Sub
Private Sub Workbook_Open()
Seleccion.Show
End Sub

In Another Instance of Excel
This will run your destination open workbook code only if the application instance is visible.
It will open the destination workbook in another invisible instance and do the job, ensuring the instance gets closed properly and informing of success.
Destination ThisWorkbook Module
Option Explicit
Private Sub Workbook_Open()
If Application.Visible Then
Application.Visible = False
Seleccion.Show
End If
End Sub
Source 'wherever the button is' Sheet Module
Option Explicit
Private Sub BotonBalanza_Click()
Const ProcName As String = "BotonBalanza"
Dim ErrNum As Long
On Error GoTo ClearError
Dim xlApp As Application: Set xlApp = New Application
Dim wb As Workbook: Set wb = xlApp.Workbooks.Open( _
Filename:="C:\Users\proc_221\Desktop\Balanza.xlsm", _
Password:="genesis1969")
' do your stuff, e.g.:
Dim ws As Worksheet: Set ws = wb.Worksheets("Sheet1")
Dim rg As Range: Set rg = ws.Range("A1")
rg.Value = Now
rg.EntireColumn.AutoFit
SafeExit:
On Error Resume Next
If ErrNum = 0 Then
If Not wb Is Nothing Then
wb.Close SaveChanges:=True
End If
xlApp.Quit
MsgBox "Success", vbInformation
Else
If Not wb Is Nothing Then
wb.Close SaveChanges:=False
End If
xlApp.Quit
MsgBox "Failed.", vbCritical
End If
On Error GoTo 0
Exit Sub
ClearError:
ErrNum = Err.Number
Debug.Print "'" & ProcName & "' Run-time error '" _
& Err.Number & "':" & vbLf & " " & Err.Description
Resume SafeExit
End Sub

Related

How to prevent excel from relocating or changing active sheet to newly created sheet after creating a new sheet via function button

I have created a button that would create a new sheet which works just fine. However, when I created a new sheet with the function, it relocates or redirect me to that new sheet which make. I also have a delete button in which it just accepts the sheet name and delete it instantly with no redirection or relocating. Is there a way to prevent the redirecting from happening? I am still a beginner so if I am doing something wrong, pls kindly correct me! Thanks in advance.
Here is the code.
Option Explicit
Public sheetName As Variant
Sub AddSheet()
On Error Resume Next
sheetName = InputBox("New Sheet Name", "Prototype 01")
If sheetName = "" Then
MsgBox "Sheet name cannot be empty!"
Exit Sub
End If
Sheets.Add(After:=Sheets(Sheets.Count)).Name = sheetName
MsgBox "" & sheetName & " was successfully created!"
End Sub
Sub DeleteSheet()
On Error Resume Next
sheetName = InputBox("Sheet Name", "Prototype 01")
If sheetName = "" Then Exit Sub
Sheets(sheetName).Delete
MsgBox """" & sheetName & """ was successfully removed!"
End Sub
Yo can switch sheets via Worksheet.Activate function of vba.
Sheets("YourSheetName").Activate
Once you create the new sheet, add this code to return back to your original sheet.
Add a Worksheet or Delete a Sheet
It is assumed that the delete code will be called by a button so the active sheet (the one with the button) cannot accidentally be deleted.
Add
Option Explicit
Sub AddSheet()
Const PROC_TITLE As String = "Add Sheet"
If ActiveSheet Is Nothing Then Exit Sub ' no visible workbooks open
If Not TypeOf ActiveSheet Is Worksheet Then Exit Sub ' not a worksheet
Dim aws As Worksheet: Set aws = ActiveSheet
Dim wb As Workbook: Set wb = aws.Parent
Dim SheetName As String
SheetName = InputBox("Enter name of sheet to be ADDED", PROC_TITLE)
If Len(SheetName) = 0 Then
MsgBox "Sheet name cannot be empty!", _
vbCritical, PROC_TITLE
Exit Sub
End If
Dim nws As Worksheet
Set nws = wb.Sheets.Add(After:=wb.Sheets(wb.Sheets.Count))
Dim ErrNum As Long
On Error Resume Next ' invalid or existing sheet name
nws.Name = SheetName
ErrNum = Err.Number
On Error GoTo 0
Dim IsSuccess As Boolean
If ErrNum = 0 Then
IsSuccess = True
Else
Application.DisplayAlerts = False
nws.Delete
Application.DisplayAlerts = True
End If
aws.Select
If IsSuccess Then
MsgBox "Worksheet """ & SheetName & """ successfully added.", _
vbInformation, PROC_TITLE
Else
MsgBox "Could not rename to """ & SheetName & """.", _
vbCritical, PROC_TITLE
End If
End Sub
Delete
Sub DeleteSheet()
Const PROC_TITLE As String = "Delete Sheet"
If ActiveSheet Is Nothing Then Exit Sub ' no visible workbooks open
If Not TypeOf ActiveSheet Is Worksheet Then Exit Sub ' not a worksheet
Dim aws As Worksheet: Set aws = ActiveSheet
Dim wb As Workbook: Set wb = aws.Parent
Dim SheetName As String
SheetName = InputBox("Enter name of sheet to be DELETED", PROC_TITLE)
If Len(SheetName) = 0 Then
MsgBox "Sheet name cannot be empty!", _
vbCritical, PROC_TITLE
Exit Sub
End If
Dim dsh As Object ' allowing charts to be deleted
On Error Resume Next
Set dsh = wb.Sheets(SheetName)
On Error Resume Next
If dsh Is Nothing Then
MsgBox "There is no sheet named """ & SheetName & """!", _
vbCritical, PROC_TITLE
Exit Sub
End If
' Don't delete the ActiveSheet, the one with the buttons.
If dsh Is aws Then
MsgBox "Cannot delete the 'button' worksheet """ & aws.Name & """!", _
vbCritical, PROC_TITLE
Exit Sub
End If
' A very hidden sheet cannot be deleted. There is no error though.
If dsh.Visible = xlSheetVeryHidden Then
MsgBox "Cannot delete the very hidden sheet """ & SheetName & """!", _
vbCritical, PROC_TITLE
Exit Sub
End If
Application.DisplayAlerts = False
dsh.Delete
Application.DisplayAlerts = True
aws.Select
MsgBox "Sheet """ & SheetName & """ successfully deleted.", _
vbInformation, PROC_TITLE
End Sub

VBA - Check if a sheet exists then import in my workbook else show an error message

i'm having a bit of a headache with VBA which i haven't used since 2006.
I have my destination excel file where I need to import 3 predefined sheets from another excel file of the user's choice.
After selecting the source file to import I would like to perform a check, IF the "Cover" sheet exists THEN copy it to the target workbook ELSE print an error message in the excel file in order to have a log, once this is done I have to do the same check for the "Functional" and "Batch" sheets.
Before inserting the IFs, I was able to import the sheets but I didn't have control over whether they existed or not, "Cover" is mandatory while "Functional" and "Batch" I need at least one of the two to be able to proceed with the next steps.
Now I can check if the "Cover" sheet exists and import it ELSE I exit the Sub, after which I should check if the other sheets also exist and import them but I immediately get the "absent sheet" error.
Below is the code I am getting stuck with:
Sub Import()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim TargetWorkbook As Workbook
Dim SourceWorkbook As Workbook
Dim OpenFileName
Set TargetWorestBookkbook = ActiveWorkbook
'Select and Open Source workbook
OpenFileName = Application.GetOpenFilename("Excel Files (*.xls*),*.xls*")
If OpenFileName = False Then
MsgBox "Nessun file Source selezionato. Impossibile procedere."
Exit Sub
End If
On Error GoTo exit_
Set SourceWorkbook = Workbooks.Open(OpenFileName)
'Import sheets
' if the sheet doesn't exist an error will occur here
If WorksheetExists("Cover e Legenda") Then
SourceWorkbook.Sheets("Cover e Legenda").Copy _
after:=TargetWorkbook.Sheets(ThisWorkbook.Sheets.Count)
Application.CutCopyMode = False
SourceWorkbook.Close False
Else
MsgBox ("Cover assente. Impossibile proseguire.")
Exit Sub
End If
If WorksheetExists("Test Funzionali") Then
SourceWorkbook.Sheets("Test Funzionali").Copy _
after:=TargetWorkbook.Sheets(ThisWorkbook.Sheets.Count)
Application.CutCopyMode = False
SourceWorkbook.Close False
Else
MsgBox ("Test Funzionali assente.")
End If
If WorksheetExists("Test Batch") Then
SourceWorkbook.Sheets("Test Batch").Copy _
after:=TargetWorkbook.Sheets(ThisWorkbook.Sheets.Count)
Application.CutCopyMode = False
SourceWorkbook.Close False
Else
MsgBox ("Test Batch assente.")
End If
'Next Sheet
Application.ScreenUpdating = True
Application.DisplayAlerts = True
SourceWorkbook.Close SaveChanges:=False
MsgBox ("Importazione completata.")
TargetWorkbook.Activate
exit_:
Application.ScreenUpdating = True
Application.DisplayAlerts = True
If Err Then MsgBox Err.Description, vbCritical, "Error"
End Sub
Best to check all of the sheets before importing any of them.
Try something like this:
Sub Import()
Dim wbTarget As Workbook, wbSource As Workbook
Dim OpenFileName, haveCover As Boolean, haveFunz As Boolean, haveTest As Boolean
On Error GoTo haveError
Set wbTarget = ActiveWorkbook
'Select and Open Source workbook
OpenFileName = Application.GetOpenFilename("Excel Files (*.xls*),*.xls*")
If OpenFileName = False Then
MsgBox "Nessun file Source selezionato. Impossibile procedere."
Exit Sub
End If
Set wbSource = Workbooks.Open(OpenFileName)
'check which sheets exist
haveCover = WorksheetExists(wbSource, "Cover e Legenda")
haveFunz = WorksheetExists(wbSource, "Test Funzionali")
haveTest = WorksheetExists(wbSource, "Test Batch")
If haveCover And (haveFunz Or haveTest) Then 'have the minumum required sheets?
Application.ScreenUpdating = False
Application.DisplayAlerts = False
ImportSheet wbTarget, wbSource.Worksheets("Cover e Legenda")
If haveFunz Then ImportSheet wbTarget, wbSource.Worksheets("Test Funzionali")
If haveTest Then ImportSheet wbTarget, wbSource.Worksheets("Test Batch")
Application.DisplayAlerts = True
Else
MsgBox "Required sheet(s) not found!", vbExclamation
End If
wbSource.Close SaveChanges:=False
MsgBox "Importazione completata"
wbTarget.Activate
Exit Sub 'normal exit
haveError:
MsgBox Err.Description, vbCritical, "Error"
Application.DisplayAlerts = True
End Sub
'copy sheet `ws` to the end of `wbTarget`
Sub ImportSheet(wbTarget As Workbook, ws As Worksheet)
ws.Copy after:=wbTarget.Worksheets(wbTarget.Worksheets.Count)
End Sub
'does sheet `wsName` exist in workbook `wb` ?
Function WorksheetExists(wb As Workbook, wsName As String) As Boolean
On Error Resume Next
WorksheetExists = Not wb.Worksheets(wsName) Is Nothing
On Error GoTo 0
If Not WorksheetExists Then
'log error to errors sheet
With ThisWorkbook.Worksheets("Import Errors").Cells(Rows.Count, "A").End(xlUp)
.Resize(1, 3).Value = Array(Now, wb.Name, "Sheet '" & wsName & "' not found")
End With
End If
End Function
Import Mandatory and Optional Worksheets
Sub ImportWorksheets()
Dim Mandatory() As Variant: Mandatory = VBA.Array("Cover e Legenda")
Dim Optionally() As Variant ' 'Optional' is a keyword
Optionally = VBA.Array("Test Funzionali", "Test Batch")
Dim twb As Workbook: Set twb = ThisWorkbook ' workbook containing this code
' Select and open the Source workbook.
Dim OpenFilePath As Variant
OpenFilePath = Application.GetOpenFilename("Excel Files (*.xls*),*.xls*")
If OpenFilePath = False Then
MsgBox "Nessun file Source selezionato. Impossibile procedere.", _
vbExclamation
Exit Sub
End If
Dim swb As Workbook: Set swb = Workbooks.Open(OpenFilePath)
' Check if all the mandatory worksheets exist.
Dim sws As Worksheet, n As Long
For n = 0 To UBound(Mandatory)
On Error Resume Next ' prevent error if worksheet doesn't exist
Set sws = swb.Worksheets(Mandatory(n))
On Error GoTo 0
If sws Is Nothing Then
'swb.Close SaveChanges:=False
MsgBox "The mandatory worksheet """ & Mandatory(n) _
& """ was not found in """ & swb.Name & """.", vbCritical
Exit Sub
Else
Set sws = Nothing
End If
Next n
' Check if at least one of the optional worksheets exists.
Dim oDict As Object: Set oDict = CreateObject("Scripting.Dictionary")
oDict.CompareMode = vbTextCompare
For n = 0 To UBound(Optionally)
On Error Resume Next ' prevent error if worksheet doesn't exist
Set sws = swb.Worksheets(Optionally(n))
On Error GoTo 0
If Not sws Is Nothing Then oDict(sws.Name) = Empty: Set sws = Nothing
Next n
If oDict.Count = 0 Then
'swb.Close SaveChanges:=False
MsgBox "No optional worksheets found in """ & swb.Name & """.", _
vbCritical
Exit Sub
End If
' Import the worksheets and close the Source workbook.
Application.ScreenUpdating = False
For n = 0 To UBound(Mandatory)
swb.Sheets(Mandatory(n)).Copy After:=twb.Sheets(twb.Sheets.Count)
Next n
Dim oKey As Variant
For Each oKey In oDict.Keys
swb.Sheets(oKey).Copy After:=twb.Sheets(twb.Sheets.Count)
Next oKey
swb.Close SaveChanges:=False
Application.ScreenUpdating = True
' Inform.
MsgBox "Imported Worksheets" & vbLf & vbLf _
& "Mandatory:" & vbLf & Join(Mandatory, vbLf) & vbLf & vbLf _
& "Optionally:" & vbLf & Join(oDict.Keys, vbLf), vbInformation
End Sub

Change links to new workbook

I'm saving a workbook as a copy with date.
I did it with the code suggested on this site (save as copy).
Now I'm getting an error concerning the links in my new workbook. Is there a way to set the correct links (on the new workbook) to the new workbook together with the save as copy method?
Sub Button15_Click()
ActiveWorkbook.Save
'https://stackoverflow.com/questions/18899824/how-to-use-vba-saveas-without-closing-calling-workbook
'SaveAsCopy
Dim thisWb As Workbook, wbTemp As Workbook
Dim ws As Worksheet
On Error GoTo Whoa
Application.DisplayAlerts = False
Set thisWb = ThisWorkbook
Set wbTemp = Workbooks.Add
On Error Resume Next
For Each ws In wbTemp.Worksheets
ws.Delete
Next
On Error GoTo 0
For Each ws In thisWb.Sheets
ws.Copy After:=wbTemp.Sheets(1)
Next
wbTemp.Sheets(1).Delete
'wbTemp.SaveAs "C:\Users\Me\Desktop\FileName & Format(CStr(Now), dd-mm-yy-hhumm).xlsm", 52 'Save as timestamp
wbTemp.SaveAs ("C:\Users\Me\Desktop\") & "FileName" & Format(Now, "dd-mm-yy-hhumm") & ".xlsm", _
FileFormat:=xlOpenXMLWorkbookMacroEnabled, CreateBackup:=False
LetsContinue:
Application.DisplayAlerts = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub

Macro Protection in all Worksheets but only for cells with some value

i need some help to make my code work. My code is pretty simple. It goes through all my worksheets and make simple check in Columns A:D. If one cell has some text it will be locked. All free cells will stay for users unlocked.
It starts with other macros from my worksheet with Workbook_Open as Call command.
I used it all the time in each Worksheet separatly, but it won't work with new sheets so i decided to make it somehow global and dynamic for old sheets and new added sheets.
Old code:
Public Sub auo_open()
Dim strPassword As String
strPassword = "Athens"
With Tabelle1
.Unprotect Password:=strPassword
.Cells.Locked = True
On Error Resume Next
.Range("A:D").SpecialCells(xlCellTypeBlanks).Locked = False
On Error GoTo 0
.Protect Password:=strPassword, UserInterfaceOnly:=True, AllowFormattingCells:=True, AllowInsertingRows:=True
End With
Exit Sub
As you see it wasn't that good i had to put for each sheet a call command
new Code:
Public Sub Protection()
Dim ws As Worksheet
Dim strPassword As String
strPassword = "Athens"
For Each ws In ThisWorkbook.Worksheets
ws.Unprotect Password:=strPassword
ws.Cells.Locked = True
On Error Resume Next
ws.Range("A:D").SpecialCells(xlCellTypeBlanks).Locked = False
On Error GoTo 0
ws.Protect Password:=strPassword, UserInterfaceOnly:=True, AllowFormattingCells:=True, AllowInsertingRows:=True
Next ws
End Sub
Further to my comment above, try something like this. This code will automatically be applicable to the newly added worksheets
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim strPassword As String: strPassword = "Athens"
On Error GoTo Whoa
Application.EnableEvents = False
If Not Intersect(Target, Columns("A:D")) Is Nothing Then
With Sh
.Unprotect strPassword
Cells.Locked = True
Range("A:D").SpecialCells(xlCellTypeBlanks).Locked = False
.Protect strPassword
End With
End If
Letscontinue:
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume Letscontinue
End Sub
Screenshots
Put the code in the ThisWorkbook code area.

VBA Use variable value across modules

I'm trying to use the name of a workbook which I set in module 1, across other private modules but I'm getting different errors depending on how I set it up. I added comments in the code that explain what happens in the different scenarios.
Option Explicit
Sub TestSharedVars()
CopyCellsthenClose
OpenNewWksheet (AlphaExportBook)
' *** Like this
' OpenNewWksheet (AlphaExportBook) I get "Error Variable not defined"
' *** Like this
' OpenNewWksheet I get "Error Argument not optional"
CloseWkbook
End Sub
Private Sub CopyCellsthenClose()
Dim AlphaExportBook As Workbook
Dim theRows
Dim theColumns
With ActiveSheet.UsedRange
theRows = .Rows.Count
theColumns = .Columns.Count
Range(Cells(1, 1), Cells(theRows, theColumns)).Select
End With
Selection.Copy
Set AlphaExportBook = ActiveWorkbook
End Sub
Private Sub OpenNewWksheet()
'******************************
' Open the File Dialog
'******************************
Dim ReversionWBook As Workbook
With Application.FileDialog(msoFileDialogOpen)
.AllowMultiSelect = False
.Show
.Execute
If (.SelectedItems.Count = 0) Then
MsgBox "User Cancelled Operation"
' GoTo EndofInstructions
Else
End If
End With
ActiveWorkbook.Activate
Set ReversionWBook = ActiveWorkbook
End Sub
Private Sub CloseWkbook(AlphaExportBook As Workbook)
'**********************************
' Close Alpha Export WorkBook
'**********************************
AlphaExportBook.Activate
Application.DisplayAlerts = False
AlphaExportBook.Close SaveChanges:=False
Application.DisplayAlerts = True
End Sub
Firstly, you shouldn't be getting an "Argument not optional" error when calling OpenNewWksheet because that subroutine is not expecting arguments. You would get that error trying to call CloseWkbook without specifying a parameter, because that subroutine expects a Workbook object to be passed to it.
The easiest way to make the workbook available to all subroutines is to declare the variable with module-level scope, e.g.
Option Explicit
Dim AlphaExportBook As Workbook
Sub TestSharedVars()
CopyCellsthenClose
OpenNewWksheet
CloseWkbook
End Sub
Private Sub CopyCellsthenClose()
Dim theRows
Dim theColumns
With ActiveSheet.UsedRange
theRows = .Rows.Count
theColumns = .Columns.Count
'Note - the following line won't do what you expect unless
' UsedRange starts at cell A1
Range(Cells(1, 1), Cells(theRows, theColumns)).Select
End With
Selection.Copy
Set AlphaExportBook = ActiveWorkbook
End Sub
Private Sub OpenNewWksheet()
'******************************
' Open the File Dialog
'******************************
Dim ReversionWBook As Workbook ' Does this need to be module-level scope too?
With Application.FileDialog(msoFileDialogOpen)
.AllowMultiSelect = False
.Show
.Execute
If .SelectedItems.Count = 0 Then
MsgBox "User Cancelled Operation"
End If
End With
'ActiveWorkbook.Activate ' This is redundant - the ActiveWorkbook is already active
Set ReversionWBook = ActiveWorkbook
End Sub
Private Sub CloseWkbook()
'**********************************
' Close Alpha Export WorkBook
'**********************************
'You don't need to activate the workbook before you close it
'AlphaExportBook.Activate
Application.DisplayAlerts = False
AlphaExportBook.Close SaveChanges:=False
Application.DisplayAlerts = True
End Sub
Alternatively, you could pass the workbook object between subroutines as follows:
Option Explicit
Sub TestSharedVars()
'Dimension object to have scope only within this subroutine, but we
' will pass a reference to this object to the other subroutines that
' need to reference it
Dim AlphaExportBook As Workbook
CopyCellsthenClose AlphaExportBook
OpenNewWksheet
CloseWkbook AlphaExportBook
End Sub
Private Sub CopyCellsthenClose(wb As Workbook)
Dim theRows
Dim theColumns
With ActiveSheet.UsedRange
theRows = .Rows.Count
theColumns = .Columns.Count
'Note - the following line won't do what you expect unless
' UsedRange starts at cell A1
Range(Cells(1, 1), Cells(theRows, theColumns)).Select
End With
Selection.Copy
Set wb = ActiveWorkbook
End Sub
Private Sub OpenNewWksheet()
'******************************
' Open the File Dialog
'******************************
Dim ReversionWBook As Workbook ' Does this need to be module-level scope too?
With Application.FileDialog(msoFileDialogOpen)
.AllowMultiSelect = False
.Show
.Execute
If .SelectedItems.Count = 0 Then
MsgBox "User Cancelled Operation"
End If
End With
'ActiveWorkbook.Activate ' This is redundant - the ActiveWorkbook is already active
Set ReversionWBook = ActiveWorkbook
End Sub
Private Sub CloseWkbook(wb As Workbook)
'**********************************
' Close Alpha Export WorkBook
'**********************************
'You don't need to activate the workbook before you close it
'wb.Activate
Application.DisplayAlerts = False
wb.Close SaveChanges:=False
Application.DisplayAlerts = True
End Sub

Resources