vbams-wordbuttonclick

When I click the button, it doesn't work at all


I have made two ".docm" files that have proper button and "_click()" procedure respectively. The first "myDocument1" works well, no problem at all. The other one "myDocument2" does not. I guess, I need "onAction" or something, but don't know any more. Pls tell me what to do.

The first one has its codes in "ThisDocument" and The second one has in "myModule". The code is single line only "Msgbox OK" both of them.

I'd like to see that it works at the "myModule" not in "ThisDocumet" in case of second file.

Button(s)

myDocument1's click code

myDocument2's click code

[EDIT] I'd like to add some line of VBA codes that I've used when I made this Button(s). That is not the best routine (wow, a guru says that is even depricated....), but the only route that worked for me after long web searching.

Dim myButton
Set myButton = Selection.InlineShapes.AddOLEControl(ClassType:="Forms.CommandButton.1")
    myButton.OLEFormat.Object.TakeFocusOnClick = False
    myButton.OLEFormat.Object.Width = 100
Dim myCompo
Set myCompo = ActiveDocument.VBProject.VBComponents.Add(1)
    myCompo.Name = "myModule"
Dim myModu
Set myModu = myCompo.CodeModule
    myModu.InsertLines 1, _
    "Sub " & myButton.OLEFormat.Object.Name & "_Click()" & vbCr & vbCr & _
    "    Msgbox ""OK""" & vbCr & vbCr & _
    "End Sub"

and adding another screen capture, trying to make ClickEvent possible but not attained its goal. I have failed to find proper Event related section from my VBE.


Solution

  • The reason this does not work is because this type of Command Button is an ActiveX control, i.e. a COM control, that is contained within the document surface. Word expects event code for the object to be in the ThisDocument module and automatically connects that Event code to the COmmandButton1 object when (say) it opens the document.

    That's why in the VB Editor, when you have the code open for the ThisDocument module, you will see in the dropdown box above the code, on the left hand side, (General) and CommandButton1. If you select CommandButton1 in that dropdown, the other dropdown displays the available events. Word uses a naming convention to generate the appropriate Sub for the event using the pattern objectname_eventname - in this case, CommandButton1_Click.

    In any other module, Word doesn't recognise the name CommandButton1 as having anything to do with the object in the document surface, and doesn't make that connection automatically.

    So, if you open myModule and look at the equivalent dropdown, all you will see is (General). Putting a routine called CommandButton1_Click in the module just means that you have a regular subroutine. Word does not look at the name, recognise its pattern, and connect it to the actual object in the document. So that routine is not called when you click the Button.

    In fact you can put ActiveX control code in a routine other than ThisDocument, but I certainly don't know what all the consequences of doing that might be. Personally, I think it involves enough additional complication thaat I would leave the code in ThisDocument unless I absolutely had to put it somewhere else.

    For one thing ActiveX controls are legacy controls (possibly even deprecated). They don't work in any version of Word except Windows Desktop Word. So there is a case for using something else instead.

    But if you do want to put event code elsewhere, you can do it this way:

    The code has to be in a Class Module (not an ordinary Module). Let's say you create one called myClass.

    In myClass, declare a variable like this:

    Public WithEvents cb As MSForms.CommandButton
    

    (You can't use WithEvents in an ordinary module)

    Then you should be able to find "cb" in the dropdown above the code window, and you can create its _Click event handler, e.g.

    Sub CommandButton1_Click()
    Msgbox "OK"
    End Sub
    

    But then your code has to create an object of type myClass and connect its .cb variable to the actual CommandButton1 object in your document. So you need to call something, somewhere that does something like this:

    Dim myC As myClass
    
    Sub CreateMyClass()
    Set myC = New myCLass
    Set myC.cb = ThisDocument.CommandButton1
    End Sub
    

    and you probably need something like this in the same module:

    Sub TearDownMyClass()
    Set myC.cb = Nothing
    Set myC = Nothing
    End Sub
    

    You could for example put that code in ThisDocument and use a Document Open event or routine to call CreateMyClass.

    Or if you are trying to take advantage of the facilities available in Class Modules, you could hide the cb variable, and write your class module like this:

    ' cb not visible outside the class module.
    Private WithEvents cb As MSForms.CommandButton
    
    Public Property Set myButton(myButton As MSForms.CommandButton)
    Set cb = myButton
    End Property
    
    Public Property Get myButton() As MSForms.CommandButton
    Set myButton = cb
    End Property
    
    Private Sub cb_Click()
    MsgBox "OK"
    End Sub
    
    Private Sub Class_Initialize()
    End Sub
    
    Private Sub Class_Terminate()
    Set Me.myButton = Nothing
    End Sub
    

    Your other code could be like this:

    Dim myC As myClass
    
    Sub CreateMyClass()
    Set myC = New myCLass
    Set myC.myButton = ThisDocument.CommandButton1
    End Sub
    
    Sub TearDownMyClass()
    Set myC = Nothing
    End Sub
    

    or, if you only need your class to work specifically with CommandButton1, you could use this in the class

    Private Sub Class_Initialize()
    ' You can only do this because CommandButton1 is visible from this module
    Set myButton = ThisDocument.CommandButton1
    End Sub
    

    then in your ordinary module,

    Sub CreateMyClass()
    Set myC = New myCLass
    End Sub
    

    None of this stops Word from calling any relevant code in ThisDocument as well. So if you have this new class code and you leave your CommandButton1_Click code in ThisDocument, Word should pop up two message boxes when you click the Command Button.

    If you use either of the other two types of control in your document (legacy Form Fields, which are also available on Mac Word, or Content Controls, which are partly available on Mac Word, be aware the coding needs to be quite different.

    Incidentally, if you are trying to write code that encapsulates objects and you like the idea of using private class variables (cf. cb) and property let/set/get statements to access them, you can use those statements in ThisDocument because it is a Class Module.

    Here are some screenshots from the VB Editor:

    Selecting the Class Module in the Project browser

    Related module code

    Select the WIthEvents object variable

    View the related events (partial)