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 gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Looking for help on an Idea for Navigation 1

Status
Not open for further replies.

Scott24x7

Programmer
Jul 12, 2001
2,826
JP
Hi All,
So I've spent a couple of days trying to get something to work, have taken a few approaches, but seems to lead me to a dead end.
I have a set of graphic objects (flags) that I have placed on a map. The flags are only "visible" when their location matches to the client. So some clients have more than one office in the city, so I have a routine that counts the number of locations and displays it in a label over the flag.
What I want to do now is expand that, so when you "hover" over the flag, a small list (like "tool-tip text") pops up with the list of locations for each one. I tried using a dynamic drop-down box, and I got the items to list, but getting the box to "appear/disappear" didn't work well. (It would appear, but I couldn't select items, and the box would not disappear after click or leaving it (even having This.Visible = .F. in the MouseLeave or LostFocus events.)

I thought maybe a list box would be the best way to do it, but the "MouseEnter" on the flag field isn't taking into consideration the entire flag. One problem is, the flags overlap too, so ZOrder is a problem, as flag that's not visible, but "on top" of another flag interferes with the MouseEnter issue.

The flag and the textbox are in a Container and it seems the boundary of the container also impacts things like "tool-tip text" (it fires on leading right edge and bottom edge, but not on top or left side...)

I think the idea is a cool one, as it would allow "1-click navigation" visually within the form, rather than having to click on other buttons or lists to get to them.

Has anyone else implemented something like this? I feel I've "over complicated it", but I've been fighting with the controls for 2 days.
Thanks for any suggestions.


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Hi Scott,

There are a few different issues here.

First, I would suggest that instead of trying to show/hide a "dynamic" listbox, or any other individual control, you place your list of locations in a form. It will be a small form - just large enough to hold the list - with no title bar and a fixed single border (or no border at all). The form will hold a listbox, or perhaps a grid, which will fill the form.

To show/hide the form, you could simply DO FORM and then release the form when you have finished with it. Or you could open the form at the outset but keep it invisible; then toggle its Visible property when you want to show/hide it (we discussed this techique in thread184-1776138).

As far as the mouse hovering is concerned, one approach might be to write the code for toggling the form in the MouseEnter and MouseLeave of the container, and then use BindEvents() to ensure that it is triggered when the mouse is over the actual flag and its label. I'm not sure how well that would work, or what the implications would be of one flag being on top of another.

I vaguely remember having a similar problem myself some years ago. When I get time, I'll see if I can find the code, and let you know if it is of any help.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hi Mike,
I like the sound of this idea. I hadn't thought about using a form that would have DO (FORM) and a RELEASE(). I like the idea of the listbox, because it's so clean, and I only need to show 2 columns, so might work better than a GRID, though admittedly in all the years I've used VFP I can't think of a single instance where I've used a listbox in the past. So I'll give this approach a fair shake. It make sense as well to bracket the MouseEnter/MouseLeave code so that if the condition isn't right for that one it bypasses it.

I'm also thinking to try to dynamically size the window of the form so that it's always the size of the rows in it.
Thanks heaps, if you find an example, that would be great. I've been looking at the samples in the VFP9 samples directory, but there was nothing quite like what I'm looking for.

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Scott, glad to hear that you have made progress with this.

Just to be clear, I wasn't arguing against a listbox, but only against a listbox within the main form. My point was that, whatever mechanism you use to select the location, it should be contained within its own form. It looks like you are on the right track with that.

Now, just to confuse the issue, it occurs to me that there is another solution: a shortcut menu (the kind that pops up when you right-click on a control).

You would create and display the menu in the MouseEnter event. You do that with DEFINE POPUP and DEFINE BAR commands. The bars would display the client's locations. The menu would automatically close when the user makes a choice. Or you could programmatically release the menu in the MouseLeave.

I think this might be simpler than my earlier suggestion, and has the advantage that you don't have to worry about the positioning on the screen (FROM MROW(), MCOL() in the DEFINE POPUP takes care of that). If you are not familiar with commands for shortcut menus, you should be able to create one with the Menu Designer.

Just a thought.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike,
Just when I got the form thingy working, now I really do like your other idea quite a lot... There was a lot of complexity in the creation of the items to put in the list because I'm working with geographically ambiguous boundaries, and I've had to do a lot to only "get" the items I need at the time. It is a little bit clunky, and I'm getting an odd "error" that doesn't actually exit VFP (something about calling from within itself), I've had a very hard time tracking it down, and since it wasn't breaking the process, I've left that alone. but this solution may be a better one. I'll have to concatenate some data together for display in the menu, but that could solve another problem I have with is the "return value" from the called form back, and then repositioning the record to the right location after the selection.
I've spent 2 days on this now... I hate how rusty I've become. I have built dynamic menus in the past, and this application does take advantage of one, so I have an example of code I can use, as it's all built during run time (I use it to launch PDFs after making a list of any docs that are in a specific directory, which is really handy). So now that I have the logic sorted for the selection of the items, maybe it's best to load them into a menu instead of a grid in a form... Thanks for that idea, I'll give it a try now.


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Hi Mike,
So I decided to stick with the grid in the borderless/headerless form. The error I was getting was because of calling a ThisForm.Refresh() from within the Refresh method of another control (oops). Once I figured that out it all became a lot smoother, and because I'm showing two identification fields (Facility name and Facility address), and then using the primary key value (not displayed, but contained in the cursor) for repositioning the record pointers after the selection, it is a lot easier to manage than the menu option. But for simpler examples of this, I will keep the menu element in mind. It is working really well now, exactly the way I had envisioned it when I started on this idea 3 days ago. Many thanks for your guidance.


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Hi Scott,

