Logo: TechTrax...brought to you by MouseTrax Computing Solutions

Automating Watermarks, Part Deux

by Dian Chapman, MVP, MOS
Skill rating level 7.

In the fall issue of Susan Daffron's Ezine, Computor Companion, I wrote an article called Automating Watermarks. In that article, I showed you how to create various watermarks, save them to AutoText and then record individual macros that would automatically insert the watermark you needed. In that article, we left off by having several macros...one named for each watermark you needed, such as InsertWatermark_Confidential, InsertWatermark_Draft, and so on.

However, as we left it, you would need to either go to Tools > Macro > Macro and choose the individually named watermark macro you needed, or choose the one you needed from a custom toolbar, if you decided to add each macro to a custom menu or toolbar.

In this article, we'll take the automation process a bit further. We'll make some modifications to the code so that only one macro will be needed to insert whatever watermark you need. When the one macro is run, either by accessing it from the macro menu or through a custom toolbar or menu, a custom dialog box will be displayed. The dialog box will show all the watermarks you have available and will allow the user to choose which one they need. By capturing their answer and passing that information by use of a variable, we will be able to dynamically modify the insertion code so one macro will insert different AutoText items.

Ready? Wait! If you're working along with this article now, be sure that you first go read the previous article linked above so you have the AutoText, macros and the understanding to continue with this article.

Reviewing What We Have So Far

At this point, you should have a variety of watermarks created and saved to AutoText. You will also have a macro for each AutoText that inserts a watermark into a document with just a click.

In my sample, I went ahead and created the suggested custom menu so I can easily choose which watermark will be inserted into the doc by choosing which of my two watermark macros I want to run. By clicking on the Confidential Watermark, that watermark is inserted into the header of my document, as you can see below.

Alternatively, if I needed the document to show that it is a draft, I can click the other option, as shown in the next image.

So far, this is pretty nice automation that will save you some time. But for those who want to take this process further, we'll add further automation to make the process a bit slicker.

Creating a Custom Dialog Box

First we'll create a custom dialog box that will display all the choices to the user. Within Word, enter the VB Editor (VBE) by hitting Alt + F11.

Now this next point is important and one that causes new VBA developers a lot of frustration. You need to make sure that you are working within the template where you want the code contained! For example, if you are creating this for yourself and don't plan to share this code with others, then working within your Normal.dot is just fine. This will mean that the code will be available to you for all your new documents, because the default Normal.dot template is a global template and is always available to you.

However, if you plan to share this code with your colleagues, then you will want to create a custom template, possibly called Watermarks.dot. Then this Watermark.dot can be shared with your company users by passing it to everyone (or to your system admin) and having them store this DOT in their StartUp folder for Word. This will cause this Watermark.dot to become globally accessible to the user.

Sure, you can move the necessary code files over to a custom template later to create that custom, global template (see this Sharing Macros article for details to do that), but if you have already created that Watermark.dot in anticipation of sharing, then you need to continue working within that DOT when you add more code to the project.

Note that you can learn more about creating dialog boxes by also reading this TechTrax article: Creating Custom Dialog Boxes. Also note that, if you simply recorded the previous macros, the default location for all recorded macros is within the NewMacros code module inside your Normal.dot.

In my case, I will just stay within the Normal.dot. So in the image below, you will notice that I have highlighted my Normal.dot (project) before I insert a User Form that will become my custom dialog box. But if you have a Watermark.dot created, then you will want to make sure to have it open and have that project (DOT) selected before you insert the form to make sure it goes inside that project.

Click Insert > UserForm to insert your user form, which will become your custom dialog box. Notice that the form is inserted with the default name of UserForm#, with # being the next consecutive number. As you can see below, I have several other UserForms. It can be confusing if you have a lot of generic named forms, so it's best to rename the form to something more identifiable. As you can see in the image below, I have named this form to frmWatermarks. Note that frm is a standard naming convention for forms. That means it's a good idea to prefix all forms with frm.

Now you will need to start customizing your dialog box (UserForm). Make sure your ActiveX Control Toolbar is displayed. This should display automatically when you click on the form. If not, click View > Toolbox. Add a label to the form to provide the user with some basic information. Note that you can then select the label and use the Properties window to apply various attributes to the label, such as changing the size/appearance of the font being applied to the label, as you can see I have done in the image below. If you don't see the Properties window, click View > Properties.

You will now add one option button for each watermark you have created. Since I have only created two, Confidential and Draft, I only need to add two options.

After you add each option, be sure to select it and move to the Name field in the Properties window and give this control a proper name. If you don't, it will just be called OptionButton1, which is very confusing and difficult to remember when you will be writing the rest of the code. So give each one a meaningful name! I have named my Confidential option as optConfidential. Likewise, the Draft option button control will be named optDraft.

Also note that the VBE has many of the standard graphic features that you will find in any graphic program. That means that you can select both of the option buttons and choose from several Format options to better align the controls on your form. And note that if you want to align them on the form, it's best to Group them. But remember to Ungroup them to more easily work with them individually.

Once you have added an option for each watermark and have them align on the form the way you want, you'll need to also add an OK command button and a Cancel command button. Be sure to select each command button and give them their own, proper name. Mine are named cmdOK and cmdCancel.

Be sure to go through all the Properties for each control. You will need to add the proper Caption and can also set an Accelerator character. This is the underlined letter that can be activated from the keyboard. This is important! Without this added access to your dialog box, many users, such as secretaries who prefer using the keyboard or, more importantly blind users who cannot use a mouse, will not be able to access your dialog box from the keyboard.

Note! If you don't know what a particular Property is for, highlight it within the Properties window and hit the F1 help key. If you have gone through the process to add the VBA Help files (which are not added by default and must be added manually through a custom Office installation), details for this Property will be displayed to give you further information.

If you want to learn more about using the VBE, see this article for a pile of cool tips to help you work more efficiently: Help! I’m Stuck in the VBE!!

We're almost done creating the dialog box. However, there are a few additional items that you want to make sure are finalized. Right click the form and choose Tab Order to set your form's tab order. This is the order in which the Tab key will jump if the user moves through the dialog box by hitting the tab key. Also be sure to add a Caption to your form itself so the dialog box is not called UserForm any longer. As you can see below, I've named mine: Watermark Choices.

Adding/Modifying the Code

With the form finished, it's time to add some new code and work on your previous code to make some modifications to work with this new dialog box.

When you double click any form control, you enter the code default for that control. We'll start by entering the click event for the Cancel button to add that code, since that is the easiest. Double click the Cancel button.

Once within the cmdCancel_Click() event, add the following code:

Private Sub cmdCancel_Click()
     frmWatermarks.Hide
     Unload frmWatermarks

End Sub

Let's test the form out now by running it to see how it looks and works at this point. Click the Run button in the VBE or hit F5. Since the OK button doesn't have any code, it won't work yet. But you should be able to now click the Cancel button to have the dialog box go away.

Now on to the more difficult code. However, you already should have several macros that are very similar except for the name of the AutoText that is being inserted. So we'll start by grabbing one of those procedures. We can then modify one of them as our new master and we'll pass the name of the AutoText to the code with a variable.

Below is the code I originally recorded in the previous article. This code opens the header and inserts the Watermark_Confidential AutoText. Note the bold area where the name of the AutoText is inserted. If I were to change that name from "Watermark_Confidential" to "Watermark_Draft", this same code would then alter the item inserted and, hence, the Draft AutoText watermark would be inserted into the doc. This is where we will now pass the name through the use of a variable.

Sub InsertWatermark_Confidential()
'
' InsertWatermark Macro
' Macro recorded 9/25/2004 by Dian Chapman
'
     If ActiveWindow.View.SplitSpecial <> wdPaneNone Then
          ActiveWindow.Panes(2).Close
     End If
     If ActiveWindow.ActivePane.View.Type = wdNormalView Or ActiveWindow. _
               ActivePane.View.Type = wdOutlineView Then
                     ActiveWindow.ActivePane.View.Type = wdPrintView
     End If
     ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader
     Application.DisplayAutoCompleteTips = True
     NormalTemplate.AutoTextEntries("Watermark_Confidential").Insert Where:= _
               Selection.Range, RichText:=True
     ActiveWindow.ActivePane.View.SeekView = wdSeekMainDocument
End Sub

Go back to your dialog box form and double click on the OK button to access the code area for this control. Note that you can just double click on the name of your form to have it display again so you can access the OK button. Within the code area for the OK button, add the following code.

Private Sub cmdOK_Click()

     'declares a variable for the results
     Dim strAnswer As String

     'checks to see if this option is selected, if so, sets the variable value here
     If frmWatermarks.optConfidential.Value = True Then
          strAnswer = "Watermark_Confidential"
     End If

     'checks to see if this option is selected, if so, sets the variable value here
     If frmWatermarks.optDraft.Value = True Then
          strAnswer = "Watermark_Draft"
     End If

'if neither are selected, a message box sends a wakeup call to the user
'and bails from the procedure so the rest of the code doesn't run

If frmWatermarks.optConfidential.Value = False _
          And frmWatermarks.optDraft.Value = False Then
     MsgBox "You must select an option"
     Exit Sub
End If

     'calls the next procedure and passes the variable value
     Call InsertWatermark(strAnswer)

     'removes the form from sight and memory
     frmWatermarks.Hide
     Unload frmWatermarks

End Sub

There are more sophisticated ways to handle this code, such as using a Select Case procedure of grouping the options, but since some of you are probably beginners, I'm shooting for the most direct code to make it easier to understand.

What this code says:

  • Declare a variable called strAnswer and tell the computer that the information that will be coming into this variable will be a string of text.

  • Now check the frmWatermarks dialog box and see if the optConfidential control value is true...meaning it has been selected. If it has been selected, then make the strAnswer variable equal to the AutoText name of the Confidential item, which is Watermark_Confidential.

  • However, if the optDraft control in the frmWatermarks dialog box has been selected so that that value is true, then set the variable equal to Watermark_Draft.

    Note! Realize that the names being set in these two sections of code are the exact names of the AutoText for which the watermarks were named when they were saved. If you named them something else, change the code accordingly.

  • But! If both the optConfidential AND the optDraft controls are equal to false, meaning that neither has been selected, then display a message box that tells the user they must make a selection and bail out of the rest of this code. This will leave the dialog box sitting there to wait until your user decides to follow directions...or click Cancel.

  • If one of the options were successfully selected, then call the InsertWatermark procedure and pass it the name of the AutoText that is needed by passing it within the answer variable...whatever that value may turn out to be.

  • Finally, it tells the dialog box to go away and get out of memory! Note that this is important so items are unloaded from memory to not cause crashes due to too much memory being eaten up by leftover objects.

Granted, there's still some work to do...but the code is almost finished.

By the way, notice the comments in red. See how they are prefixed by an apostrophe. You can and definitely should always write yourself little notes to remind yourself what the code is doing. It may seem quite elementary at this point, but when you return to this code next year, it will help you remember what the heck you were thinking when you wrote this code. And trust me...you will forget! You can add as many notes as you want, as long as each comment line is preceded with an apostrophe.

Let's go back to that original InsertWatermark_Confidential code we recorded and we'll use that as our master code, with a few modifications. Further below is the original code we recorded that was displayed previously in this article. I've highlighted the areas we'll change in green. Since the procedure we need to now call is InsertWatermark, the _Confidential part of that code needs to be removed. Delete that so the procedure is now just called InsertWatermark().

However, we also need to tell this code that some information will be coming, so between the parenthesis, we need to add the following: strAnswer as String. Therefore, the final name (first line) of the procedure (below code) should look like this:

Sub InsertWatermark(strAnswer as String)

Here is the original code.

Sub InsertWatermark_Confidential()
'
' InsertWatermark Macro
' Macro recorded 9/25/2004 by Dian Chapman
'
     If ActiveWindow.View.SplitSpecial <> wdPaneNone Then
          ActiveWindow.Panes(2).Close
     End If
     If ActiveWindow.ActivePane.View.Type = wdNormalView Or ActiveWindow. _
               ActivePane.View.Type = wdOutlineView Then
                     ActiveWindow.ActivePane.View.Type = wdPrintView
     End If
     ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader
     Application.DisplayAutoCompleteTips = True
     NormalTemplate.AutoTextEntries("Watermark_Confidential").Insert Where:= _
               Selection.Range, RichText:=True

     ActiveWindow.ActivePane.View.SeekView = wdSeekMainDocument
End Sub

The name of the AutoText now needs to be replaced with the name of the variable that we are passing...which will carry with it the selected name the user chose. Make sure you also remove the quotes, since only an actual string value requires quotes, variables don't use quotes. Therefore, the line above, highlighted in green, will now look like this:

     NormalTemplate.AutoTextEntries(strAnswer).Insert Where:= _
               Selection.Range, RichText:=True

Okay, one more basic step. When the user clicks to start the process rolling, we need to have the dialog box display, but other than hitting the F5 button within the VBE, we don't yet have a way to get the ball rolling. So we need to create a new procedure to call the dialog box. Select a new area within the code module and enter the following new procedure.

Sub ShowWatermarkDialog()
     frmWatermarks.Show
End Sub

Time to put it all together and make it work. I'd suggest that you create a custom menu and add the ShowWatermarkDialog macro to that menu so the user can get it rolling by just clicking that option. See this article if you need help creating a custom menu: Customize Toolbars and Menus. Note, too, that there is a lot of information related to menu and template customization in this article: Sharing Macros.

Time to test it. Click your new menu item to display your selection dialog box.

Realize that although I dragged the ShowWatermarkDialog procedure to the toolbar, I decided to give it a more userfriendly name by right clicking the area and entering &Choose a Watermark. This is explained in detail in the toolbar articles above. Also, the ampersand before the C causes that letter to be underlined as the Accelerator character.

Make your choice and click OK.

If all is well, the correct watermark should be inserted.

Recap

As a review, here's what's happening.

  • The user clicks the menu to display the dialog box.
  • The user chooses an option and clicks OK.
  • The code under the OK button checks to see which option has been selected.
  • If none have been selected, a message box is displayed to remind the user to pay attention to what they are doing! The code then stops and waits for the user to do something right, such as make a choice or click Cancel.
  • Otherwise, if an option has been selected, it will insert the matching AutoText name into the answer variable.
  • The next procedure is then called, and the name of the AutoText is passed to the next process through the variable.
  • The recorded insertion code is run and inserts whatever AutoText name contained inside the variable.
  • The dialog box goes away and is removed from memory.

A Few Additional Notes

Note that using the Call command to call a procedure is a bit old fashioned and I generally don't use that. But it works and I'm using it here to help newbies understand going on. If you decide not to use the Call command for the InsertWatermark process, then you also need to remove the parenthesis. Below shows both correct methods.

Call InsertWatermark(strAnswer)

InsertWatermark strAnswer

Also, if you plan to share this code, realize that the user may make one choice and then change their mind and choose to change to another watermark. With the code as we have it now, this would cause all the watermarks to pile up in the document. So it would be wise to also add code that, when the code goes into the header, it first selects all and deletes anything found. Then inserts the requested AutoText. You can record this process and add the code into the insert code at the appropriate location. Or you can create it as a separate procedure and call it before the AutoText is inserted.

That's about it. Remember that you must ensure that the Watermarks have been properly created and that they reside inside the template you are using. Also, if you name anything differently from the names I used, make sure that you make the necessary modifications to the code so it all works properly.

Finally, a disclaimer! Know that if you follow the directions in this and the previous article correctly and you don't make any mistakes...this will work! So, before you email me saying "I read your articles and did everything just like you said I should do, but it doesn't work!", realize that that statement is not true! If you did it exactly, it will work. So there must be a mistake. Take that fact into account and proof your code. If you have made a mistake and can't get it to work, you can email me as long as you have all the exact error details to pass along. But please don't email me saying "It doesn't work, I get an error!" There are literally thousands of errors that you might get...so that information doesn't tell me much! In order to get a good support response, realize you need to provide good information.

(Pssst...I really don't mean to sound rude, but if you saw how many emails I get that do say "I read your article and it doesn't work!"<sigh>...you'd understand my stance!<smile>)

And remember, even better you can also join my Word_VBA free support group here: http://groups.yahoo.com/group/Word_VBA/, where you can post your further questions and members will try to help you understand the details.

Writing programming code takes patience and precision! One tiny mistake and you will get an error. So it must be exactly CORRECT or you'll have to debug your code to decipher what you did wrong and fix it. Take your time...and have fun learning!


Dian Chapman is not only an instructor, but also a VBA developer, specializing in time saving Word automation, as well as database driven ASP web sites. If you want to learn how to write better VBA code, her popular Word AutoForms & Beginning VBA training course is available in both ebook/web and enhanced video CD formats. See her TechCourse page for more details. You can also find numerous other free VBA tutorials here: http://www.mousetrax.com/techpage.html#autoforms. And if you're wasting valuable time in your business by dealing with a lot of redundant paperwork, you might want to checkout some of the timesaving solutions Dian has already provided to smart business owners who understand the ROI from efficient automation techniques!

Click to rate this article.

 

Go up to the top of this page.
This site powered by the Logical Web Publisher™: Content management by Logical Expressions, Inc.