PDA

View Full Version : [SOLVED:] How to de-link a document from a userform



johndavidson
05-17-2022, 12:33 PM
I have a VBA macro that opens three documents (A, B & C), putting them in an array for later referral. The macro then opens a small userform that permits various Word searches in A, B & C.

However, whenever I click anywhere on the userform, the last of the three documents opened (C) comes to the fore. Why does this happen and how to prevent it? It is as if the userform has developed a permanent link with C. If the user closes C, then clicking on the userform no longer changes the focus document.

The code is all in a separate template, the documents have no code in them at all.

There is a statement aDoc.Activate that makes A, B or C the current active document, but clicking anywhere on the userform always brings C into focus, obscuring the other docs.

ShowModal is False and the userform is ‘shown’ with vbModeless.

I have an API call that keeps the small userform on top.

I’m using Word 2003 under Windows 7.

When minimizing doc C, the userform goes out of focus until doc C is brought back into focus.

Closing doc C does the trick, but is somewhat radical for our purposes.

The code is a little complex to post here.

Any guidance on underlying principles would be most welcome!

Thanks

Aussiebear
05-17-2022, 01:21 PM
Without seeing the code, most people will simply be guessing, so be prepared for all sorts of answers. Can a.Doc be set to nothing on exit?

johndavidson
05-17-2022, 02:02 PM
Yes, I'm more or less reduced to wild guesses myself. I do frequently reach places in my programming where I'm uncertain whats going on!

Well, that suggestion is good housekeeping and I've added a couple of Set aDoc = Nothing at appropriate places but it makes no difference.

Whatever is the last document opened and activated before opening the user form remains linked to the the userform until that document is closed.

johndavidson
05-18-2022, 02:14 AM
Without seeing the code, most people will simply be guessing, so be prepared for all sorts of answers.

OK. Here's the code, a little simplified ...



Public aDocArray(1 To 10) As Variant ' max no of docs
Public DocNameArray(1 To 10) As String ' max no of docs
Public arrCnt As Integer
Public arrNoofDocs As Integer
Public sFRText As String
Public frmFRT As frmFRTPARTs

Sub FindIn()' Find-Replace, inn PARTs I, II & III
' This routine opens the three documents and loads the userform.
' Clicking the START/NEXT/FINISH button on the userform simply calls the routine DoTDocs (see below)
' There is nothing else of any significance to this issue in the userform code


Dim currDocFR As Word.Document
Dim sStart As Long, sEnd As Long
Dim currDocFRName As String

If Documents.count < 1 Then
MsgBox "Please open a document"
Exit Sub
End If

Set currDocFR = Application.ActiveDocument

If currDocFR.ActiveWindow.View.SplitSpecial <> wdPaneNone Then
MsgBox "Please close any open endnote or other viewing pane"
Exit Sub
End If

sStart = Selection.Start
sEnd = Selection.End

Application.ScreenUpdating = False

' Save selected text, if any
If Selection.Start <> Selection.End Then
sFRText = Selection.Text
Selection.Collapse wdCollapseStart
Else
MsgBox "Please select a search string"
Exit Sub
End If

Call OpenDoc("PART IV") ' Path and filenames are correct. These are abbreviations for the sake of this post
Set aDocArray(3) = Application.ActiveDocument
DocNameArray(3) = "PART IV"

Call OpenDoc("PART III")
Set aDocArray(2) = Application.ActiveDocument
DocNameArray(2) = "PART III"

Call OpenDoc("PART II")
Set aDocArray(1) = Application.ActiveDocument
DocNameArray(1) = "PART II"

arrNoofDocs = 3
arrCnt = 1
Set frmFRT = New frmFRTPARTs

Call ClearFormatting1 ' Does what it says
Call API_NamedWindowOnTop("Find-Replace", 1290, 218)

End Sub


Sub DoTDocs()


' On clicking the Start/Next button, we sequentially make each document PART active
' If the user has selected a string in the original document, and that string is found,
' we hand control back to the user until he clicks 'Next'.
' Else we search the next document PART in sequence

