EXCEL VBA regarding functions & userforms - vba

I am new in Excel VBA programming therefore I've met a few difficulties within my very own project.
Long story short, I have 10 UserForm(s), and 10 TextBox(s) in each UserForm with the same TextBox name.
Is it possible for me to create a function that I can call it in every UserForm so that I don't have to manually code it for every UserForm(s). Regarding the function, it will reset the value of TextBox, as well as bring it back to the 'initial' state.
That's all for my question. Any help would be highly appreciate.Thanks in advance.

Create a Sub in a Module that you call from each form
eg
Sub TextBoxInit(tb As MSForms.TextBox)
tb.Text = ""
End Sub
Call it in each UserForm as you see fit
eg
Private Sub Userform_Initialize()
Module1.TextBoxInit TextBox1
End Sub

Tan,
You should think about making use of Class Modules. I actually just learned about them recently, and they are a very effective way to manage multiple userforms with similarly constructed controls.
Go Here: VBA USERFORM: PREVENT COMBOBOX ESCAPE ON KEYDOWN
Or Here: EXCEL VBA: dblClick, Repetitive Code Improvement
The basics of how these Class Modules work is that you create your own object, you write the code for it, and you assign your desired userform controls as that object type (class). For instance, if you had 20 textboxes which performed the same way (they rebooted their own values), you would just write that identical code in the class module section. Bam! That's pretty much it (you'd also have to write a paragraph of code to loop through & assign which textboxes you'd want this functionality for).
It might take a while to understand, but it will significantly improve your project.

Related

Detect Button Press Event on an Excel Sheet MultiPage Form (NOT a VBA MultiPage)

I am struggling to figure out how to detect a button press event on a MultiPage form that resides directly on an Excel sheet. In other words, the form is not generated using VBA, it is built directly on the sheet.
I expect the syntax to be something like:
Private Sub MultiPage1_Frame1_CommandButton1_Click()
Do Stuff
End Sub
However, that doesn't work because I think I also need to specify the page in the MultiPage. For example, a text box on the same form can be accessed via:
MultiPage1.Pages(0).Frame1.TextBox1.Text = "Some Text"
Unfortunately,
Private Sub MultiPage1_Pages(0)_Frame1_CommandButton1_Click()
gives a Compile error: Expected: identifier with the zero inside (0) selected.
So, how do I convert
MultiPage1.Pages(0).Frame1.CommandButton1
to a Sub name that will detect the button press event?
Thank you!
I'm not sure but I think you may have stumbled onto a bug.
There is a Microsoft Forms 2.0 Control under More Controls, but I'm pretty sure it's only intended only for use on UserForms.
I tried adding it to a worksheet and got an error. However, once I added one to a UserForm and went back to the worksheet, I was able to add it... but things got "glitchy" for moment, and when I opened the Properties dialog for the bod, the font was poorly rendered.
All the documentation that I looked at (like this, this and this) only have examples of it being used on a UserForm, or in Outlook.
There are many types of ActiveX controls, and not all of them can be used anywhere. As a rule of thumb in Excel, it's best to stick to the controls that are built-in.
Also, from another forum:
Q: It seems that I could not find and add Multipage control into worksheet.
How to add a Multipage control to Excel worksheet?
A: Unless you put it on a UserForm first, you can't display it on a Worksheet. The UserForm provides the user interface to VBA. The MultiPagecontrol is designed to work with this user interface, and not the Excel Worksheet. Is there a problem using the UserForm to display the MutliPage control? Source: Leith Ross
This evidence combined tells me, even if you can get it to work, you shouldn't. There's no predicting how it will behave.
In case you decide to use a MultiPage on a UserForm, note that in your example above, MultiPage1 is the name of the control; that's not referring to "page 1". The control as a whole has a Click event which is not specific to a page:
Private Sub MultiPage1_Click(ByVal Index As Long)
For the sake of completeness, I'll paste in a complete code sample but once again: this is not recommended for a worksheet-based control.
How to: Access a Page in a MultiPage Control
The following example accesses an individual page of a MultiPage in several ways:
Using the Pages collection with a numeric index.
Using the name of the individual page in the MultiPage.
Using the SelectedItem property.
To use this example, copy this sample code to the Script Editor of a form. Make sure that the form contains a MultiPage named MultiPage1 and a CommandButton named CommandButton1.
Sub CommandButton1_Click()
Dim PageName
Set MultiPage1 = Item.GetInspector.ModifiedFormPages("P.2").MultiPage1
For i = 0 To MultiPage1.Count - 1
'Use index (numeric or string)
MsgBox "MultiPage1.Pages(i).Caption = " & MultiPage1.Pages(i).Caption
MsgBox "MultiPage1.Pages.Item(i).Caption = " & _
MultiPage1.Pages.Item(i).Caption
'Use Page object without referring to Pages collection
If i = 0 Then
MsgBox "MultiPage1.Page1.Caption = " & MultiPage1.Page1.Caption
ElseIf i = 1 Then
MsgBox "MultiPage1.Page2.Caption = " & MultiPage1.Page2.Caption
End If
'Use SelectedItem Property
MultiPage1.Value = i
MsgBox "MultiPage1.SelectedItem.Caption = " & _
MultiPage1.SelectedItem.Caption
Next
End Sub
(Source)
Now I'm going to delete that buggy worksheet and reboot; I'd suggest you do the same!
Mikerickson and Jaafar Tribak on MrExcel.com figured it out:
https://www.mrexcel.com/forum/excel-questions/1054446-detect-button-press-event-excel-sheet-multipage-form-not-vba-userform-multipage-2.html
Big thanks to both of them!

