How to disable a ribbon button in Excel if a particular worksheet exists with VBA - vba

I'm building an Excel add-in which allows users to interact with PowerPoint and export data. The users have an option to insert a template into an existing workbook via a button in the ribbon. When they click this, the button becomes disabled as you can't have two templates in one workbook.
The user may then save their workbook and come back to it at a later point. My issue is that I need to detect that they have the template inserted into an existing workbook and I do this by trying to detect if a named range exists (called LoadedToken).
The issue I have is that both the onLoad function of the Ribbon and the VBA class Auto_Open launch before a large workbook is fully loaded. Therefore I'm not actually detecting if the template exists and can't actually disable the button.
Is there such a thing as events in Excel which can be called at a worksheet level (like worksheet_open) but detected in a class?
My code is:
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' When the Ribbon loads
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub OnRibbonLoad(ribbonUI As IRibbonUI)
Set MyRibbonUI = ribbonUI
Dim Authenticate As New AuthenticationClass
On Error Resume Next
' Enable/Disable buttons based on authentication status
If Authenticate.Authentify = False Then
Authenticated = False
Debug.Print ("Unauthorized!")
Else
Authenticated = True
Debug.Print ("Authorized!")
End If
' If the template doesn't exist then disable a grouping on the ribbon
If TemplateExists = False Then
Call RefreshRibbon(Tag:="Grouping1")
Else
Call RefreshRibbon(Tag:="Grouping2")
End If
End Sub
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Check if the Template sheet is visible and prevent other buttons from working
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Function TemplateExists()
Dim Helpers As New HelpersClass
If Helpers.IsNamedRange("LoadedToken") Then
TemplateExists = True
Else
TemplateExists = False
End If
End Function
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' From the Helpers Class - Check if a named range exists
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function IsNamedRange(RName As String) As Boolean
Dim N As name
IsNamedRange = False
For Each N In ActiveWorkbook.Names
If N.name = RName Then
IsNamedRange = True
Exit For
End If
Next
End Function
Note: The authentication class is just another class to connect to my API.

Related

VBA Word Macro to Allow User to Select and Copy Text Multiple Times

