Input box with another single option in VBA - vba

I have a simple inputBox to enter the ID of an employee:
id = InputBox("Enter ID NUMBER of the employee")
If id = "" Or Not IsNumeric(id) Then
MsgBox "No ID entered"
Call prepareToExit
Exit Sub
End If
Until now it was sufficient for me but now I need to be able to enter another parameter in the dialog box which will represent whether the user will use the default settings of the program or want to enter another menu to choose options (for example to change the default folder to user difined).
Can somebody explain how to add this single option in the input box.
I understood that it cannot be done with InputBox method.
All I need is another button like "Advanced..." to know if the user wants to go to additional settings.
Thanks!

Three options come to mind:
1. Use a tailored userform
2. Add another msgbox to ask about the extra option (yes/no)
3. Include the option in the entered string. This is rather simple here, but for such things, regular expressions can be very useful. It kind of depends on your target audience if this may seem too 'cryptical' for some users.
An example:
Dim rx, rxM
Dim ID As String
Dim IDvalue As Long
Dim optionFlag As Boolean
Set rx = CreateObject("vbscript.regexp")
rx.Pattern = "^(\d+)(\+)?$"
ID = InputBox("Enter ID NUMBER of the employee" & vbCrLf & _
"Add '+' for advanced options, e. g. 100345+")
If Not rx.test(ID) Then
'If ID = "" Or Not IsNumeric(ID) Then
MsgBox "No ID entered"
Call prepareToExit
Exit Sub
Else
Set rxM = rx.Execute(ID)
IDvalue = CLng(rxM(0).submatches(0))
optionFlag = (rxM(0).submatches(1) = "+")
MsgBox IDvalue & vbCrLf & optionFlag
End If

Related

MS Word VBA Macro from validation

