Understanding Code behind auto closing and saving in excel - vba

The Goal: I'm trying to auto close out of workbooks for the reports I update as there are users who have them open, and forget to close them at night. I've set the auto close time to 12am.
Question 1: So I already have a couple of solutions for this problem. I found answers through a smattering of searches on google, and combined a few pieces of code to get exactly what I wanted. Now I'm wondering if it's possible to have the excel vba auto save & close in just one Module or ThisWorkbook. Essentially keeping all the code in one place.
Question 2: I know that the 1st and 2nd macro work I'm wondering which is more efficient and clean, and why?
1ST MACRO
' Insert into ThisWorkbook
Private Sub Workbook_Open()
Static SchedSave
If SchedSave <> 0 Then
Application.OnTime SchedSave, "SaveWork", , False
End If
SchedSave = TimeValue("09:29:00") ' Insert Desired time in Military
Application.OnTime SchedSave, "SaveWork", , True
End Sub
' Insert into module
Sub SaveWork()
ThisWorkbook.Save
ThisWorkbook.Close
End Sub
2ND MACRO
' Insert into ThisWorkbook
Private Sub Workbook_Open()
Reset
End Sub
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
Reset
End Sub
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Reset
End Sub
' Insert into Module
Sub Reset()
Static SchedSave
If SchedSave <> 0 Then
Application.OnTime SchedSave, "SaveWork", , False
End If
SchedSave = TimeValue("12:00:00") ' 12AM
Application.OnTime SchedSave, "SaveWork", , True
End Sub
Sub SaveWork()
ThisWorkbook.Save
ThisWorkbook.Close
End Sub
Also posted: http://www.mrexcel.com/forum/excel-q...ml#post3830083 (This is where I got help to get the 1st Macro to work)

I might not be a genius but nothing prevents you to put the "module-code" in "thisworkbook".
I don't see why you have to call the "Reset" Macro each time the workbook is opened, each time a worksheet is changed and... well isn't a worksheet activated as soon as you open a workbook? I'd say the 1st is the best.
EDIT: Lol I didn't see the unformatted 'insert this into thisworkbook

Related

VBA How to save and close workbook after time of inactivity, unless userform is open?

This is my first time posting on this site, and would appreciate some help. I'm a member of the mrexcel forums, and have received a lot of help from those great people over there, but have not been able to find an answer to my question. At work, I've created a workbook that allows us to enter data into different worksheets via a userform. I'm trying to make this as user-friendly as I possibly can, to attempt to eliminate as many "user-errors" as possible. One issue I'm trying to avoid is a user forgetting to close the sheet when their shift is over, and locking everyone out because the workbook is read-only when another user has the file open. So, I have a code that will save and close the workbook after 40 minutes of inactivity. One issue this is causing (and it is a very minor issue, but one that has been brought up to me by one of my employees), is that every once in a while, coincidentally the user will be entering data into the userform right around that 40 minutes of inactivity, and the workbook will close before they had a chance to submit the data. I was wondering if anyone could help me modify my code so that when it reaches that 40 minutes of inactivity, before it saves and closes, it sees that the userform is open and cancels the action if it is. Here is the code that I've got. Thanks for any help I can get.
In Module 1:
Dim CloseTime As Date
Sub TimeSetting()
CloseTime = Now + TimeValue("00:40:00")
On Error Resume Next
Application.OnTime EarliestTime:=CloseTime, _
Procedure:="SavedAndClose", Schedule:=True
End Sub
Sub TimeStop()
On Error Resume Next
Application.OnTime EarliestTime:=CloseTime, _
Procedure:="SavedAndClose", Schedule:=False
End Sub
Sub SavedAndClose()
ActiveWorkbook.Close Savechanges:=True
End Sub
In ThisWorkbook:
Private Sub Workbook_Open()
Call TimeSetting
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Call TimeStop
End Sub
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Call TimeStop
Call TimeSetting
End Sub
Just call the TimeStop() sub on the Userform_Initialize() event, and then call the TimeSetting() sub when you close the userform
You can see if a userform is loaded by using this function:
Function IsUFLoaded(ByVal UFName As String) As Boolean
Dim UForm As Object
For Each UForm In VBA.UserForms
If UForm.Name = UFName Then
IsUFLoaded = True
Exit For
End If
Next
End Function
And then in SavedAndClose Sub:
Sub SavedAndClose()
' change userform_name to your userform name
If IsUFLoaded("userform_name") = False Then ActiveWorkbook.Close Savechanges:=True
End Sub
Why not, instead of doing what you're suggesting: allowing a user to accidentally leave themselves logged in to a userform which would cause the issue you're trying to avoid, you instead also reset the timer with Call TimeStop and Call TimeSetting within the change events of fields in the userform?