' ********** There are other buttons on the userform. Clicking these or any other part of the userform, brings the PART II document to the fore,
'even if the user was working on, say, the PART III or PART IV documents. THIS IS THE ESSENCE OF THE PROBLEM ****************


Dim doc As Document
Dim aDoc As Document

Nextdoc:
If arrCnt > arrNoofDocs Then
Call CloseDocs
MsgBox "Searched all requested documents"
Set aDoc = Nothing
Unload frmFRT
Exit Sub
End If

Nextdoc1:
Set aDoc = aDocArray(arrCnt)
arrCnt = arrCnt + 1
On Error GoTo Nextdoc ' If user has closed the doc, read next doc in array
If IsFileOpen(DocNameArray(arrCnt - 1)) = False Then GoTo Nextdoc ' On Error GoTo Nextdoc does not always catch it
aDoc.Activate
frmFRT.lblCurrDoc.Caption = aDoc & vbCrLf & vbCrLf & "Search string:" & vbCrLf & vbCrLf & sFRText

If arrCnt > arrNoofDocs Then
frmFRT.cmdDoTDocs.Caption = "Finish"
Else
frmFRT.cmdDoTDocs.Caption = "Next PART"
End If

frmFRT.cmdSearchNext.Enabled = True
frmFRT.Repaint
DoEvents

Selection.HomeKey Unit:=wdStory
With Selection.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = sFRText
.Replacement.Text = sFRText
.Wrap = wdFindAsk
.Forward = True
.Format = False
.MatchCase = frmFRT.chkMatchCase
.MatchWholeWord = frmFRT.chkWholeWord
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With


If Selection.Find.Execute = False Then
If Application.ActiveDocument = aDoc Then
aDoc.Close 'Close doc after not finding the string
End If
GoTo Nextdoc
End If

' If string found or no string selected
Set aDoc = Nothing
Application.ScreenUpdating = True
Call PosTopToMid(True) ' Position found text 10 lines down from the top of the screen
CommandBars("Edit").Controls("Replace...").Execute ' Find & Replace


End Sub


Sub CloseDocs()
Dim i As Integer
Dim aDoc As Document

For i = 1 To arrNoofDocs
Set aDoc = aDocArray(i)
If IsFileOpen(DocNameArray(i)) = True Then aDoc.Close
Next
End Sub

Aussiebear
05-18-2022, 03:01 AM
can you set current document crrDocFr to nothing? To me this seems to relate to what ever is left over in memory as the active document.

johndavidson
05-18-2022, 03:28 AM
That sounded like a good idea, but I put 'Set currDocFR = Nothing' before 'Call OpenDoc("PART IV")' and again before 'End Sub' and the problem persists.

It seems to me that the issue is definitely the relationship between the userform and whatever is the active document at the time the userform is opened. As soon as the user clicks anywhere on that userform, whatever was the active document when the userform was opened takes the focus, also obscuring other documents if they are on the same screen. Use of the API to bring the userform to the top helps (it stops the userform from disappearing), but is not the complete answer.

I've had this with other userforms (also toolbars). A connection is established between the active document and the userform/toolbar that is active when the userform/toolbar is opened/loaded.

johndavidson
05-18-2022, 04:17 AM
I just tried making currDocFR the active document just before opening the userform. Then closing and reopening currDocFR and setting currDocFR to Nothing. Didn't work! In fact it made matters worse because the userform disappeared too, only showing its face when currDocFR was again made the focus by the user.

Closing currDocFR would work I suspect (but that defeats the object), just as closing the PART II document after searching works, which is what I presently have it doing.

What/why is the connection of a userform to a document and how to disengage it?

Paul_Hossler
05-18-2022, 11:37 AM
I have a VBA macro that opens three documents (A, B & C), putting them in an array for later referral. The macro then opens a small userform that permits various Word searches in A, B & C.


Attach the DOCM with the macro and userform to make it easier to review

johndavidson
05-18-2022, 01:07 PM
I understand, and I really appreciate the input, but I've been trying to keep it simple. The template (*.dot actually for Word 2003) containing this macro and userform is in fact 4.6MB in size with hundreds of macros and multiple userforms, also linked to other templates for various utility routines. Three decades of intermittent programming to address various needs on a huge literary project. About 12MB in all. It would be easier to write a sample macro that illustrates the issue. I'll have a think about it. Time is presently at a premium. I was hoping there would be something simple that I was doing wrong that the experts could easily spot! :content:

johndavidson
05-19-2022, 01:44 AM
Actually, I think the problem can be demonstrated very simply without programming. It even looks like its ‘the way Word/VBA works’, so what I’m looking for is a VBA workaround.

Try this:

1. Open a Word document (‘A’).

2. Open any simple modeless userform you may have. This appears to link document 'A' to the userform.

3. With the userform positioned over document ‘A’, open another Word document (‘B’) – the userform disappears unless you have set it as topmost using the API.

4. Now bring A back into focus, and the userform re-appears. This demonstrates that in some way the userform is linked to document A.

5. Move the userform onto another screen or part of the screen if you are using only one screen.

6. Now bring document B into focus.

7. Now click any blank space on the userform – document A retakes the focus.

8. The issue is, “How to de-link document A from the userform”. This can be achieved by closing document A. Then the userform is either closed with document A, or if it is not closed, it remains on top even if you have more than one document open. Why the userform is sometimes closed when document A is closed is another part of the mystery. Note, Modeless is set both when the userform is loaded and in the userform properties. Closing document A is of course not a desirable way of doing things. The user may want to have kept it open.

johndavidson
05-20-2022, 01:34 PM
I think I’ve found a way to do it: When the next doc to be processed has been made the active document, unload the existing userform and then reopen it. Seems to be working.

Will check more tomorrow.

Paul_Hossler
05-20-2022, 04:34 PM
2. Open any simple modeless userform you may have. This appears to link document 'A' to the userform.

Where is this UF located? A or B or C?

johndavidson
05-20-2022, 07:50 PM
The UF and its code are in a separate template (John.dot), which is loaded when Word is started. i.e. it lives in C:\Users\<username>\AppData\Roaming\Microsoft\Word\StartUp\John.dot.

The UF is initially associated with doc C, which happens to be the active document when the UF is opened. When the user indicates (by clicking a NEXT button on the UF) that work on doc C has been completed, then, by closing the UF, making B the active doc, and then (in the re-jigged routine) re-opening the UF, the UF is then associated with doc B. Likewise for doc C. This seems to get around the problems I was having.

It seems to me that UFs always begin life associated with the document that is active at the time the UF is opened, which is why, when you have multiple Word docs open at one time, a UF can disappear off screen or even get closed when the original doc is closed or when another doc is given the focus by clicking on it or from within VBA.

It would be good to know if there is a way to open a userform that is entirely unrelated to any particular Word document.

Paul_Hossler
05-21-2022, 12:16 AM
What triggers the UF in John.dot?

I don't have Word 2003 and Win7, so i (and most others I'm assuming) can only guess

johndavidson
05-21-2022, 01:13 AM
The VBA macros work the same in Word 2003 as they do in later versions of Word. Except that from Word 2007 onwards, intensive text processing macros work up to eight times slower in the ribbon versions of Word than they do in Word 2003. Did you try out the doc/userform check (steps 1 to 8 above)? I suspect that the issue will be the same. It's a global issue, not one related to a particular macro.

Thanks to yourself & Aussiebear for your input. Often with these problems all that is needed is for someone to suggest an alternative way of looking at it to provide the stimulation to come up with a solution. Or to pose the question, What exactly are you trying to achieve (always a good question!)? That's what happened here. Great stuff, guys!

Paul_Hossler
05-22-2022, 05:20 PM
The UF and its code are in a separate template (John.dot), which is loaded when Word is started. i.e. it lives in C:\Users\<username>\AppData\Roaming\Microsoft\Word\StartUp\John.dot.

The UF is initially associated with doc C, which happens to be the active document when the UF is opened. When the user indicates (by clicking a NEXT button on the UF) that work on doc C has been completed, then, by closing the UF, making B the active doc, and then (in the re-jigged routine) re-opening the UF, the UF is then associated with doc B. Likewise for doc C. This seems to get around the problems I was having.

