PDA

View Full Version : [SOLVED:] Code works when stepping but not when running



calvin-c
02-13-2014, 11:52 AM
Up to a point my macro works OK. It creates a table & populates it, 2 rows at a time, until it reaches the bottom of the page. The 1st cell in each 'set' contains an image. The 2nd contains information about the image. (Starting with the file name.) When I reach the end of the row (by counting the images inserted, there are 6 images/row) I 'tab' to create the next row, then I 'tab' 6 more times to create a second row. The problem:

My AddImage routine moves up 1 line (to the 'image' row), inserts the image, then moves down 1 line to type the filename & other info, then moves right to the next column. This works fine when stepping through the code, even when the new rows are on a new page. When I'm running it for production though the macro doesn't move down before typing the filename & other info. It adds that to the same cell as the image & that messes up everything that follows on the new page.

I don't understand why it works correctly in debug mode but not in production. I'll post the code if necessary (I'd like to remove the unrelated stuff first, like how it calculates the info that it'll type) but in essence the question isn't with how to do what I want to do but why it does it fine when debugging but not when running straight through. Thanks.

Frosty
02-13-2014, 01:06 PM
Impossible to know without you posting code. Most of the time, the difference between running code vs. stepping through in debug.mode has something to do with the way it's programmed. Rarely, it might be some kind of word bug which you then have to program around.

But based on your general description of 'tabbing' to crete a second row means you're working with something which started as a recorded macro (for example, you can use .Rows.Add to create a row properly).

I suspect you'll learn a lot by posting the code you're using an adopting whatever new code is recommended... but first step is on you.

Please remember cross-posting etiquette.

calvin-c
02-13-2014, 01:31 PM
Cross-posting? IIRC that's posting the same question in multiple forums. This is the only forum I've ever deliberately posted any question in. Can you explain how I violated cross-posting etiquette? If I did that I certainly didn't mean to.

I agree that I could use Rows.Add to create a row-but I don't see why that's any more proper than the way I'm doing it. And I do have a reason (besides starting with a recorded macro). It's simpler (IMO)-I use the same code that moves me from cell to cell to add the row. I could add 2 rows at once using Rows.Add but then I'd need to check whether I'm at the end of a row before moving to the next cell. I'm still working on creating a simplified macro I can post. I'll post the simplified AddImage function below but until I finish simplifying the entire macro I can't test it. The code I removed (calculating the additional info) shouldn't change the behavior-but I can't be sure until I test this. If I knew for sure what was causing the behavior I wouldn't need to ask the question, right?

So, the simplified AddImage function is:

Function AddImage(ByVal ImagePath As String, ByVal ImageFile As String) As Boolean
Dim OtherInfo as String
Selection.MoveUp Unit:=wdLine, Count:=1
Selection.InlineShapes.AddPicture FileName:=ImagePath & ImageFile
'error checking code that sets AddImage = False & exits if there's a problem
OtherInfo = "This & That"
Selection.MoveDown Unit:=wdLine, Count:=1
Selection.TypeText Text:=ImageFile
Selection.TypeParagraph
Selection.TypeText Text:=OtherInfo
Selection.MoveRight Unit:=wdCell
AddImage = True
End Function

Thanks.
Hmm. The <VBA></VBA> tags don't seem to work. Hopefully you can make sense out of the code. Thanks.

I've been thinking. Maybe I should start over, seeking help to set this up the way I'd like it to be set up. Right now I let the cells autosize to fit the contents because I can't figure out how to resize the contents to fit the cell. For the images that's not a big deal-if a folder contains incorrectly sized images the document won't be right, the users will report that, and I'll go in & resize the images in that folder. But, there's the possibility that the other info will expand beyond 4 lines thus increasing the height of the info row-which might push other rows to the next page so currently I need to check for the end of page.

If I could resize contents to fit a fixed-size cell then I could use a standard number of cells/page. I might end up with a messier document (a separate table on each page, for example) but I can live with that-the documents might get regenerated but should not be edited. So, should I start over? Thanks.

Frosty
02-13-2014, 04:09 PM
My first comment wasn't because you cross-posted, but because as a 1 post-count new user, that's generally the scenario where someone *might* be cross-posting. No worries.