How do you create an automatic timer using Excel 2016 VBA macro editor?

I need to create a timer in Excel 2016 VBA editor that will go-off every second and display a message.
I have a simple code that will do just that; however when I run the code a message box appears and then an error follows. My code is presented below:
Private Sub Workbook_Open()
RunEveryTwoMinutes
End Sub
Sub RunEveryTwoMinutes()
MsgBox ("Stop!")
Application.OnTime Now + TimeValue("00:00:01"), "RunEveryTwoMinutes"
End Sub
The error I receive states:
"Cannot run the macro 'C:user|generic\Book1.xlsm'. The macro may not be available in this workbook or all macros may be disabled.
I am not sure what is occurring. I simply need to find out a way to create a one second timer that initiates as soon as the code initializes.
Place this code in your workbook code module:
Private Sub Workbook_Open()
RunEveryTwoMinutes
End Sub
and place this code in a standard code module:
Sub RunEveryTwoMinutes()
MsgBox ("Stop!")
Application.OnTime Now + TimeValue("00:00:01"), "RunEveryTwoMinutes"
End Sub
Alternatively, you can have all the code in your Workbook code module, but you need to qualify the macro name:
Private Sub Workbook_Open()
RunEveryTwoMinutes
End Sub
Sub RunEveryTwoMinutes()
MsgBox ("Stop!")
Application.OnTime Now + TimeValue("00:00:01"), "ThisWorkbook.RunEveryTwoMinutes"
End Sub
I believe the first method is preferable.

Excel VBA - Application.OnTime not working and WScript.Shell.PopUp timer not working

I have an automated task that will open Excel and run some VBA code at a specific time every morning. If a user has the excel file open I want to warn them the file will be automatically closed in a few moments via a popup message, then shortly thereafter have Excel automatically save and quit. In case the user is away from their computer, I want the popup message to close automatically after 5 seconds so it doesn't freeze my SaveExit subroutine.
The popup message is appearing, but it will not close automatically.
It is only closing if "OK" is clicked. This is preventing the SaveExit routine from running.
Under Microsoft Excel Objects in This Workbook:
Private Sub Workbook_Open()
ThisWorkbook.Worksheets("Pull Data").Activate
Application.OnTime TimeValue("1:00:00 AM"), "CloseWarn", TimeValue("1:02:00 AM")
Application.OnTime TimeValue("1:03:00 AM"), "SaveExit", TimeValue("1:04:00 AM")
End Sub
In a module called autoclose:
Sub SaveExit()
Application.DisplayAlerts = False
With ThisWorkbook
.Save
Application.Quit
End With
End Sub
Sub CloseWarn()
Select Case CreateObject("WScript.Shell").PopUp("closing soon", 5, "Warning")
Case 1, -1
End Select
End Sub
How do I get a popup warning message to display at a specific time, then close if no user input occurs??
Figured it out! Thanks #Evan for pointing me in the right direction. I don't understand why, but when using the Application.OnTime command under Workbook_Open, things work better if I identify the module where the routine is located. After I figured this out I moved my subs to ThisWorkbook to streamline my code. I created a userform called CloseAlert that informs users that Excel is about to close automatically. The userform closes after 5 seconds, or upon user clicking "OK".
Under Microsoft Excel Objects in ThisWorkbook:
Private Sub Workbook_Open()
ThisWorkbook.Worksheets("Pull Data").Activate
Application.OnTime TimeValue("16:08:00"), "ThisWorkbook.ShowCloseAlert"
Application.OnTime TimeValue("16:09:00"), "ThisWorkbook.SaveExit"
End Sub
Private Sub ShowCloseAlert()
CloseAlert.Show vbModeless
Application.OnTime Now + TimeValue("00:00:05"), "Unloadit"
End Sub
Sub SaveExit()
Application.DisplayAlerts = False
With ThisWorkbook
.Save
Application.Quit
End With
End Sub
In a separate module called unload_CloseAlert:
Public Sub Unloadit()
unload CloseAlert
End Sub

