PDA

View Full Version : Can styles help format a hash?



mansky
03-06-2006, 11:30 AM
Hi,
I'm just learning how to use styles in Word and wanted to know if they can be used to do the following. I have a hash at the begining of a document (defined in an attached template) that is in it's own paragraph. The hash consists of several lines of text, each line of the form:
Label: Value.

I've created some custom styles of my own and using:

ActiveDocument.Paragraphs(1).Style = "VMText"

where VMText is one of my custom styles (w/Style Type = wdStyleTypeParagraph). This statement applies my style to all the text in the paragraph specified, as I expected.

However, I want finer control over the text in the "hash" paragraph. I want on each line the text to the left of the colon to be boldface and in one font, pointsize and color, the text to the right of the colon to be in a different font, pointsize and color.

I noticed that the Styles object has only two values for Type: wdStyleTypeCharacter and wdStyleTypeParagraph. No wdStyleTypeWord enum value.

To get a particular style associated with a "word" do I have to count characters and/or search for a delimiter (eg. the colon char) ? Or is there an easier way to get my hash labels all boldface? As you can tell, I'm not really sure how to use the wdStyleTypeCharacter.:think:


Any ideas on how to get finer control of text are greatly appreciated!


Ed

fumei
03-06-2006, 09:50 PM
Styles apply, as you have discovered, to characters, or paragraphs. In later versions of Word there are also Table and List styles - however, that is not really relevant here.

Anyway, the answer is....Word uses styles with characters, or paragraphs. Not words. That is the way it is.

OK, a few questions. You state the hash paragraph is "defined in an attached template".

1. Are you creating this document as a clone from that template?

2. Why do you not simply have that paragraph formatted properly in the template? Then it would be formatted that way in any cloned document. The only reason I can this not working is if you have the values (Label: value) being creating dynamically. If this is correct, this is a significant piece of information. Please confirm.

3. You state the hash is in
it's own paragraph.However you also state
The hash consists of several linesHow are these line breaks being done? If it is ONE paragraph (as is implied)...then there are no line breaks. If there ARE line breaks, then either there are multiple paragraphs, or you are using a line break. As you can see it helps to describe in detail.

The reason I am asking these is that there are a couple of possible solutions, but they depend on what exactly is happening.

mansky
03-07-2006, 09:42 AM
Hi Gerry,
Here are the answers to your questions:



1. Are you creating this document as a clone from that template?

Yes, the document that contains the text that I want to finely control the formatting of is created via code in a Document_New() module of the attached template.



2. Why do you not simply have that paragraph formatted properly in the template? Then it would be formatted that way in any cloned document. The only reason I can this not working is if you have the values (Label: value) being creating dynamically. If this is correct, this is a significant piece of information. Please confirm.

Yes, the information in some of the values is dynamic. For example, some of the hash values contain information from iTunes (another app on the Mac). The particular values depends on the selction made by the User at runtime. Here's an example:

Document Name: Document3
Pathname:
VM Filename: 20060111 131153.wav
KW:
VM Participants:
Date Recorded: 1/11/2006
Subject:
Length of Recording: 00:31:18
Recording Device: iPod
Location of Recording:

where the "VM Filename" and "Length of Recording" fields have values that are filled in at runtime from iTunes.

Here's a code snippet from the Document_New() module of the attached template:

' code snippet .....
ActiveDocument.Paragraphs.Add
ActiveDocument.Paragraphs.Add
ActiveDocument.Paragraphs.Add

ActiveDocument.Paragraphs(1).Style = "VMText"
ActiveDocument.Paragraphs(2).Style = wdStyleBodyText
ActiveDocument.Paragraphs(3).Style = wdStyleBodyText

'Insert VMHash into document
Set F1 = ActiveDocument.Paragraphs(1).Range
For i = 1 To NoHFields
If (i = 1) Then 'first time thru
If (MyHashes.VMHash(i, 2) = "blank") Then
F1.Text = MyHashes.VMHash(i, 1) & vbCrLf
ElseIf (MyHashes.VMHash(i, 2) = "objectName") Then
F1.Text = MyHashes.VMHash(i, 1) & " " & _
ActiveDocument.Name & vbCrLf