As for your other question... hrm. You might want to post enough posts (I think it's 5) in order to post a sample document with a table like you're inserting the picture and picture data in. Doesn't need to be "real" pictures, but the format can be important.

When you have code which makes use of the Selection, it is very breakable if your selection isn't in the "right" spot. How do you know your selection is in the right location when it runs? If I ran the above code on a blank new document, it would fail at the very first line (Selection.MoveUp wdLine, 1), because the Selection is already *at* the first line of the document.

But it wouldn't fail when I'm stepping through, because I'd probably have my cursor somewhere else in the document.

I suspect you'll end up needing/wanting to understand working with range objects to make your code less breakable, but greg maxey's website also has something which addresses something like this, I believe (although I don't remember the actual one).

http://gregmaxey.mvps.org/word_tips.html is the generic link, and I think this link might be helpful...

http://gregmaxey.mvps.org/word_tip_pages/add_table_row_with_content.html

fumei
02-13-2014, 05:57 PM
It is not VBA (open and close tags) anymore; it is code (open and close) tags.

calvin-c
02-13-2014, 06:26 PM
Thanks for clearing up the cross-posting, Frosty. & thanks for the tag clarification, fumei. I'll check GregMaxey's site.

I like Range objects but don't have a problem with using Selection. As long as the program isn't interactive (and works as tested) I know where the cursor is. I'm not sure whether your comment that Selection is breakable refers to the problem I'm having (which, as far as I can see isn't related to cursor position unless Selection.Move acts differently during debug than when running) or is simply a general observation about it. I don't have a lot of experience with VBA but I do with VB (from version 6 to 2005 .Net) so I'll agree with your general observation-particularly when other programmers start making modifications. I retired 3 years ago so all my programming is for myself now. If I screw it up because I used Selection I think I know who to blame.

Thanks.

Frosty
02-13-2014, 06:41 PM
Unfortunately, the advice has to be general until you can give demo code which breaks when running on a sample doc but doesn't in debug mode.

There are a host of differences implied in debug mode vs running the code-- the addin being open, word being launched, the document being the correct document, the ribbon fully loaded. Etc etc.

There are no general reasons for what your generic description isn't working. But obviously it isn't. You may be encountering a bug in Word's selection object (unlikely, as it is probably the most tested object in Word), or you may be switching documents without knowing it, and so the selection you have when debugging is the same as you expect, but it isn't when running it.

What's actually happening when it doesn't work?

fumei
02-13-2014, 11:42 PM
calvin, you need to post your full code. There is not much anyone can do without being able to test it ourselves. I do suspect that Jason is correct in that it most likely has something to do with using Selection. But nothing can be confirmed without seeing the full code.

calvin-c
02-14-2014, 09:09 AM
Seems like a lot to post when the problem is only in a small function but... I would like to figure this out even if I end up starting over. Here's the full code & I'm attaching a zipped folder with test document & images.

Sub NewCatalog()
'
'Create a new catalog document
'
'location of header templates, changes with different users & versions of Windows or Office
Dim BuildingBlocks As String
BuildingBlocks = "C:\Users\Calvin\AppData\Roaming\Microsoft\Document Building Blocks\1033\Building Blocks.dotx"

Dim Topic As String
Topic = "Animals"

'create new document from Normal template so it doesn't contain this macro
Dim TopicDoc As Document
Set TopicDoc = Documents.Add(Template:="Normal", NewTemplate:=False, DocumentType:=0)
With Selection.PageSetup
.TopMargin = InchesToPoints(0.5)
.BottomMargin = InchesToPoints(0.5)
.LeftMargin = InchesToPoints(1)
.RightMargin = InchesToPoints(0.5)
.HeaderDistance = InchesToPoints(0.5)
.PageWidth = InchesToPoints(8.5)
.PageHeight = InchesToPoints(11)
.SectionStart = wdSectionNewPage
.OddAndEvenPagesHeaderFooter = False
.DifferentFirstPageHeaderFooter = False
End With
'attach BuildingBlocks template
ActiveDocument.AttachedTemplate = BuildingBlocks
'add 1st header
ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader
FirstHeader (Topic)
ActiveWindow.ActivePane.View.SeekView = wdSeekMainDocument
CreateTable1

Dim ImageFile As String
Dim ImagePath As String
Dim ImageCount As Integer
Dim PageNum As Integer
Dim OldPage As Integer
Dim TestCount As Integer
Dim Result As Boolean

'need path to insert image but filename must be separate for info
ImagePath = "C:\Test\" & Topic & "\"
ImageFile = Dir(ImagePath & "*.*")
'error check in case Topic folder is empty
If ImageFile = "" Then
MsgBox (Topic & " contains no files")
Exit Sub
End If

ImageCount = 1
PageNum = 1
TestCount = 1

Do Until ImageFile = "Done"
'add images & file names from folder
'AddImage advances to next cell which, if at end of row, adds next row
'but need to add 2 rows so use ImageCount to find end of row (6 images/row)
Result = AddImage(ImagePath, ImageFile, TestCount)
If Result = False Then
ImageFile = "Done"
End If

If ImageCount = 6 Then
'easiest way to add another row is tab thru the current row
Selection.MoveRight Unit:=wdCell, Count:=6
ImageCount = 1
'ImageFile = "Done"
Else
ImageCount = ImageCount + 1
End If
TestCount = TestCount + 1

If ImageFile = "Done" Then
Exit Do
End If
ImageFile = Dir
If ImageFile = "" Then
ImageFile = "Done"
End If
Loop
'save/close new document when all images have been added
End Sub

Sub FirstHeader(ByVal Topic As String)
ActiveDocument.AttachedTemplate.BuildingBlockEntries( _
" Blank (Three Columns)").Insert Where:=Selection.Range, RichText:=True
Selection.HomeKey Unit:=wdLine
Selection.Delete Unit:=wdCharacter, Count:=1
Selection.Font.Name = "Broadway BT"
Selection.Font.Size = 14
Selection.TypeText Text:="Catalog Name"
Selection.MoveRight Unit:=wdCharacter, Count:=1
Selection.MoveRight Unit:=wdCharacter, Count:=1, Extend:=wdExtend
Selection.Delete Unit:=wdCharacter, Count:=1
Selection.Font.Name = "AR JULIAN"
Selection.Font.Size = 14
Selection.TypeText Text:=Topic
Selection.MoveRight Unit:=wdCharacter, Count:=1
Selection.MoveRight Unit:=wdCharacter, Count:=1, Extend:=wdExtend
Selection.Delete Unit:=wdCharacter, Count:=1
Selection.Font.Name = "AR JULIAN"
Selection.Font.Size = 14
Selection.TypeText Text:="Page "
ActiveDocument.AttachedTemplate.BuildingBlockEntries("Plain Number"). _
Insert Where:=Selection.Range, RichText:=True
Selection.TypeParagraph
Selection.Font.Name = "Calibri"
Selection.Font.Size = 11
Selection.TypeText Text:="Note"
End Sub

Private Sub CreateTable1()
ActiveDocument.Tables.Add Range:=Selection.Range, NumRows:=2, NumColumns:= _
6, DefaultTableBehavior:=wdWord9TableBehavior, AutoFitBehavior:= _
wdAutoFitFixed
'start w/ cursor in bottom row so AddImage will work
Selection.MoveDown Unit:=wdLine, Count:=1
End Sub

Function AddImage(ByVal ImagePath As String, ByVal ImageFile As String, ByVal TestCount As Integer) As Boolean

Dim OtherInfo As String
Selection.MoveUp Unit:=wdLine, Count:=1
Selection.InlineShapes.AddPicture FileName:=ImagePath & ImageFile
'error checking code that sets AddImage = False & exits if there's a problem
'Stopping after inserting 1st image on new page (image 37), then continuing works
'Stopping after inserting image 38 (or simply running without stopping) messes up 2nd page
Debug.Assert TestCount < 38

OtherInfo = "This & That"
Selection.MoveDown Unit:=wdLine, Count:=1
Selection.Font.Name = "Arial Narrow"
Selection.Font.Size = 10
Selection.TypeText Text:=ImageFile
Selection.TypeParagraph
Selection.TypeText Text:=OtherInfo
Selection.MoveRight Unit:=wdCell
AddImage = True
End Function

calvin-c
02-14-2014, 09:17 AM
Per comments in the AddImage function, running Debug.Assert TestCount < 37 works fine even when you Continue immediately after the Debug pauses execution. Running Debug.Assert TestCount < 38 (which logically should give the same results) causes a problem. What difference does pausing the execution (and doing nothing else) make?

Frosty
02-14-2014, 09:23 AM
Well, the problem isn't "in" the small function, the problem is likely to do with where the selection is when stepping through vs. running it.

So seeing the context of the code and what you intend to happen is critical. There's nothing wrong with your function. I wouldn't write it that way, but so what? Like any function, it depends on other things though, and in this case, I suspect the location of the selection is causing the failure.

Can you describe how it fails too? Where is your cursor left?

calvin-c
02-14-2014, 09:49 AM
Where the cursor is left-at what point? Technically the program doesn't fail, it just doesn't produce the results I want. When I use Debug.Assert TestCount < 37 (and switch to the document to check cursor position) the cursor is in the same cell as & immediately following the just-inserted image. The next statement, Selection.MoveDown, correctly moves the cursor to the cell immediately below the image. This occurs whether I step through that statement or simply Continue from the Debug.Assert statement.

When I use Debug.Assert TestCount < 38 the cursor is also immediately following the just-inserted image but that image has been inserted a row higher than the preceding one (because Selection.MoveDown didn't move the cursor to the cell below image 37). I've attached the output from the incorrect processing. Thanks.

calvin-c
02-14-2014, 10:06 AM
Unfortunately posting a document doesn't show the cursor position. I'll try to find something that does but I did put Debug.Assert TestCount < 37 immediately before Selection.MoveDown & the cursor was immediately after the just-inserted image. I then moved the Debug.Assert statement to immediately following Selection.MoveDown-and the cursor position hadn't changed. To me that indicates a problem with the Selection.MoveDown statement. I'm open to the possibility of it being something else but can't, by myself, imagine what that 'something else' could be. I've definitely narrowed down the problem to a single statement that works when execution pauses immediately before it but fails (without producing an error message) when execution runs through it-but only on a new page. I'd like to figure out why but experience says that 'why' is often unanswerable. Is there a different way to move the Selection to the next cell down?

Frosty
02-14-2014, 10:13 AM
I haven't checked out the code yet, as I'm posting from my phone. But here are a couple of ideas:
1. DoEvents
2. Selection.Range.Select
3. Application.ScreenRefresh
4. Making use of a range object instead, and traversing your table that way
5. Trigger a manual re pagination of the document (can't remember the method off the top of my head)

you're right, it sounds like it might have to do with Selection.MoveDown in a specific circumstance (like being at the bottom of a page?)

in that case, the only answer is to try and "jiggle the handle", programmatically (like forcing word to update itself in some fashion) or approach from a different way (like using ranges).

You our already know which way I would suggest, but try the other stuff first and if they don't work, then time to work with ranges. Incidentally, .MoveDown is the one thing which doesn't have an analog on the range object, but you can easily use row and cell objects (and the cells collection on a row object) to navigate around a uniform table (I.e., no merged cells anywhere)

calvin-c
02-14-2014, 11:32 AM
Application.ScreenRefresh works so I'll mark this Solved. Thanks. I still might rewrite this after I understand what Greg Maxey is doing but at least I'm past the current problem. I do wonder what causes it. Given the solution I suspect it's that Word (or Windows) manages the cursor position on a cached copy (possibly the screen memory on the video card) and it needs time to refresh the cache when something changes (like a row moving to a new page because an image is inserted). That would explain why even a slight pause would also work-which means DoEvents would probably work too but I think I prefer Application.ScreenRefresh as that makes it clear why it needs the 'pause'. Thanks.

Frosty
02-14-2014, 11:48 AM
Yes, that's the other issue with using Selection. If you're doing a lot of operations, then you'll occasionally need to allow the entire application time to catch up. My guess is that Selection in this case is trying to stay on the same page when doing the .MoveDown method. I wonder if it would also work to operate in Normal view rather than Print View (or Page Layout view, depending on the version of Word).

Since normal view (where you don't see the page borders) overall uses less resources to display the document, your code using Selection would probably run faster and also not encounter the same issue with .MoveDown at the bottom of a "page"