I am working on a VBA script with Microsoft Word that allows the user to select text that will be be copied to the clipboard so that it can exported to an Excel file. The user will make a number of selections and finally indicate he/she is done when the contents of the clipboard will be copied to a template Excel file.
There are two forms: the first (UserForm1 in the code below) queries the user for the Word filename. The filename variable is passed to the second form. The second form (frmModeLessForInput) is a modeless form. The behavior I need is that program control goes to the second form with two buttons "Continue" and "Done".
The user is allowed to navigate the document and place the cursor anywhere in the document. Then when "Continue" is pressed the form will call a subroutine (Highlight_Sentence) to copy the selected text to a "clipboard" variable. When "Done" is pressed control will be passed to called main module which will then copy the clipboard to the Excel file.
Below is the code. I have noted with comments where I am trouble with the code. One problem is the variables defined as Public in the ThisDocument module are not defined in the userforms and their subroutines.
The second problem is in the main module that the frmModelessForInput is supposed to be displayed and control is not supposed to be transferred to next statement {MsgBox "Sentences will now be copied to Excel file"....this is where I will put the code to copy the clipboard to the Excel file.} but the message appears before the frmModelessForInput form is run...thus the clipboard will be empty.
The third problem is that in frmModelessForInput form the statement str_clipboard = str_clipboard + str_clipboard_line is not working. Each time the "Continue" button is pushed str_clipboard loses it previous contents.
Any assistance in resolving these problems is appreciated. As VBA programming is a sideline for me I am still learning.
Note this an updated question Pause VBA Word macro, allow user to make a selection, and restart where it left off adding some more detail on the requirement and the sample code.
MAIN MODULE:
Option Explicit
Public str_clipboard As String
Public txt_active_document As String
Public i_how_many_sentences As Integer
Private Sub Test_master_macro()
UserForm1.Show
i_how_many_sentences = 0
Call DisplayModeless
MsgBox "Sentences will now be copied to Excel file" 'Problem: this msg displays before the frmModelessForInput is displayed
End Sub
Sub DisplayModeless()
Dim frm As frmModelessForInput
Set frm = New frmModelessForInput
With frmModelessForInput
.str_word_doc_filename = txt_active_document
.str_no_copied = "0"
.Show False
End With
Set frm = Nothing
End Sub
USERFORM1: form has field for user entering the document filename to user (str_filename) and a command button to close form (cmd_start_selecting_text)
Private Sub cmd_start_selecting_text_Click()
'User enters filename on form for use in frmModelessForInput subroutine
txt_active_document = UserForm1.str_filename 'Problem: VBA reports txt_active_document as undefined even though it is a Public variable
Unload Me
End Sub
FRMMODELESSFORINPUT: Form displays filename of Word file entered in UserForm1 and how many sentences have been copied to the clipboard
Option Explicit
Private Sub cmdContinue_Click()
Dim str_clipboard, str_clipboard_line As String
Call Highlight_Sentence(str_clipboard_line)
i_how_many_sentences = i_how_many_sentences + 1 'Problem: VBA reports i_how_many_sentences as undefined even though it is a Public variable
frmModelessForInput.str_no_copied = i_how_many_sentences 'Same Problem
str_clipboard = str_clipboard + str_clipboard_line 'Problem: each time I select a new text/sentence str_clipboard does not contain the contents of the previous selection
End Sub
Private Sub cmdDone_Click()
Me.Hide
End Sub
Private Sub UserForm_Activate()
'Position the form near the top-left of the window
'So that the user can work with the document
Me.Top = Application.ActiveWindow.Top + 15
Me.Left = Application.ActiveWindow.Left + 15
End Sub
Private Sub Highlight_Sentence(clipboard As String)
'This sub extends the selection to the entire sentence and copies the selection, the page number on which the selection is contained and the filename to the clipboard variable
Dim txt_sentence, txt_page_no As String
With Selection
' Collapse current selection.
.Collapse
' Expand selection to current sentence.
.Expand Unit:=wdSentence
End With
txt_sentence = Selection.Text
txt_page_no = Selection.Information(wdActiveEndPageNumber)
clipboard = txt_active_document & vbTab & txt_page_no & vbTab & txt_sentence & vbCrLf 'Problem: VBA reports txt_active_document as undefined even though it is a Public variable
End Sub
From what you stated you are running this from the ThisDocument Class Module and unless you fully qualify your references to those Public variables with the Class Name that is why you cannot access them from the UserForms Class Modules.
If you are going to leave your "Main Module" code in the ThisDocument Class Module then whenever you reference those Public variable you need to add ThisDocument.str_clipboard to the command.
I recommend however, to place your Main Module in a general Module such as NewModule and if you need to run it at a Document_Open event that you put a call to the Main Module and its Public variables in the Private Sub Document_Open event of the ThisDocument Class Module.
Your Msgbox is appearing at the wrong time because you are displaying a modeless user form, which means the VBA script thread continues to run after the UserForm is displayed. Move the Msgbox to the UserForm_Activate routine of the second UserForm you are displaying or move it to the Click_Done routine of the first UserForm before you Hide or Unload it.
Finally, you are not really using the Clipboard and using that term makes your code confusing in my opinion. I think you should rename it. Your code also appears to just be building one continuous string of text. Is that really what you want to do? Or, do you really mean to capture each selected text string and ultimately place each into separate cells within an Excel Worksheet? If that is the case, use an Array for the separate text strings.

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

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

Disable checkboxes when sheet opened in vba

I have 3 checkboxes. When a user opened my sheet, he/she must not check checkboxes. I want them to be disabled. How can I do that?
Not sure if you meant ActiveX or FormControl, so here you go
Code
Private Sub Worksheet_Activate()
Dim myActiveX As Object
Set myActiveX = Sheet1.OLEObjects("CheckBox1")
myActiveX.Object.Value = True
myActiveX.Object.Locked = False ' Make it False if you wish to enable it
myActiveX.Object.Enabled = False ' Another option to disable
Dim myFormControl As CheckBox
Set myFormControl = ActiveSheet.Shapes("Check Box 1").OLEFormat.Object
myFormControl.Value = True
myFormControl.Enabled = False ' Make it True if you wish to enable it
End Sub
Live GIF demo
You have to write some VBA code in order to do that.
Let's suppose that you have 3 CheckBoxes in your first sheet.
By holding the "Alt" key on your keyboard and the pressing one time the "F11" key, opens Microsoft Visual Basic. ( Alt + F11 )
At your left hand you can see the "VBAProject" tree.
Double click on the "ThisWorkbook" file and copy the following code in the window it will appear:
Private Sub Workbook_Open()
void = uncheckAllCheckboxes()
End Sub
Function uncheckAllCheckboxes()
ThisWorkbook.Worksheets(1).CheckBox1.Value = False
ThisWorkbook.Worksheets(1).CheckBox2.Value = False
ThisWorkbook.Worksheets(1).CheckBox3.Value = False
End Function
Save the excel file as "Excel 97-2003 Workbook" type (.xls)
Close your excel.
Open the file you have previously saved and everything will work fine.
;)
P.S.: It is important to enable macros from your excel settings