Excel VBA - Remember Last Userform Textbox Cursor Focus

I have 10 text boxes on an Excel VBA Userform, and when I switch away from the window (say, to do other work in a different program) and come back, I want the focus to be on the textbox I was last using.
I think this should be an obvious question to an experienced person, but I can't find a well-asked question about this topic anywhere. If anyone can direct me to a proper answer, give me a searchable topic, or a good piece of code, that would be golden. I'm a sponge, I'll take anything.
Thank you!
-Chris
Cursor focus is not an event in VBA, thus it is a bit tough to do it. BUT you can use the _Change event and remember the last changed Textbox, which is quite close to you want.
You need a public variable in a module, for the name of the last changed TextBox. Thus, the next time the Form is activated, you may use a simple select case and use .SetFocus to the corresponding name of the form. The code below works with two TextBoxes.
In the form:
Option Explicit
Private Sub TextBox1_Change()
strLastTb = "TextBox1"
End Sub
Private Sub TextBox2_Change()
strLastTb = "TextBox2"
End Sub
Private Sub UserForm_Activate()
Select Case strLastTb
Case "TextBox1"
TextBox1.SetFocus
Case "TextBox2"
TextBox2.SetFocus
End Select
End Sub
In a module:
Option Explicit
Public strLastTb As String
In general, you may create a function that concatenates TextBox&Digit, so you will not be required to write 100s lines if you have 50 TextBoxes. And it would be looking better.

Keeping ComboBox Lists Populated

I have created a Word 2010 VBA Macro Sub with a UserForm. The Sub searches for ==Codes== in a form document, places the found ==code== as a label into the Userform and then allows the user to replace the ==code== with his or her input in the Combobox (part of the same UserForm).
Each string of inputted data is then saved to the Combobox list in the UserForm for later selection if needed.
This works fine until this Macro/Userform expires because a searched document is completed (or cancelled).
I would then like to open the next form document, and in the new launch of this same Macro/Sub retain the former combobox list of data (as options to fill this next opened document - for instance, the code ==Client Name== will come up frequently, and I'd rather select a combobox list entry rather than having to type the client name over and over)
But I can't seem to keep the combobox list in the new launch of this Macro Sub populated with the previous combobox data - even if I isolate this routine as a separate module and pre-define the variables with "Public" dimensions.
So, before I knock myself out trying to figure this out ... just a simple question:
Once a Macro terminates are all of the Public variables "dropped"? When I used to program in DOS WP.51 Macros you could keep data strings in the RAM endlessly (until you "killed" them, or closed WP)
If the Public variable are not "dropped", could someone give me a sample of code by which Public variables could be retained and populated into a duplicately launched combobox userform.
Any ideas, howsoever brief, would help
Thanks much in advance. . .
Mike
Not entirely sure what you're trying to do, but what I'd recommend is the following (Assuming that the form is named, "UserForm1" and then "UserForm2":
1) Create a Module that you use to open the form using:
Sub test()
UserForm1.Show
'Rest of things that you want to do...you will be able to access the values in your combobox in userform1
UserForm2.Show
End Sub
2) In your UserForm1, include a button that will close the form and include the following code:
Sub btn_Exit_Click()
Me.Hide
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = 0 Then
Cancel = True
MsgBox "The X is disabled, please use a button on the form.", vbCritical
End If
End Sub
This will allow you to maintain control of the UserForm and ensure that you can keep the values. It may be possible to disable the Closing button, but I wasn't able to figure it out (my experience with forms is mostly in Access and those have different properties).
Hiding the form keeps the values so that you can look at them whereas when the user closes the form you lose the values that were in it.
*Note: Code to disable the X button taken from VBA Express

Running Macros from Toolbar/Running one macro from another

