Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Destroy event and Do while

Status
Not open for further replies.

neculai

Programmer
Jul 21, 2004
13
CA
I have a Do while loop in a form. This loop is running, waiting for a logical variable to exit (stop). When I try to close the form clicking on [X] (and firing this way the Destroy event), the form is not closing, because the loop is still running. How can I do this?

Thanks.
Neculai
 
Such a do while loop is not a good solution, as you see. I don't know the nature of what it's doing, so I can't recommend anything, but if you do this to keep the form alive, think about READ EVENTS, if you wait for something, rather do that in a timer.

As a first solution you should of course set the exit condition of the while loop. The QueryUnload event is the place to do so, that is the event triggered by the X close button first. In general take a look at event tracking, if you want to find out which events run in which order and are triggered by which actions.

Bye, Olaf.

 
Actually, I used this code in the Click and DblClick events of a TreeView ACtiveX object:

*** ActiveX Control Event ***

* --- Be sure we enable the button only if we select a Child, not a Parent node
ThisForm.B1.Enabled = .F.

* --- Be sure we select a Child, not a Parent node
q = .T.
Do While q
For i = 1 To This.Nodes.Count​
If This.Nodes.Item(i).Selected​
Exit​
Endif​
Next​
If !(This.Nodes.Item(i).FullPath=='Taxonomy' or This.Nodes.Item(i).FullPath=='Identifiers' or This.Nodes.Item(i).FullPath=='Hormones')​
If (This.Nodes.Item(i).Parent.Key=='TX' or This.Nodes.Item(i).Parent.Key=='ID' or This.Nodes.Item(i).Parent.Key=='FB' or This.Nodes.Item(i).Parent.Key=='R' or This.Nodes.Item(i).Parent.Key=='NT' or This.Nodes.Item(i).Parent.Key=='MT' or This.Nodes.Item(i).Parent.Key=='G' or This.Nodes.Item(i).Parent.Key=='OT')​
ThisForm.B1.Enabled = .T.​
q = .F.​
Endif​
Endif​
Enddo

The idea is, I wanted to enable that button B1 only if I have one child selected. If I select one Parent and want to close the form on [x], the form doesn't fire the Destroy event and I am stuck in the form. To be able to exit the form, I need to select one Child first.

Thanks.
Neculai
 
Hi Neculai,

A loop is not the best way to do this. It would make more sense to use the Treeview's Nodeclick event to detect when a node is selected. The code in that event can then examine the selected node to see if it is a child node (for example, by looking at its .parent property). When that happens, set a custom property of the form to .T.

Then, in your QueryUnload, test that property. If it indicates that the form cannot be closed, execute NODEFAULT, otherwise just don't do anything special.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
This is the nodeclick event, isn't it?

A Nodeclick event makes a chnage in regard to Selected nodes. The next chance for a change is the next nodeclick.

So you don't need the while loop at all, you do this:
Code:
For i = 1 To This.Nodes.Count
   If This.Nodes.Item(i).Selected
      If !(This.Nodes.Item(i).Fullpath=='Taxonomy' Or This.Nodes.Item(i).Fullpath=='Identifiers' Or This.Nodes.Item(i).Fullpath=='Hormones')
         If (This.Nodes.Item(i).Parent.Key=='TX' Or This.Nodes.Item(i).Parent.Key=='ID' Or This.Nodes.Item(i).Parent.Key=='FB' Or This.Nodes.Item(i).Parent.Key=='R' Or This.Nodes.Item(i).Parent.Key=='NT' Or This.Nodes.Item(i).Parent.Key=='MT' Or This.Nodes.Item(i).Parent.Key=='G' Or This.Nodes.Item(i).Parent.Key=='OT')
            Thisform.B1.Enabled = .T.
            Exit
         Endif
      Endif
   Endif
Next

And as Mike points out, a child node is a child node, when it has a parent.key, any parent key, so why check all the specific values?

