Toggle macro button

G

Guillermo

Hello all,

I'd like to know how a macro button can be turned into a toggle, like the bold button
in the format bar, for example.

TIA,

Guillermo
 
G

Greg

Guillermo,

I has nothing to do with the button but with the code the button causes
to execute. For example, if you assigned the following code to a
macrobutton, toolbar button, menu item, shortcut key, etc., it would
toggle text formatted with automatic font color to red font color or
red font color to automatic.

Sub Toggle()
Dim oState As Long
oState = Selection.Range.Font.Color
If oState = -16777216 Then
Selection.Range.Font.Color = 255
ElseIf oState = 255 Then
Selection.Range.Font.Color = -16777216
End If
End Sub

The numbers associated with font colors can be determined using the
object browser and search for wdColor.
 
G

Guillermo

I see, so it all comes down to a conditional statement. I thought it was something else.

Thank you very much, Greg.
 
C

Charles Kenyon

You _can_ also change the appearance of the button, but this is a real
change in your toolbar, not just the button state.
--
Charles Kenyon

Word New User FAQ & Web Directory: http://addbalance.com/word

Intermediate User's Guide to Microsoft Word (supplemented version of
Microsoft's Legal Users' Guide) http://addbalance.com/usersguide


--------- --------- --------- --------- --------- ---------
This message is posted to a newsgroup. Please post replies
and questions to the newsgroup so that others can learn
from my ignorance and your wisdom.
 
K

Klaus Linke

I wouldn't put it that way ;-)

With CommandBars.ActionControl
.State = Not (.State)
End With

Regards,
Klaus
 
C

Charles Kenyon

Guess I don't know how to create buttons that have multiple states. I know
it works with the built-in ones.
--
Charles Kenyon

Word New User FAQ & Web Directory: http://addbalance.com/word

Intermediate User's Guide to Microsoft Word (supplemented version of
Microsoft's Legal Users' Guide) http://addbalance.com/usersguide


--------- --------- --------- --------- --------- ---------
This message is posted to a newsgroup. Please post replies
and questions to the newsgroup so that others can learn
from my ignorance and your wisdom.
 
G

Greg

Klaus,

If you don't mind, have a look at the pictures of the toolbar I created
for an addin. There are three images at the bottom of the page:

http://gregmaxey.mvps.org/Bookmark_Tool.htm

Before these I had one tool bar with all four buttons. Helmut
suggested that I "dim" the "show" and "hide" buttons when the form was
closed. I couldn't figure out how to do this so opted with the
interactive style as shown. Unfortunately (and dimming may result the
same) everytime the addin is used and then I closed Word it would
trigger the "Do you want to save changes to BlahBlah.dot"

I got around that by adding a blahblah.dot Saved flag in the close
routine.

Can you explain to us masses ;-) how to dim a command bar button and if
that would eliminate the problem of Word asking to save changes to the
addin?

Thanks
 
K

Klaus Linke

Hi Greg,

DIMming the button won't get rid of your code "dirtying" the template, I'm
afraid.
If you want to ignore just the greying or toggling of the button, you can
save/reset the .Saved state just for that piece of code.

If you don't know the template you'll put the code in (or want to be free to
move it), this will get a bit difficult though, because you'll have to find
out the template that's responsible for that special button.

Maybe I missed an easy way to determine the template that created the button
(and saves any changes to it)...
Anyway, the code below, looping all active templates, should work:

Dim myCBB As CommandBarButton
Dim myButtonTemplate As Template, myTemplate As Template
Dim boolSaved As Boolean
' If the code is in the macro is the one that is run by the button:
Set myCBB = CommandBars.ActionControl
' Which template put that button there anyway?
For Each myTemplate In Application.Templates
If myCBB.Parent.Context = myTemplate.FullName Then
Set myButtonTemplate = myTemplate
End If
Next myTemplate
boolSaved = myButtonTemplate.Saved
' Do your dirty work...
myCBB.State = Not (myCBB.State)
' myCBB.Enabled = Not (myCBB.Enabled)
' ... and then reset the .Saved state:
myButtonTemplate.Saved = boolSaved

It would be nice if you could wrap that in a macro that toggles any button:
Call ToggleButtonState(myCBB)
(without changing the .Saved state of the template it comes from)
.... but I don't think you can pass controls as arguments.
Would be great if someone knows how to do that!

Regards,
Klaus
 
T

Tony Jollans

Hi Klaus,

1. Providing the CommandBar belongs to a Template you can (using your
variable names) ..

Set myButtonTemplate = Templates(myCBB.Parent.Context)

