Shortcut to toggle line spacing (leading?)

T

Top Spin

How can I create a pair of shortcut keys (eg, Ctrl+L & Ctrl+Shift+L)
that will toggle the line spacing for the current line (paragraph).
When I say "line spacing", I probably mean leading. It's the "spacing"
settings (before and after) in the Format / Paragraph panel.

I would like Ctrl+L to toggle the "space before" setting between 6
points and 0 points and Ctrl+Shift+L to do the same for the "space
after" setting.

I do not want any other settings affected.

Can anyone direct me on how to accomplish this?

Thanks
 
L

Larry

I'll take you step by step through it.

First, you get the basic code for this by recording a macro. Turn on
the macro recorder (in the Tools menu), give the macro the name
SpaceBeforeToggle, then perform the action you want, such as making the
space before for the current paragraph 6 points, by opening the
FormatParagraph dialog box and changing that setting for the current
paragraph. When done, turn off the macro recorder and go to the VB code
window (Alt+F11).

The code in the VB window will look something like this:

Sub SpaceBeforeToggle()

With Selection.ParagraphFormat
.LeftIndent = InchesToPoints(0)
.RightIndent = InchesToPoints(0)
.SpaceBefore = 6
.SpaceAfter = 0
.LineSpacingRule = wdLineSpaceSingle
.Alignment = wdAlignParagraphLeft
.WidowControl = True
.KeepWithNext = False
.KeepTogether = False
.PageBreakBefore = False
.NoLineNumber = False
.Hyphenation = True
.FirstLineIndent = InchesToPoints(0)
.OutlineLevel = wdOutlineLevelBodyText
End With
End Sub

Now, you don't want to have all those things happen every time you run
the macro. You only want to toggle between 6 points and 0 points before
the paragraph. So, the only part you want is this:

With Selection.ParagraphFormat
.SpaceBefore = 6
End With

You don't need the With ... End With" structure here, so you can
re-write it like this:

Selection.ParagraphFormat.SpaceBefore = 6

But you want this to be a toggle between 6 points and 0 points. This is
the way you do that:

If Selection.ParagraphFormat.SpaceBefore = 6 Then
Selection.ParagraphFormat.SpaceBefore = 0
Else
Selection.ParagraphFormat.SpaceBefore = 6
End If

That's it. Now you just need to assign a keystroke. For that, go to
Customize Keyboard dialog box (Tools, Customize, Keyboard) (by the way,
there's a built in command to open this dialog to which you can assign a
keystroke). In the left pane, choose Macros. In the right pane, find
your SpaceBeforeToggle. Then assign a keystroke.

With the Space after, you don't need to do a recording, since you
already have the basic code. Just change "SpaceBefore" to "SpaceAfter"
and make your second macro.

Larry
 
T

Top Spin

Larry,

That's so sweet. Your directions were so easy to follow and it works
like a charm. MSFT needs to hire you to write their online help.

Flushed with success, I think I'll expand the macro to cycle through a
sequence of settings involving both space before and after.

Next time you are in Palo Alto, give me a call and I'll buy you a beer
or dinner.

Thanks so much.
 
T

Top Spin

Larry,

Armed with your excellent instructions, I expanded the macro to handle
the case where the current setting is neither 0 or 6 -- which might
mean that I put the cursor on the wrong line. I don't want to change
something that is set to 12 or 18, since my toggle can't put it back
the way it was.

My new and improved code is: (critiques welcomed)


Sub SpaceBeforeToggle()
'=====================================================================
' Macro: SpaceBeforeToggle, Recorded on 07/21/04
'
' Toggle the Space Before paragraph setting between 0 and 6 points
' If it's not currently 0 or 6, ask the user for instructions
'=====================================================================
Dim setting, reply

setting = Selection.ParagraphFormat.SpaceBefore
If setting = 6 Then 'If it's 6 now,
Selection.ParagraphFormat.SpaceBefore = 0 'Set it to 0
ElseIf setting = 0 Then 'If it's 0 now,
Selection.ParagraphFormat.SpaceBefore = 6 'Set it to 6
Else 'Otherwise, ask the user
reply = MsgBox("Space after = " & setting & ", set it to 0?", _
vbYesNoCancel, "SpaceBeforeToggle macro")
If reply = vbYes Then 'If they say yes,
Selection.ParagraphFormat.SpaceBefore = 0 'Set it to 0
End If 'Otherwise, do nothing
End If

End Sub
 
L

Larry

You're welcome. I agree there's a need for more clearly written Help
materials.