Code:
For i = 1 To This.Nodes.Count
   If This.Nodes.Item(i).Selected AND !EMPTY(This.Nodes.Item(i).Parent.Key)
      Thisform.B1.Enabled = .T.
      Exit
   Endif
Next

If this errors because Nodes without a parent have no parent.key, then check for PEMSTATUS first:
Code:
For i = 1 To This.Nodes.Count
   If This.Nodes.Item(i).Selected AND PEMSTATUS(This.Nodes.Item(i).Parent,"Key",5) AND !EMPTY(This.Nodes.Item(i).Parent.Key)
      Thisform.B1.Enabled = .T.
      Exit
   Endif
Next
But you know better than us why you would check so many specific key values. Take a look at INLIST() at least, to simplify this: INLIST(...Key,"TX","ID",....).

Bye, Olaf.
 
Mike Lewis said:
Another possibility: Do what I suggested re the Nodeclick event, but instead of putting code in your QueryUnload, simply toggle the form's Closable property.

Even better.

But the bottom line is DO NOT try to control event flow in code. Work with VFP's event model instead of against it.

My spidey sense tingles any time I see a DO WHILE in event code. Yours should too. To be perfectly honest, I can't remember the last time I wrote a DO WHILE loop. They have their place, but controlling program flow isn't that place and hasn't been since 1991.
 
Thank you all for your valuable ideas. I've done the code working, and as you pointed out, it's better to avoid Do While loops at all costs. Here is the code I've used in the NodeClick event.


Lparameters Node

Thisform.B1.Enabled = .F.

* --- Be sure we select a Child, not a Parent node ... and only certain children, not all of them

For i = 1 To This.Nodes.Count
If This.Nodes.Item(i).Selected​
Exit​
Endif​
Next
If !(Inlist(This.Nodes.Item(i).FullPath, 'Taxonomy', 'Identifiers', 'Hormones'))
If Inlist(This.Nodes.Item(i).Parent.Key, 'TX', 'ID', 'FB', 'R', 'NT', 'MT', 'G', 'OT')​
FullNodeCrochiu = This.Nodes.Item(i).FullPath​
ThisForm.B1.Enabled = .T.​
Endif​
Endif

Now, even if I select a Parent, I can anytime close the form. With Do while loop I couldn't do this and I was stuck in the loop.

All the best,
Neculai

 
Well,

your solution will not work, if the first selected node you find in the upper loop does not meet the requirements of the following if.
I gave you a single loop you'd only exit after finding the first selected node being a child node, and you should modify your final code correspondingly, because if you now select a parent node and then add a child node to the selection (multiselect is possible), that won't work.

Code:
For i = 1 To This.Nodes.Count
   If This.Nodes.Item(i).Selected
      If !(Inlist(This.Nodes.Item(i).Fullpath, 'Taxonomy', 'Identifiers', 'Hormones'))
         If Inlist(This.Nodes.Item(i).Parent.Key, 'TX', 'ID', 'FB', 'R', 'NT', 'MT', 'G', 'OT')
            FullNodeCrochiu = This.Nodes.Item(i).Fullpath
            Thisform.B1.Enabled = .T.
            Exit
         Endif
      Endif
   Endif
Next

This will also work, if the first wrong selection of a parent node is extended with a child node.

Bye, Olaf.
 
....and if you only want to check the currently clicked node, it's simply the node that is passed in as parameter to the NodClick event, you'd only check, whether the click selected or deselected it and whether it's a child node. You need not loop all other nodes at all in that case:

Code:
Lparameters toNode
If toNode.Selected
   If !(Inlist(toNode.Fullpath, 'Taxonomy', 'Identifiers', 'Hormones'))
      If Inlist(toNode.Parent.Key, 'TX', 'ID', 'FB', 'R', 'NT', 'MT', 'G', 'OT')
         FullNodeCrochiu = toNode.Fullpath
         Thisform.B1.Enabled = .T.
         Exit
      Endif
   Endif
Endif
Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top