(If it belongs to a document then use Documents(myCBB.Parent.Context) of
course)

2. I don't have any problem passing a button to a procedure something like
this (to toggle any boolean property)

Sub ToggleState(myControl As CommandBarControl, myState As String)

Dim SavedState As Boolean
Dim OldState As Boolean
Dim ControlTemplate As Template

Set ControlTemplate = Templates(myControl.Parent.Context)
SavedState = ControlTemplate.Saved

OldState = CallByName(myControl, myState, VbGet)
CallByName myControl, myState, VbLet, Not OldState

ControlTemplate.Saved = SavedState
Set ControlTemplate = Nothing

End Sub

which can be called like

ToggleState myCBB, "Enabled"

Greg .. Note (if you didn't pick it up from Klaus' post) it is the Enabled
property which controls dimming.
 
G

Greg Maxey

Tony,

Yes I did pick that up. I decided that for my purposes I liked the
show/hide approach better.
 
G

Greg Maxey

Tony,

Your code is a bit over my head. Could you provide a little more detail as
to how I would create the toolbar with a button to be enabled and disabled
and then actually enabled and disabled using your code?

Thanks.
 
T

Tony Jollans

Hi Greg,

You create the toolbar as normal. You can use my code with your existing
toolbar.

Drop the Sub into your template somewhere (do you have a module for common
routines? No, you don't - I've just looked so drop it into the Bookmarker
module)

Then when you want to change one of your buttons call it. For example, you
could change your Sub Hide() like this:

Sub Hide()
oFrm.Hide
ToggleState CommandBars("Bookmarker").Controls("Show"), "Visible"
ToggleState CommandBars("Bookmarker").Controls("Hide"), "Visible"
End Sub

That simply toggles the visible state of each of the two controls - assuming
the Hide one is visble and the Show one isn't, then it will change it so
that the Show one is visible and the Hide one isn't.

What the code does is grab a reference to the template which 'owns' the
control and saves the "Saved" setting. Then it gets the (in this example,
Visible) setting of the control and sets it to the opposite. Then it resets
the Saved property of the template to what it saved before, releases the
template object and that's it. All you have to do is pass it a reference to
the control and the name of the property as a string - it will work for any
boolean property of a control (Visible, Enabled, State, etc.). The
CallByName construct is just a way of using a string for a property name
instead of having to code a reference to it - the string gets resolved at
runtime instead of compile time.
 
G

Greg Maxey

Tony,

Ok thanks. I see how I could use this to toggle the show and hide buttons

Sub ToggleShowHide()
ToggleState CommandBars("Bookmarker").Controls("Show"), "Visible"
If CommandBars("Bookmarker").Controls("Hide").Visible = True Then
oFrm.Hide
Else
oFrm.Show vbModeless
End If
ToggleState CommandBars("Bookmarker").Controls("Hide"), "Visible"
End Sub

Sub ToggleState(myControl As CommandBarControl, myState As String)
Dim SavedState As Boolean
Dim OldState As Boolean
Dim ControlTemplate As Template
Set ControlTemplate = Templates(myControl.Parent.Context)
SavedState = ControlTemplate.Saved
OldState = CallByName(myControl, myState, VbGet)
CallByName myControl, myState, VbLet, Not OldState
ControlTemplate.Saved = SavedState
Set ControlTemplate = Nothing
End Sub


With both the Open/Close and Show/Hide buttons being set to toggle, I think
I am going to play it safe and leave my code as is in this case. In the
future I can keep this method in mind. For now I am going to stick with old
saw "If it isn't broke, don't fix it." Thanks again.
 
T

Tony Jollans

I agree - if it ain't broke don't fix it.

I'm not sure I'd actually use it in its current form - I just posted it in
response to Klaus' post saying he didn't know how to do it.
 
G

Greg Maxey

Tony,