' ..... code snipped here for clarity
End If
Else
If (MyHashes.VMHash(i, 2) = "blank") Then
F1.InsertAfter (MyHashes.VMHash(i, 1) & vbCrLf)
ElseIf (MyHashes.VMHash(i, 2) = "objectName") Then
F1.InsertAfter (MyHashes.VMHash(i, 1) & " " & _
ActiveDocument.Name & vbCrLf)
ElseIf (MyHashes.VMHash(i, 2) = "objectPath") Then
F1.InsertAfter (MyHashes.VMHash(i, 1) & " " & _
ActiveDocument.Path & vbCrLf)
ElseIf (MyHashes.VMHash(i, 2) = "Date") Then
F1.InsertAfter (MyHashes.VMHash(i, 1) & " " & _
Date & vbCrLf)
' ... more code snipped here
End If
Next i

where MyHashes is a User-defined data type containing the labels I want in the hash. The MyHashes UDT also contains text in the value field that is used in the Document_New code to place a Date, or a document name, or the length (in time) of a particular iTunes selection in a particular value field.

You mentioned about "properly formatting" the paragraph in the template itself. How would one format a paragraph in a template when some of the info in the paragraph is not known until runtime and comes from apps outside of Word (or even Office)?



3. How are these line breaks being done?

I explicitly put in vbCrLf chars in the range of the paragraph I am creating.

Does my insertion of vbCrLf chars mean I am creating a new paragraph each time I place a vbCrLf char in a range? I thought I was doing all this formatting in the first paragraph of the document.

Hope this makes a little clearer what I am doing. :)


Ed

fumei
03-07-2006, 12:44 PM
1. Please use the underscore character in your code. NOT using it makes the code window here stretch out so I have to scroll left/right as well as up/down. It is a pain. Thanks.


Does my insertion of vbCrLf chars mean I am creating a new paragraph each time I place a vbCrLf char in a range? I thought I was doing all this formatting in the first paragraph of the document.2. These two sentences are not connected. Yes, including a vbCrLf means you are making a new paragraph. That is what vbCrLf does. However, yes, you are doing the format to the first pargraph.

ActiveDocument.TypeParagraph
ActiveDocument.TypeParagraph
ActiveDocument.TypeParagraph

makes three paragraph. So there are three paragraphs.

F1.Text = "blah blah" & vbCrLf (with F1 = paragraph 1) does indeed put that text there. But it does add a paragraph mark...so now there are FOUR paragraphs.

3. I guess I have to ask again for clarification.

Document Name: Document3
Pathname:
VM Filename: 20060111 131153.wav
KW:
VM Participants:
Date Recorded: 1/11/2006
Subject:
Length of Recording: 00:31:18
Recording Device: iPod
Location of Recording:

Does each of these lines have a paragraph mark??? In other words, is Document Name paragraph 1, Pathname paragraph 2, VMFilename paragraph 3...etc.?

4. Is the number of paragraph - this is assuming the answer to #3 above IS that they are separate paragraphs - a known quantity? In other words, like Pathname above, is the label there, but the value may not? Or will the labels be variable?

5. Regarding the format of the paragraph in the template...as far I understand there IS not paragraph in the template. Your Document_New make it (them).

Here is what I would do, but this greatly depends on how you are getting the hash together, I mean the hash that will be in the document.

Also first of all, I would suggest that since you are using a defined style for part of your text...use defined styles for all of it. I am going to do that for this example, and have two styles: "LabelStyle" as the bold (ignoring for now the other attributes), and "ValueStyle" as the not bold. These would be character styles. This would permit ? if you wanted to - to have the ":" between label and value the attributes of the paragraph style. This could be different again from both Label and Value. I mean if you wanted to.

So your paragraphs ? note the plural! ?in the template would be like this:

"Label1" : "Value1"
"Label2" : "Value2"
"Label3" : "Value3"
"Label4" : "Value4"

Labelx and Valuex are bookmarks. But note ? VERY important! ? that in the template, there is NO text. Repeat NO text. This would allow your Document_New to insert text (both Label and Value) there. As each bookmark has its text entered, the appropriate character style is also attached.

I am attaching a template file (hash.dot) that demonstrates what I am talking about.

