Running excel macros only on one sheet - vba

Hi Iam new to writing VBA code and need assistance. My VBA code and Macro works fine as long as I am on the active sheet.
My Problem:
My VBA code and macro, stops running automatically, when i change from the active sheet to another within the same workbook and
My VBA code and macro, stops running automatically, when i open a new excel workbook
Solution required:
Run the VBA code and macro only on desired worksheet and prevent it from running on other worksheets and workbooks.
Background:
I have an excel file, named "Net Weight" with two sheets. sheet 1 is named : "weight", sheet 2: is named "base data".
sheet 1 is used as a user input form.
In sheet 1- cell B1 : user will type in a product code , in cell E1: a look up formula will place the description of the product code using the data from sheet 2
I have setup a VBA code and macro that does the following:
As soon as a user inputs a product code into cell B1, in sheet 1, sheet 1 is saved as PDF file into a predefined folder location data from cell B1 and E1
A macro saves and overwrties the PDF file every 10 seconds.
This process is repeated every time a new product code is entered
There are no buttons on sheet 1, everything is done automatically.
Here is my current code:
Sheet 1: set as Worksheet
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$B$1" Then
Call Macro1
End If
End Sub
Module 1 macro : set as general
Sub Macro1()
Application.DisplayAlerts = False
If ThisWorkbook.Name = "Nett Weight.xlsm" And ActiveSheet.Name = "Weight" Then
Sheets("Weight").ExportAsFixedFormat Type:=xlTypePDF, _
Filename:="C:\Nett weight\" & Range("B1 ").Text & Range(" E1").Text
Application.OnTime Now + TimeValue("00:00:10"), "Macro1"
Else
Exit Sub
End If
End Sub

First, you need to create a public variable to hold your timer, otherwise you'll never be able to cancel it so it will continue trying to fire even when your workbook is closed. You should also create a public variable to store when the timer is running, so you can check before creating a new timer.
At the top of a code module put:
Public nextTime As Date
Then in your Workbook_BeforeClose() event method (within ThisWorkbook), disable the existing timer so it doesn't keep trying to fire after the workbook is closed.
Private Sub Workbook_BeforeClose(Cancel As Boolean)
On Error Resume Next ' Continue with next line of code if we encounter an error
Application.OnTime Earliesttime:=nextTime, Procedure:="Macro1", Schedule:=False
On Error GoTo 0 ' Resume error-trapping
End Sub
In Macro1() you should explicitly and directly reference your workbook components - ThisWorkbook always refers to the workbook the code is running from, so you don't need your If statement. Then you set the nextTime and activate the timer using that variable if it is not already running.
Sub Macro1()
Dim sht As Worksheet ' Creates a variable to hold your Weight worksheet
Set sht = ThisWorkbook.Sheets("Weight") ' Sets the reference
Application.DisplayAlerts = False
sht.ExportAsFixedFormat Type:=xlTypePDF, Filename:="C:\Nett weight\" & sht.Range("B1").Text & sht.Range("E1").Text ' Remember to preceed Range with sht. to explicitly reference the range of your Weight worksheet
On Error Resume Next ' Continue with next line of code if we encounter an error
Application.OnTime Earliesttime:=nextTime, Procedure:="Macro1", Schedule:=False
On Error GoTo 0 ' Resume error-trapping
nextTime = Now + TimeSerial(0, 0, 10) ' Adds 10 seconds to Now
Application.OnTime Earliesttime:=nextTime, Procedure:="Macro1", Schedule:=True
timerIsRunning = True
Application.DisplayAlerts = True ' Remember to enable alerts at the end of code
End Sub
Your Worksheet_Change() event method can stay as is. Now if there is a change in B1 it will call Macro1(). Macro1() will save the Weight worksheet as a PDF regardless of whether the workbook or worksheet is active, and create a new timer to re-run Macro1() every 10 seconds after deactivating an existing timer. When you're finished with the workbook, you close it and the existing timer is also deactivated.
EDIT:
Fortunately (as it fixes a spreadsheet of my own) I have figured out why the solution I originally provided wasn't working. Placing the Public variables under ThisWorkbook meant they no longer held their values after code execution. The remedy was to place them in a module instead. Once that was sorted out, I also realised that when the timer fires to call Macro1() it will throw an error when trying to unschedule the existing timer (as none exists unless Macro1() was called ad hoc by the Worksheet_Change() event).
Long story short: Public variables have been moved to a code module, and the timerIsRunning flag has been removed entirely and errors when attempting to unschedule the timer are simply ignored in the event that no timer exists.

