Excel VBA Application.StatusBar in Worksheet_Deactivate fails with 50290 - vba

I have a Worksheet, which updates the StatusBar based on which cell is selected (this works fine). My problem is, with the code that sets the StatusBar back to empty when the user goes to another Worksheet:
Private Sub Worksheet_Deactivate()
Application.StatusBar = vbNullString ' Run time error here
End Sub
Err.Description is: "Method 'StatusBar' of object '_Application' failed", Err.Number is: 50290.
This error occurs only if the user changes from Worksheet to Worksheet rapidly (by pressing Ctrl+PgUp or Ctrl+PgDown) and does not happen in case of switching to another Sheet slowly.
Why do I have this error?

Just set it to False
Application.StatusBar = False
from Microsoft:
This property returns False if Microsoft Excel has control of the status bar. To restore the default status bar text, set the property to False; this works even if the status bar is hidden.

I found the problem. When an event handler starts execution, the Excel Application may not be ready, so this has to be checked if the code refers to objects related to the Application:
Private Sub Worksheet_Activate()
If Application.Ready = False Then Exit Sub
' Rest of the code referring to Application.x or Me.y or ActiveSheet.z, etc.
End Sub

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

Inconsistent error when moving worksheet

The code below is a function to move a worksheet in a workbook. It gets called from a userform that contains a listbox that lists the worksheets in the workbook. The input is an integer that gives the direction which to move the sheet. Left/right in workbook is up/down in the userform listbox, and the userform has up and down buttons that calls the function with different input (+1 for moving right and -2 for moving left).
This function sometimes gives the error Method 'Move' if object '_Worksheeet' failed, but not consistently. Mostly the error comes when moving a sheet a second time, so that I am not able to move a sheet more than once. Once the error occurs I am not able to move the sheet again. I can, however, select a different sheet and move this once before the same thing occurs.
If I implement a message box in the error handling, the behaviour changes. After closing the message box upon error, I can proceeed to move the same sheet again after an error. With a message box I can therefore move a sheet as many times as I want, but it only moves on every other button press. I guess the message box breaks code execution, which for some reason makes the function work again even one the same sheet that gave the error. I have tried replacing the message box with a delay or a selfclosing infobox but this does not give the same result.
To further complicate matters, sometimes when I open the userform application, the move buttons work perfectly without any error. I think this happens when the worksheet is already open before the application is opened.
It all seems very inconsistent, and beyond my knowledge. Any help or suggestions much appreciated.
Function FlyttMåling(Retning As Integer) As Boolean
Application.EnableEvents = False
Application.ScreenUpdating = False
'code to reference the correct workbook based on outside parameters
Dim wb As Workbook, ws As Worksheet
FlyttMåling = True
If Hovedvindu.LuftlydKnapp.Value = True Then
Set wb = ÅpneBok(1)
ElseIf Hovedvindu.TrinnlydKnapp.Value = True Then
Set wb = ÅpneBok(2)
End If
'sets variable to the index of sheet to be moved, chosen from list in userform
Dim nummer As Integer
Set ws = wb.Sheets(1)
If Hovedvindu.MålingerFrame.Liste.ListIndex < 0 Then
Exit Function
Else
Set ws = wb.Sheets(Hovedvindu.MålingerFrame.Liste.Value)
End If
nummer = ws.Index
'exit function if trying to move first sheet to the left or last sheet to the right
If (Retning = 1 And nummer = wb.Sheets.count) Or (Retning = -2 And nummer = 2) Then
Exit Function
End If
'code that moves worksheet
ws.Activate
On Error GoTo errHandler:
errResume:
ws.Move after:=wb.Sheets(nummer + Retning) 'THIS LINE CAUSES ERROR
On Error GoTo 0
Call oppdaterListe
'reselect the moved worksheet in the userform list
For i = 0 To Hovedvindu.MålingerFrame.Liste.ListCount - 1
If ws.Name = Hovedvindu.MålingerFrame.Liste.List(i) Then
Hovedvindu.MålingerFrame.Liste.Selected(i) = True
Exit For
End If
Next i
Application.EnableEvents = True
Application.ScreenUpdating = True
Exit Function
'error handling just sets the return to false to notify failure to move sheet
errHandler:
FlyttMåling = False
End Function
Found a workaround for this problmem. Changing the wb.move to a wb.copy, and then deleting the old sheet and renaming the copy to the name of the original sheet makes this code work as intended.