You may note some tricky code regarding the bookmarks. As I want to make the bookmark itself have the character style I need to essentially recreate it. Inserting text using a bookmark does NOT (in most versions of Word) make the bookmark range that text. This is even with using Bookmarks("BlahBlah").Range.Text = "MoreBlah" If you select Bookmarks("BlahBlah") the inserted text is NOT included, therefore a style can not be attached. So the code resizes the selection, attaches the style to the selection, and recreates the bookmark with selection.range.

You can see it in the attached demo. BTW: I used four paragraphs for the demo. This could be made dynamic. That is why I asked about whether the number of Labels/Values is fixed, or not.

Hope this helps.

fumei
03-07-2006, 12:47 PM
Oh crap. I just realized that I made the example styles weird fonts...and you may not have those. I was playing around so the Label and Value portions would be as visibly different as possible. If you have problems post back and i will change it.

fumei
03-07-2006, 12:51 PM
Heck with it. Here is the same file, but with both LabelStyle and ValueStyle using Time Roman. LabelStyle is larger and bold.

mansky
03-07-2006, 02:03 PM
Gerry,
Sorry if the posted code was difficult to read. I've edited the original post to add _ to make it easier to read now.

Wow, I am suprised to find out that vbCrLf adds a paragraph mark, in addition to a carriage return and line feed combination. I must've missed that in the reading I've been doing!

I've been working under the assumption that each label/value pair of the hash were all in the paragraph I started in (the first).

So, to answer your question, yes I have a vbCrLf at the end of each label/value pair. That was the only way I thought to get the next line of text to actually appear on the next line in the document. Of course, if there's a different/better way to get the next label/value pair to appear on the next line and keep it all in the same paragraph, I'd like to know how.

And, secondly, yes the number of label/value pairs in a given hash is known at the time the document is created. This integer value is stored in the variable "NoHFields" in the code snippet I posted.

Also, there is no text or formatting in the window of the template. I have one template read in the hash from a flat file. The second template then graps that particular hash from a UDT that I populate by the code in the first template. The upshot is that all the text in the hash in the document created by the Document_New module is done in code.

Futhermore, the labels in the hashes are all known, but the values may not all be populated at runtime. If the value is known (Date, document name, length of recording, etc.), I fill it in during the loop that processes the hash in the Document_New module. The various branches in this loop determine what appears in the value field of the new document that's created from the Document_New module.

So it appears that I have a lot more paragraphs in the document than I thought I did, and have coded for! Not what I was expecting

One goal of all this code was to have the definition of a hash for a new document type be driven from a flat file.

I'll post back with questions after I look at the code in your zip file. Thanks!


Ed

fumei
03-07-2006, 02:51 PM
So, to answer your question, yes I have a vbCrLf at the end of each label/value pair. That was the only way I thought to get the next line of text to actually appear on the next line in the document.You are confusing "line" with "paragraph". This is a very important point.
Of course, if there's a different/better way to get the next label/value pair to appear on the next line and keep it all in the same paragraph, I'd like to know how.Yes this is very possible, but I strongly, strongly advise against this. It is poor design as far as I am concerned.
yes the number of label/value pairs in a given hash is known at the time the document is created. This integer value is stored in the variable "NoHFields" in the code snippet I posted.In that case you have two choices, either the template HAS all possible labels as text (bookmarks), or it does not. If it does, then - if I understand correctly - you are stating that some of this list would need to be removed. If it does NOT have them already there, then you are back to populating the new document with them. Could be done. You could create the bookmarks on the fly. That is, IMHO, not very good design though.
Also, there is no text or formatting in the window of the template. HUH????? "window of the template"...I have no idea at all what that may be about.

mansky
03-07-2006, 04:02 PM
Gerry,
Sorry if I was unclear. By "window of the template" I mean when you open a template a window is presented by Word with the template filename in the title bar of a window. It's that window I was referring to. I have nothing in that window. Rather, I have the hash defined in code in the Document_New module visible in the VBE. Hope that's a little clearer now.




You are confusing "line" with "paragraph". This is a very important point.

I think you are quite right about this. I am indeed now confused over what exactly defines a "paragraph". I never thought putting a vbCrLf at the end of a string of text would also put something there that increases the number of paragraphs in the document.