I am trying to develop a macro for a publisher document. This macro will, when run, show a pop-up allowing the user to select one of three types of clients, and add different bullet points to a text box depending on which option was selected. I'm having two different problems which I suspect are coming from the same source. Problem number one is that I can't get the button on my User Form to run a different macro when the button is clicked. Problem two is that I've added my macros to one of the toolbars, and nothing happens when I click on them. In both cases, it's simply not running the macro. What am I doing wrong?
UserForm1
Private Sub CommandButton1_Click()
Application.Run ("ShapeTest")
End Sub
Private Sub UserForm_Initialize()
With ListBox1
.AddItem ("Federal")
.AddItem ("State")
.AddItem ("Local")
End With
End Sub
ThisDocument
Private Sub GenerateStatement()
UserForm1.Show
End Sub
Private Sub ShapeTest()
MsgBox ("Hello!")
Application.ActiveDocument.Pages(1).Shapes(1).TextFrame.TextRange.InsertAfter`enter code here`(Chr(13) & "My Text")
End Sub
Why are you using Application.Run("ShapeTest") rather than simply ShapeTest?
I don't have enough information to be 100% sure, but the following should work: To make ShapeTest callable from the userform you do two things:
1) Move it from ThisDocument to a general code module (first Insert/Module in the editor).
2) Eliminate the word Private in front of Sub ShapeTest()-- you don't want this to be a private sub since you want code outside of the module to be able to use it.
On edit: Alternatively -- you could keep ShapeTest() where it is in ThisDocument, get rid of the Private qualifier and in the userform code refer to ShapeTest as ThisDocument.ShapeTest. I prefer using the first method since I tend to like to keep as much code as possible in general code modules (reserving things like ThisDocument for event handlers) but OTOH my VBA experience is mostly Excel with a smattering of Word and there might be reasons to keep the code in ThisDocument in Publisher. I don't know Publisher, but a problem that I have run into in Word at times is I have sometimes accidentally put code in the Normal template that I wanted to go in the document's project. If something similar is possible in Publisher you should double check where your code is living.

Macro Fails, 'The macro may not be available in this...'

Hello and thank you in advance for your assistance.
I have some code that I admittedly borrowed from a site. It changes the sheet that is being displayed every X seconds. In my case 3 seconds. When I run it it will change to the next sheet one time and then error out after the 3 seconds.
The error I receive is "Cannot run the macro "C:\users\BenjaminSmith\Desktop\Book1.xlsm'!displaysheets'. The Macro may not be available in this workbook or all macros may be disabled."
Here is the code for my Macro
Sub displaysheets()
ShtNum = ActiveSheet.Index
ShtNum = ShtNum + 1
If ShtNum > Sheets.Count Then
ShtNum = 1
End If
Sheets(ShtNum).Activate
Application.OnTime Now + TimeValue("00:00:03"), "displaysheets"
End Sub
If I remove the line
Application.OnTime Now + TimeValue("00:00:03"), "displaysheets"
I can run the macro over and over and there are no issues. Other than the fact it doesn't continue on its own...
The spreadsheet is an XLSM.
MS VBA is 7.0.
Excel is 2010.
I am thinking maybe the issue is because the code is recursive?
Thanks for your suggestions.
Further from the comments...
The code didn't work because you didn't paste the code in a module. This is a very common mistake among new programmers. In such a case, Excel is unable to find the code as it searches the module.
#Siddharth Rout I had the code in 'ThisWorkbook' I inserted a module 'Module1' and moved the code there and everything works as expected. What is the difference with these two places?
I would recommend going through Chip Pearson's link HERE
Extract from the link if the link ever rots.
Standard Code Modules, also called simply Code Modules or just
Modules, are where you put most of your VBA code. Your basic macros
and your custom function (User Defined Functions) should be in these
modules. For the novice programmer, all your code will be in standard
modules. In addition to your basic procedures, the code modules
should contain any Declare statements to external functions (Windows
APIs or other DLLs), and custom Data Structures defined with the Type
statement.
Your workbook's VBA Project can contain as many standard code modules
as you want. This makes it easy to split your procedure into
different modules for organization and ease of maintenance. For
example, you could put all your database procedures in a module named
DataBase, and all your mathematical procedures in another module
called Math. As long as a procedure isn't declared with the Private
keyword, or the module isn't marked as private, you can call any
procedure in any module from any other module without doing anything
special.
Workbook And Sheet Modules are special modules tied directly to the
Workbook object and to each Sheet object. The module for the
workbook is called ThisWorkbook, and each Sheet module has the same
name as the sheet that it is part of. These modules should contain
the event procedures for the object, and that's all. If you put the
event procedures in a standard code module, Excel won't find them, so
they won't be executed. And if you put ordinary procedures in a
workbook or sheet module, you won't be able to call them without fully
qualifying the reference.
User Form Modules are part of the UserForm object, and contain the
event procedures for the controls on that form. For example, the
Click event for a command button on a UserForm is stored in that
UserForm's code module. Like workbook and sheet modules, you should
put only event procedures for the UserForm controls in this module.
Class Modules are used to create new objects. Class modules aren't
discussed here, except to say that a class module is used to handle
Application Event Procedures.
Try : (i use this code)
With Application
.EnableEvents = True 'needed
.OnTime EarliestTime:=Now + TimeSerial(0, 0, 3), Procedure:="displaysheets", Schedule:=True
End With
Try to put your timer in a global variable and add it each time you run the function, also configure OnTime to be schedulable
Global tmrTimer1
Sub displaysheets()
tmrTimer1 = Now + TimeValue("00:00:03")
'Enable the schedule
Application.OnTime tmrTimer1 , "displaysheets", , True
End Sub