I'm trying to do what, I think, ought to be the simplest of things, but I can't get it to work. i have an MS Word document with a number of legacy drop-down and text fields:
The first option in each drop-down is "Select ...", and if a user tabs out of one of the drop-downs without choosing something other than the first "Select ...", I want a msgbox to appear to tell them to make a selection, which works. What doesn't work, is that after the user dismisses the msgbox, I want the insertion point to return to the drop-down that they didn't select.
I understand that VBA has "timing issues", and from what I've read, one way to address these timing issues is to call the "return" macro from the validation macro. So I've written two macros:
Sub Validate()
' Dim strBookmark As String
' strBookmark = Selection.Bookmarks(1).Name
10: If (bool_debug) Then MsgBox ("NotSelected() - 10: strBookmark = " & strBookmark)
With ActiveDocument
If (strBookmark = "Locality") Then
Call Salary_Step
ElseIf (strBookmark = "Series") Then
20: If (bool_debug) Then MsgBox ("NotSelected() - 20: .FormFields(strBookmark).Name = " _
& .FormFields(strBookmark).Name)
If ((Len(.FormFields(strBookmark).Result) <> 4) Or (Not IsNumeric(.FormFields(strBookmark).Result))) Then _
MsgBox ("Please enter a 4 digit number.")
Call GoBackToPrevious(.FormFields(strBookmark).Name)
ElseIf (.FormFields(strBookmark).DropDown.Value = 1) Then
MsgBox ("Please select a " & Replace(Selection.FormFields(strBookmark).Name, "_", " ") & ".")
Call GoBackToPrevious(.FormFields(strBookmark).Name)
End If
End With
End Sub
and
Sub GoBackToPrevious(strPreviousField)
10: If (bool_debug) Then MsgBox ("GoBacktoPrevious - 10: strPreviousField = " & strPreviousField)
ActiveDocument.Bookmarks(strPreviousField).Range.Fields(1).Result.Select
End Sub
But when I tab out of any of the form fields, the insertion point jumps to the next form field and not back to the one that I just tabbed out of.
I know from the debug code that GoBackToPrevious is being passed the name of the current form field, but MS Word advances to the next field regardless.
I'd really appreciate it if someone can tell me how make MS Word return to and select the drop-down the user did not select appropriately instead of jumping to and selecting the next form field in the document.
Thank you.
P James Norris
EDIT:
Based on #TimothyRylatt comments, I have modified my macro and when they're called.
I have edited Validate as above (commenting out the Dim the strBookmark assignment, and I call it "on entry" to the next form field.
strBookmark is Dimed on the module's declaration section:
Option Explicit
Const bool_debug As Boolean = True
Const str_password As String = "###" ' I have a different password
Public strBookmark As String
and "on exit" from the "current" form field, I attempt to store the "current" bookmark name:
Sub StoreBookmark()
strBookmark = Selection.Bookmarks(1).Name
10: If (bool_debug) Then MsgBox ("StoreBookmark() - 10: strBookmark = " & strBookmark)
End Sub
which I call from the current form field "on exit".
But when I tab out of the current form field to the next form field, the insertion point doesn't go back to the "current" but instead stays in the next form field.
Anyone have any other suggestions/insights?
Thanks,
P James Norris

Catia V5 Macro: Incomplete renaming function

I've been dealing with this a while and even had help but i can't work it out.
The following macro renames PartName or InstanceName depending on user and CADSelection.
Problem is it's not working in PartName alteration.
Can someone help me complete this macro? and ideally explain what i did incorrectly?
Sub CATMain()
If CATIA.Documents.Count = 0 Then
MsgBox "There are no CATIA documents open. Please open a CATIA document and try again.", ,msgboxtext
Exit Sub
End If
If InStr(CATIA.ActiveDocument.Name, ".CATProduct") < 1 Then
MsgBox "The active document is not a Product. Please open a CATIA Product and try again.", ,msgboxtext
Exit Sub
End If
Dim oSelection As Selection
Set oSelection = CATIA.ActiveDocument.Selection
If oSelection.Count < 1 then
MsgBox "Pick some components using cad selection."
Else
'****** Alter Instance Name *****'
Dim msg
msg = MsgBox ("Click ""Yes"" to change Instance Name, ""No"" to change Part Name or ""Cancel"" to exit", _
vbYesNoCancel, "Renaming Tool")
if vbYes = msg then
'****** Inputbox for Instance name alteration *****
Dim NewIName As String
NewIName = InputBox("Please input the desired Instance Name. Example: E","Instance name alteration","E")
'****** Inputbox for Instance number alteration *****
Dim NewINumber As Integer
NewINumber = InputBox("Please input the initial number for the 1st component. Example: 1","Instance numbering alteration","1")
Dim oIBody
Dim InstName As Body
For oIBody = 1 to oSelection.Count
Set InstName = oSelection.Item(oIBody).Value
'****** Instance name alteration *****
InstName.Parent.Parent.ReferenceProduct.Products.Item( _
InstName.Name).Name= NewIName + CStr(NewINumber)
NewINumber=NewINumber+1
Next
elseif vbNo = msg then
'****** Inputbox for Part name alteration *****
Dim NewPName As String
NewPName = InputBox("Please input the desired Part Name. Example: E","Part Name alteration","E")
'****** Inputbox for Part number alteration *****
Dim NewPNumber As Integer
NewPNumber = InputBox("Please input the initial number for the 1st Component. Example: 1","Part numbering alteration","1")
Dim oPBody
Dim PartName As Body
For oPBody = 1 to oSelection.Count
Set PartName = oSelection.Item(oPBody).Value
'****** Part name alteration *****
PartName.ReferenceProduct.Name= NewPName + CStr(NewPNumber)
NewPNumber=NewPNumber+1
Next
End If
End If
oSelection.Clear
End Sub
The part "name" is really the Part Number and is changed using the "PartNumber" property.
So try changing
PartName.ReferenceProduct.Name= NewPName + CStr(NewPNumber)
to
PartName.ReferenceProduct.PartNumber= NewPName + CStr(NewPNumber)
This doesn't influence the document name unless you have not saved your part already.
What else :
1) Your variable naming is confusing. You call the Product "InstName" in one place and "PartName" in another. At first glance I thought those were strings. Using oProduct would be less confusing.
2) You seem real confident that the user has pre-selected the correct types. Since you are selecting in an assembly, instead of using Selection.Item(i).Value, you can use Selection.item(i).LeafProduct which will always be the instance product of whatever object is selected. Even if the user picks a surface, it will return the instance product which contains the selected surface.