Should I have used the vbNewLine constant instead of vbCrLf? Or something else?

As for the hash, it is fully defined and known at the time the Document_New module is called. If a particular value is blank, that's OK. I don't want it deleted or removed, rather I want the label to appear in the cloned document, and leave it to the User to fill in text at that point in the document. I want the code, when it encounters a hash value that is blank (I use the string literal "blank" to signal this state), to then move on to the next hash element (label/value pair). I was hoping to keep the rest of the hash elements in the same paragraph, and not keep creating new paragraphs -one for each element of the hash.

Thanks for the help, it is greatly appreciated. Your solution, using bookmarks, is quite clever. I never thought of using bookmarks in this way.:yes


Ed

fumei
03-07-2006, 05:37 PM
By "window of the template" I mean when you open a template a window is presented by Word with the template filename in the title bar of a window. I will repeat my...HUH???? I have absolutely no idea what you are talking about. I have used templates with Word for 15 years. I have no idea what you are talking about. What window is presented by Word? What does this window DO? Finally, if you are opening the template to do this thing, then you are totally using templates incorrectly. Templates are not to be opened at all - except for designing them. Templates are to be used, not opened. They are to be cloned, using File > New.

What defines a paragraph? This is simple. A paragraph is any range of text, or graphic, that has its terminus a paragraph mark. The attributes of this range is defined by the properties contained within that paragraph mark. That is, the paragraph mark holds the attribute of the range. There is ALWAYS at least one paragraph in a Word document. Always. It is impossible to remove the final (or if it is the only one - the only one) paragraph mark.

Further, cells in a table are paragraphs. A paragraph count of a document counts each cell in the document as a paragraph.

Again, I do not like to use it, by the VBA equivalent to a Shift-Enter is vbVerticalTab. This does in fact make a new line, but retains the current paragraph mark.
I was hoping to keep the rest of the hash elements in the same paragraph, and not keep creating new paragraphs -one for each element of the hash. I am not sure what your objection is to having individual paragraphs for each line of your labels, but even Microsoft discourages the use of vbVerticalTab. And I concur - it is poor document design. Why do you think it is important to have a single paragraph?

In any case I believe we are diverging, so hopefully you can find something helpful in this thread. It is my opinion that your template should contain the text for all possible labels, and then go on from there.

Good luck.

mansky
03-08-2006, 10:00 AM
Gerry,
The "window" I am referring to is the window displaying the template file during my designing of the template code only, not the usage of the template via the cloned document. Sorry if my previous posts were unclear about the difference.

In addition to your solution, via Bookmarks, I've come up with a solution involving a subroutine call that will switch the style of the text I want finer formatting control over on a character-by-character basis.

Here's a code snippet :

' code snippet from the Document_New ...

ActiveDocument.Paragraphs(1).Style = "VMText"
ActiveDocument.Paragraphs(2).Style = wdStyleBodyText
ActiveDocument.Paragraphs(3).Style = wdStyleBodyText

iStart = 1
iEnd = 0

'Insert VMHash into document
Set F1 = ActiveDocument.Paragraphs(1).Range
For i = 1 To NoHFields
If (i = 1) Then 'first time thru
If (MyHashes.VMHash(i, 2) = "blank") Then
F1.Text = MyHashes.VMHash(i, 1) & vbCrLf
ElseIf (MyHashes.VMHash(i, 2) = "objectName") Then
F1.Text = MyHashes.VMHash(i, 1) & " " _
& ActiveDocument.Name & vbCrLf
' ... code snipped for clarity ...
End If
iEnd = F1.End
Else
If (MyHashes.VMHash(i, 2) = "blank") Then
F1.InsertAfter (MyHashes.VMHash(i, 1) & vbCrLf)
ElseIf (MyHashes.VMHash(i, 2) = "objectName") Then
F1.InsertAfter (MyHashes.VMHash(i, 1) & " " _
& ActiveDocument.Name & vbCrLf)
ElseIf (MyHashes.VMHash(i, 2) = "objectPath") Then
F1.InsertAfter (MyHashes.VMHash(i, 1) & " " _
& ActiveDocument.Path & vbCrLf)
' ... more code snipped ...
Else
F1.InsertAfter (MyHashes.VMHash(i, 1) & " " _
& MyHashes.VMHash(i, 2) & vbCrLf)
End If
iStart = iEnd + 1
iEnd = F1.End
End If