Excel VBA Run-time error 438 first time through code

I'm a novice self-taught VBA programmer knowing just enough augment Excel/Access files here and there. I have a mysterious 438 error that only popped up when a coworker made a copy of my workbook (Excel 2013 .xlsm) and e-mailed it to someone.
When the file is opened, I get a run time 438 error when setting a variable in a module to a ActiveX combobox on a sheet. If I hit end and rerun the Sub, it works without issue.
Module1:
Option Private Module
Option Explicit
Public EventsDisabled As Boolean
Public ListBox1Index As Integer
Public cMyListBox As MSForms.ListBox
Public cMyComboBox As MSForms.Combobox
Public WB As String
Sub InitVariables()
Stop '//for breaking the code on Excel open.
WB = ActiveWorkbook.Name
Set cMyListBox = Workbooks(WB).Worksheets("Equipment").Listbox1
Set cMyComboBox = Workbooks(WB).Worksheets("Equipment").Combobox1 '//438 here
End Sub
Sub PopulateListBox() '//Fills list box with data from data sheet + 1 blank
Dim y As Integer
If WB = "" Then InitVariables
ListBox1Index = cMyListBox.ListBoxIndex
With Workbooks(WB).Worksheets("Equipment-Data")
y = 3
Do While .Cells(y, 1).Value <> ""
y = y + 1
Loop
End With
Call DisableEvents
cMyListBox.ListFillRange = "'Equipment-Data'!A3:A" & y
cMyListBox.ListIndex = ListBox1Index
cMyListBox.Height = 549.75
Call EnableEvents
End Sub
...
PopulateListBox is called in the Worksheet_activate sub of the "Equipment" sheet.
All my code was in the "Equipment" sheet until I read that was bad form and moved it to Module1. That broke all my listbox and combobox code but based on the answer in this post I created the InitVariables Sub and got it working.
I initially called InitVariables once from Workbook_open but added the If WB="" check after WB lost its value once clicking around different workbooks that were open at the same time. I'm sure this stems from improper use of Private/Public/Global variables (I've tried understanding this with limited success) but I don't think this is related to the 438 error.
On startup (opening Excel file from Windows Explorer with no instances of Excel running), if I add a watch to cMyComboBox after the code breaks at "Stop" and then step through (F8), it sets cMyComboBox properly without error. Context of the watch does not seem to affect whether or not it prevents the error. If I just start stepping or comment out the Stop line then I get the 438 when it goes to set cMyComboBox.
If I add "On Error Resume Next" to the InitVariables then I don't error and the project "works" because InitVariables ends up getting called again before the cMyComboBox variable is needed and the sub always seems to work fine the second time. I'd rather avoid yet-another-hack in my code if I can.
Matt
Instead of On Error Resume Next, implement an actual handler - here this would be a "retry loop"; we prevent an infinite loop by capping the number of attempts:
Sub InitVariables()
Dim attempts As Long
On Error GoTo ErrHandler
DoEvents ' give Excel a shot at finishing whatever it's doing
Set cMyListBox = ActiveWorkbook.Worksheets("Equipment").Listbox1
Set cMyComboBox = ActiveWorkbook.Worksheets("Equipment").Combobox1
On Error GoTo 0
Exit Sub
ErrHandler:
If Err.Number = 438 And attempts < 10 Then
DoEvents
attempts = attempts + 1
Resume 'try the assignment again
Else
Err.Raise Err.Number 'otherwise rethrow the error
End If
End Sub
Resume resumes execution on the exact same instruction that caused the error.
Notice the DoEvents calls; this makes Excel resume doing whatever it was doing, e.g. loading ActiveX controls; it's possible the DoEvents alone fixes the problem and that the whole retry loop becomes moot, too... but better safe than sorry.
That said, I'd seriously consider another design that doesn't rely so heavily on what appears to be global variables and state.

Excel worksheet triggers and events