As you learn more, you may also want to learn using Word's styles to
change the paragraph formatting.

Larry
 
T

Top Spin

Larry,

Armed with your excellent instructions, I expanded the macro to handle
the case where the current setting is neither 0 or 6 -- which might
mean that I put the cursor on the wrong line. I don't want to change
something that is set to 12 or 18, since my toggle can't put it back
the way it was.

My new and improved code is: (critiques welcomed)


Sub SpaceBeforeToggle()
'=====================================================================
' Macro: SpaceBeforeToggle, Recorded on 07/21/04
'
' Toggle the Space Before paragraph setting between 0 and 6 points
' If it's not currently 0 or 6, ask the user for instructions
'=====================================================================
Dim setting, reply

setting = Selection.ParagraphFormat.SpaceBefore
If setting = 6 Then 'If it's 6 now,
Selection.ParagraphFormat.SpaceBefore = 0 'Set it to 0
ElseIf setting = 0 Then 'If it's 0 now,
Selection.ParagraphFormat.SpaceBefore = 6 'Set it to 6
Else 'Otherwise, ask the user
reply = MsgBox("Space after = " & setting & ", set it to 0?", _
vbYesNoCancel, "SpaceBeforeToggle macro")
If reply = vbYes Then 'If they say yes,
Selection.ParagraphFormat.SpaceBefore = 0 'Set it to 0
End If 'Otherwise, do nothing
End If

End Sub

I just encountered a little glitch.

It appears that Word returns "9999999" in response to

setting = Selection.ParagraphFormat.SpaceBefore

if the selection includes more than 1 line and they do not all have
the same setting. That is, if the Format / Paragraph panel would have
that field blank.

