G
Greg Maxey
This is a long post with multiple questions. Please don't be discouraged
and feel free to answer all or part. Thank you.
The other day I became interested in creating an Template AddIn that will
add a group to the built-in Add-Ins tab. The group holds one Dropdown. I
wanted the dropdown item count, labels, and OnAction events to be dynamic
based on information stored in a table contained in the AddIn.
The RibbonX was fairly simple. I just added a new group to the Add-Ins tab
that contained one dropdown control:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui"
onLoad="Onload">
<ribbon>
<tabs>
<tab idMso="TabAddIns">
<group id="Grp1" label="Proof Reading">
<dropDown id="DD1" label="Add Marks" getItemCount="GetItemCount"
getItemLabel="GetItemLabel"
getSelectedItemIndex="GetSelectedItemIndex"
onAction="MyDDMacro">
</dropDown>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
I used call backs to set the dropdown list count, the label for each list
item, and the default displayed list item
As a practical exercise (and prompted by a another post in the newsgroups) I
decided to use the OnAction callback to insert pre-definded comments in the
text at the selection. I used a two column table in the Addin to define the
dropdown labels and default comment text. E.g.,
Column 1 Column2
Select error
agree. Agreement of subject and verb
ant. Antecendnet. "the person believed that
they." The sentence is incorrect because person is singular, and they is
plural
The code in my VB Project (with comments) is as follows:
Option Explicit
Public myRibbon As IRibbonUI
Private myArrayPri() As String
Private myArraySec() As String
'This procedure fires when the Add-In is loaded. Its purposes is to load
the values contained in the template Add-In table into a pair of arrays.
myArrayPri() holds the data to be used for the dropdown labels.
myArraySec() holds the data for the predefined comment text. The procedure
opens a new document based on the template AddIn and populates the arrays
with data in the tables. The new document is then closed without saving
changes.
Sub AutoExec()
Dim aTemplate As Template
Dim oDoc As Word.Document
Dim oTbl As Table
For Each aTemplate In Templates
If aTemplate.Name = "Proofreading Marks.dotm" Then
Set oDoc = Documents.Add(aTemplate.FullName, , , False)
Set oTbl = oDoc.Tables(1)
myArrayPri() = GetErrorArray(oTbl)
myArraySec() = GetDescriptiveArray(oTbl)
oDoc.Close wdDoNotSaveChanges
Exit For
End If
Next
End Sub
'This procedure fires when the template AddIn is opened directly for editing
(i.e., either the VB code or the table data)
Sub AutoOpen()
AutoExec
End Sub
'The next two function actually populate the two arrays.
Function GetErrorArray(ByVal oTbl As Table) As String()
Dim i As Long
Dim tempArray() As String
ReDim tempArray(oTbl.Rows.count)
For i = 1 To oTbl.Rows.count
tempArray(i - 1) = Left(oTbl.Cell(i, 1).Range.Text, Len(oTbl.Cell(i,
1).Range.Text) - 2)
Next i
GetErrorArray = tempArray
End Function
Function GetDescriptiveArray(ByVal oTbl As Table) As String()
Dim i As Long
Dim tempArray() As String
ReDim tempArray(oTbl.Rows.count)
For i = 1 To oTbl.Rows.count
tempArray(i - 1) = Left(oTbl.Cell(i, 2).Range.Text, Len(oTbl.Cell(i,
2).Range.Text) - 2)
Next i
GetDescriptiveArray = tempArray
End Function
'This is a RibbonX callback needed to create a ribbon object (I think that
is what it does???)
Sub Onload(ribbon As IRibbonUI)
Set myRibbon = ribbon
End Sub
'This RibbonX callback establishes the number of items in the dropdown. The
"id" of the dropdown created by the RibbonX is "DD1." The count of items is
= to the number of items in myArrayPri()
Sub GetItemCount(ByVal control As IRibbonControl, ByRef count)
Select Case control.id
Case "DD1"
count = UBound(myArrayPri)
Case Else
'Do Nothing
End Select
End Sub
'This RibbonX callback is used to define the labels for each item in the
dropdown. The procedure is called once for each item in the dropdown:
Sub GetItemLabel(ByVal control As IRibbonControl, Index As Integer, ByRef
label)
Select Case control.id
Case "DD1"
label = myArrayPri(Index)
Case Else
'Do nothing
End Select
End Sub
'This RibbonX callback sets the default dropdown item to display when the
Ribbon control is created. In this AddIn, I want "Select error" to be
displayed intially and after each OnAction event:
Sub GetSelectedItemIndex(ByVal control As IRibbonControl, ByRef Index)
Select Case control.id
Case "DD1"
Index = 0
Case Else
'Do nothing
End Select
End Sub
'This RibbonX callback is fired when the user selects one of the items in
the dropdown. It does several things:
'1. Determines if there is an open document. If not, the control is
invalidated (causes the control to be rebuilt with "Select error" displayed)
'2. Determines if there is text selected to comment on. If not the control
is invalidated
'3. Uses the dropdown item selected to insert a custom (customizable)
comment at the selection
' a. Displays a userform containing pre-defined comment text
' b. Temporarily sets the Application.UserInitials = the contol label
text
Sub MyDDMacro(ByVal control As IRibbonControl, selectedId As String,
selectedIndex As Integer)
Dim oFrm As UserForm1
Dim pUserInt As String
Select Case control.id
Case "DD1"
If Documents.count < 1 Then
myRibbon.InvalidateControl control.id
Exit Sub
End If
If Selection.Type = wdSelectionIP Or wdNoSelection Then
MsgBox "Please select the proofreading error in the text before
inserting comments."
myRibbon.InvalidateControl control.id
Exit Sub
End If
Select Case selectedIndex
Case Is = 0
'Do Nothing
Case Else
pUserInt = Application.UserInitials
Set oFrm = New UserForm1
oFrm.TextBox1 = myArraySec(selectedIndex)
oFrm.Show
Application.UserInitials = myArrayPri(selectedIndex)
Selection.Comments.Add Selection.Range, oFrm.TextBox1.Text
Unload oFrm
Set oFrm = Nothing
Application.UserInitials = pUserInt
myRibbon.InvalidateControl control.id
End Select
Case Else
'Do Nothing
End Select
End Sub
The UserForm contains one textbox and one command button. The textbox is
set for multi-line. The command button code is:
Private Sub CommandButton1_Click()
Me.Hide
End Sub
Problems/Questions:
1. I am not very confident of my process for populating the two arrays with
the data needed for the callbacks. My goals is to find the simplest way to
make the data customizable to the user and accessible to the the callback.
By putting the data in a table contained in the template. All the user needs
to do is open the template and edit the table. Once that is done, then when
the template loads the the compiler has to get to it. AutoExec is the only
event that I know of that fires when a template is loaded. Is this correct
and is this the best way?
2. a. I have not been able to isolate why, but when I put my Addin in the
Word Startup Folder and start Word I always get an error message "Subscript
out of range."
b. If I remove the AddIn from the Startup folder and attempt to load
the Add-In manually, I get a get the same message: "Subscript out of
range."
c. If I leave Word running, remove the AddIn, and load it a second time
it loads and works perfectly without error.
d. The error message never happens when I open the AddIn directly. I
assume that this problem is caused by some sort of timing conflict with the
AutoExec procedure and maybe I could correct it with a Do Events
statement but I am not very familiar with those and I don't know how to
proceed.
Any thoughts or ideas to fix this?
I'll be happy to share the complete template with anyone that is interested
in assisting to resolve the issue above. Just contact me vai my website
feedback at the link below and I will send it as an attachment.
Thanks.
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Greg Maxey - Word MVP
My web site http://gregmaxey.mvps.org
Word MVP web site http://word.mvps.org~~~~~~~~~~~~~~~~~~~~~~~~~~
and feel free to answer all or part. Thank you.
The other day I became interested in creating an Template AddIn that will
add a group to the built-in Add-Ins tab. The group holds one Dropdown. I
wanted the dropdown item count, labels, and OnAction events to be dynamic
based on information stored in a table contained in the AddIn.
The RibbonX was fairly simple. I just added a new group to the Add-Ins tab
that contained one dropdown control:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui"
onLoad="Onload">
<ribbon>
<tabs>
<tab idMso="TabAddIns">
<group id="Grp1" label="Proof Reading">
<dropDown id="DD1" label="Add Marks" getItemCount="GetItemCount"
getItemLabel="GetItemLabel"
getSelectedItemIndex="GetSelectedItemIndex"
onAction="MyDDMacro">
</dropDown>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
I used call backs to set the dropdown list count, the label for each list
item, and the default displayed list item
As a practical exercise (and prompted by a another post in the newsgroups) I
decided to use the OnAction callback to insert pre-definded comments in the
text at the selection. I used a two column table in the Addin to define the
dropdown labels and default comment text. E.g.,
Column 1 Column2
Select error
agree. Agreement of subject and verb
ant. Antecendnet. "the person believed that
they." The sentence is incorrect because person is singular, and they is
plural
The code in my VB Project (with comments) is as follows:
Option Explicit
Public myRibbon As IRibbonUI
Private myArrayPri() As String
Private myArraySec() As String
'This procedure fires when the Add-In is loaded. Its purposes is to load
the values contained in the template Add-In table into a pair of arrays.
myArrayPri() holds the data to be used for the dropdown labels.
myArraySec() holds the data for the predefined comment text. The procedure
opens a new document based on the template AddIn and populates the arrays
with data in the tables. The new document is then closed without saving
changes.
Sub AutoExec()
Dim aTemplate As Template
Dim oDoc As Word.Document
Dim oTbl As Table
For Each aTemplate In Templates
If aTemplate.Name = "Proofreading Marks.dotm" Then
Set oDoc = Documents.Add(aTemplate.FullName, , , False)
Set oTbl = oDoc.Tables(1)
myArrayPri() = GetErrorArray(oTbl)
myArraySec() = GetDescriptiveArray(oTbl)
oDoc.Close wdDoNotSaveChanges
Exit For
End If
Next
End Sub
'This procedure fires when the template AddIn is opened directly for editing
(i.e., either the VB code or the table data)
Sub AutoOpen()
AutoExec
End Sub
'The next two function actually populate the two arrays.
Function GetErrorArray(ByVal oTbl As Table) As String()
Dim i As Long
Dim tempArray() As String
ReDim tempArray(oTbl.Rows.count)
For i = 1 To oTbl.Rows.count
tempArray(i - 1) = Left(oTbl.Cell(i, 1).Range.Text, Len(oTbl.Cell(i,
1).Range.Text) - 2)
Next i
GetErrorArray = tempArray
End Function
Function GetDescriptiveArray(ByVal oTbl As Table) As String()
Dim i As Long
Dim tempArray() As String
ReDim tempArray(oTbl.Rows.count)
For i = 1 To oTbl.Rows.count
tempArray(i - 1) = Left(oTbl.Cell(i, 2).Range.Text, Len(oTbl.Cell(i,
2).Range.Text) - 2)
Next i
GetDescriptiveArray = tempArray
End Function
'This is a RibbonX callback needed to create a ribbon object (I think that
is what it does???)
Sub Onload(ribbon As IRibbonUI)
Set myRibbon = ribbon
End Sub
'This RibbonX callback establishes the number of items in the dropdown. The
"id" of the dropdown created by the RibbonX is "DD1." The count of items is
= to the number of items in myArrayPri()
Sub GetItemCount(ByVal control As IRibbonControl, ByRef count)
Select Case control.id
Case "DD1"
count = UBound(myArrayPri)
Case Else
'Do Nothing
End Select
End Sub
'This RibbonX callback is used to define the labels for each item in the
dropdown. The procedure is called once for each item in the dropdown:
Sub GetItemLabel(ByVal control As IRibbonControl, Index As Integer, ByRef
label)
Select Case control.id
Case "DD1"
label = myArrayPri(Index)
Case Else
'Do nothing
End Select
End Sub
'This RibbonX callback sets the default dropdown item to display when the
Ribbon control is created. In this AddIn, I want "Select error" to be
displayed intially and after each OnAction event:
Sub GetSelectedItemIndex(ByVal control As IRibbonControl, ByRef Index)
Select Case control.id
Case "DD1"
Index = 0
Case Else
'Do nothing
End Select
End Sub
'This RibbonX callback is fired when the user selects one of the items in
the dropdown. It does several things:
'1. Determines if there is an open document. If not, the control is
invalidated (causes the control to be rebuilt with "Select error" displayed)
'2. Determines if there is text selected to comment on. If not the control
is invalidated
'3. Uses the dropdown item selected to insert a custom (customizable)
comment at the selection
' a. Displays a userform containing pre-defined comment text
' b. Temporarily sets the Application.UserInitials = the contol label
text
Sub MyDDMacro(ByVal control As IRibbonControl, selectedId As String,
selectedIndex As Integer)
Dim oFrm As UserForm1
Dim pUserInt As String
Select Case control.id
Case "DD1"
If Documents.count < 1 Then
myRibbon.InvalidateControl control.id
Exit Sub
End If
If Selection.Type = wdSelectionIP Or wdNoSelection Then
MsgBox "Please select the proofreading error in the text before
inserting comments."
myRibbon.InvalidateControl control.id
Exit Sub
End If
Select Case selectedIndex
Case Is = 0
'Do Nothing
Case Else
pUserInt = Application.UserInitials
Set oFrm = New UserForm1
oFrm.TextBox1 = myArraySec(selectedIndex)
oFrm.Show
Application.UserInitials = myArrayPri(selectedIndex)
Selection.Comments.Add Selection.Range, oFrm.TextBox1.Text
Unload oFrm
Set oFrm = Nothing
Application.UserInitials = pUserInt
myRibbon.InvalidateControl control.id
End Select
Case Else
'Do Nothing
End Select
End Sub
The UserForm contains one textbox and one command button. The textbox is
set for multi-line. The command button code is:
Private Sub CommandButton1_Click()
Me.Hide
End Sub
Problems/Questions:
1. I am not very confident of my process for populating the two arrays with
the data needed for the callbacks. My goals is to find the simplest way to
make the data customizable to the user and accessible to the the callback.
By putting the data in a table contained in the template. All the user needs
to do is open the template and edit the table. Once that is done, then when
the template loads the the compiler has to get to it. AutoExec is the only
event that I know of that fires when a template is loaded. Is this correct
and is this the best way?
2. a. I have not been able to isolate why, but when I put my Addin in the
Word Startup Folder and start Word I always get an error message "Subscript
out of range."
b. If I remove the AddIn from the Startup folder and attempt to load
the Add-In manually, I get a get the same message: "Subscript out of
range."
c. If I leave Word running, remove the AddIn, and load it a second time
it loads and works perfectly without error.
d. The error message never happens when I open the AddIn directly. I
assume that this problem is caused by some sort of timing conflict with the
AutoExec procedure and maybe I could correct it with a Do Events
statement but I am not very familiar with those and I don't know how to
proceed.
Any thoughts or ideas to fix this?
I'll be happy to share the complete template with anyone that is interested
in assisting to resolve the issue above. Just contact me vai my website
feedback at the link below and I will send it as an attachment.
Thanks.
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Greg Maxey - Word MVP
My web site http://gregmaxey.mvps.org
Word MVP web site http://word.mvps.org~~~~~~~~~~~~~~~~~~~~~~~~~~