VBA Excel - run string variable as a line of code

In the aim to allow users from different countries to use my application, I would like to initialize a translation of each object in each existing userform (labels,commandbuttons,msgbox,frames, etc...) at the start of the application.
I'll write all the translation in my Languages sheet:
I've already made a first userform where the user types his login, password and selects his language.
After this step, the main userform called "Menu" will be launched.
I've already tried to type a piece of code (here below) to find the line of code, in a msgbox that I want to run (example : menu.commandbutton1.caption="Envoyer email")
Private Sub UserForm_Initialize()
' Definition of language selected during login
Set langue = Sheets("Languages").Cells.Find("chosen",
lookat:=xlWhole).Offset(-1, 0)
' Initialisation of the texts in the selected language
Dim cel As Range
Dim action As String
For Each cel In Sheets("Languages").Range("d3:d999")
If cel <> "" Then
action = cel & "=" & """" & cel.Offset(0, -2) & """"
MsgBox (action)
End If
Next cel
End Sub
I've already read some topics about this subject but those does not correspond exactly to what i would like to do.
If you have a solution, or a work around, it would be very helpful.
If you simply want different MsgBox, based on a coutry, this is probably the easiest way to achieve it. Imagine your file is like this:
Then something as easy as this would allow you to use different strings, based on the country:
Public Sub TestMe()
Dim country As String
Dim language As Long
country = "Bulgaria" 'or write "England" to see the difference
language = WorksheetFunction.Match(country, Range("A1:B1"), 0)
MsgBox (Cells(2, language))
MsgBox "The capital of " & country & " is " & (Cells(3, language))
End Sub
The idea of the whole trick is simply to pass the correct column, which is done through WorksheetFunction.Match.
Taken from an old CR post I have here, this solution pretty much mimicks .NET .resx resource files, and you can easily see how to extend it to other languages, and if I were to write it today I'd probably use Index+Match lookups instead of that rather inefficient loop - but anyway it works nicely:
Resources standard module
Option Explicit
Public Enum Culture
EN_US = 1033
EN_UK = 2057
EN_CA = 4105
FR_FR = 1036
FR_CA = 3084
End Enum
Private resourceSheet As Worksheet
Public Sub Initialize()
Dim languageCode As String
Select Case Application.LanguageSettings.LanguageID(msoLanguageIDUI)
Case Culture.EN_CA, Culture.EN_UK, Culture.EN_US:
languageCode = "EN"
Case Culture.FR_CA, Culture.FR_FR:
languageCode = "FR"
Case Else:
languageCode = "EN"
End Select
Set resourceSheet = Worksheets("Resources." & languageCode)
End Sub
Public Function GetResourceString(ByVal resourceName As String) As String
Dim resxTable As ListObject
If resourceSheet Is Nothing Then Initialize
Set resxTable = resourceSheet.ListObjects(1)
Dim i As Long
For i = 1 To resxTable.ListRows.Count
Dim lookup As String
lookup = resxTable.Range(i + 1, 1)
If lookup = resourceName Then
GetResourceString = resxTable.Range(i + 1, 2)
Exit Function
End If
Next
End Function
The idea is, similar to .NET .resx files, to have one worksheet per language, named e.g. Resources.EN and Resources.FR.
Each sheet contains a single ListObject / "table", and can (should) be hidden. The columns are basically Key and Value, so your data would look like this on sheet Resources.EN:
Key Value
menu.caption Menu
menu.commandbutton1.caption Send email
menu.commandbutton1.controltiptext Click to send the document
And the Resources.FR sheet would have a similar table, with identical keys and language-specific values.
I'd warmly recommend to use more descriptive names though; e.g. instead of menu.commandbutton1.caption, I'd call it SendMailButtonText, and instead of menu.commandbutton1.controltiptext, I'd call it SendMailButtonTooltip. And if your button is actually named CommandButton1, go ahead and name it SendMailButton - and thank yourself later.
Your code can then "localize" your UI like this:
SendMailButton.Caption = GetResourceString("SendMailButtonText")
The Resources.Initialize procedure takes care of knowing which resource sheet to use, based on Application.LanguageSettings.LanguageID(msoLanguageIDUI) - and falls back to EN, so if a user has an unsupported language, you're still showing something.

