Updating Word Form Field - vba

I have a Word form that I am working on.
It has one field that is supposed to be calculated from other fields.
In the prior iteration, you could click the cell in the table and hit F9 and the field would update.
I have since added some other buttons and VBA and now you can no longer click the cell when "Restrict Editing" is on.
I have tried a button tied to VBA that will update all fields, but when you click that button, you cannot edit any of the fields.
How can I update this field, and still be able to manually update my other fields?

The problem was that Content Controls and ActiveX buttons are not altogether compatible. Also, the programmer I had inherited the form from was using a simple field calculation based on the table in the document instead of VBA. I was able to come up with a better solution. I used the sub:
Private Sub Document_ContentControlOnExit(ByVal thisControl As ContentControl, Cancel As Boolean)
End Sub
to execute code onExit from the controls. This function executes on ALL Content Controls as the user exits the Content Control. Another tool I developed was the following function which will find the index of the control with the given title:
'Function to get control index given the control title
'PARAMETER Control Title as String
'RETURN Control Index as Integer
Public Function GetControlIndex(ccTitle As String) As Integer
'Function Variable Declaration
Dim objCC As ContentControl
'look at each ContentControl
For i = 1 To ActiveDocument.ContentControls.count
Set objCC = ActiveDocument.ContentControls.Item(i)
With objCC
If .Title = ccTitle Then
GetControlIndex = i
End If
End With
Next i
End Function

Related

How to add userform into this code instead of msgbox?