VBA Events: load workbook before running code using workbook_open

I want to run a VBA macro AFTER the workbook has finished opening. I tried to use workbook_open but this runs before the workbook has finished opening. This doesn't work for me as I need to loop through each sheet like so...
Private Sub Workbook_Open()
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
'do stuff on each sheet
Next ws
End Sub
Does anyone know if there is an event which runs once the workbook has finished opening? Or have any other suggestions on how I can achieve this?
I had a similar problem that I solved using Application.OnTime.
From the linked MSDN Library Article:
Schedules a procedure to be run at a specified time in the future
(either at a specific time of day or after a specific amount of time
has passed).
You could try using this method to provide the workbook with enough time to open before running the DoStuff procedure:
Private Sub Workbook_Open()
Application.OnTime Now + TimeValue("00:00:01"), "DoStuff"
End Sub
Ensure the DoStuff procedure is not in a worksheet module:
Private Sub DoStuff()
'Implementation...
End Sub
The time can be adjusted but one second was satisfactory for me.
Put your code in the Workbook_Activate event. It happens after the Open event.
Private Sub Workbook_Activate()
' Code goes here
End Sub
Try using ThisWorkbook rather than ActiveWorkbook:
Private Sub Workbook_Open()
Dim osht As Worksheet
For Each osht In ThisWorkbook.Worksheets
Debug.Print osht.Name
Next osht
End Sub

Macro to Clear multiple Columns

Below is my code that automatically runs the TimeStamp Macro when I open the workbook. However, it only runs if the Time is 6:45 am or later. My problem is that I am trying to get it to clear the cell contents in Columns A through D from Row 2 and on if the time is before 6:45 am and before it runs the TimeStamp macro. I tried to do it with just Column A and the debugger says that the top line is an issue. I can't seem to figure out why it is an issue though. I assume I am breaking some sort of syntax rule but I am not sure.
Private Sub Workbook_Open()
If Time > TimeSerial(6, 45, 0) Then
Call TimeStamp
Else
Sub Clear()
Dim wb3 As Workbook
Set wb3 = ThisWorkbook
With wb3.Worksheets("Avnet")
.Range("A2:A" & .Range("A2").End(xlDown).Row).ClearContents
End With
End Sub
Application.Wait "06:45:00"
Call TimeStamp
End Sub
It worked prior to me adding in the Sub Clear() section...
UPDATE:
Just tried making the Sub Clear() a separate module and using the call Clear() but that didnt work either. Here is what it looked like
The Clear () Code
Sub Clear()
Dim wb3 As Workbook
Set wb3 = ThisWorkbook
With wb3.Worksheets("Avnet")
Range("A2:A" & .Range("A2").End(xlDown).Row).ClearContents
End With
End Sub
The Part to call the Clear()
Private Sub Workbook_Open()
If Time > TimeSerial(20, 0, 0) Then
Call TimeStamp
Else
Call Clear
Application.Wait "19:35:00"
Call TimeStamp
End Sub
Declaring a sub within a sub will not work (I'm 99.9999% sure, but it's never entered my head to try this!)
Move your Sub Clear declaration so that it's after Workbook_Open, and then just call Clear from within Workbook_Open, in the same way that you call TimeStamp. (You're also missing an End If' at the end of WorkBook_open)
So your code would become:
Private Sub Workbook_Open()
If Time > TimeSerial(6, 45, 0) Then
Call TimeStamp
Else
Call Clear
Application.Wait "06:45:00"
Call TimeStamp
End If
End Sub
Sub Clear()
Dim wb3 As Workbook
Set wb3 = ThisWorkbook
With wb3.Worksheets("Avnet")
.Range("A2:A" & .Range("A2").End(xlDown).Row).ClearContents
End With
End Sub
As an aside, your Workbook_Open code can be simplified to:
Private Sub Workbook_Open()
If Time <= TimeSerial(6, 45, 0) Then
Call Clear
Application.Wait "06:45:00"
End If
Call TimeStamp
End Sub