PDA

View Full Version : Not just me...toggleButton 'Runtime error: Method ~ of object ~ failed



DaVinney
04-15-2011, 12:35 PM
So I created a ribbon toggleButton based on a book tutorial, except my version toggles hiddentext on/off separate from non-printing characters. The book sample toggles picture placeholders. Mine works fine when I load my template via the \Startup folder, so long as I use it only on a single document. However, once I switch windows to a 2nd document, thereafter I always get the subject error (image attached below) upon pressing the button.

I thought it was something I screwed up, but alas (hours later) I found the same problem with the code in the example book:

Option Explicit
Private ribbonUI As IRibbonUI

Private Sub rxIRibbonUI_onLoad(ribbon As IRibbonUI)
'Store the ribbonUI for later use
Set ribbonUI = ribbon
End Sub
Public Sub rxtglPicHold_getPressed(control As IRibbonControl, ByRef returnedVal)
'Callback for rxtglPicHold getPressed
returnedVal = ActiveDocument.ActiveWindow.View.ShowPicturePlaceHolders
End Sub
Public Sub rxtglPicHold_getImage(control As IRibbonControl, ByRef returnedVal)
'Callback for rxtglPicHold getImage
Select Case ActiveDocument.ActiveWindow.View.ShowPicturePlaceHolders
Case True
returnedVal = "SignatureInsertMenu"
Case False
returnedVal = "DesignMode"
End Select
End Sub
Public Sub rxtglPicHold_click(control As IRibbonControl, pressed As Boolean)
'Callback for rxtglPicHold onAction
ActiveDocument.ActiveWindow.View.ShowPicturePlaceHolders = pressed
ribbonUI.InvalidateControl "rxtglPicHold"
End Sub

Snippets of the xml:


<customUI
onLoad=”rxIRibbonUI_onLoad”
xmlns=”http://schemas.microsoft.com/office/2006/01/customui”>


<toggleButton id=”rxtglPicHold”
label=”Picture Placeholders”
getPressed=”rxtglPicHold_getPressed”
getImage=”rxtglPicHold_getImage”
onAction=”rxtglPicHold_click”/>


Same problem, four different computers. Any ideas what the problem is and how to overcome this?

Frosty
04-15-2011, 06:52 PM
Start by error trapping. You know what's failing, thanks to Microsoft... it's the .ShowPicturePlaceHolders method. But you have it in multiple routines.

Can you have your macro project open and also recreate the error? If so... click the debug button (it will be available if the macro project is open-- it can still be in the startup folder too).

However, if you can only recreate when the project isn't open, you're going to need to do some error trapping. Start by seeing what the code things the current document is.

If you have a button which toggles based on the state of a document... you're going to need to start using document change events to make sure the toggle state of that button reflects the document you just changed to (i.e., you can show picture place holders in one document, but not another... you need your toggle button to reflect that)

Just start with some basic error trapping around the failing method...

'at the top of the routine
On error goto l_err

'regular code

l_exit:
exit sub
l_err:
msgbox err.number & " " & err.description & vbcr & "Activedocument.Name:= " & activedocument.name
resume l_exit
End sub

That's one structure for error trapping-- check your book, they may have a more fully expressed bit about it.

DaVinney
04-15-2011, 08:08 PM
Can you have your macro project open and also recreate the error?I get: "Project is unviewable."


I read somewhere that such errors may be caused when more than one instance of the same operation occurs at the same time. Is that the case here?

Thanks for the helpful reply, Frosty. I'll see how far I get error trapping.

DaVinney
04-15-2011, 10:28 PM
The info I was referring to in the preceding post...


Jezebel:
"You might be looking in the wrong place for the problem. That error message
comes from VB (not Word) -- most commonly you get it if you try to run the
same VB project twice simultaneously. There's nothing wrong with your code
snippet, unless your string variables contain something seriously wierd."
http://tinyurl.com/3aqbaj3

