I'm trying to create a macro to save an ms-project file in a specific format to a given location at a set interval while the application is open. I've got it mostly working, except the executing on an interval part.
I've had a bit of a google around and when using excel or word you can use the Application.OnTime method & a time offset to call a sub at the required interval. Unfortunately it doesn't look like this method exists in MS-Project.
Is there an alternative method I can use here or should I abandon this idea?
I realize this is a late answer, but I have a solution I used for a similar problem. Just jump on the Project_Change event since it runs frequently, and compare against a variable.
Public lastSave As Date
Private Sub Project_Change(ByVal pj As Project)
If DateDiff("n", lastSave, Now()) > 1 Then ' Replace 1 with # of minutes between saves.
Application.FileSave
lastSave = Now()
End If
End Sub
Related
I have a process where I use VBA to enter a webpage and download a daily file around 6 pm, although this certain file can be uploaded any time later.
Since I need to schedule automatic run for this macro because not always I will be able to run it manually (nor other person), I was thinking if there's some way to stop a macro execution after some time has passed. This is because, after the download, it should do some other things, but also the download takes a while, so if I do
Dir(file)
Do While file = ""
Do events
' CODE TO EXIT LOOP AFTER SOME TIME
Loop
The code can be hours stuck because there is no file available on the webpage, so I would like that loop to break after, let's say, 1 minute. So maybe I was thinking to catch the current time and adding the time I want it to run and then on each loop compare the current time with the time I set to stop, and then break the loop, however, I don't get how to do the time part.
Any help will be appreciated
Maybe Application.OnTime can be helpful?
https://learn.microsoft.com/en-us/office/vba/api/excel.application.ontime
As commented by Ricardo Díaz and according to this thread:
VBA - Exit Function if a timer passes 2 minutes
This is the code that works as a solution:
Dim startTime As Date
startTime = Now
Do
If DateDiff("s", startTime, Now) > 10 Then
MsgBox "There seems to be an issue. Please try again!"
Exit Do
End If
dostuff
Loop
I want to evaluate how long the spreadsheet has been open and once it hits a certain time (say an hour), warn the user that it will automatically close in 15 mins.
I have a tab called Reference where I can put auto-open code to log when they opened it but I want the spreadsheet to check unprompted at certain intervals how long the sheet has been open.
I want to force a close where a user has accidentally left a spreadsheet open so it's important it isn't assessed based on user input.
Note - I don't care if they lose work, I just want to close the spreadsheet.
To schedule the call of a routine, use Application.OnTime. To ensure that the routine is scheduled to "one hour after opening", create a Workbook-Open sub (in ThisWorkbook-Module) and put something like this into it:
Private Sub Workbook_Open()
Application.OnTime DateAdd("h", 1, Now), "InformUser"
End Sub
This will call the Sub InformUser one hour after the Workbook was opened. In this routine you could add another call to OnTime. However, you need to be a little bit careful how to inform the user. If you simple use MsgBox but the user is not reacting to that, the MsgBox-Window stays active and as it is a modal window, the code will not continue to run and the OnTime-procedure will never be triggered. It's not easy to create a MsgBox with a TimeOut (see Display a message box with a timeout value), so maybe create a simple form and show it Non-Modal.
Sub InformUser()
InfoForm.Show modal:=False
Application.OnTime DateAdd("n", 15, Now), "ShutDown" ' "n": Minutes ("m" stands for months)
End Sub
Sub ShutDown
ThisWorkbook.Close SaveChanges:=True ' Or "False" if you don't want to save - use on your own risk...
End Sub
I am a VBA beginner trying to determine the "normal" behavior of excel during a timed call to a macro using Application.OnTime. In my code (below) I am calling ActiveWorkbook.RefreshAll but I think this question may be relevant to the timed call to any macro. As a newbie, I want to understand the behavior and limits of VBA so that I can determine if VBA is the right tool or if I should use another solution in certain cases (perhaps python / openpyxl).
My set up: I am using Microsoft Excel 365 (annual subscription) and the Account page says I am using Version 2006 (Build 13001.20384 Click-to-Run). I have a single workbook containing a single Sheet1 which contains the formulas to import stock data using the built in feature under the Excel Data tab. I have several rows (one stock per row) of columnar data corresponding to the stock fields such as ticker symbol, price, etc.
To automatically refresh the data, I borrowed & modified code to refresh the data every minute. The code works fine. The "issue" I have is that between refreshes, if I start editing any cell on the sheet and continue to do so during the time when the next automatic call to the refresh should occur, it indefinitely delays the execution of said call until the moment I complete (or cancel) the cell edit. When it does the refresh upon my edit completion that refresh does seem to work correctly.
If I start a cell edit and do not complete it for several minutes then only a single refresh occurs when I complete (or cancel) the edit, even though several intervals may have passed (it does not makeup/catchup the missed/delayed calls).
This behavior is OK with me in this application, but I would like to understand if this is considered "normal" behavior, and if I should expect it to always behave this way. Perhaps this question extends beyond a refresh call but also to any timed call to any macro that may be delayed as a result of a cell edit in progress.
Here is my code.
This is in a file called VBA-Test-02-StockData.xlsm under ThisWorkbook (Code):
Private Sub Workbook_Activate()
'ActiveWindow.WindowState = xlMaximized
Application.Speech.Speak ("Activating stock workbook")
Call AutoRefresh
End Sub
This is in the same xlsm file under Module1 (Code):
Sub RefreshStockData()
Application.Speech.Speak ("Refreshing stock data")
ActiveWorkbook.RefreshAll
End Sub
Sub AutoRefresh()
Call RefreshStockData
Application.OnTime Now + TimeValue("00:01:00"), "AutoRefresh"
End Sub
In an Excel spreadsheet/VBA script I'm making, I need to call data from a database, and refresh the values every 5 minutes. The program starts from the push of a button, and should run continuously until the user breaks the execution. I'm currently not sure how to make Excel/VBA 'wait' 5 minutes without pausing the spreadsheet and, ideally, without being computationally inefficient.
I've tried using the "Application.Wait" and "Sleep" functions, but both of those pause the spreadsheet during the 5 minute wait.
My current solution is to use a "While" loop with "DoEvents" inside it, as shown in the code below. This makes the program just run the "While" loop for 5 minutes, and it does not pause the spreadsheet thanks to "DoEvents". However, while the spreadsheet is usable, this is computationally inefficient, since the program execution isn't technically paused, it's just running the "While" loop continuously, and some of the slower computers that may end up using my program might be significantly slowed by this.
My current solution is as follows:
Sub MainProgram()
'dimension variables, open database connection, etc.
Do While 1 < 2 'ad infinitum
'get database data, write to spreadsheet, etc.
WasteTime()
Loop
End Sub
Sub WasteTime()
EndTime = Now + TimeSerial(0,5,0)
While Now < EndTime
DoEvents
Wend
End Sub
The problem with this, as mentioned above, is the computational inefficiency. CPU utilization is fairly high throughout the WasteTime loop. So I'm wondering, is there any way to pause the script without pausing the spreadsheet and without running the code continuously, thus burdening the CPU?
As BigBen mentions in comments Application.OnTime is the best option for this. It avoids the overhead you describe by scheduling a second macro to be called at a future time.
Below is an example. You can modify the wait time with the constant variable. These should be within the same Module (or change theCalculation macro to not be private).
Sub TheTimerMac()
'enter in timevalue (hour:Minute:Second)
Const DelayTime As String = "00:05:00"
Dim nextRunTime As Date
nextRunTime = Now + TimeValue(DelayTime)
'Schedules application to execute below macro at set time.
Application.OnTime nextRunTime, "TheCalculation"
End Sub
Private Sub TheCalculation()
'whatever you use for your calc here
Application.CalculateFull
'This will restart the timer portion.
Call TheTimerMac
End Sub
When Excel VBA macro excecuting, can we change values of cell in excel in which program is running?
Editing option i want to enable when script/program is running
When your VBA consists of a lot of loops you can still do things in excel by adding:
DoEvents
Add this inside the loop(s), this will allow for other events (such as the user changing stuff) to happen while the program runs.
Do keep in mind the warnings others already gave you, you can seriously disrupt your VBA script, because the user could actually mess with all the excel spreadsheet content that you might interact with in your script.
A little "fun" example:
Option Explicit
Sub example_DoEvents()
Dim timer1 As Date
timer1 = Now()
Do While Now() < timer1 + 10 / 60 / 60 / 24 'only let it last for 10 seconds
DoEvents
ActiveSheet.Range("A1").Value2 = Selection.Address
Loop
MsgBox "END"
End Sub