What's the proper way to test for this condition? Compare against
"9999999" (7 9's)?
 
J

Jay Freedman

Top Spin said:
I just encountered a little glitch.

It appears that Word returns "9999999" in response to

setting = Selection.ParagraphFormat.SpaceBefore

if the selection includes more than 1 line and they do not all have
the same setting. That is, if the Format / Paragraph panel would have
that field blank.

What's the proper way to test for this condition? Compare against
"9999999" (7 9's)?

That's the numeric value of the built-in constant wdUndefined.

If you want to work on only the first paragraph when this occurs, you
can insert this before the line you quoted:

If Selection.ParagraphFormat.SpaceBefore = wdUndefined Then
Selection.Collapse wdCollapseStart
End If
 
T

Top Spin

Have a look at this article from the Word MVP site

http://word.mvps.org/FAQs/MacrosVBA/DeclareVariables.htm

which explains why it is better to declare variables with explicit data types.

Yes, I agree. Part of the reason was that it's just a quickie macro --
not a 5,000 module.

Also, I didn't know what the data type would be.

Is the result of "Selection.ParagraphFormat.SpaceBefore" Double?
Single? Integer? Long? ???

Is the result of MsgBox String?

I didn't want to spend the time to go figure it out and I knew that
Variant would handle anything.

Now, following your chastening, I did a little research. It appears
that "Selection.ParagraphFormat.SpaceBefore" returns a Single and
MsgBox a Long. Is that correct?

The Help file actually says that SpaceBefore returns a Single, but
check out this from the the MsgBox help:

=============== extract from VBA help file ==============
Dim Msg, Style, Title, Help, Ctxt, Response, MyString
Msg = "Do you want to continue ?" ' Define message.
Style = vbYesNo + vbCritical + vbDefaultButton2 ' Define buttons.
Title = "MsgBox Demonstration" ' Define title.
Help = "DEMO.HLP" ' Define Help file.
Ctxt = 1000 ' Define topic
' context.
' Display message.
Response = MsgBox(Msg, Style, Title, Help, Ctxt)
If Response = vbYes Then ' User chose Yes.
MyString = "Yes" ' Perform some action.
Else ' User chose No.
MyString = "No" ' Perform some action.
End If
=================================================

Do as I say, not as I do, I guess.

Maybe you should send your suggestion to the MSFT VBA help file
writers. ;-)

Anyway, here's the latest version of the macro:

Option Explicit

Sub SpaceBeforeToggle()
'=====================================================================
' Macro: SpaceBeforeToggle, Recorded on 07/21/04
'
' Toggle the Space Before paragraph setting between 0 and 6 points
' If it's not currently 0 or 6, ask the user for instructions
' If the selection contains different settings,
'=====================================================================
Dim setting As Single, reply As Long, msg As String

setting = Selection.ParagraphFormat.SpaceBefore
If setting = 6 Then 'If it's 6 now,
Selection.ParagraphFormat.SpaceBefore = 0 'Set it to 0
ElseIf setting = 0 Then 'If it's 0 now,
Selection.ParagraphFormat.SpaceBefore = 6 'Set it to 6
ElseIf setting > 999 Then 'If there are different
settings,
msg = "The selection contains multiple Space Before settings. " _
& "Set them all to 0?"
reply = MsgBox(msg, vbYesNoCancel + vbDefaultButton2,
"SpaceBeforeToggle macro")
If reply = vbYes Then 'If they say yes,
Selection.ParagraphFormat.SpaceBefore = 0 'Set it to 0
End If 'Otherwise, do nothing
Else 'Otherwise, ask the user
reply = MsgBox("Space before = " & setting & ", set it to 0?", _
vbYesNoCancel + vbDefaultButton2, "SpaceBeforeToggle macro")
If reply = vbYes Then 'If they say yes,
Selection.ParagraphFormat.SpaceBefore = 0 'Set it to 0
End If 'Otherwise, do nothing
End If

End Sub

How's that?

Thanks
 
M

Martin

Top Spin said:
Anyway, here's the latest version of the macro:

How's that?
Yes, you're right, SpaceBefore does return a Single; my help file
(Word 2000) says that MsgBox returns an integer, not a long, *but*
strictly speaking it returns a vbMsgBoxResult, which is an enumerated
type containing the values vbYes, vbNo etc, which are all just
constants representing numeric values.

You can see this if you hit F2 within the VBA Editor which will open
up the object browser. Type msgbox into the Search Text box and click
on the binoculars to search. Within the Search Results pane click on
the line which has Class Interaction, Member MsgBox. Then at the very
bottom of the screen you will see the definition of the function,
including the return type "As VbMsgBoxResult". If you click on that
hyperlink the lower pane will then show you the members and if you
click on one of them you can see at the buttom what actual numeric
value each of the constants represents.

In your code if you

Dim reply as vbMsgBoxResult

then as soon as you type

If reply =

you will get a popup menu containing all the members of the type,
which you can then select one from.

I agree too that some of the examples in the VBA/VB help files are
dreadful because of their practice of leaving out the variable types!!

You're obviously keen so may I be picky with your code? :

* Why have Yes, No and Cancel buttons in your message boxes, when
you're only interested in Yes or No?
* I would make the string "SpaceBeforeToggle macro" into a constant;
then if you want to change it you only have to do so in one place, not
search and replace (obviously in this tiny macro it's not a great job
to do so but I am talking good practice here!)

Having started to think about things I realised that I would do a few
things differently and I ended up with the following :

Sub SpaceBeforeToggle()
'=====================================================================
' Macro: SpaceBeforeToggle, Recorded on 07/21/04
'
' Toggle the Space Before paragraph setting between 0 and 6 points
' If it's not currently 0 or 6, ask the user for instructions
' If the selection contains different settings,
'=====================================================================

Dim sngSetting As Single, strMsg As String

' Store the existing setting
sngSetting = Selection.ParagraphFormat.SpaceBefore

Select Case sngSetting

Case 6
sngSetting = 0

Case 0
sngSetting = 6

Case Is > 999 'If there are different settings,
strMsg = "The selection contains multiple Space Before
settings. Set them all to 0?"

Case Else
strMsg = "Space before = " & sngSetting & ", set it to 0?"

End Select

If Len(strMsg) <> 0 Then ' If there is a message to display

If MsgBox(strMsg, vbYesNo + vbDefaultButton2 + vbInformation,
"SpaceBeforeToggle macro") = vbYes Then
sngSetting = 0
End If

End If

' Set to new setting (or existing if no change is to be made)
Selection.ParagraphFormat.SpaceBefore = sngSetting

End Sub


You'll notice that
* I have used a Select Case statement which to me is clearer to read
* there is more white space, again making it nicer to read
* there is now only one MsgBox statement, so the need for a constant
has gone away
* that I don't assign the return value from the MsgBox function to an
intermediate variable but just test it directly
* my variable names are prefixed so that it is immediately clear what
datatype they are

Your code worked fine, and some of what I have done is purely
stylistic. I hope it gives you some different ideas which you can use
in the future if you choose. If you, or anyone else, would like to
argue about how I have done things that will be just fine :)

Martin
 
T

Top Spin

On 28 Jul 2004 08:04:46 -0700, (e-mail address removed) (Martin) wrote:

Martin,

Thanks for the comments. I will play with them when I get a chance.
 

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