I have the following code that loads a worksheet in full screen for 1 minute, and then moves onto the next worksheet in the workbook, using the exactly the same methodology.
This is to show stats on a big screen, looping through several stats pages.
This works perfectly on Excel 2007 and 2010.
Yet when the same code is executed on Excel 2013, Excel simply maxes out 1 core of my CPU and stays at not responding. I cannot even Escape to break the code execution. Stepping through the code line by line works fine on all versions.
'Loads up Daily Dispatch Figures worksheet
Application.ScreenUpdating = False
Sheets("Daily Dispatch Figures").Select
Range("A1").Select
Range("A1:C36").Select
ActiveWindow.Zoom = True
Range("A1").Select
ActiveWindow.DisplayHeadings = False
Application.DisplayFormulaBar = False
Application.DisplayFullScreen = True
Application.ScreenUpdating = True
' Stays on this screen for 1 min
TimVal = Now + TimeValue("0:01:00")
Do Until Now >= TimVal
Loop
Ooo, don't do this:
' Stays on this screen for 1 min
TimVal = Now + TimeValue("0:01:00")
Do Until Now >= TimVal
Loop
Try this:
Application.OnTime Now + TimeValue("0:01:00"), "ProcedureToRun"
You don't want to catch your application in an infinite loop with no sleeps.
Any time you sit in an infinite loop without sleeping, it will use 100% of your Processor time doing nothing. Application.OnTime "schedules" an event and returns control to the Excel UI Thread instead of infinitely looping.
You can read more here: https://msdn.microsoft.com/en-us/library/office/ff196165.aspx
I'm not sure what you're doing after your loop, but you need to make sure you have the code in a separate subroutine and call it.
Here is a Subroutine to go to the next sheet.
Sub MoveNext()
On Error Resume Next
Sheets(ActiveSheet.Index + 1).Activate
If Err.Number <> 0 Then Sheets(1).Activate
On Error Goto 0
End Sub
You can add the Application.OnTime to the end of it and have it call itself:
Sub MoveNext()
On Error Resume Next
Sheets(ActiveSheet.Index + 1).Activate
If Err.Number <> 0 Then Sheets(1).Activate
On Error Goto 0
Application.OnTime Now + TimeValue("00:01:00"), MoveNext
End Sub
This way it will loop and go from sheet to sheet forever (or until you stop it in whatever method you choose to use).
Finally, you can cancel this by storing the scheduled time and using Scheduled:=False.
Your final code could look something like this:
Public scheduledTime as Date
Sub StartDisplaying()
'Your start code:
'---------------------------------------------
Application.ScreenUpdating = False
Sheets("Daily Dispatch Figures").Select
Range("A1").Select
Range("A1:C36").Select
ActiveWindow.Zoom = True
Range("A1").Select
ActiveWindow.DisplayHeadings = False
Application.DisplayFormulaBar = False
Application.DisplayFullScreen = True
Application.ScreenUpdating = True
'---------------------------------------------
scheduledTime = Now + TimeValue("00:01:00")
Application.OnTime scheduledTime, MoveNext
End Sub
Sub StopDisplaying()
'Your stop code:
'---------------------------------------------
Application.ScreenUpdating = False
Sheets("Daily Dispatch Figures").Select
ActiveWindow.Zoom = False
ActiveWindow.DisplayHeadings = True
Application.DisplayFormulaBar = True
Application.DisplayFullScreen = False
Application.ScreenUpdating = True
'---------------------------------------------
Application.OnTime EarliestTime:=scheduledTime, Procedure:="MoveNext", Schedule:=False
End Sub
Sub MoveNext()
On Error Resume Next
Sheets(ActiveSheet.Index + 1).Activate
If Err.Number <> 0 Then Sheets(1).Activate
On Error Goto 0
scheduledTime = Now + TimeValue("00:01:00")
Application.OnTime scheduledTime, MoveNext
End Sub
Related
I have the following macro assigned to a button:
Sub refresh()
Application.Calculation = xlCalculationManual
ActiveWorkbook.RefreshAll
Application.Calculation = xlCalculationAutomatic
Call repeat
End Sub
Sub repeat()
TimeToRun = Now + TimeValue("00:05:00")
Application.OnTime TimeToRun, "refresh"
End Sub
If the button is clicked more than once, I get multiple instances of this macro running.
Is there a way to cancel any macros running prior to commencing the Sub refresh()?
Something like this:
Dim TimeToRun
Sub refresh()
Application.Calculation = xlCalculationManual
ActiveWorkbook.RefreshAll
Application.Calculation = xlCalculationAutomatic
Call repeat
End Sub
Sub repeat()
If TimeToRun > 0 Then
'cancel previous...
Application.OnTime TimeToRun, "refresh", False
End If
TimeToRun = Now + TimeValue("00:05:00")
Application.OnTime TimeToRun, "refresh"
End Sub
I tried to add the cancellation code in repeat but it did not work. I have added another sub that should run when the button is clicked. Range("G1") is a cell i use to store the time value.
Sub refresh()
Application.Calculation = xlCalculationManual
ActiveWorkbook.RefreshAll
Application.Calculation = xlCalculationAutomatic
Call repeat
End Sub
Sub repeat()
TimeToRun = Now + TimeValue("00:00:10")
'stoer the TimeToRun
Range("G1") = TimeToRun
'schedule the next refresh
Application.OnTime EarliestTime:=TimeToRun, Procedure:="refresh", Schedule:=True
End Sub
Sub subForClick()
If Not (IsEmpty(Range("G1"))) Then
Application.OnTime EarliestTime:=Range("G1").Value, Procedure:="refresh", Schedule:=False
End If
Call refresh
End Sub
Late for the party, but I create a function to check the time and let the user run the code again after some time.
Private Function timeCheck() As Boolean
If VBA.Now() > TimeControl.Range("A1").Value + VBA.TimeValue("00:05:00") Then
timeCheck = True
Else
timeCheck = False
End If
End Function
Where TimeControl is the name of the sheet that holds the time value on range A1.
So you just need to use this function as below:
If timeCheck = True Then
TimeControl.Range("A1").Value = VBA.Now()
do something
else
do something else
end if
I am trying to figure out why this "Delete Method of Range Class" error is popping up. It does not always occur when this macro runs, which makes it all the more perplexing.
Can anybody explain this?
Sub ResetSheet()
If WindowsOS Then
'*******************************************************************************************************'
'Resets the Data sheet. Called by the resetSheetButton procedure (located in module: m7_Macros1_5). '
'Also called by the OkCommandButton_Click procedure in the OnOpenUserForm form. '
'*******************************************************************************************************'
Application.EnableEvents = False
Sheet4.Visible = True
Sheet4.Activate
Sheet4.Select
Sheet4.Rows("2:101").Select
Selection.Copy
'TC Edit
Sheet1.Activate
Sheet1.Range("A2").PasteSpecial (xlPasteAll)
'Sheet1.Paste
Sheets("Data").Select
Sheet1.Rows("102:10000").EntireRow.Delete
Sheet4.Visible = False
'TC Edit 2.0 - Adding code to reset the exception checkboxes
If WindowsOS Then
Call resetCheckBoxes
End If
Application.EnableEvents = True
This is the macro code that causes the error (sometimes)
This is the error pop-up
try with below simplified code
Sub ResetSheet()
'If WindowsOS Then
Application.EnableEvents = False
With Worksheets("Sheet4")
.Visible = True
.Rows("2:101").Copy Worksheets("Sheet1").Range("A2")
End With
With Worksheets("Sheet1")
.Rows("102:101").EntireRow.Delete
End With
Worksheets("Sheet4").Visible = False
If windowsOS Then
Call resetCheckBoxes
End If
Application.EnableEvents = True
End Sub
I've tried just about every option of modeless possible to get this to work I just cannot get it figured out. What I have is a Userform ( Main_Window ) that has a script, and on command button it executes Master_Flex_Filter_Generate()
In that code I have
' Connect and execute the SQL
rs.Open sqlString, conn, adOpenStatic
' Check if we have data.
If Not rs.EOF Then
' Dump column names in first row.
For i = 0 To rs.Fields.count - 1
ActiveSheet.Cells(1, i + 1) = rs.Fields(i).Name
Next i
Do
' Transfer results beginning at A2 from rs
ActiveSheet.Range("A2").CopyFromRecordset rs
Loop Until rs.EOF
' Close the recordset
rs.Close
' Define Record_Count as the amount of records returned. Subtract 1 for the header
Record_Count = Cells(Rows.count, "A").END(xlUp).Row - 1
' Return box on success
Answer = MsgBox((Record_Count & " Records returned") & vbCrLf & vbCrLf & "Reminder" & vbCrLf & "- This data set is already defined as a range. This allows you to create a new pivot table and use the named range: " & ActiveSheet.Name & vbCrLf & vbCrLf & "Do you want to create a Pivot Table from this data?", vbYesNo + vbQuestion, "Query generated succesfully")
' close user form
Unload mod_loading
Unload Main_Window
' Clean up
If CBool(conn.State And adStateOpen) Then conn.Close
Set conn = Nothing
Set rs = Nothing
'Now lets define this data as a range for pivot table use
Dim ActSheet As Worksheet
Dim ActSheetName As String
'This sets up an object reference to the activesheet
Set ActSheet = Sheets(ActiveSheet.Name)
'This places a string value in the variable
ActSheetName = ActiveSheet.Name
Set wb = ActiveWorkbook
Set ws = ActiveSheet
Set sheetname = ActiveWorkbook.ActiveSheet
ws.Range("A1").Select
ActiveWorkbook.Names.Add Name:="data", RefersToR1C1:= _
"=OFFSET(R1C1,0,0,COUNTA(C1),COUNTA(R1))"
wb.Names("data").Name = ActSheetName
'Filter, freeze pain, and align columns
Rows("1:1").Select
Selection.AutoFilter
Selection.Font.Bold = True
Columns("A:IV").AutoFit
With ActiveWindow
.SplitColumn = 0
.SplitRow = 1
End With
ActiveWindow.FreezePanes = True
'Take answer form msgbox and do something with it
If Answer = vbYes Then
'If yes, create pivot table
Sheets("Pivot").Select
ActiveWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:= _
"data", Version:=xlPivotTableVersion14).CreatePivotTable TableDestination _
:="Pivot!R1C1", TableName:="PivotTable1", DefaultVersion:= _
xlPivotTableVersion14
Sheets("Pivot").Select
Cells(1, 1).Select
End If
Else
mod_loading.Hide
MsgBox "Error: No records returned for your criteria.", vbCritical
End If
This form works perfectly as is here. I have another Userform called mod_loading that looks like this
Sub UserForm_Activate()
DoEvents
Do
mod_loading.loading_beag.Visible = False
mod_loading.loading_splines.Visible = True
Sleep 2000
DoEvents
mod_loading.loading_splines.Visible = False
mod_loading.loading_sheep.Visible = True
Sleep 5000
DoEvents
mod_loading.loading_sheep.Visible = False
mod_loading.loading_meteor.Visible = True
Sleep 5000
DoEvents
mod_loading.loading_meteor.Visible = False
mod_loading.loading_ozone.Visible = True
Sleep 5000
DoEvents
mod_loading.loading_ozone.Visible = False
mod_loading.loading_terrain.Visible = True
Sleep 5000
DoEvents
mod_loading.loading_terrain.Visible = False
mod_loading.loading_gravity.Visible = True
Sleep 5000
DoEvents
mod_loading.loading_gravity.Visible = False
mod_loading.loading_advisor.Visible = True
Sleep 5000
DoEvents
mod_loading.loading_advisor.Visible = False
mod_loading.loading_pool.Visible = True
Sleep 5000
DoEvents
mod_loading.loading_pool.Visible = False
mod_loading.loading_leaks.Visible = True
Sleep 5000
DoEvents
mod_loading.loading_leaks.Visible = False
mod_loading.loading_beag.Visible = True
Sleep 5000
DoEvents
Loop
End Sub
Both of these forms work as is, where I'm having the problem is placing mod_loading.Show anywhere in Master_Flex_Filter_Generate(). No matter what I set for modeless the mod_loading will run until it completely finishes. It won't let the code in Main_Window to continue running, so it halts that code. Any ideas? I was thinking it's perhaps because I'm not playing mod_loading.Show inside a loop, but since my connection string doesn't have a loop I can't figure out how to do it.
I placed the code inside If Not rs.EOF THEN but 99% of the code loads on rs.Open which is outside of the loop.
EDIT
Okay so I have changed my script all around and have placed all SQL logic inside the userform for the loading dialog. So I have Main_Window which is the form, then it calls the sub from the loading userform which pops up just fine. So I now have the loading dialog pop up and goes away just fine as intended. My only problem is now, it doesn't loop through my sleep commands. It just remains on the very first one.
Here is my code for the loading userform
Sub UserForm_Activate()
DoEvents
Call Master_Flex_Filter_Generate
DoEvents
If Cancel = True Then
Unload loading_masterflexfilter
Exit Sub
End If
loading_masterflexfilter.loading_beag.Visible = False
loading_masterflexfilter.loading_splines.Visible = True
Sleep 500
DoEvents
If Cancel = True Then
Unload loading_masterflexfilter
Exit Sub
End If
loading_masterflexfilter.loading_splines.Visible = False
loading_masterflexfilter.loading_sheep.Visible = True
Sleep 1000
DoEvents
If Cancel = True Then
Unload loading_masterflexfilter
Exit Sub
End If
loading_masterflexfilter.loading_sheep.Visible = False
loading_masterflexfilter.loading_meteor.Visible = True
Sleep 1000
DoEvents
If Cancel = True Then
Unload loading_masterflexfilter
Exit Sub
End If
loading_masterflexfilter.loading_meteor.Visible = False
loading_masterflexfilter.loading_ozone.Visible = True
Sleep 1000
DoEvents
If Cancel = True Then
Unload loading_masterflexfilter
Exit Sub
End If
loading_masterflexfilter.loading_ozone.Visible = False
loading_masterflexfilter.loading_terrain.Visible = True
Sleep 1000
DoEvents
If Cancel = True Then
Unload loading_masterflexfilter
Exit Sub
End If
loading_masterflexfilter.loading_terrain.Visible = False
loading_masterflexfilter.loading_gravity.Visible = True
Sleep 1000
DoEvents
If Cancel = True Then
Unload loading_masterflexfilter
Exit Sub
End If
loading_masterflexfilter.loading_gravity.Visible = False
loading_masterflexfilter.loading_advisor.Visible = True
Sleep 1000
DoEvents
If Cancel = True Then
Unload loading_masterflexfilter
Exit Sub
End If
loading_masterflexfilter.loading_advisor.Visible = False
loading_masterflexfilter.loading_pool.Visible = True
Sleep 1000
DoEvents
If Cancel = True Then
Unload loading_masterflexfilter
Exit Sub
End If
loading_masterflexfilter.loading_pool.Visible = False
loading_masterflexfilter.loading_leaks.Visible = True
Sleep 1000
DoEvents
If Cancel = True Then
Unload loading_masterflexfilter
Exit Sub
End If
loading_masterflexfilter.loading_leaks.Visible = False
loading_masterflexfilter.loading_beag.Visible = True
Sleep 1000
DoEvents
End Sub
I have a macro that checks if some names on column Q appear on column A (which is ordered alphabetically) and prints them out on column S if they do. However, every time I run it it freezes after an undefined amount of iterations (never on the same amount of iterations) so it's really hard to know what's going on. If I run it with a breaking point and press F5 for each iteration it doesn't freeze, the thing is I have thousands of names to compare and I really don't want to press F5 that many times.
Here's my code:
Sub test()
Range("Q2").Select
analizados = 0
falsos = 0
Do Until IsEmpty(ActiveCell)
id1 = ActiveCell.Value
primera = Left(id1, 1)
Range("A2").Select
Do While Not ActiveCell.Value Like "" & primera & "*"
ActiveCell.Offset(1, 0).Select
Loop
Do While ActiveCell.Value Like "" & primera & "*"
If id1 = ActiveCell.Value Then
Range("S2").Select
ActiveCell.Offset(falsos, 0).Select
ActiveCell.Value = id1
falsos = falsos + 1
Exit Do
End If
ActiveCell.Offset(1, 0).Select
Loop
analizados = analizados + 1
Range("Q2").Select
ActiveCell.Offset(analizados, 0).Select
Loop
End Sub
Thank you
As you noticed, it's not actually frozen. It's just that Excel can't keep up with updating the screen as fast as you're bombarding it with "something has changed on the active sheet" events, and at one point it gives up and lets the macro complete without bothering with refreshing - at least that's how I understand it (might not be exactly what's going on though).
Try this:
Sub Test()
On Error GoTo ErrHandler
Application.ScreenUpdating = False
'...
'(rest of your code)
'...
CleanExit:
Application.ScreenUpdating = True
Exit Sub
ErrHandler:
MsgBox Err.Description
Resume CleanExit
End Sub
Basically you tell Excel to not even bother with repainting itself until you're done: this should greatly speed up your loops.
You may want to combine this with different settings for Application.Calculation and Application.Cursor, too; and for a better UX you could use the status bar to tell the user to wait a little:
Sub Test()
On Error GoTo ErrHandler
Application.StatusBar = "Please wait..."
Application.ScreenUpdating = False
'...
'...
CleanExit:
Application.StatusBar = False
Application.ScreenUpdating = True
Exit Sub
I created one button and after my workbook loads, I want my button to appear after 10 seconds (not right away).
Dim ButtonOneClick As Boolean
Sub Button3_Click()
Sub disenable()
Dim b1 As Button
Set b1 = Sheets("Sheet2").Button3_Click()
Sheets("Sheet2").Button3_Click.Enabled = False
DoEvents
Application.ScreenUpdating = True
For i = 1 To 10
Application.Wait (Now + TimeValue("0:00:1"))
Next i
'Sheets(1).button1.Enabled = False
End Sub
Try this on activating the sheet or adjust to your needs
Private Sub Worksheet_Activate()
Me.Buttons("Button 1").Visible = False
Application.ScreenUpdating = True
Application.Wait (Now + #12:00:10 AM#)
Me.Buttons("Button 1").Visible = True
End Sub