Related

Workbook not opening at startup (splash screen frozen)

I use Excel 2016. The file I am using runs some code in workbook Open event handler.
Depending on what the code does the workbook may never get opened (visible).
in Workbook_Open the event handler establishes a connection with a data base and load some data eventually warn the user if an error occurs for instance.
Establishing the connection with a data base and load some data works most of the time. Some times it does not and the Excel splash screen remains on the screen for ever. After closing the splash screen clicking on the close cross, the Excel process continues running in the background.
If an error occurs I don't see the pop up form which is opened to warn the user as long as the workbook is not visible.
when I kill the process an reopen Excel (not the workbook), Excel suggest to retrieve the file which was opened earlier proving somehow that it has in deed been opened.
The second process just does not work unless the workbook is visible. If I run Excel and then open the workbook it s ok (in case an error occurs the warning pop up form is opened).
If Excel is closed and i open the workbook it does not work (splash screen frozen).
what is the proper way to start a VBA application where It is necessary to manage some cosmetics tasks (show some sheets, hide some other) and run a connection to a data base?
Here is a simplified version of the code (can't provide it all - too complex - too long)
In this code the function bConnectToTheDatabase is forced to return False which make the bLogin function useless (the code is not provided for this reason).
Private mLoginForm As frmLgn ' a form to login the application (see image)
Private mCustomMsgBox As frmMsgBox ' a form to display custom messages (see image)
Public Const gsPFU_VBA_PWD as String = "my secret password"
Public Const gsBLANK_WKS_NAME As String = "Blank"
Private Sub Workbook_Open()
'
Call HidShowSomeSheets()
' start the application up
Call LoginIntoTheApplication()
End Sub
' hide all sheets but the one named gsBLANK_WKS_NAME
' protect/unprotect to chnage visibility
Sub HidShowSomeSheets()
With Application.Workbooks(ThisWorkbook.Name())
.Unprotect (gsPFU_VBA_PWD)
.Sheets(gsBLANK_WKS_NAME).Visible = xlSheetVisible
For Each wks In .Sheets
With wks
.Unprotect (gsPFU_VBA_PWD)
End With
Next wks
For Each wks In .Sheets
With wks
If (StrComp(gsBLANK_WKS_NAME, .Name) <> 0) Then
.Unprotect (gsPFU_VBA_PWD)
On Error Resume Next
.Visible = xlSheetVeryHidden
Else
.Protect (gsPFU_VBA_PWD)
.Activate
End If
End With
Next wks
.Protect (gsPFU_VBA_PWD)
End With
End Sub
Sub LoginIntoTheApplication()
if( bConnectToTheDatabase() ) then
call bLogin
else
'create a custom form (it has it own even handler - block the execution flow)
'set mCustomMsgBox= new frmMsgBox
'mCustomMsgBox.Show vbModeless 'this does not work
MsgBox "something went wrong" 'this works
end if
end Sub
Function bLogin() as Boolean
'login into the application
End Function
Function bConnectToTheDatabase() as Boolean
'do the connection
'get the data
'etc ....
bConnectToTheDatabase= False 'fore it to False for the purpose of the explanation
End Function
The login form
The custom message box

VBA - Close "ThisWorkbook", and re-open after Delay

I have a workbook that contains a Macro that checks the workbook out from our SharePoint server, updates it, and then should check it back in. Afterwards, it should remain open for the user review and possibly execute other updates. The main problem I have is that the ".checkin" method closes out the Workbook, terminating the macro before it can re-open the workbook. I had found a proposed solution here: https://stackoverflow.com/a/22380886/8858822 , however I have encountered a problem with how Application.OnTime operates.
If I attempt to use the Application.Workbook.Open procedure as an argument for the Application.OnTime method, as suggested by the link above, the .Open procedure gets called immediately, without waiting the desired delay. In this scenario, the workbook has not been checked-in and closed yet, causing an error:
Sub TestSub()
Dim wb As Workbook
Set wb = ThisWorkbook
Dim FPath As String
FPath = wb.FullName
Workbooks.CheckOut (FPath)
'''''''''''''''''''''''''
'execute workbook updates
'''''''''''''''''''''''''
Application.DisplayAlerts = False
On Error Resume Next
Application.OnTime Now + TimeValue("00:00:10"), Application.Workbooks.Open(FPath)
wb.CheckIn
Application.DisplayAlerts = True
End Sub
Is there a reason that Application.Workbooks.Open(FPath) executes immediately, instead of waiting the specified 10 seconds? If I can delay that execution by 10 seconds, the code would execute correctly.
I noticed that if instead of directly opening the file, I call one the macros in the file, it does wait the desired 10 seconds. This allows for the file to first be checked in and closed, then re-opens it and executes the specified macro.
Sub TestSub()
Dim wb As Workbook
Set wb = ThisWorkbook
Dim FPath As String
FPath = wb.FullName
Workbooks.CheckOut (FPath)
'''''''''''''''''''''''''
'execute workbook updates
'''''''''''''''''''''''''
Application.DisplayAlerts = False
On Error Resume Next
Application.OnTime Now + TimeValue("00:00:10"), " ' file address & name '!OtherMacroName "
wb.CheckIn
Application.DisplayAlerts = True
End Sub
With this code, the file is checked in, closes, and then after 10 seconds reopens the file and runs the macro. Unfortunately, due to trust center settings I believe, I cannot directly call macros from workbooks saved on our SharePoint server, and this code generates an permissions error. If I relocate the file to my personal or our network drive, it executes without error. I have not been able to resolve the SharePoint permissions issue, even after following: https://stackoverflow.com/a/21175812/8858822 .
If I can understand why the Application.Workbooks.Open procedure operates immediately, while the macro call procedure waits the desired 10 seconds, when each is an argument used by Application.OnTime, I believe the code would work as desired. If there is a way to call the macro within the closed workbook after 10 seconds, I presume there must be some way of just opening the workbook after the 10 seconds? Thank you for your time and assistance.
OnTime takes the name of a subroutine as its argument. You need to create a new routine for OnTime to call (it doesn't actually have to do anything if all you need is the workbook reopened).
Is there a reason that Application.Workbooks.Open(FPath) executes
immediately, instead of waiting the specified 10 seconds? If I can
delay that execution by 10 seconds, the code would execute correctly.
Yes. The answer you linked is incorrect.
Application.OnTime Now + TimeValue("00:00:10"), SecondArgument
The SecondArgument is the name of a subroutine to call.
What you're doing when you put Application.Workbooks.Open(FPath) in SecondArgument is opening the workbook, then returning a reference to the workbook, in the same way you would go:
Set wb = Application.Workbooks.Open(FPath)
Put differently, when you do this...
Application.OnTime Now + TimeValue("00:00:10"), Application.Workbooks.Open(FPath)
... you're actually doing this:
Set wb = Application.Workbooks.Open(FPath)
Application.OnTime Now + TimeValue("00:00:10"), wb
So that answers your question, but to solve your problem...
From this link, there's some sort of dirty workaround where the key is apparently to call the Application.OnTime method a moment before you close the workbook (check in the workbook in your case):
Sub CloseMe()
Application.OnTime Now + TimeValue("00:00:02"), "OpenMe"
ThisWorkbook.Close ' check in
End Sub
Sub OpenMe()
' literally does nothing
End Sub
So Excel knows to run the OpenMe method in 2 seconds' time, and it is that act of attempting to run the OpenMe method that actually re-opens the workbook.
You can test this by having two workbooks:
E:\Documents\Book3.xlsm has the following code:
Sub TestMe()
MsgBox "test"
End Sub
E:\Documents\Book2.xlsm has the following code:
Sub OpenAnotherWorkbook()
Application.Run "'E:\Documents\Book3.xlsm'!TestMe"
End Sub
Making sure that E:\Documents\Book3.xlsm is currently closed, we run OpenAnotherWorkbook from E:\Documents\Book2.xlsm.
It will open E:\Documents\Book3.xlsm and run TestMe.

Excel VBA - How to use worksheet event in add-in module?

I am new to Excel Add-ins and I am not sure how to write mi programm.
I would like to put in an add-in a code so that, when the workbook that uses the add-in is opened, it creates a sheet named "mainSheet".
I can use the event handler in the Workbook, but is it possible to put the code in the module of the add-in and still be able to run it?
I found this on the "Automate Excel" web site. Hope this helps
The following code works opening a workbook. It automatically adds a new sheet and labels it with the name. It also checks to see that the sheet doesn’t already exist – to allow for the possibility of it being opened more than once a day.
This code makes use of the Workbook Open Event and must be placed in the workbook module under the “Open work Book” event. The function Sheet_Exists must be placed in a module and this checks whether or not the sheet exists:
Private Sub Workbook_Open()
Dim New_Sheet_Name As String
New_Sheet_Name = "mainSheet"
If Sheet_Exists(New_Sheet_Name) = False Then
With Workbook
Worksheets.Add().Name = New_Sheet_Name
End With
End If
End Sub
==
Function Sheet_Exists(WorkSheet_Name As String) As Boolean
Dim Work_sheet As Worksheet
Sheet_Exists = False
For Each Work_sheet In ThisWorkbook.Worksheets
If Work_sheet.Name = WorkSheet_Name Then
Sheet_Exists = True
End If
Next
End Function

Input Box on workbook open

I am trying to come up with some vba code to open an input box automatically as soon as the workbook is opened and have the user enter a date and then have the date placed in the A1 cell. I have written the code below but the input box is not pulling up at all it just opens the workbook and moves on.. not sure what is happening. Any and all help is appreciated.
Thanks!
Option Explicit
Private Sub workbook_open()
Dim cellvalue As Variant
Dim ws As Worksheet
Set ws = Worksheets("Workbench Report")
ReShowInputBox: cellvalue = Application.InputBox("Please Enter Todays Date (dd/mm/yyyy)")
If cellvalue = False Then Exit Sub
If IsDate(cellvalue) And CDate(cellvalue) < Date Then
ws.Range("A1").Value = DateValue(cellvalue)
Else: MsgBox ("Invalid Date!")
GoTo ReShowInputBox
End If
End Sub
Your code triggers upon the Workbook opening for me. Try these steps.
Open up Excel and Save As, changing the extension to .XSLM
Open up the VBA Editor (ALT + F11)
In the left-hand window, locate your macro file (the one you just created and named - it's in brackets after "VBA Project"), drilldown to "This Workbook" and double-click it.
Paste your code into the right-hand window
Save the file and re-open.
See attached diagram.
By the way, "cellValue = false" should probably be cellValue = "" since InputBox is returning a string and not a boolean value.
For Workbook_Open events the script needs to reside in the private module (ThisWorkbook)
From Ozgrid:
the Workbook_Open event is a procedure of the Workbook Object and as
such, the Workbook_Open procedure MUST reside in the private module of
the Workbook Object (ThisWorkbook).

Excel macro doesn't update correctly

i have created macro for excel but it seems somewhere i have done something wrong,
i want to fetch an image from a URL and then update it up to 1 second (more or less)
Sub GetPicture()
PictureURL = "This is where i put the URLi want"
Set MyPict = ActiveSheet.Pictures.Insert(PictureURL)
Cells(1).Value = Now
nextTime = Now + TimeValue("00:00:01")
End Sub
when i run the macro doesn't do anything,only when i press f5 the it updates as fast as i press f5,also what is the value to update less than 1 second ("00:00:01"),when i try ("00:00:0.5") it comes up with "run time error 13" "type mismatch"
Any help is very much apreciated.
In Excel, you can use VBA to trigger code that updates a Worksheet on specific intervals. The code below shows how you would activate a Timer each time the Worksheet is activated by a user. Whenever the Timer fires (on 1 second intervals here) this code updates Cell A1 in the ActiveSheet with the current Time.
To further customize, you would add code to the OnTimerMacro in order to update a Picture or whatever else you recurring task might be.
(Props to Hartmut Gierke for his post on the topic.)
Option Explicit
Dim Execute_TimerDrivenMacro As Boolean
Sub Start_OnTimerMacro()
Execute_TimerDrivenMacro = True
Application.OnTime Time + TimeValue("00:00:01"), ActiveSheet.Name & ".OnTimerMacro"
End Sub
Sub Stop_OnTimerMacro()
Execute_TimerDrivenMacro = False
End Sub
Public Sub OnTimerMacro()
If Execute_TimerDrivenMacro Then
' Do something e.g. put the actual time into cell A1 of the active sheet
ActiveSheet.Cells(1, 1).Value = Time
' At the end restart timer
Application.OnTime Time + TimeValue("00:00:01"), ActiveSheet.Name & ".OnTimerMacro"
End If
End Sub
Private Sub Worksheet_Activate()
'Start the timer driven method when opening the sheet
Start_OnTimerMacro
End Sub
Private Sub Worksheet_Deactivate()
'Stop the timer driven method when opening the sheet
Stop_OnTimerMacro
End Sub
if you would like the macro to repeat you have to put it in a do...until loop. The only problem, is that you can't really have the macro run all the time. There has to be a way to stop it. The do...until loop will help with this, but you have to come up with a reasonable exit from the loop. Can you give a little more background as to what you ultimately want this to do?
Also it sounds like you want the running of the macro to be triggered by something other than the pressing of F5. Can you explain when you would like to see it start?