Good to hear that you are near a solution. After I posted my idea about a shortcut menu, I realised I had made it slightly more complicated than it need be. I mentioned that you could programmatically release the menu in MouseLeave, but of course you don't need to do that. Like all such menus in Windows, the menu disappears as soon as the user clicks anywhere outside of it.

I realise this isn't relevant now, given you have decided to go back to using a form, but I thought I would mention it for the benefit of anyone else who might be interested.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike,
There are likely other areas in this application where that may be highly applicable. And I may come back to this at some point if I can't get the performance tweaked entirely the way that I'm hoping. But because one item deals with so many pieces of data, and my own shortcomings of working in that method, for now I've got it working in a pretty nice fashion. The complexity here is passing into the for, 4 pieces of data concatenated together, since you can only pass one variable into the form. So I then have to parse out into the 4 variables that get used while the form is alive. Maybe there is a more elegant solution for that, but for the moment, I'm pretty happy with the outcome. It will be interesting to see if it still performs well on a "lesser" machine, since I use a beast of a workstation for development, I always have to test on lower capacities. Fortunately these days, since VFP was written for speed back in the age of the Pentium, it still does pretty well even on a poor spec machine.
Thanks once again for the direction and insight, it was just the guidance I needed to make what I had envisioned, a reality.
I'm hoping to make it to SWFox Dev convention again this year. A couple of years ago when I demoed this part (with the map and flags) there, people liked it a lot. So I'm hoping to show now, more "navigation through un-obvious means", but that make the interface much easier to interact with. I'm driven by a "1-click" only philosophy. And this makes that happen in this case!


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
The complexity here is passing into the for, 4 pieces of data concatenated together, since you can only pass one variable into the form. So I then have to parse out into the 4 variables that get used while the form is alive.

Scott, I might have missed something earlier in the thread, but when you say that you can "only pass one variable" into a form, are you referring to form parameters - that is, the sort that you pass with the WITH clause of DO FORM?

If so, you can indeed pass more than one. This type of parameter is the same as the parameters that you pass to a procedure or function, so you can have up to 26 of them. For example:
[tt]
DO FORM MyForm WITH ID, Name, Address[/tt]

and in the form's Init

[tt]LPARAMETERS tnID, tcName, tcAddress[/tt]

But if you are referring to information that is passed back from the form to the caller, then you are right: you can only pass one value. The solution is - as you have discovered - to concatenate the multiple values and then to parse them out individually. Alternatively, you can return an object (which can has whatever properties you give it), or you can pass an array into the form, and have the form populate the elements of the array with the values you want to return.

Passing information back from a form back to the caller is only relevant if the called form is modal. In your case, I don't think the form will be modal, because you want the user to be able to dismiss the form by clicking anywhere outside of it. You can't do that with a modal form.

I hope I haven't misunderstood what you are aiming to do.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike,
Well, that is crazy helpful, as I was doing it backward! (Still worked, but no need to try so hard, eh?). For this case, luckily I only need to pass one item back. But now I'm going to fix the parameter for future maintenance on the form, 'cause that's crazy. Funny I've had it wrong in my head for over 2 years now.
I'm still having some problems getting the exact behavior that I need from it, but I know it's a logic issue somewhere else. Trying to track it down. Once I have that solved I am good... but only 99% of the way there for the moment. I believe I know what's happening, now I just have to find where it's happening.
Thanks once again.


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Hi Mike,
So one other oddity I'm trying to resolve now. When the window pops up, I have the grid fulling filling the window space (and I shrink/grow this dynamically based on the number of rows in the grid, by changing the Height of the Grid and Window it sits in with simple Height of Header+height of row * number of rows).
Then in the Grid MouseLeave event I have "ThisForm.Release", so that the expected behavior is to close the window if they move the mouse out of it.
However, I find that it only does this when I push the mouse up through the top of the grid. My theory is because that clause expects the GRID to have the focus, and the mouse is over the grid columns, which have text boxes in them... so when I move out of the form left right or down, it doesn't pass back through the Header where the "GRID" gets the focus again. Thus allowing the form to be destroyed as it exits the top of the grid.
How can I get it to close the form either by tricking the GIRD object to have focus when you go out the sides, OR is there a better method to have the form recognize when the mouse is outside it, and then close it that way? The annoying thing is the FORM doesn't have a "MOUSELEAVE" event so I can't control it that way. I tried it with MOUSE MOVE but that didn't work either, I think maybe again because the grid objects are on top of it? Any suggestions?


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Scott, I'm not sure what the answer is to that question. I was thinking that you would close the form when the user clicks outside it (rather than simply moves the mouse outside it), in which case you could use the form's Deactivate event. But I can see that wouldn't be a slick as your approach.