Excel 2013 - issue when closing multiple workbooks if one workbook is hidden

I've written a program in Excel VBA which uses a UserForm to enter data by the users. Specifically, it is a Telemarketing Tracker tool: the user fills in the details of the call in a text box on the UserForm and then clicks the relevant button to indicate whether it was a good or bad call, and can then continue with the next call.
This data is stored on a worksheet and our users often prefer to hide the workbook and just view the UserForm. I have developed a couple of methods of hiding the workbook. If there is just one workbook open, I hide the Excel Application. If there is more than one workbook open, I just hide the window. Here is the code I use for this:
Private Sub HideUnhideButton_Click() 'User clicks Hide/Unhide button
If Workbooks.Count > 1 Then
Windows(ThisWorkbook.Name).Visible = Not Windows(ThisWorkbook.Name).Visible
HideUnhideButton.Tag = Windows(ThisWorkbook.Name).Visible
Else
ThisWorkbook.Application.Visible = Not ThisWorkbook.Application.Visible
HideUnhideButton.Tag = ThisWorkbook.Application.Visible
End If
ThisWorkbook.Activate
End Sub
This works well but obviously certain issues arise when the user has the workbook hidden and then open a different Excel Workbook. I've worked round most of these issues, but there is one thing I can't seem to work out: if the Telemarketing workbook is hidden, with another workbook open, if I click the Close button, both workbooks try to close.
I've tried creating a class module with an Application Level event tracker so that all workbooks' close events are monitored. But my problem is that when I click the close button, the first workbook that tries to close is the hidden workbook. So I can catch the close event and prevent the hidden workbook from closing but if I set Cancel to True, it prevents all the workbooks from closing!
The only workaround I can think of is when the user tries to close a workbook, I cancel the Close Event and Unhide the hidden workbook. But I don't know how to identify which workbook the user was attempting to close - so I can't work out how to automatically close the correct workbook.
I have currently set up the WorkbookBeforeClose event as follows:
Public WithEvents A As Excel.Application
Private Sub A_WorkbookBeforeClose(ByVal Wb As Workbook, Cancel As Boolean)
If Workbooks.Count > 1 Then
If Windows(ThisWorkbook.Name).Visible = False Then
If Wb.Name = ThisWorkbook.Name Then
Cancel = True
End If
End If
End If
End Sub
If I step through this code, I find that the Wb.Name is the name of the Telemarketing Workbook (even though it's hidden) and the name of the workbook that the user is actually trying to close does not appear at all - as far as I can work out.
Can anyone make any further suggestions?
The other thing I should mention is that it needs to work over Excel 2013 and Excel 2010.
I'm sorry to post an answer to my own question so quickly. It sort of indicates I didn't do quite enough research beforehand. However, for anyone who has a similar problem, here's my solution. This code needs to be posted in a class module and an instance of the class needs to be created before it will work, of course.
Note: in the below example, "TT" relates to the Telemarketing Tracker
Public WithEvents A As Excel.Application
Private Sub A_WorkbookBeforeClose(ByVal Wb As Workbook, Cancel As Boolean)
Dim VIS As Boolean, myAW As Workbook
If Workbooks.Count > 1 Then 'if there is more than one workbook open...
If Windows(ThisWorkbook.Name).Visible = False Then 'and if TT is invisible...
If ActiveWorkbook.Name = ThisWorkbook.Name Then 'and if the workbook being closed is the TT.
Windows(ThisWorkbook.Name).Visible = True
Else 'more than one wb open, TT is invisible, and the workbook being closed is NOT the TT.
Set myAW = ActiveWorkbook
Cancel = True
Windows(ThisWorkbook.Name).Visible = True
Application.EnableEvents = False
myAW.Close
Application.EnableEvents = True
If TelesalesForm.HideUnhideButton.Tag = "False" Then 'NB: I use a tag on the Hide/Unhide button on the UserForm to store whether the workbook should be hidden or not.
If Workbooks.Count > 1 Then
Windows(ThisWorkbook.Name).Visible = False
Else
ThisWorkbook.Application.Visible = False
End If
End If
Exit Sub
End If
ElseIf ActiveWorkbook.Name <> ThisWorkbook.Name Then
'more than one workbook open and the TT is visible and the workbook being closed is NOT the TT
Exit Sub
End If
End If
'code gets to this point ONLY under the following circumstances:
'There is only one workbook open (i.e. the TT) OR
'There is more than one WB open and the WB being closed is the TT.
'The rest of the code goes here for managing the closing of the TT.
End Sub
If anyone thinks of any other embellishments or improvements to the code then I would be very glad to hear of them!