In one of my workbooks I use both the Worksheet_Activate() trigger and also the Workbook_SheetActivate trigger. I'm using the latter as an over riding handler to control which users can see which worksheets. Using the following:
Private Sub Workbook_SheetActivate(ByVal ws As Object)
Dim HigherAccess As String
HigherAccess = "Sheet1, Sheet2, Sheet3"
If InStr(1, HigherAccess, ws.Name, vbTextCompare) > 0 Then
If UserList.Count = 0 Or ThisUser = "" Then Call UserDL
Application.EnableEvents = True
On Error GoTo err
If Not UserList.item(ThisUser)(7) = "Employee" Then
ThisWorkbook.Sheets(ws.Name).Activate
Else
ThisWorkbook.Sheets("Landing Page").Activate
MsgBox "You do not have permission to view this." & vbNewLine _
& "If this is an error please contact xxxx"
End If
End If
Exit Sub
err:
MsgBox "An Error has occurred. The application will now refresh"
ThisWorkbook.Sheets("Landing Page").Activate
End Sub
My issue is is that the Worksheet_Acivate() trigger seems to fire before the Workbook_SheetActivate one. Is there anyway to change the order in which these fire?
As Events are fired from the "smallest" object (in the Excel Object Model) to the "largest" object (worksheet to application), you cannot change the order of the events fired.
You can, however, work within that order to accomplish your goals, as #MacroMan has stated with his example of testing the Worksheet that caused the Change Event in the Workbook_SheetChange event.
See Chuck Pearson's tutorial on Events for more information.

VBA errors when opening xl document

I added some VBA code for my xl sheets .
This code seems to compile when i open the WorkBook.
An exemple of the type of error i got when i open the document .
Private Sub ComboBox1_Change()
If ComboBox1.Value = "GGS" Then
Sheets("Index").CommandButton2.Visible = True
==> Sheets("Index").Label6.Visible = True
Sheets("MNO").CommandButton5.Visible = True
Sheets("ServiceProvider").CommandButton5.Visible = True
Sheets("ServiceDeployer").CommandButton5.Visible = True
Sheets("CardVendor").CommandButton5.Visible = True
Sheets("LoadFile").CommandButton5.Visible = True
Else
Sheets("Index").Label6.Visible = False
Sheets("Index").CommandButton2.Visible = False
Sheets("MNO").CommandButton5.Visible = False
Sheets("ServiceProvider").CommandButton5.Visible = False
Sheets("ServiceDeployer").CommandButton5.Visible = False
Sheets("CardVendor").CommandButton5.Visible = False
Sheets("LoadFile").CommandButton5.Visible = False
End If
I got a "Run-time errror '438' : Object doesn't support the property or method " on the marked line
Sometimes there is the same error for this line in another sheet
Me.ListBox1.Clear
So I end the debuging , then all the code works properly ,even those last lines .
Is it possible to disable the auto compilation at the opening of the document ?
It seems that the VBA editor tries to run the code before the View is created.
The debug just drop an "Object required" .I checked before stoping debuging and the object was not in the objects list .When i stoped the debuging then checked the list, the object was there
(I'm French so there might have some english mistakes )
Thank you for reading me
Spikeze
EDIT :
I found the problem.
The "ComboBox1.Style " is on fmStyleDropDownList to avoid the user to edit the options .
But this option makes the Combobox automatically choose the first option when the document opens.
So I guess it runs "ComboBox1_Change()" when the first option is choosed but some view elements are not loaded at this time and the VBA editor drops an "Objec required".
I set the style to fmStyleDropDownCombo and fmStyleDropDownList when the sheets is active but if the WorkBook is saved and reopened the style is on fmStyleDropDownList again and I got the error again .
To solve it I had those sub
Private Sub Worksheet_Activate()
ComboBox1.Style = fmStyleDropDownList
End Sub
In the Index sheet code and
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Sheets("Index").ComboBox1.Style = fmStyleDropDownCombo
End Sub
In the WorkBook code .
Spikeze
You can just use error handling. Not the best solution, but it should work. If you are sure these objects exist, when you need them, you can use
On Error Resume Next
Or handle the error properly, with checking code error and resuming only on 438