Frosty
04-16-2011, 11:09 AM
The project is unviewable "error" is generally just an order of operations. Restart Word, open the template from the startup directory before you try to expand it in the VBA Editor... and that unviewable message should go away.

Then you should actually be able to debug the code. But if you've got something else going on in the project, you might have an issue.

I did test to see if that method would fail in any of the standard views, and it didn't. If I have some time, I'll test to see if the same thing happens on my machine. This is 2007 or 2010?

DaVinney
04-16-2011, 01:34 PM
It's 2007.

Thanks for the help.

DaVinney
04-19-2011, 12:48 PM
Debugging indicates the culprit is the single code line in the 'getpressed' callback:

Public Sub rxtglPicHold_getPressed(control As IRibbonControl, ByRef returnedVal)
'Callback for rxtglPicHold getPressed
returnedVal = ActiveDocument.ActiveWindow.View.ShowPicturePlaceHolders
End Sub


Using (Frosty) error trapping msgbox...
If I have two documents open (Test1.doc, Test2.doc), I press the togglebutton first using Test1, the routine runs fine. Switch over to Test2, press toggle, the error trap msgbox indicates Test1 is the activedocument (not the expected Test2)! :doh:

Any thoughts why this might be and how to resolve?

If not too much trouble I may notify the authors their book code has this flaw.

Frosty
04-19-2011, 01:51 PM
Did a little testing... it's definitely a bug, but I wouldn't blame the authors. The code they are showing you is almost always of the "proof of concept" sort, as you should never really distribute this stuff without error trapping.