Call Switch2Bold(F1, iStart, iEnd)
Next i

where the subroutine is:

Sub Switch2Bold(ByRef F1 As Range, _
ByVal iBegin As Integer, ByVal iFinal As Integer)
Dim ColonIndex As Integer, i As Integer

ColonIndex = InStr(iBegin, F1.Text, ":")
If (ColonIndex > iFinal) Then
Exit Sub
End If

For i = iBegin To ColonIndex - 1
With F1.Characters(i)
.Style = "VMLabel"
End With
Next i
End Sub

where "VMLabel" is a custom defined style w/Type=wdStyleTypeCharacter.

The key point for me to get the "Switch2Bold" subroutine to work was to get the iStart and iEnd integers correctly incremented so as to move down the range F1 as it is appended to in the main loop.

Finally, thanks for the info on paragraph marks. I didn't know vbCrLf chars added a paragraph mark to a document, nor that cells in a table were counted as paragraphs. I did more testing as a result of your previous posts, and it indeed appears to me that vbCr, vbLf and vbNewLine also result in the paragraph count being incremented by 1.

I'd like to read more about which chars (or objects) add paragraph marks (and thereby increment the paragraph count -if that's the correct language). Can you point me in the direction of a VBA help entry, or other pointer, where I might read more about paragraph marks?


Sorry if my posts were unclear. I was speaking in my earlier posts strictly in terms of the design/development part of the template code, not the end use of a template (via a cloned document).

Thanks again for all your help, it is greatly appreciated!


Ed

fumei
03-08-2006, 11:01 PM
Hi Ed. Regarding further post...it is important to let us know these things! For one thing, there are errors that can ONLY appear during run-time. Running code from the VBE (as the designer) and running code as the user, can often make a fine, but very distinct, difference.

Well.....you can do whatever you want of course, but I think you are making this way, way, too complicated.

Shrug....whatever. As for:
I'd like to read more about which chars (or objects) add paragraph marks (and thereby increment the paragraph count -if that's the correct language).This is easy.

None. I am not quite sure what you mean by "chars", but if you mean characters...no characters make paragraph marks. As for objects. None. No object makes paragraph marks.

A paragraph mark is created:

by code - vbCrlf, vbNewLine, vbCr
manually - pressing the Enter key

That is it.

However, if you want to find out more about what a paragraph mark means....that is another story. Help is of no help. Existing books are not much better. Microsoft web site is not much better either.

It MAY help to do this. Record a macro that does everything possible to a paragraph - changes the font in it, borders of it, line spacing, before and after spacing, everything you can possible think. Numbering, bullets, style...everything.

Now look at the code. EVERY scrap of code there, EVERY line, every With statement, everything there....wait for it....IS a paragraph mark. Every single paragraph mark in a document IS that code. Every time you add those "extra" Enter keys to make space between paragraphs (that have text)? Guess what? Each one of those IS a paragraph mark (or rather a paragraph...which means a paragraph mark), and contains all that code which MUST be parsed and read by Word. Word does not ignore paragraphs (ie paragraph marks) that do not have text within the range...no sirree Bob. Word parses and checks out EVERY single parameter.

You do not have borders around your paragraph? How does Word know that? So EVERY single pargraph has Word checking to see if EACH separate border is set to True, or not.ParagraphFormat
.Borders(wdBorderLeft).LineStyle = wdLineStyleNone
.Borders(wdBorderRight).LineStyle = wdLineStyleNone
.Borders(wdBorderTop).LineStyle = wdLineStyleNone
.Borders(wdBorderBottom).LineStyle = wdLineStyleNone
With .Borders
.DistanceFromTop = 1
.DistanceFromLeft = 4
.DistanceFromBottom = 1
.DistanceFromRight = 4
.Shadow = False
End With
End With
With Options
.DefaultBorderLineStyle = wdLineStyleSingle
.DefaultBorderLineWidth = wdLineWidth050pt
.DefaultBorderColor = wdColorAutomatic
End WithSo...I can not stress this enough. Paragraphs are THE back bone of Word. Well, maybe...nah...I'll stick with that.