06-20-2008 10:36 AM
This posting is evolved from an earlier one, mostly because of altenbach's comments. I decided the VI should have been a state machine all along, and using this strategy more explicitly makes it much cleaner and uses dataflow better. I can't post my real problem because it's proprietary but the attached examples demo some of its required behavior. They still need a few local variables to get things out from inside several loops, but it's much less like a text-based programming approach. The end eventually got cute. I am sorry about that.
MultipleMethodsWithEditHang.vi shows the original approach, and it malfunctions because event handlers intended to work in different machine states step on each other. As Dennis Knutson and TonP point out, event structures are enabled whether the other structures surrounding them are or not.
MultipleMethodsWithRegisteredEvents.vi tries to fix this by using "Dynamic Event Registration", but still doesn't work. I think I'm doing something wrong, and after reading TonP's link, the "caveats and recommendations...", Help, and some of Travis & Kring, still don't see the light. Maybe there's some minor error or maybe the whole approach is completely wrong.
Questions:
1) Is this code still convoluted and stuck in text-based thinking?
2) The only reason MultipleMethodsWithEditHang.vi fails is because the event handlers are fighting each other, right?
3) How could "Dynamic Event Registration" fix this? Or, what did I do wrong in MultipleMethodsWithRegisteredEvents.vi?
Thanks!
06-21-2008 06:46 AM
06-21-2008 12:28 PM
I fully agree with Mike! All you need is a single event structure. The biggest NoNo(!) is placing event structures inside case structures. An event structure needs to be able to handle events, and thus should never be bypassed by the dataflow.
mikeporter wrote:
1. Yes
2. No
3. See below...
06-22-2008 02:18 PM
06-22-2008 02:19 PM
Here's the rest of what I wanted to post:
I started to create a posting example for my "workaround" approach and was pouring so much time into it I stopped. Since the only event handler is in one loop, and as much as possible is within the "state machine cases" inside the other loop, it has functionality scattered between the event loop and the state machine loop, an absolute mess. So far it still works, but it certainly seems like the wrong structure, a nightmare of confusion that gets 30% worse with every 10% increase in functionality. For example, I have a motor that moves a sample, and there are 3 choices for speed, and the user clicks one of three buttons to select one of the speeds. So, these are three separate event handlers, at the very top tier of the organization. If I had opted to have the user enter the speed into a numerical control instead, it would be one control with one little wire, all buried pretty deep down inside one of the chunks of code in the "Adjust Sample" state's case. Doesn't this mean an otherwise minor choice about the user's options for setting motor speed would have to drive a major rewrite of the overall structure of the main program?
I could create the entire system with an event handler as its basic level of organization, perhaps. This would mean the machine mode (a very fundamental thing) appears nested at multiple levels inside events (a very local and even arbitrary thing). I'm not sure what I would do when programming parts that respond to two different kinds of events, except perhaps just start taking some of the controls away to avoid the situation.
In a state machine, the most basic level of organization is thinking in terms of the machine states, which looks useful. In the event handler loop, the highest level of organization is what event you're responding to. This just doesn't seem smart for the most basic level of organization. From the point of view of the user, in one mode, a mouse click on the "Up" button and a press of the up arrow key are equivalent, and should move the sample holder upward a millimeter, but in the event structure they don't even appear at the same level of the heirarchy because controls generate separate events for each control, while the keyboard generates the same single event for all keystrokes. And in another mode when the user wants to open a data file and add comments to the header, at first the up arrow key is going to change the selection to the file that appears above the currently selected file, but seconds later it's going to let the user move the cursor up one line of text in that file. Users switch their working definitions of controls like this all the time, just by using Windows. The program's response to an event is very different in different modes, in ways the user wouldn't find surprising. So, why should the identity of the event be the most basic level of program organization? Right now, that looks as odd as, say, having the most basic level of organization be whether integer or floating point arguments are used.
Or, maybe having an event structure loop and a state machine loop both running in parallel in the main VI is the right thing to do? It sure seems like quicksand so far.
Why should an event structure never be bypassed by the dataflow? The "move sample up" code never needs to execute if the system's in "Open Data File" mode. In fact, there are a zillion events that are not handled by any event structure, so why not have Key Down sometimes get handled and sometimes be one of the many events without handlers, depending on what the program is trying to accomplish right now? Even the way the LabVIEW IDE works reflects this. If you're editing text and hold the Shift key down, it has the effect of changing the character added, but if you're dragging a front panel control it has the effect of making it move exclusively in horizontal or vertical directions. If you're reading the Help system, the Shift key doesn't make anything happen. Surely the basic level of organization of the source code for LabVIEW's IDE itself isn't organized around having an event handler for keystrokes, with scan codes driving a case statement, and the code for inserting characters versus moving a control bitmap versus doing nothing, written into the different cases of that case statement.
Why is placing event structures inside case structures a NoNo? Apparently you have to do something special to "turn them off", but why isn't that enough?
About disabling controls if I don't want their events to occur - how do I disable the entire keyboard? I think the hang I started this thread with is because I have a Key Down event handler that I wished wasn't running in one of my states.
About static events versus dynamic events - sorry, I don't have LabVIEW with me, and I don't think I understand this, but will look it up tomorrow. I don't know that I do want dynamic events in particular. I thought I wanted to handle events in some situations and not handle them in others, and something somewhere lead me to Dynamic Events.
One last thing - I guess it's pretty unlikely anybody's going to go for this - but, suppose for the sake of discussion, we really did want to have event handlers inside case structures. What'd I do wrong in MultipleMethodsWithRegisteredEvents? How could I change it so that it would do what I wanted? How do you make an event handler stop trying?
06-22-2008 04:16 PM
06-23-2008 10:58 AM
06-23-2008 12:01 PM - edited 06-23-2008 12:01 PM
06-23-2008 12:27 PM
06-23-2008 12:47 PM