In my Word (Office 365) document, I can insert a Quick Part for the company name by clicking Insert / Quick Parts / Document Property / Company.
I'd like a macro to do that, so I can pop a button on my Quick Access toolbar to make it one click not four.
When I record the process, the macro does not register the insert. I found that the following VBA code inserts the current text of the field, but not the content control itself:
ActiveDocument.Content.InsertAfter
ActiveDocument.BuiltInDocumentProperties(wdPropertyCompany)
I figure there must a single line of VBA that would insert the Company Quick Part field into my document, as if I had done those four clicks.
The trick is to map the content control to the Company
Sub insertCompanyCC()
On Error GoTo err_insert
Dim cc As ContentControl
Set cc = ActiveDocument.ContentControls.Add(wdContentControlText, Selection)
With cc
.Title = "Company"
.XMLMapping.SetMapping "/ns0:Properties[1]/ns0:Company[1]"
End With
exit_insert:
Exit Sub
err_insert:
Select Case Err
Case 4605
MsgBox "Please move your cursor outside of the content control.", vbExclamation
Case Else
Err.Raise Err.Number, Err.Source
End Select
Resume exit_insert
End Sub
e.g. /ns1:coreProperties[1]/ns0:creator[1] would insert the author.
Related
I am very new to VBA and I am using it in MS Word 2016. I have an ActiveX text box (conFull) for a full name and I am wanting to pull out the first name and populate it throughout the document. I got this to work once, and then Word froze up on me with every subsequent attempt. What am I doing wrong here?
Here is my code:
Private Sub conFull_LostFocus()
For Each ContentControl In ActiveDocument.SelectContentControlsByTag("nameTag")
With ContentControl
.Range.Text = Split(conFull.Text, " ")(0)
End With
Next
End Sub
Any help is much appreciated!
I just inherited a personnel database at work that has not been touched in a few years and they want me to make it functional. I've been able to update most of the things but I've run into an issue with a macro that was input that uses the SendKeys action:
Private Sub Command3_Click()
On Error GoTo Err_Command3_Click
DoCmd.OpenTable "tblEmployees", acNormal, acEdit
DoCmd.GoToControl [employee]
DoCmd.FindRecord Forms![EmployeeRemoval]![cboEmpSelect],
DoCmd.GoToControl [pastemployee]
SendKeys "1~", True
DoCmd.Close acTable, "tblEmployees"
Exit_Command3_Click:
Exit Sub
Err_Command3_Click:
MsgBox Err.Description
Resume Exit_Command3_Click
At this point with Access 2010 it just sends the program into a loop opening and closing the table while also turning Num Lock on and off. I figured the best replacement would be an Update statement, but am not sure what the Where criteria would be to update the single cell that needs updating (in this case only the PastEmployee cell for the one employee in question at any given time would need to update to True instead of False). In the macro it was referencing (through the FindRecord command) a ComboBox in which the employee is selected that queried Last Name, First Name, and employee number from the employee table.
db.Execute Update tblEmployees Set [PastEmployee] = 1 Where XXXXXXXX
Any help in either a way to make the SendKeys command just work or to get the update statement working would be helpful.
The posted code is not a macro, it is VBA. Macros in Access are very different.
Users should not interact with tables and queries, just forms and reports.
In Access Yes/No field, 0 is False and -1 is True.
Consider:
Private Sub Command3_Click()
On Error GoTo Err_Command3_Click
CurrentDb.Execute "UPDATE tblEmployees SET PastEmployee=True WHERE employee=" & Me.cboEmpSelect
Exit_Command3_Click:
Exit Sub
Err_Command3_Click:
MsgBox Err.Description
Resume Exit_Command3_Click
End Sub
If the form were bound to tblEmployees and focus on the record to edit, instead of the UPDATE action, simply: Me!PastEmployee = True. Although, if the record is viewed on form, user just needs to click checkbox bound to PastEmployee and no code would be needed.
I have an embedded Word document (*.docm) in my Excel worksheet.
The Word document contains a table, that has relationship between its corresponding Table in Excel's WorkSheet.
I want count of table rows in embedded Word document been dynamically set in Document_Open event, with bellow value, from its involving Worksheet:
ThisWorkbook.Worksheets("Sheet1").ListObjects("Salary").ListRows.Count
How can I pass values between Excel (macro container document) and its embedded macro container word document? -If its a right answer for above bold issue- or another solution?
If there is another solution answer, Please note that cover need of:
Fill destination table (that is in embedded word document) cells with corresponding values from source data are in parent Table from Worksheet?, same instead of with auto generating fields with Document_Open events from macro container embedded word document.
I suggest to embed .docx document to avoid macros disabled alert each time it's opened, and to place all the code within Excel VBA Project. Here is the example, showing how to change number of rows in embedded Word document from Excel VBA:
Sub ChangeRowsCount()
Dim n As Long
With ThisWorkbook.Worksheets("Sheet1")
n = .ListObjects("Table1").ListRows.Count
With .Shapes("Object 1")
Select Case True
Case .Type <> msoEmbeddedOLEObject
MsgBox "Invalid OLE Object type"
Case InStr(1, .OLEFormat.progID, "Word.Document", vbTextCompare) <> 1
MsgBox "Invalid Application"
Case Else
.OLEFormat.Object.Verb xlVerbOpen
With .OLEFormat.Object.Object.Parent ' Word.Application
With .ActiveDocument.Tables(1).Rows
Do While .Count <> n
If .Count > n Then .Item(.Count).Delete Else .Add
Loop
End With
.Quit
End With
.Select
MsgBox "Success"
End Select
End With
End With
End Sub
I am trying to build a main page for my costing model. On this page I have created a drop down list using a combo box and then I want to assign a macro that creates a list of different buttons/command buttons once an option is selected from the list. Then I want to build another macro that is assigned to those buttons which then take the user to another tab/sheet within the same workbook depending on the option they selected from the drop down.
Can someone please give me an idea as to what code I should be using, first to create a command button that refers to the selected option from the drop down and then assign a simple macro to that button which then takes me to the specified tab/sheet?
So far, I have got the following:
Option Explicit
Sub Select_Change()
With ThisWorkbook.Sheets("Main Page").Shapes("Select").ControlFormat
Select Case .List(.Value)
Case "Vehicle1": All_States1
Case "Vehicle2": All_States2
Case "Vehicle3": All_States3
Case "Vehicle4": All_States4
Case "Vehicle5": All_States5
Case "Vehicle6": All_States6
Case "Vehicle7": All_States7
End Select
End With
End Sub
I then tried to use the name All_States1 to create various buttons but it's not working properly, as all selected options are showing the same button and the button won't go away either. Also, I can't seem to assign a macro to the created button.
This is just an example of :
creating a Button
assigning a macro to it
.
Sub button_maker()
Dim r As Range
Set r = Selection
ActiveSheet.Buttons.Add(94.5, 75.75, 51, 27.75).Select
With Selection
.OnAction = "mooney"
.Characters.Text = "Bump"
End With
r.Select
End Sub
Sub mooney()
Range("A1").Value = Range("A1").Value + 3
End Sub
If I understand the problem correctly, you want to have a dropdown (combo box) on your sheet, and when a button is clicked you want to run a macro based on the selection. The following does that - see if it helps you.
First - create a combobox, and a range for the inputs (names in the combobox) and output (value selected). For example, you could call the input selectionIn and the result selectionOut.
Exact steps:
Wrote values of combobox selections in E1:E4 . Selected the four cells, then typed selectionIn in the name box (to the left of the formula bar). That creates a named range (there are other ways to create named ranges, but this is my preferred method).
Called cell F1 selectionOut
Created a combobox, and referenced these two ranges for its input and output:
Created a button, gave it the label "Go" and linked it to the action runIt.
Finally, I created the following code in a workbook module:
Sub runIt()
Dim whatToDo, makeName As Boolean
' look up the name of the combo based on the value:
whatToDo = Range("selectionIn").Cells([selectionOut].Value, 1)
MsgBox "have to do '" & whatToDo & "'"
makeName = False
Select Case whatToDo
Case "one"
' example of putting the code you need right in the select:
MsgBox "doing the first thing"
Case "two"
' example of calling a specific routine:
Call caseTwo
Case "three"
Application.Run "case" & whatToDo ' making the name of the function on the fly
Case "four"
makeName = True
End Select
If makeName Then
Dim nameToRun
nameToRun = "case" & whatToDo
Application.Run nameToRun
End If
End Sub
Sub caseTwo()
MsgBox "called the code for case two"
End Sub
Sub caseThree()
MsgBox "doing case three here"
End Sub
Sub caseFour()
MsgBox "even four can be done"
End Sub
This shows a few different ways to handle different cases depending on what was selected. Of course you can have a macro run every time the combobox selection is changed - but it sounds from your description like that is not what you want.
Let me know how you get on with this code example - I tried to keep it simple but show some options at the same time.
One alternative (which might be simpler) would be to have an array with the names of the functions that you want to call:
Sub otherMethod()
Dim functionList()
functionList = Array("caseOne", "caseTwo", "caseThree", "caseFour")
Application.Run functionList([selectionOut].Value - 1)
End Sub
That's certainly the most compact way I can think of to do this... you need the offset of -1 because the array index is base 0 (by default anyway) and the combobox returns 1 for the first selection. You could make your code more robust by writing
functionIndex = [selectionOut].Value + LBound(functionList) - 1
Application.Run functionList(functionIndex)
This ensures that if you change the base index of the functionList array to another value, it will all still work correctly.
I have many word document with lots of bookmarks.
I use VBA code to change these bookmarks with data from a DB.
The problem is, sometimes the users need to edit these documents, and they tend to accidentally delete/change my bookmarks, which leads to the VBA code not recognizing the bookmark anymore.
So basically, what i'm wondering is how i can restrict users from editing my bookmarks in a word document.
I don't need a super secure solution, just enough protection so that the user knows that, "i should not touch this part".
Thanks in advance for your answer..
EDIT:
I was reading on different forums, and came across this,
http://social.msdn.microsoft.com/Forums/office/en-US/f70ca604-bbdb-4b5a-8363-f9e126105e91/writeprotection-of-bookmarks-in-word?forum=vsto
Which sort of does what i want. but was not able to implement/convert it to VBA code. Can someone also see how i maybe can use it?
Thanks again.
EDIT: office 2007 / 2010.
The following idea is tested for Word 2010. It should work for 2007 and 2013 as well but not for 2003.
I would suggest to use ContentControls (called CC further in the text) together with Bookmarks. Next, you will need to control one event which will check if user is selecting inside any of the ContentControl. If so, we will show the message and/or move selection outside protected area.
Step 1st. Each of your bookmarks should be enclosed inside RichText ContentControl. You could do it manually for selected bookmarks or you can run the following simple code to do it for all bookmarks inside your active document.
(Important assumption! there are not any other ContentControls in your document!)
Sub Add_Bookmark_CC()
Dim bookM As Bookmark
For Each bookM In ActiveDocument.Bookmarks
ActiveDocument.ContentControls.add wdContentControlRichText, bookM.Range
Next
End Sub
2nd step. We will control one event: Document_ContentControlOnEnter. Go to ThisDocument module in your Document VBAProject and create the following event (see some comments inside the code):
Private Sub Document_ContentControlOnEnter(ByVal ContentControl As ContentControl)
Debug.Print Now, ContentControl.Range.Bookmarks.Count
If ContentControl.Range.Bookmarks.Count > 0 Then
'Optional message box for user
MsgBox "There is bookmark inside this area which you should not change. " & _
vbNewLine & "You will be moved out of this range"
'optionam selection change right after CC area
Dim newPos As Long
newPos = ContentControl.Range.End + 2
ActiveDocument.Range(newPos, newPos).Select
End If
End Sub
Alternative for step 1st and 2nd. If you don't want to use CC event you could add CC to each bookmarks with CC content protection. In this situation you only need 1st step and the following sub:
Sub Add_Bookmark_CC_Protected()
Dim bookM As Bookmark
Dim CC As ContentControl
For Each bookM In ActiveDocument.Bookmarks
Set CC = ActiveDocument.ContentControls.add(wdContentControlRichText, bookM.Range)
CC.LockContents = True
Next
End Sub
Final! As you can see there are some more possible combination of steps 1 and 2.
The following code allows you to delete all CC if you need for any initial tests:
Sub Remove_All_CC()
Dim CC As ContentControl
For Each CC In ActiveDocument.ContentControls
CC.Delete
Next CC
End Sub
Protect your whole document using
'whole document readonly
ThisDocument.Protect Password:="password", NoReset:=False, Type:=wdAllowReadOnly
or
'only write in form fields (can't delete them, just fill them out)
ThisDocument.Protect Password:="mypassword", NoReset:=False, Type:=wdAllowOnlyFormFields
and now give some parts of the document free for editing:
ThisDocument.Bookmarks("myBookmark").Range.Editors.Add wdEditorEveryone
Selection.Range.Editors.Add wdEditorEveryone
Alternative
(not tested)
don't protect your whole document, just restrict the bookmarks you want to lock
ThisDocument.Bookmarks("myBookmark").Range.Editors.Add wdEditorOwners
or
ThisDocument.Bookmarks("myBookmark").Range.Editors.Add "abc#test.com"