I'll let you know if I come up with any ideas.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike,
How do you detect a "Click" outside the form? Especially when the form is Modal?
I would be ok with this for now...

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Hi Mike,
I'm an idiot... found a solution to this.
I had made the GRID and the FORM the same size. If I make the form 1 pixel wider than the space around the gird, then when the mouse passes across it, it triggers the MouseLeave event on the GRID control (DUH).
So now moving the mouse outside the boundaries of the grid control (and I just made the 1 pixel background the same color as the grid so you don't see a difference between where one starts and the other stops), and it works like magic.
No need for outside clicking at all, and when the mouse enter event fires over the flag again, it just makes the form over again. VERY slick I think... Intuitive, and gives that "discovery" feel to the app when hovering over it. I also found my logic error in the control after selection (which was some filter condition being set on a table that I have no idea why I had done that.. .it's probably been there for 2 years and will explain some other funky behaviors I've had). I've had this idea for months of putting this on this form, and finally, it is a reality.
Thanks heaps once again.
(Oh, BTW, I am still curious how you detect a mouse click outside a window though...)
Cheers.

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
If I make the form 1 pixel wider than the space around the gird, then when the mouse passes across it, it triggers the MouseLeave event on the GRID control

Ah, yes. Why didn't I think of that?.

I am still curious how you detect a mouse click outside a window though

Very simple. You use the form's Deactivate event. If the user clicks anywhere outside the form, then by definition the form is deactivated. But .... it won't work in this case because your from is modal. By definition, you can't deactivate a modal form, you can only close it.

Then again, is there any special reason for this form to be modal? The only reason I can think of is if the parent form (the one containing the flags, etc.) is itself modal (a form called by a modal form is always itself modal). If that's not the case, you should be able to make the form containing the grid modeless.

Of course, this is all academic. The approach you are using (closing the form when you move the mouse outside of it) should be much slicker.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike,
The form is Modal because (and I hope you're going to tell me I have this wrong too), I thought you could only use a Modal form with a DO FORM <form> WITH <ags> TO <returnVal>.
It's the use of the "TO" clause that I believe the form must be Modal?
I hope I'm wrong here, it would make my life infinitely easier. :)


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Mike,
Oh, forgot to put in... about the Mouse Click outside the window...
Even though I now have it working where mouse across the window causes it to close... it's not 100%... if you go VERY fast across it, often the event doesn't fire. So you wind up having to move back into the window and out again to get it close, and since it's modal, if you're already half way across the screen, you have to back track to where it was... so that's annoying. In this case having the alternate to "click" (and I had already built that into the flag as well... a "Click" will open the window in the same way the mouse over does), it would kill 2 birds with one stone... close the other window, and open one on the new location at the same time.


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Just confirmed that TO clause can only be used with MODAL form... so that is why I have it set as modal. Tell me another way to pass the value from the form back to my calling form, and I can switch it, but this was the only way I could figure out how to pass a variable back to a calling form...

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Silly me. I'd forgotten you needed to return a value from the grid form. Of course you are right: it needs to be modal. (In fact, there are other ways of returning values from forms other than via the TO clause; for example, you could pass the calling form's object reference to the called form, and have the called form put the relevant value in a property within that object reference; but the called form would still need to be modal because otherwise the caller has no way of waiting until the return value is available.)

Looks like you will have to stay with your idea of closing the form when the mouse moves out of it - unless I can come up with a better suggestion, in which case I'll let you know.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Sorry to interrupt. The solution is in Mikes suggestion in passing in an object. You are not only able to set some of its properties, you can also call some of its method, or define a returnvalue property you give an assign method, so setting the returnvalue triggers the passed in objects assign method to do anything with the return value.

The object to pass could be anything, but perhaps simplest would be the main form passes itself (thisform) on. The form receiving that as init parameter obviously has to store at, and while you can't do addobject to add another form to a form, you can simply set a property oCallerform to the passed in object reference.

mainform.mouseenter: do someform with thisform, other, parameters
someform.init has
[tt]LPARAMETERS toCallerform, other, parameters
thisform.oCallerform = toCallerform[/tt]

someform.deactivate has:
[tt]thisform.oCallerform.returnvalue = anything[/tt]
mainform does not only have that returnvalue property but also a mainform.returnvalue_assign method.

Or you simply define a method the called form has to call and pass out the return value, eg
someform.deactivate has:
[tt]thisform.oCallerform.callback(anything)[/tt]

I'll leave it at that sketch, make the best of it.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top