Ammend code to include drop down selection instead of type-in prompt

I have the following code which prompts the user which open file/window to switch to. I am using this to get around the fact the name of my dependent data file is changing on a daily basis. The following code works. However, instead of asking in the prompt box to type the name of the file to switch to, I would like for it to recognize the open files and give me a drop down or some sort of selection to choose from to just select the file I want to switch to.
Anybody know how to do that?
Sub switch()
Dim i As Integer
Dim n As Integer
Dim s As String
Dim t As Variant
n = Windows.Count
s = "Pick From:"
For i = 1 To n
s = s & Chr(10) & Windows(i).Caption
Next
t = Application.InputBox(prompt:=s, Type:=2)
If t = False Then
Exit Sub
End If
Windows(t).Activate
End Sub

Debugging "Search for Name" Code in VBA

I have solid experience in C++ but am still getting used to the syntax of VBA and I think that's what's tripping me up in my code.
What I'm trying to do is have a button that asks the user for a name. If the name entered is in column B, then tell the user the name was found and select where it is (no problem with this). If the name is not found, then ask if the user wants to try another name (no problem with this, either).
Where I'm having trouble is with the "Cancel" buttons. At any time, I want the user to be able to hit "Cancel" and immediately stop the loop, but stay in the sub because I'll be adding to this later.
Here's the code:
Dim inputName As String
Dim row As Integer
Dim i As Integer
Dim tryAgainResponse As Integer
tryAgainResponse = vbOK
'Ask user for name they would like to replace'
inputName = InputBox("What is the name of the person you would like to find? (First Last)")
'Find the row that the name is located and tell the user where it is'
Do While tryAgainResponse = vbOK
For i = 1 To 1000
If Cells(i, 2).Value = inputName Then
MsgBox ("Found the name! It's located at cell B" & i & ".")
ActiveSheet.Cells(i, 2).Select
tryAgainResponse = 0
Exit Do
End If
Next i
tryAgainResponse = MsgBox("We didn't find the name you were looking for. Please try again.", vbOKCancel)
If tryAgainResponse = vbCancel Then
Exit Do
End If
inputName = InputBox("What is the name of the person you would like to find? (First Last)")
Loop
I've tried plenty of things, but the main error is when you hit cancel for the first MsgBox, it tells you the name was found in the first blank square.
Any help or suggestions would be greatly appreciated! This is my first VBA program, so it's not the prettiest, but it's definitely a lot of fun. Thanks!
I'm not sure if I'm understanding what you're asking for, and I can't comment for clarification, but I think your hang up is that when you click cancel on the INPUT box, your input box is returning a blank string, and the rest of your code is then finding a blank cell.
Use the Application.Input Method, declare your input string as a variant, and test if it is false. If it is, use an Exit Sub to exit the macro. You could also test if your input string = "" and then exit the macro if true with the code you have.
From MrExcel
There are 2 versions of InputBox in VBA.
The InputBox Function is called without an object qualifiier and returns the contents of the text box or a zero-length string ("") if the user clicks Cancel.
The InputBox Method is a member of the Application object, so it is called by using Application.InputBox. It returns the contents of the text box or False if the user clicks Cancel. It is more versatile than the InputBox Function because it has a Type argument which specifies the return data type.
The function InputBox() will return an empty string if cancelled. The empty string will compare equal to the first cell that is empty.
Here's the doc of the function: http://msdn.microsoft.com/en-us/library/6z0ak68w(v=vs.90).aspx