Of note: you can avoid this error if you switch to one of the documents and click any other tab than the one this button is on (i.e., I put this button on a custom tab, and if only one of my open documents was "on" that tab... I didn't get the error when I clicked the button).

I would imagine this is an order of operations issue in terms of when Word "paints" the ribbon vs. when it defines the current ActiveView (activedocument is actually a little misleading in this case).

Try the following for your code:

Option Explicit
Private ribbonUI As IRibbonUI

Private Sub rxIRibbonUI_onLoad(ribbon As IRibbonUI)
'Store the ribbonUI for later use
Set ribbonUI = ribbon
End Sub
Public Sub rxtglPicHold_getPressed(control As IRibbonControl, ByRef returnedVal)
Dim bShowingPicPlaceholders As Boolean
On Error Resume Next
bShowingPicPlaceholders = ActiveWindow.View.ShowPicturePlaceHolders
'Callback for rxtglPicHold getPressed
returnedVal = bShowingPicPlaceholders
End Sub
Public Sub rxtglPicHold_getImage(control As IRibbonControl, ByRef returnedVal)
Dim bShowingPicPlaceholders As Boolean

On Error Resume Next
bShowingPicPlaceholders = ActiveWindow.View.ShowPicturePlaceHolders
'Callback for rxtglPicHold getImage
Select Case bShowingPicPlaceholders
Case True
returnedVal = "SignatureInsertMenu"
Case False
returnedVal = "DesignMode"
End Select
End Sub
Public Sub rxtglPicHold_click(control As IRibbonControl, pressed As Boolean)
On Error Resume Next
'Callback for rxtglPicHold onAction
ActiveWindow.View.ShowPicturePlaceHolders = pressed
ribbonUI.InvalidateControl "rxtglPicHold"
End Sub

This will allow the code to run, although your toggle state is not going to be accurate when you have multiple documents open (but, actually, it wasn't going to be accurate anyway, because you're not setting the state when you switch between documents... which is the true event of how to keep toggle buttons synched.

In general, if you're getting errors on single lines... try setting those values to a variable, and then seeing if you can error trap for the value of the variable. You can't figure out what MS is doing with ActiveWindow, but you can decide what you want to do if MS can't figure it out (i.e., default to True, default to false).

Having done this is previous versions of Word, I would say, as a general rule, that it is not worth the effort to try and synch document state buttons, unless they are on a sub-menu (in which case, you can synch whenever the sub menu is called). Trying to load up a document_change even with a bunch of buttons you want synched to whatever the activedocument is creates some overhead and, I suspect, other issues with MS.

Someone who has more experience with how the ribbon uses memory (I'm still working my way through the quirks) may be able to give a better explanation... but the bottom line is that I would just use the most rudimentary error trapping, and accept that your icon is going to be "wrong" some times when you're switching between documents... or skip the concept of the toggle all together, and re-think what you actually want to do and when.

Sometimes the simplest things can be the biggest pains. This seems like it should be simple, but you've dived into a bit of a hornet's nest here.

Frosty
04-19-2011, 02:16 PM
Oh, and I looked for a button under All Commands which would already do this function, and it doesn't seem to exist, unfortunately. And then I was curious how I'd make this work (I have a lot of exploration to do in Word 2010, so this is as good an experiment as any), and here's what I came up with.

You need a class module named ThisApplication, with the following code in it:

Option Explicit
Private WithEvents myApp As Word.Application
Private Sub Class_Initialize()
Set myApp = Application
End Sub
Private Sub myApp_DocumentChange()
ribbonUI.InvalidateControl "rxtglPicHold"
End Sub
And then use the following code in a standard module in place of your other ribbonX code:

Public global_ShowPicPlaceholders As Boolean
Public appWord As ThisApplication
Public ribbonUI As IRibbonUI
Private Sub rxIRibbonUI_onLoad(ribbon As IRibbonUI)
'Store the ribbonUI for later use
Set ribbonUI = ribbon
End Sub
Public Sub rxtglPicHold_getPressed(control As IRibbonControl, ByRef returnedVal)
'Callback for rxtglPicHold getPressed
returnedVal = global_ShowPicPlaceholders
End Sub
Public Sub rxtglPicHold_getImage(control As IRibbonControl, ByRef returnedVal)
On Error Resume Next
global_ShowPicPlaceholders = ActiveWindow.View.ShowPicturePlaceHolders
'Callback for rxtglPicHold getImage
Select Case global_ShowPicPlaceholders
Case True
returnedVal = "SignatureInsertMenu"
Case False
returnedVal = "DesignMode"
End Select
End Sub
Public Sub rxtglPicHold_click(control As IRibbonControl, pressed As Boolean)
On Error Resume Next
'Callback for rxtglPicHold onAction
global_ShowPicPlaceholders = pressed
ribbonUI.InvalidateControl "rxtglPicHold"
ActiveWindow.View.ShowPicturePlaceHolders = global_ShowPicPlaceholders
End Sub
Public Sub AutoExec()
Register_Event_Handler
End Sub
Public Sub Register_Event_Handler()
If appWord Is Nothing Then
Set appWord = New ThisApplication
End If
End Sub
Remember, this is just proof of concept. I wouldn't distribute this code without better (some!) error trapping, and a lot more plunking away on it. But this creates a button which represents the current state of the current document, I think.

EDIT: I wrote this somewhat fast, and it's a slight update to what I just posted, so that it retains whatever the current document's view state is.

DaVinney
04-20-2011, 08:05 AM
Thanks for your helpful efforts, Frosty :hi:

I'm studying the code, trying to figure it out, possibly adapt it for my needs if I can. I have several of these toggle settings buttons I'd like to incorporate. First on the list is understanding class modules :think:

Frosty
04-20-2011, 10:25 AM
No problem. I'm learning too as I do it.

Classes is a big topic. I'd stick with just document events for now.

DaVinney
04-21-2011, 09:30 AM
Ended up using Frosty's suggestion in post #8 above to workaround the subject runtime error. For the _getPressed event, instead of say:
returnedVal = ActiveWindow.View.ShowHiddenText
(results in the runtime error when used on more than one doc)

I used a global variable and set the value:
global_ShowHiddenText = ActiveWindow.View.ShowHiddenText

Then in the _getPressed event:
returnedVal = global_ShowHiddenText

Works in the meantime...while I study the workings of code in post #9.

Thanks Frosty :hi: