PDA

View Full Version : [SOLVED:] Cycle a userform through the images in a document (or an array of values)



AndrewMc
11-05-2013, 07:37 PM
Hi All

I regularly copy and paste images from a graphics package into a Word document, then need to resize and crop the images. I am trying to develop a Word addin that will make this process easier. Copying and pasting the images is easy, but editing each image size is tedious (involving lots of scrolling through the document and right-clicking on each image).

Instead, I want to have a macro that displays a form that shows the size and margin settings for a picture along with settings I can modify and apply to the picture. I want the form to have buttons "Previous" and "Next" to jump the previous or next image (if there is one).

Currently, I have developed a procedure to create an array listing the index numbers of all of the inline shapes in the document that are a picture type (ThisDocument.InlineShape(index).Type=wdInlineShapePicture).
I have another procedure that displays the picture size and margin cropping information in a simple form.

Now I am stuck. While I can get the form opening with the information from the first image, I cannot work out the logic to get the "Previous" and "Next" buttons to load the form with new information. The code for the main procedure is shown below:


Sub FigureSizeManipulation()
Dim wd As Document
Set wd = ThisDocument
If wd.InlineShapes.Count > 0 Then
Dim alPictureList() As Long 'array to hold index numbers of picture shapes
'''get array if inlineshape picture index values; return False if none found
If GetPictureList(alPictureList) Then
glIndex = 1 'global: array index number
MsgBox UBound(alPictureList) & " inline picture shapes found!", vbInformation
'''show form with info from InlineShape(alPictureList(glIndex))
Call ShowForm(alPictureList)
Else
MsgBox "No inline picture shapes found!", vbCritical
End If
Else
MsgBox "No inline shapes found!", vbCritical
End If
End Sub

The code for the "Previous" and "Next" buttons is:

Private Sub cmdPrevious_Click()
'decrement the array index number
glIndex = glIndex - 1
End Sub
Private Sub cmdNext_Click()
'increment the array index number
glIndex = glIndex + 1
End Sub

I have used a global variable to store the index of the array value to display, but the array is only a local variable. Should I make the array global so that the cmdPrevious_Click() and cmdNext_Click() procedures can call ShowForm() to display the new info?

Or instead, should I redesign the project and use Find to search for graphics "^g", and move through the document to each image?

Does anyone have any suggestions (or pseudocode) for a way to do what I am wanting?

Cheers
Andrew Mc

macropod
11-05-2013, 08:17 PM
A fairly simple implementation:

Option Explicit
Dim i As Long
Private Sub CommandButton1_Click()
With ActiveDocument
If i > .InlineShapes.Count Then Exit Sub
With .InlineShapes(i)
.Select
Me.TextBox1.Value = Format(PointsToCentimeters(.Width), "0.00")
Me.TextBox2.Value = Format(PointsToCentimeters(.Height), "0.00")
End With
End With
i = i + 1
End Sub
'
Private Sub UserForm_Initialize()
i = 1
With ActiveDocument
If i > .InlineShapes.Count Then Exit Sub
With .InlineShapes(i)
.Select
Me.TextBox1.Value = Format(PointsToCentimeters(.Width), "0.00")
Me.TextBox2.Value = Format(PointsToCentimeters(.Height), "0.00")
End With
End With
End Sub
The above goes through all InlineShapes in the body of the document, returning their width and height.

fumei
11-05-2013, 10:59 PM
Just want to add that to use a previous and next make

Sub cmdNext_Click() would use i = i + 1

and

Sub cmdPrevious_Click() would use i = i - 1

AND that these should go at the START of the instructions, as in

Private Sub cmdNext_Click()
With ActiveDocument
If i > .InlineShapes.Count Then Exit Sub
i = i + 1
With .InlineShapes(i)
.Select
Me.TextBox1.Value = Format(PointsToCentimeters(.Width), "0.00")
Me.TextBox2.Value = Format(PointsToCentimeters(.Height), "0.00")
End With
End With
End Sub

AndrewMc
11-08-2013, 03:51 PM
Thank you for the most helpful replies. I had not thought of working with the form code in that way.
After adapting the suggested code, I came up with the following which displays the required values in a form and enables "Previous" and "Next" buttons to scroll through the inline shapes in the document.

Here is the code for UserForm_Initialize:

Private Sub UserForm_Initialize()
i = 1
If i > ActiveDocument.InlineShapes.Count Then
Exit Sub
Else
Call PopulateForm(i)
End If
End Sub

This procedure calls another procedure PopulateForm which sets the values to be displayed in the form. Because I want to show the picture cropping values, I first check for the type of the inline shape otherwise an error will result for shape types that cannot be cropped and thus do not have cropping values.


Sub PopulateForm(index As Long)
With ActiveDocument
frmVBAExpress2.Caption = "Picture " & index & " of " & .InlineShapes.Count
.InlineShapes(index).Select
If .InlineShapes(index).Type = wdInlineShapePicture Then
With .InlineShapes(index).PictureFormat
frmVBAExpress2.lblCropLeft.Caption = Format(PointsToCentimeters(.CropLeft), "0.0")
frmVBAExpress2.lblCropRight = Format(PointsToCentimeters(.CropRight), "0.0")
frmVBAExpress2.lblCropTop.Caption = Format(PointsToCentimeters(.CropTop), "0.0")
frmVBAExpress2.lblCropBottom = Format(PointsToCentimeters(.CropBottom), "0.0")
End With
Else
frmVBAExpress2.lblCropLeft.Caption = "n/a"
frmVBAExpress2.lblCropRight = "n/a"
frmVBAExpress2.lblCropTop.Caption = "n/a"
frmVBAExpress2.lblCropBottom = "n/a"
End If
End With
End Sub

The "Next" and "Previous" buttons on the form use the following simple code to either increment or decrement the index value before calling PopulateForm to update the form with the new values. I have set up the buttons so that the form 'loops' through the available inline shapes; if on the first shape, pressing "Previous" takes you to the last shape, and if on the last shape, pressing "Next" takes you to the first shape.


Private Sub cmdNext_Click()
If i < ActiveDocument.InlineShapes.Count Then
i = i + 1
Else
i = 1
End If
If i > ActiveDocument.InlineShapes.Count Then
Exit Sub
Else
Call PopulateForm(i)
End If
End Sub

Private Sub cmdPrevious_Click()
If i > 1 Then
i = i - 1
Else
i = ActiveDocument.InlineShapes.Count
End If
If i > ActiveDocument.InlineShapes.Count Then
Exit Sub
Else
Call PopulateForm(i)
End If
End Sub

Cheers
Andrew Mc

fumei
11-08-2013, 10:29 PM
Thanks for posting a full accounting of how you progressed this. I am sure it may be helpful for others. Good one.