Jump to content

Improving updates of treeview


Recommended Posts

Treeview is a great way to display nested data. There are libraries to help interface with the control that make it easier to populate the data in the control.

Code structure...

The code has two loops (well, more, but those are not important for this). The first loop is the "user interface". This loop updates the front panel and responds to user actions (button presses, menu selection, etc.), and passes events to the second loop. The second loop, the "action" loop, performs the "real work" of modifying (load, save, add, remove, move elements up/down, etc.) the data displayed on the front panel. The action loop can send an event to the user interface loop to update the front panel.

Situation...

The user goes to, say, add a new item in the middle of the data displayed in the tree. He selects a point to add at, selects what to add, and clicks OK. The user interface loop handles this until it's time to do the actual add. The user interface sends an event to the action loop which actually performs the add on the data. The action loop sends an event back to the user interface loop to update the front panel. The user interface loop, wisely, defers panel updates, modifies the treeview, the turns off the defer.

But how does the user interface loop update the treeview?

The user interface loop has no "memory" (nor should it) of what it sent to the action loop, so it can't be smart about updating the treeview. The action loop is merely sending an update message and is not sending any intelligence to the user interface loop. The user interface loop can only delete the entire tree and recreate it. This could be acceptable (it's not), it is less than optimal.

My question (finally!) to people is how they have resolved this? I have a couple of ideas but would like to hear from people.

Tim

Link to comment

The user interface loop has no "memory" (nor should it) of what it sent to the action loop, so it can't be smart about updating the treeview.

Agreed. This is a very important part of UI design, especially when you start to have multiple UI components which can independently operate on whatever the underlying data model is. Even more important if these operations are performed asynchronously.

The action loop is merely sending an update message and is not sending any intelligence to the user interface loop.

To me it's the lack of "intelligence" that's the problem. For this reason I usually try to send some sort of context along with an update message. That is not a global "something changed", but more along the lines of "DataX has changed". Sometimes a context can't be supplied, in which case a UI is forced to do a full re-draw, but in many cases narrowing down what has changed can really help. This means however that each UI needs to maintain some state information so it can cross reference the the context with what it's displaying. Does that make sense or am I being too abstract?

Link to comment

To me it's the lack of "intelligence" that's the problem. For this reason I usually try to send some sort of context along with an update message. That is not a global "something changed", but more along the lines of "DataX has changed". Sometimes a context can't be supplied, in which case a UI is forced to do a full re-draw, but in many cases narrowing down what has changed can really help. This means however that each UI needs to maintain some state information so it can cross reference the the context with what it's displaying. Does that make sense or am I being too abstract?

I agree that the "Update UI" event needs to have some data that goes along with it; you are not being abstract.

The UI loop and Action loop both need access to the data (the UI for display purposes, the Action for performing edits on the data). I've started pondering the Action passing to the UI what parent has changed and letting the UI loop process from there. This would maintain separation between Action and UI. I'm looking at the Damerau–Levenshtein distance algorithm (http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance) as a means to determine what has been changed and how it's been changed. As I'm typing this, I'm realizing that the Action loop knows what change has occurred, thus the path can be:

UI -> Action: Change this by doing that
Action: Make change
Action -> UI: Change to this made by doing that

Such messaging doesn't require the UI to remember anything and allows the Action loop to block (such as trying to move the item at the top of the tree up).
Link to comment

I use string messaging for passing data between UI and action loops/VIs. The command channel is usually a queue and updates are via events.

Basic setup is that the UI only handles operator input and control updates (usually only control name and data). As in your case, those strings then get passed to either another loop in the same VI or, more often than not, a dynamically launched "controller". (strings will typically be of the form "VIName->ControlName->Command->ControlData")

This is straight forward for most controls, but the tree view is a bit of an anomaly. To get round the property nodes being required to manipulate the control, I flatten the controls reference as part of the data payload The controller knows how to interpret this payload, retrieves the reference and updates the control according to the command.

For treeview type controls this often means that those controls have a controller loop/vi in the top level VI specifically for them since I generally consider the Top level VI to be only for UI interaction and it separates other processes that can be run (as I previously said-dynamically) without forcing the front panels into memory or risking them being run in the UI thread.

Since I consider the top level VI to be for UI. Why bother with a separate controller loop/VI. The reason is that you can also run a TCPIP process and, using exactly the same string commands, control it remotely.

Link to comment

Tim_S, you can read about my basic MVC design here: http://lavag.org/top...dback-required/

In my design the UI loop only sends messages to the control loop, it is a one directional queue of user generated events.

The FP controls are updated from the control loop even from dynamically loaded plugins like Actors or LVLibPs.

This is accomplished by a preliminary traverse scan of the main FP, saving all the control references and passing them to all the plugins among other common data using a db class.

Notice that in my design each FP control has a replica in a class control and thus, the FP is not being used as a db for the control operation.

Once you have the reference of the tree view you can do all that you want to do.

Besides that I use the PropSaver to load/save property combinations.

By using a direct update (the update is handled by the write property node of the parallel FP control in the class control) I can defer FP updates forever.

P.S. - the design from the post is old and was much improved since but I'm still not sure if this methodology has some drawbacks like forcing the FP into memory in the plugins when you use property nodes on the control references or making the property nodes run in the UI thread, maybe ShaunR can answer this.

However, if the FP doesn't need many updates (real time graphs) I think I prefer my design even with some drawbacks since it is clean and easy to maintain.

Edited by 0_o
Link to comment
like forcing the FP into memory in the plugins when you use property nodes on the control references or making the property nodes run in the UI thread, maybe ShaunR can answer this. However, if the FP doesn't need many updates (real time graphs) I think I prefer my design even with some drawbacks since it is clean and easy to maintain.

Not so much loading FPs into memory but definitely running in the UI thread,

"Property nodes for controls always run in the UI thread" -- true

Anything under the "VI Server" category will always run in the UI thread. This includes VI references, Application references and all panel/diagram object references. If you are making a lot of these calls, you might consider moving them to a subVI that can be set to run in the UI thread. Other categories, like VISA, will use any thread. ActiveX has its own rules for which objects can be accessed from which threads. (If you don't have to know about apartments, trust me you don't want to.)

"Any control reference causes the panel of the VI containing the control to be loaded" -- true

"Any control reference will cause the panel of the VI containing the control to be included in built applications" -- false

This is related to the earlier comment about the documentation "Loads the front panel into memory" characteristic. This means that when the operation runs it forces the panel to be loaded. This is different than things that cause the panel to be loaded immediately when the VI is loaded, which is different than things that cause the application builder to include the panel by default.

reference

Link to comment

This is straight forward for most controls, but the tree view is a bit of an anomaly.

A bit might be an understatement.

To get round the property nodes being required to manipulate the control, I flatten the controls reference as part of the data payload The controller knows how to interpret this payload, retrieves the reference and updates the control according to the command.<snip>

That is an interesting idea. I'm going to have to think about that.

Tim_S, you can read about my basic MVC design here: http://lavag.org/top...dback-required/

<snip>

I'll have to re-read your design a few times to understand it. A whiteboard and some hand waving is often clearer to me than a text description.

Tim

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.