I currently have this code
Private Sub Worksheet_Change(ByVal Target As Range)
Dim myCell As Range
For Each myCell In Range("G4:G160")
If (Not IsEmpty(myCell)) And myCell.Value <> 17521 And myCell.Value <> "" Then
DisplayUserForm
Exit Sub
End If
Next myCell
End Sub
and have this for my userform
Sub DisplayUserForm()
Dim form As New WarningBox
form.LOL.Caption = "INCORRECT!"
form.Show
Set form = Nothing
End Sub
What else must I do in order for this to appear instead of msgbox to alert whoever is entering data will be showing "INCORRECT!" in bold and Surrounded by red.
Please see image below of what I am trying to show
Please follow these steps:
Insert a new Form by right-clicking on your VBA project and selecting UserForm under the Insert option.
Click once on the created form and then press the ``F4key to open theProperties``` window.
On the Properties window, the default name for your form is UserForm1. Change it to any new value as you want (e.g., WarningBox)
From the ToolBox window, drag and drop a Label on your form and adjust its size, font, font color, and all other properties that exist on the Properties window. Please rename the label to message. I will use this name later when calling the form to be shown.
If you want, like step 4, add a CommandButton to your form and change its name to for example okButton and adjust other properties as you want.
Double click on the button to write the code for this button. Write the code as follows:
Private Sub okButton_Click()
'Close the form
Unload Me
End Sub
Now, modify your DisplayUserForm() sub as follows:
Sub DisplayUserForm()
Dim form As New warningBox
form.message.Caption = "write your message here"
form.Show
Set form = Nothing
End Sub
All will be done as you want!
Marc: if your "Incorrect" message is the "LOL" object whose caption you modify with the code form.LOL.Caption = "INCORRECT!", it will be editable if it is a TextBox object. Saeed Sayyadipour's example shows using a Label object, instead, that will not be editable by the user (and I 'second' his advice about the "OK" button).
Also, though, since the event tells you which cells were changed by defining the "Target" range object, do you really need to loop through all of G4:G160, since only the cells within Target were changed by the user? Perhaps use For Each MyCell in Intersect(Target,Range("G4:G160")), or perhaps add these lines where appropriate:
Dim AffectedCells as Range
...
Set AffectedCells=Intersect(Target,Range("G4:G160"))
...
Set AffectedCells=Nothing
and change your loop to:
For Each myCell in AffectedCells
...
Next myCell
If there is no overlap between the changed range (Target) and your G4:G160, nothing happens and your code exits quickly.

VBA How to programaticly select an item in a listbox without triggering the on click event

I am using Excel 2010, Windows 10, with VBA. I have a function which runs upon clicking an item in an ActiveX ListBox control. The issue is that if you click the list box I ask if they are sure if they want to change the selection. If you click "yes" I continue, but if you say "no" I set the selection back to what it previously was.
So the issue is that when I programmatically set the list box selection back to the previous selection my function will re-run the code that runs if a user clicks an item in the list box ...which is what I don't want.
Does anyone have a better way to stop a list box selection and change it back to the old one without causing the on list box selection event to trigger?
Function prototype for on click of the list box
lsQuestions_Click()
Code for setting the list box selection
'Prototype: setListBoxSelection(query As String, listBoxName As String) As Boolean
' Purpose: Set listbox selection based on text
Public Function setListBoxSelection(query As String, listBoxName As String) As Boolean
Dim lsBox As MSForms.listBox
Set lsBox = Workbooks(mainFile).Worksheets(entrySheet).OLEObjects(listBoxName).Object
Dim I As Integer
For I = 0 To lsBox.ListCount - 1
If lsBox.List(I) = query Then
lsBox.Selected(I) = True
setListBoxSelection = True
Exit Function
End If
Next I
setListBoxSelection = False
End Function
Please note that I think the line of code below is what is triggering my click event which is what I don't want.
lsBox.Selected(I) = True
The way I do this with my VB6 projects is to define a module-scope variable
Private blnChangingInCode As Boolean
Then, when I need to utilize it, I set it to true, call the even/sub, set it back to false.
blnChangingInCode = True
btnLogin_Click()
blnChangingInCode = False
Inside the affected subs/events I start with
If blnChangingInCode Then
Exit Sub ' or Exit Function
End if
This might not be elegant, but it works, and I don't need to do it very often.

Get editbox value on "Return in Excel ribbon with VBA

My first question here.
I'm trying to add a custom search field in Excel ribbon. My problem with the usual research : its default range is "this worksheet" whereas I'd want the whole Workbook (or even other known workbooks).
So I created an editbox in the ribbon. I use "onChange" to validate my input and trigger my custom research sub.
But I'd prefer it to be triggered only when I press "Enter" key on my keyboard, or give focus to another ribbon button (a button "search" wich would trigger the research sub with my editbox value, and wich would be activated when pressing Return while focus is still on editbox.
My other problem is that leaving the field also triggers the sub (onChange is activated when leaving) ; it doesn't trigger the event if editbox has not been changed ; and I can't catch the "Enter pressed" action.
Are there ways to solve what I'm trying to do ?
If not, is there a way to call the native search function with "workbook" range as default range, instead of "this worksheet"?
Thank you for help.
JP
What I did in the end (I just need to scan the first column):
an editbox in the ribbon wich updates a variable whose range is my module.
a "Go" button in the ribbon, wich launches the research of the string stored in the variable.
The code I used (for sure that's simple, but may help other beginners such as me):
Private nomPatientRecherche As String
Public Sub RecherchePatient(control As IRibbonControl)
Dim feuille As Worksheet, zone As Range, cellule As Range
For Each feuille In ThisWorkbook.Worksheets
feuille.Activate
Set zone = feuille.Range("A2:A" & ActiveSheet.UsedRange.SpecialCells(xlCellTypeLastCell).Row)
For Each cellule In zone
If Not cellule.Find(nomPatientRecherche) Is Nothing Then
cellule.Activate
If Not MsgBox("Continuer ?", vbOKCancel, "Continuer ?") = vbOK Then
Exit Sub
End If
End If
Next cellule
Next feuille
End Sub
Public Sub DefineNomPatientRecherche(control As IRibbonControl, nom As String)
nomPatientRecherche = nom
End Sub
Thanks again #Rory for your help

VBA: Code not running after ToggleFormsDesign

I have the following code in VBA (MS Word), that is meant to run after I click in a button, named cmdFormPreencher inserted in my Document:
Private Sub cmdFormPreencher_Click()
'
If ActiveDocument.FormsDesign = False Then
ActiveDocument.ToggleFormsDesign
End If
'
ThisDocument.cmdFormPreencher.Select
ThisDocument.cmdFormPreencher.Delete
ActiveDocument.ToggleFormsDesign
'
UserForm2.Show
End Sub
The purpose of the code above is to delete that button inserted in my document.
But when I run the code only the button is selected. When I tried to figure out what is happening by debugging, it showed me the code runs until ActiveDocument.ToggleFormsDesign and not running the code remaining
Is this a bug of VBA, or am I doing something wrong? If so, how can I get around this problem?
Thanks!
Note: The ActiveX button is not in Header and Footer. The Text Wrap is set to In Front of Text
Edit:
When I try to run a macro, activating FormDesign, Selecting the ActiveX button and then deleting, I get this code:
Sub Macro1()
'
' Macro1 Macro
'
'
ActiveDocument.ToggleFormsDesign
ActiveDocument.Shapes("Control 52").Select
Selection.ShapeRange.Delete
ActiveDocument.ToggleFormsDesign
End Sub
But when I run this code nothing happens...
This is by design. When an Office application is in Design Mode code should not run on an ActiveX object that's part of the document.
I take it this is an ActiveX button and in that case, it's a member of the InlineShapes or Shapes collection - Word handles it like a graphic object. It should be enough to delete the graphical representation, which you can do by changing it to display as an icon instead of a button.
For example, for an InlineShape:
Sub DeleteActiveX()
Dim ils As word.InlineShape
Set ils = ActiveDocument.InlineShapes(1)
ils.OLEFormat.DisplayAsIcon = True
ils.Delete
End Sub
You just have to figure out how to identify the InlineShape or Shape. You could bookmark an InlineShape; a Shape has a Name property.
EDIT: Since according to subsequent information provided in Comments you have a Shape object, rather than an InlineShape, the following approach should work:
Dim shp As word.Shape
Set shp = ActiveDocument.Shapes("Shape Name") 'Index value can also be used
shp.Delete
Note that Word will automatically assign something to the Shape.Name property, but in the case of ActiveX controls these names can change for apparently no reason. So if you identify a control using its name instead of the index value it's much better to assign a name yourself, which Word will not change "on a whim".
Activate Design Mode.
Click on the control to select it
Go to the VB Editor window
Ctrl+G to put the focus in the "Immediate Window"
Type the following (substituting the name you want), then press Enter to execute:
Selection.ShapeRange(1).Name = "Name to assign"
Use this Name in the code above

Stop dropdown selection from autofilling combobox

I have an ActiveX combobox that has a dropdown which is populated and filtered when a user types characters into the combobox. The dropdown items are from cLst. So the dropdown will be open, but as soon as the user hits the arrow down, the combobox populates with the first dropdown item and all of the other items in the dropdown disappear, because it then tries to filter the dropdown by the item in the combobox, which is an exact match for one item in the dropdown (the one that was highlighted upon arrow down).
How can I avoid this autofilling behavior when arrowing down through the dropdown, and have the user hit enter on the selection they want to populate the combobox instead?
If the user avoids using the keyboard, the mouse works fine to scroll through and highlight, then click, and only populates the combobox upon the click. I would like the scroll wheel to work if possible to scroll through the dropdown.
Private Sub newCmb_Change()
filterComboList Tool.newCmb, cLst
End Sub
Private Sub newCmb_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
Tool.newCmb.DropDown
End Sub
Private Sub newCmb_GotFocus() 'or _MouseDown()
Tool.newCmb.DropDown
End Sub
Public Sub filterComboList(ByRef cmb As ComboBox, ByRef dLst As Variant)
Dim itm As Variant, lst As String, sel As String, rng As Range
With Worksheets("Database")
Set rng = Application.Intersect(.UsedRange.Rows(2), .Cells.Resize(.Columns.Count - 1).Offset(1))
End With
Application.EnableEvents = False
With cmb
sel = .Value
If IsEmpty(cLst) Then cLst = rng
For Each itm In cLst
If Len(itm) > 1 Then If InStr(1, itm, sel, 1) Then lst = lst & itm & "||"
Next
If Len(lst) > 1 Then .List = Split(Left(lst, Len(lst) - 2), "||") Else .List = dLst
End With
Application.EnableEvents = True
End Sub
I was dealing with the same issue, and ended up finding some info on a Microsoft Help-site thread that let me play around with it. I posted an answer here which seems to work for me. It is a stripped down version of what I use in a sheet for this same concept.
The basic idea involves the newCmb_KeyDown() event (though should be similar to KeyPress in overall behavior) in the sheet that the combobox is located in, which snags the arrow key presses and sets a flag. The keys' actions are canceled by setting the KeyCode value to 0 and changing the newCmb.ListIndex value by +/-1 to change the selection, and using a flag in the newCmb_Change() event you can prevent the ComboBox from changing the linked cell value due to the up and down arrows. Once you get to the end of your KeyDown or KeyPress event, you can reset the flag for when you want changes to occur.
Hope those help, there is a link in that answer to the thread I found, which has some general ideas (though focused on UserForms instead of spreadsheets). Good luck!
**Edit
Note: Those parts of code were what seemed to control this behavior in my sheet, but if you have an issue with getting it to work, I can look at it again.