It seems to me that UFs always begin life associated with the document that is active at the time the UF is opened, which is why, when you have multiple Word docs open at one time, a UF can disappear off screen or even get closed when the original doc is closed or when another doc is given the focus by clicking on it or from within VBA.

It would be good to know if there is a way to open a userform that is entirely unrelated to any particular Word document.

So, IF i'm understanding

1. John.dot has a UF and is in Word\StartUp

2. Word is NOT running yet

3. You start Word via command and File, Open C.doc -- OR -- just by double clicking C.doc

The UF will not display until something causes it to, either running a macro in John.dot or possibly an application event

What triggers the macro to get displayed?



However, I believe that just possibly 2003's Single Document Interface might have some thing to do with it.

Maybe C.doc is running Word in it's own window and showing the UF, B.doc is running in it's own window. That could explain


It seems to me that UFs always begin life associated with the document that is active at the time the UF is opened, which is why, when you have multiple Word docs open at one time, a UF can disappear off screen or even get closed when the original doc is closed or when another doc is given the focus by clicking on it or from within VBA.



The article has some things you can try


https://support.microsoft.com/en-us/topic/a-new-instance-of-word-appears-to-run-when-you-create-or-open-an-additional-document-in-word-2000-and-in-later-versions-of-word-d7392d8e-1afc-8c4c-5e53-7f60b30ff49d



By default, versions of Word that are later than Microsoft Word 97 use the Single Document Interface (SDI) design, in which each document occupies its own window (just as in Microsoft Outlook each message occupies its own window). This behavior is different from Word 97 and earlier versions of Word, which use the Multiple Document Interface (MDI), in which each document is a separate window within the Word program window. SDI was introduced in Word 2000.

johndavidson
05-22-2022, 08:30 PM
I think that the problem is simply that the UF has to be associated with a document. Part of the way VBA works with Word. I have worked around this by closing the user userform when closing a doc, and then opening the next doc and reopening the userform. Everything is working fine now. The problem is generic, not with just this particular macro. My 8 steps to demonstate post above simply identifies the way Word works. I think you can demonstrate this for yourself by opening two or more documents, and then opening any macro with a userform. Select any document other than the one that was open when you opened the userform, then click the userform. The doc that had the focus when you opened the userform will now have focus. I don't think it is an issue associated with Word 2003 alone.

To answer your question, I generally open Word by clicking on its icon in the Win. 7 taskbar. And the UF is invoked by clicking on an icon in a toolbar. John.dot and a bunch of other templates are loaded when Word is opened. This particular userform is just one of multiple macros that can be run either from menu items or from toolbar icons.

Paul_Hossler
05-23-2022, 04:09 AM
I think that the problem is simply that the UF has to be associated with a document. Part of the way VBA works with Word. I have worked around this by closing the user userform when closing a doc, and then opening the next doc and reopening the userform. Everything is working fine now. The problem is generic, not with just this particular macro..

That might happen if the macro code (which you've never posted) uses ActiveDocument.

johndavidson
05-23-2022, 04:33 AM
Yes, it does use Active Document. And I did post the relevant part of the code. See above, post 4.

Is there another way of doing things so that the user can edit the document?

johndavidson
05-23-2022, 06:18 AM
Here we go. The code is in the attached FindInTreasury_code.doc. See notes at the top of the doc. Couldn't get the upload *.frm to work so it's all in a Word doc for copy/pasting.

29772

I am happy with this code as it is, so the code is only for your interest and in case you can come up with a better way of doing it (highly likely, but what I've got here has the virtue of working). One can search docs using the range facility, but the results of a search will still have to be presented to the user in an active document that can be further edited.

johndavidson
05-23-2022, 06:27 AM
Actually, you will need the *.frm and *.frx files that are created by Word's VBA editor by exporting the userform module. But they wont upload. I get an invalid file message. So I've put them into a Zip file:

29773

johndavidson
05-23-2022, 06:44 AM
This is what the userform looks like:

29775

johndavidson
05-28-2022, 05:58 AM
Here is the latest code: May 28th 2022, in case anyone wants to modify it for their own purposes. Fixed a few minor bugs. Good for checking for presence of a string in other named docs. Could be modified also to check for a string in all currently open docs.