One more question. In setting up a toggle from scratch, I noticed that it
is a little tough to get the initial conditions set up (i.e., one showing
and one hidden). I created a new toolbar with two buttons, one "hide" and
one "show" (of course) they are both showing and applied your code. When I
clicked on either both are hidden. To get around this, I stetted out one of
the calls, executed the code and the cleared the stet ('). Is there a more
standard procedure?
 
T

Tony Jollans

Hi Greg,

When you creat the buttons you need to create the initail state - one hidden
and one shown.

That said, however, I think an optional parameter to my routine (True/False)
to force a setting rather than simply toggle might be helpful, something
like this (done quickly and not tested)

Sub ToggleState(myControl As CommandBarControl, myState As String, Optional
mySetting)

Dim SavedState As Boolean
Dim OldState As Boolean
Dim ControlTemplate As Template

Set ControlTemplate = Templates(myControl.Parent.Context)
SavedState = ControlTemplate.Saved

OldState = CallByName(myControl, myState, VbGet) ' .Enabled = Not
cc.Enabled
If Not IsMissing(mySetting) Then
If TypeName(mySetting) = "Boolean" Then OldState = Not mySetting
End If
CallByName myControl, myState, VbLet, Not OldState

ControlTemplate.Saved = SavedState

End Sub

This will (I hope!) force True or False if given as a third parameter.
 
G

Greg

Tony,

<When you creat the buttons you need to create the initail state - one
hidden
<and one shown.

I created them by dragging then to a new toolbar. I suppose I could
create the toolbar and the buttons with VBA and then achieve your
statement.

You lost me with your new code. What is cc? What is mySetting?

Using the following as an example, how would you apply your new code?

Sub ToggleShowHide()
ToggleState CommandBars("MyToggle").Controls("Bold On"), "Visible"
If CommandBars("MyToggle").Controls("Bold Off").Visible = True Then
ActiveDocument.Range.Bold = True
Else
ActiveDocument.Range.Bold = False
End If

ToggleState CommandBars("MyToggle").Controls("Bold Off"), "Visible"
End Sub
Sub ToggleState(myControl As CommandBarControl, myState As String)
Dim SavedState As Boolean
Dim OldState As Boolean
Dim ControlTemplate As Template
Set ControlTemplate = Templates(myControl.Parent.Context)
SavedState = ControlTemplate.Saved
OldState = CallByName(myControl, myState, VbGet)
CallByName myControl, myState, VbLet, Not OldState
ControlTemplate.Saved = SavedState
Set ControlTemplate = Nothing
End Sub

Thanks
 
T

Tony Jollans

Hi Greg,

Apologies - the cc is an overflow of a comment on the previous line which I
should have deleted - it's the remnants of earlier code and not relevant at
all. mySetting is also an overflow due to the line breaks added by the
system. I have reformatted in the code below to stop that happening (I
hope).

I just assumed you created your toolbar with VBA but if you've done it via
the UI then you can't make a control hidden. I guess I'd do it with a
one-off statement in the immediate window - whatever, it needs VBA.

The new code adds an optional override to the toggle setting so, for
example, you could do ..

ToggleState CommandBars("Bookmarker").Controls("Hide"), "Visible", False

to force the setting of visible to false (i.e. hide the control) instead of
toggling what was there before. myOverride might have been a better choice
of name than mySetting.

The extra parameter is optional so that the original still worked, in other
words ..

ToggleState CommandBars("Bookmarker").Controls("Hide"), "Visible"

still toggled the setting.

To use it (somewhat artificially) in your example you could be explicit in
what you set rather than toggling. I think you've got the check wrong so
I've changed it in this ..

Sub ToggleShowHide()
ToggleState CommandBars("MyToggle").Controls("Bold On"), "Visible", False
If CommandBars("MyToggle").Controls("Bold Off").Visible = False Then
ActiveDocument.Range.Bold = True
Else
ActiveDocument.Range.Bold = False
End If

ToggleState CommandBars("MyToggle").Controls("Bold Off"), "Visible", True
End Sub

Sub ToggleState(myControl As CommandBarControl, _
myState As String, _
Optional mySetting)

Dim SavedState As Boolean
Dim OldState As Boolean
Dim ControlTemplate As Template

Set ControlTemplate = Templates(myControl.Parent.Context)
SavedState = ControlTemplate.Saved

OldState = CallByName(myControl, myState, VbGet)
If Not IsMissing(mySetting) Then
If TypeName(mySetting) = "Boolean" Then OldState = Not mySetting
End If
CallByName myControl, myState, VbLet, Not OldState

ControlTemplate.Saved = SavedState

End Sub

It's your code, but I would actually do it more simply ..

Sub ToggleShowHide()
With CommandBars("MyToggle")
ActiveDocument.Range.Bold = .Controls("Bold On").Visible
ToggleState .Controls("Bold On"), "Visible"
ToggleState .Controls("Bold Off"), "Visible"
End With
End Sub

The possible permutations are endless - you could, perhaps, make the
ToggleState procedure automatically toggle two buttons at a time (as that's
what you're always doing - and probably always will) - or you could give it
two buttons and tell it to ensure one is true, the other false, etc., etc. -
the world, as they say, is your lobster (or something of the sort). As
already agreed, if it works don't fix it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top