Using VBA in MS Word 2007 to define page elements? - vba

I'd like to be able to create a page element which I can feed text and it will form itself into the preferred layout. For instance:
{MACRO DocumentIntro("Introduction to Business Studies", "FP015", "Teachers' Guide")}
with that as a field, the output should be a line, the first two strings a certain size and font, centred, another line and then the third string fonted, sized and centred.
I know that's sort of TeX-like and perhaps beyond the scope of VBA, but if anyone's got any idea how it might be possible, please tell!
EDIT:
Ok, if I put the required information into Keyword, as part of the document properties, with some kind of unique separator, then that gets that info in, and the info will be unique to each document. Next one puts a bookmark where the stuff is going to be displayed. Then one creates an AutoOpen macro that goes to that bookmark, pulls the relevants out of the keywords, and forms the text appropriately into the bookmark's .Selection.
Is that feasible?

You're certainly on the right track here for a coding solution. However, there is a simpler way with no code - this is the type of scenario that Content Controls in Word 2007 were built for and with Fields/Properties, you can bind to content controls (CC). These CC can hold styles (like centered, bold, etc.). No VBA required.
The very easiest thing to do is to pick 3 built-in document properties that you will always want these to be. For example, "Title" could be your first string, "Subject" your second string and "Keywords" your third. Then, just go to the Insert ribbon, Quick Parts, Document Properties and insert, place and format those how you like. Then go to Word's start button (the orb thingy) and then under Prepare choose Properties. Here you can type, for example "Introduction to Business Studies", into the Title box and then just deselect it somehow (like click in another box). The Content Control for Title will be filled in automatically with your text.
If you want to use this for multiple files, just create this file as a .dotx (after CC insertion/placement/formatting and before updating the Document Properties' text). Then every time all you'll have to do is set these three properties with each new file.

Well, yes, it did turn out to be feasible.
Sub autoopen()
Dim sKeywords As String
sKeywords = ActiveDocument.BuiltInDocumentProperties(4)
ActiveDocument.Bookmarks("foo").Select
Selection.Text = sKeywords
End Sub
Okay, I have some filling out to do, but at least the guts of it are there.

Related

Change Style of ListBox

In Outlook 2010 I have a UserForm with a ListBox.
This ListBox has 4 columns where I show a list of attachments (the columns "File-Name", "File-Type", "File-Size" and "Target-Directory".
Unfortunately the ListBox is restricted in layout functionality, the user can not adjust the column width at runtime (so I have to specify the width of the columns by design).
Because the file path can be quiet long, I set the width of the last column to 999 Pt.
So my ListBox has a horizontal scrollbar.
I want to have the following layout changes to my ListBox:
Add column headers
Change the alignment of a column to right-aligned
Optional: allow the user to sort the list by any column
Optional: allow the user to sort change the width of any column
Optional: show a grid in the ListBox
For 1. I found some answers that this is very complicated and I should use static labels above the list instead.
This is not possible, because my ListBox can be scrolled horizontally.
Is the ListBox really so restricted or is #1 and #2 possible somehow?
I know that there are foreign components available, but I am not allowed to buy any component.
And my solution should work at my colleagues too, so they would also have to install these components.
I have been experimenting with possible solutions to your problem. I think I have taken the listbox approach as far as it will go so I will share what I have discovered.
I can find nothing on the web to suggest that anyone believes you can have listbox column headers without using property RowSource. To use RowSource, you set it to an Excel range.
I got Outlook to create an Excel workbook and to write some data to it. Unfortunately, I could not find any way of getting an Outlook user form to access an Excel range. The syntax for setting RowSource is:
ListBox1.RowSource = "Emails!A2:D20"
This is not the standard syntax for a range and I have failed to discover any method of extending it to include a workbook name.
Jonah_Hess describes an interesting approach in https://stackoverflow.com/a/43381634/973283. He has two list boxes. One is a one-line listbox that contains the headings and the other contains the data. The two listboxes are set to the same number of columns with the same widths. This gives an attractive appearance but if you scroll the data listbox, the headings listbox does not scroll with it. This is not really any different from placing labels above a single listbox.
I tried putting the headings and the data list boxes in a frame and scrolling the frame but could not get it to work. I have used frames with VB user forms but the functionality is very different so there are no lessons learnt that I could bring to a VBA user form. Perhaps someone more familiar with VBA frames could get this approach to work.
I gave up trying to get a solution in Outlook. An Excel macro can access Outlook data so I tried that approach.
I created a macro-enabled workbook. Within it, I have two forms both of which fill the screen to conceal the worksheet. The first form just says: “Please wait while I load data from Outlook”. I am not clear about the data on your form so I imported selected details from a folder full of junk emails which I wrote to a worksheet. I sized the columns for the list box to match those for the worksheet. The result was:
The text is a little small but I think it is readable. The listbox at the bottom allows me to select emails for different periods. Long ago I had problems with RowSource which meant I could change the values in the range but I could not change the size of the range. I have either managed to avoid that problem today or it was a bug that has been fixed.
You can see that the headings are displayed. The columns are a little wide but I consider them to be a reasonable first approximation. Options to change the widths would be easy to implement.
The changes you ask for:
Add column headers. Done
Change the alignment of a column to right-aligned. Possible but difficult. You would need to pad the text with an appropriate number of leading spaces.
Optional: allow the user to sort the list by any column. The data is in a worksheet so easy.
Optional: allow the user to change the width of any column. I have set the column widths at runtime to show it is possible.
Optional: show a grid in the ListBox. Not possible.
If the above is interesting, I could show you all my code and instruct you on creating the forms so you could duplicate my experiment. Alternately, I could just explain: how I imported the Outlook data to Excel, how I included the column headings and how I set the column widths.
I cannot find anything to suggest that anything better can be achieved with listboxes.
An alternative approach is to use a grid of labels. This can give an attractive appearance and one or more columns could be right-aligned. Using the Controls property of the user form, you can treat the grid as a two-dimensional array. I have used this technique long ago and found it attractive and not particularly difficult.
In order to set the alignment of a specific column to the right, trying the opposite way might help you:
Set TextAlign attribute of the listbox to "3-fmTextAlignRight".
Add spaces at the END of the each data in the column of sourcearray, which you want to align LEFT. The number of added spaces should be so large as to exceed the width of the column in which the data appears. You don't have to mind whether the number fits to the columnwidth (overflown spaces do no harm). You may prefer to use & String(30, " ") instead (30 is just for example) .
If added spaces seem to be wholly ignored (i.e. data appear right-aligned only), further add any single character (such as "_") at the end of the spaces.
This is a cosmetic solution, but works when seeing left-aligned figures is too annoying.
After doing the above, please be careful when selecting from the list (trimming the added spaces, keeping BoundColumn data intact, etc.).
This trick works for both Excel and Outlook (not sure for other applications).
Test result in Outlook VBA (...trailing 50 spaces are added to data in column 1 and 4.)
Hope this helps.

Working with multiple discontinuous selection

I'm trying to do something with a multiple selection. I wanna add some text before every selected paragraph but, when I select multiple discontinuous paragraphs, if I do Selection.Paragraphs.Count I always get "1".
How could I work with all paragraphs apart?
Example:
Paragraph1(Selected first)
Paragraph2
Paragraph3(Selected second)
What I got when I try to add some text at the beginning of these paragraphs:
Paragraph1
Paragraph2
TEXTParagraph3
What I really want to obtain:
TEXTParagraph1
Paragraph2
TEXTParagraph3
I'm working like this:
sub x()
dim p as paragraph
for each p in selection.paragraphs
p.range.insertbefore("TEXT")
next
End sub
Word simply cannot do what you'd like for it to do. Developers have wished for this since multiple selections were introduced in 2003 (I think it was, might have been version 2007). Word's object model simply does not support it.
If this is something you want to provide to the user to make life easier you'll need to give the tool a way to mark the paragraphs so your code can recognize them. You could provide a macro, for example, that assigns an incrementing bookmark name to each selection (the user selects, then runs your macro; repeat for each paragraph). Your code can then address each bookmark and perform the actions. To make this more user friendly you can assign the macro to a keyboard shortcut and/or a button in the Ribbon/QAT and/or the right-click menu.

How can i set the name of a textbox in publisher?

I want to set the name of the text box so it can be easily accessed by code.
e.g
I am looking for an editing field similar to this
Thanks
There's a properties Window that can be accessed for each of the controls on the UI. There you may rename the controls. (Since you do not seem to have a VBA code yet and you want to rename the control from UI)
The other alternative. Record a macro, do some changes to the textbox (e.g. resize, change text etc). Then check the programme assigned default name of the textbox from the VBA editor. As you said, you can access the control via this default name and utilizing your VBA code (as you said), rename the textbox.
If you really want to be editing a worksheet object in Publisher you will have to get the OLEobject of the Shape and interpret it as an Excel.Application.
If you are just looking for a placeholder solution for Publisher documents, you could simply create a textbox that contains a certain string, then loop through all pages, all shapes on each page where HasTextFrame = msoTrue, and compare shape.TextFrame.TextRange.Text to your placeholder string. If it's the one you're after, you can do anything you want with the shape in question.
Sorry for the vague answer, but your images don't work anymore.
Edit: you can work with Shape.Name for your comparison (you mentioned this property in a comment), but I have no idea how you'd set the value from the interface, without using VBA, in the first place, so if you're making templates the approach I outlined above might be easier for users (see https://msdn.microsoft.com/EN-US/library/office/ff939233.aspx for Shape.Name). There is also a .Name property for page objects (https://msdn.microsoft.com/EN-US/library/office/ff940382.aspx), so you should be able to do something like ActiveDocument.Pages("page_name").Shapes("shape_name").TextRange.Text = "your content" once you've figured out how to actually set the name values
Edit 2:
You can also try to use search and replace as per Replacing Text in Microsoft Publisher Using Powershell if you don't need to do anything advanced beyond placing some text
Edit 3: Given the title of your question, unless you can figure something out with Publisher's interface, you can set the .Name property of the selected text box (or other shape) with dim shape = Selection.ShapeRange.TextFrame.Parent and shape.Name = "your_name". You can set the name of the selected page with ActiveDocument.ActiveView.ActivePage.Name="your_name". (Create a VBA macro that prompts you for names and you should be good to go)

Printing custom ranges or items in Word 2010 using VBA

I am fairly new to VBA (Word 2010) and I'm unsure if something I'd like to do is even possible in the way that I want to do it, or if I need to investigate completely different avenues. I want to be able to print ranges (or items) that are not currently enumerated as part of either wdPrintOutRange or wdPrintOutItem. Is it possible to define a member of a wd enumeration?
As an example, I'd like to be able to print comments by a particular user. wdPrintComments is a member of the wdPrintOutItem enumeration, but, I only want comments that have an Initial value of JQC. Can I define a wdPrintCommentsJQC constant? My code is reasonably simple; I have a userform that lets the user pick some settings (comments by user, endnotes only, etc.) and a Run button whose Click event should generate a PrintOut method with the proper attributes. Am I on the wrong track?
(If it matters, the Initial values will be known to me as I write the code. I have a discrete list.)
No, it's not possible to add a constant to a predefined enumeration type.
However, one possible way to do this would be to build a string of page numbers which contain the items you wish to print, open the print dialog in the "dialogs" collection, and set it to print a specified range, andinsert the string containing the list of pages (separate them with commas). Finally, execute the .show method of the print dialog to show it to the user and give them the opportunity to set any other items and click the "ok" button. I've done something very similar when I needed to print a specific chapter of a long document, and so I had to specify the "from" section and page and the "to" section and page for the user. Below I just show how to specify a list of pages instead of the ".form" and "to" I was using:
With Dialogs(wdDialogFilePrint)
.Range = wdPrintRangeOfPages
.Pages = "3,5,7-11"
.show
end with
I'm not sure how you want to print the comments (or other elements), but you could create another document and insert what you want to print on this document.
According to what you want, you could insert them as they were (comments, footnotes, etc) or as plain text, or any other format.

Make Word's automatic spell-checking pick up dictionary changes

In MS Word it's possible to add words to a custom dictionary so they're recognized. If a word is not recognized, Word automatically puts a red squiggly line underneath it. If you add that word to the custom dictionary, this line disappears. What I'd like to do is perform this process automatically via a macro. It appears that one has to manually open the dictionary file and write the new word, as there is no method on the Word Dictionary object to add words to a given dictionary. This is no problem, except that Word doesn't automatically pick up the new word and remove the red squiggly lines underneath the newly-added word. I've even tried clearing the custom dictionaries and adding them back in, but it doesn't seem to reload the dictionary until you manually run a spell check. Sample code for this follows:
Dim x As Dictionary
Dim fname As String
fname = "C:\Users\me\AppData\Roaming\Microsoft\UProof\md.dic"
' code to add word to dictionary goes here
With CustomDictionaries
.ClearAll
.Add fname
.ActiveCustomDictionary = CustomDictionaries.Item(fname)
End With
Is there any way to make Word recognize the newly added word(s) in a custom dictionary without running the interactive spell check? It does this silently if you manually add words, but I can't seem to replicate this behavior in VBA. I'd like the red lines to go away automatically just like they do when you manually add words.
I haven't exactly solved the problem, but I think I figured out a work around. You can get a collection of Range objects which represent spelling errors using ActiveDocument.SpellingErrors. I'm going to search this collection for text matching the word I've added to the dictionary, and then set .NoProofing = True on the object. This appears to make the red lines go away, and having added the new word to the dictionary will prevent them from coming back the next time I open the document. I haven't fully tested this approach, but it looks promising.
EDIT
This approach is flawed, as additional instances of the word which are entered during the same session will have the red squigglies underneath them because they haven't been explicitly ignored and the spell check isn't yet using the updated dictionary. If you just pull up the custom dictionary dialog manually and click OK, something happens in the background to re-read the dictionary. I just can't figure out how to do this in code.