LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

LabVIEW Drag and Drop in Tree using event structure

I did something similar for a replacement TestStand sequence editor but I did a picture control in front and overtop of the left of the tree; didn't think of making it transparent and putting it behind it. I'll have to take a look at that package! Something I was thinking of implementing was "placeholder" functionality to live update the tree with blank space as you're dragging as an alternative to the insert graphics.

0 Kudos
Message 11 of 17
(1,655 Views)

@DerrickB wrote:

I did something similar for a replacement TestStand sequence editor but I did a picture control in front and overtop of the left of the tree; 


Yes I too have a sequence editor with TestStand like functionality, but supports running the sequence on RT.  My solution is pretty involved, but also leverages multiple picture controls.  I needed columns to be glyphs that are also larger then 16 pixels.  This gets complicated when you allow scrolling in both directions, and resizable windows.  The tree is still used which can also show or hide items, which also needs to show and hide those corresponding glyphs.  Then there are conditions that might cause steps to goto another step.  So I added another picture control to highlight with arrows, what steps can potentially go to what steps.  The drag and drop indentation level works well, but there is no visual indicator of where it will go.  It just decides if you are closer to the previous item, or closer to the next item.

 

It works well enough but needless to say it comes with a decent amount of code to handle all of this.  I'm hoping I can use this improved drag and drop to replace some of its functionality.

0 Kudos
Message 12 of 17
(1,644 Views)

Wow this is really cool, it will take me some time to dive in and understand how I can use this.  I will say that you tend to put lots of things on the palettes, and I think users generally feel more comfortable with a simplified API.  Maybe it is nit-picky but does the palette really need sub functions like the Move Items, Refresh, and Overwrite on the palette?  And on the topic of Palettes, where is the New Value and New Folder? 

 

I wonder if the tag creation process could be simplified by reading the existing reference and populating the items and values with what is already there.  But yeah this is pretty great stuff, thanks.



Wow this is really cool

High praise from the one and only Hooovahh, I appreciate you taking a look at this.

 will say that you tend to put lots of things on the palettes, and I think users generally feel more comfortable with a simplified API.  Maybe it is nit-picky but does the palette really need sub functions like the Move Items, Refresh, and Overwrite on the palette?

I have not written any documentation or user guide for this code yet.  I was focused on getting it into the open-source domain first.  I hope to find time to go back and create a nice README on the GITHUB.

 

BUT, as you've seen, there are 2 primary palettes.

The "Events" palette is the high-level palette which is expected to be dropped directly into event structures.

The "Modify" palette is the lower-level palette which represents the public interface for manipulating the items in a lixtbox/tree.

The "Modfify" palette is directly called by the "Events" palette.  But, I still perceive the "Modify" palette to be a public interface, and to serve a purpose.

 

There is an expectation that if you use this code, then the user is no longer allowed to directly edit the tree/listbox ItemNames or tags by reference.  You must use the "modify" palette.

 

And on the topic of Palettes, where is the New Value and New Folder? 

This is probably misleading again due to the lack of documentation.

But the "valve" and "folder" objects that you see on the demo are strictly demo classes.  These are not apart of the actual core library.

The paradigm being established here is that each row in a tree/listbox corresponds to an object.

Thus, a handle to a tree/listbox is an array of objects.

IT's expected for the the user to create their own classes to then override the DD methods of the parent-level object for then handling things like:

- Can this class allow children?

- How does this object export to a row on a tree/listbox?

- What symbol does this object use?

 

Basically, I LVOOP-ified tree/listboxes.  This simplified the ability to easily move items around and between listbox and trees.

0 Kudos
Message 13 of 17
(1,634 Views)

@DerrickB wrote:

I did something similar for a replacement TestStand sequence editor


This VIPM package was created with this exact intent in mind: to create a custom TestStand sequence editor.

 

The demo demonstrates how it's easy to move items across tree/listboxes.  This jives with the concepts of having:

  • Listbox or trees with static command palettes where the user can drag FROM but not drag TO
  • A tree that represents the sequence where a user can drag TO but not drag FROM.
  • Again, a core requirement of this library, for me, was to make it easy to allow for the user to select indent level with their curor when dropping
0 Kudos
Message 14 of 17
(1,633 Views)

@brentjustice wrote:

There is an expectation that if you use this code, then the user is no longer allowed to directly edit the tree/listbox ItemNames or tags by reference.  You must use the "modify" palette.

 

And on the topic of Palettes, where is the New Value and New Folder? 

This is probably misleading again due to the lack of documentation.

But the "valve" and "folder" objects that you see on the demo are strictly demo classes.  These are not apart of the actual core library.


Yes I see this now that I look closer.  I feel like this might lead into more philosophical discussions around APIs.  But I tend to try to make APIs that work with the developers existing work flows as best it can, and rarely try to force them into something specific.  I get that in this case editing the tree needs helper functions.  But why does the tree need to be deleted at the start?  Couldn't it look at the existing tree to figure out things it needs to know?

 

For instance one of the first things I tried with your code is to increase the font size of a cell.  I did this using the LabVIEW IDE just by highlighting the text and increasing it.  When you run the VI it just deletes the whole tree, so fonts go back to the default.  Fine I used some property nodes to set the font size before running your stuff.  Then the fonts are larger, but the row height is static, so the text is cut off.  I have to dig into the Init to find the constants for setting various values.

 

Another example of this is in the Item Selection that you've also done a great job improving.  But again my old code did things like re-read the tree when making changes at runtime because I wanted to just be an assistant to the developers likely already existing tree code.  I couldn't know something didn't change between reads, so it did the full tree read every time.  Not great on performance, but a pretty simple user experience.

 

Forcing a developer into a specific work flow can have tighter integration, allowing for better performance.  But for my APIs I tend to have less control, and try to be easier to use at the cost of performance, and possibly more complicated code to handle outside changes.  Anyway it is obvious a lot of work went into this, and the community appreciates it.  I do wonder if some day an ultimate MCLB could be made (or QControl) combining multiple MCLB tricks and hacks into a single control.  Virtual MCLB, Multiple Glyphs, Glyphs larger then 16px, Alternate Row color, Header Sort, Improved Drag and Drop, Automatic Column Width, Item Selection, Alternate Data Type Entry, Key Navigation, Undo/Redo Move/Copy, all with pane resizing.  I've got a couple examples of hacky solutions combining some of these. But at some point the task gets so large keeping track and testing the use cases and edge cases becomes a time sink.  Maybe I'll try to post sometime but it will be ugly.

0 Kudos
Message 15 of 17
(1,625 Views)

You've nailed the tradeoff.

 

This code here represents a "tight api" (probably the wrong word) where the expectation is that the user isn't allowed to directly interact with the tree/listbox reference. As such, i never read values or properties from the reference, i only write to the reference. This allows me to optimize the heck out of performance, which was a paramount concern here. I needed this code to work with trees with thousands of tags. Any sort of lag or latency would be noticeable to end users, and would kill the user experience.

 

There's another aspect though. For me, the tree/listbox references represent an exported UI layer. I always update the UI layer, but i never read from the UI layer. Instead, the "model" layer is the "handle" that gets passed around. Which, again, i am forcing the paradigm that a tree/listbox can be modeled as an array of by value objects. The nice thing about this is that you can easily serialize and deserialize the object array in order to pass around the model.  (Sidenote, I've always been upset that you can load an array of TreeItem clusters into a tree control, but you can't export this same data structure from a tree control)

 

So, everything you are saying is correct.  By forcing a tight api, there are obvious downsides that you've pointed out. And I've cut the user off from many tree/listbox features not exposed in my tight api.

 

Also note that most of what's happening here is all pixel math. One glaring optimization that i made was a strict enforcement of constant row height. Which you've discovered when you tried to increase font size. 

 

0 Kudos
Message 16 of 17
(1,609 Views)

@brentjustice wrote:

 

 And I've cut the user off from many tree/listbox features not exposed in my tight api.


Historically, this is the main reason I've just made my own custom code to do UI stuff.  Like "Neat a cool little XControl that does 90% of what I want."  Oh and that last 10% means I need to do a ton of work first understanding the existing code, and then making sure the changes I make won't break something else that I clearly don't fully understand?  I'll just do it myself from scratch.  It makes it harder to use, so I assume others will give up on my APIs if I do the same.

 

My sequences don't have 1000s of steps.  They probably have about 20 on average, and the most is probably 40.  If an operation takes a bunch of steps, I might make a new custom step that does those set of things and wraps it into a single tree item to help reduce user complexity.  If there are 1000 steps the likelihood that they made a mistake is very high, and will take a long time to review.  I can see having huge tables of data for reviewing logged results, which is why I like the idea of a virtual MCLB.

 

I do think a QControl is probably the best solution in the end for this, maybe given some time.  There you can interact with your control in ways that appears as if it is just a normal reference, and use the familiar API for editing the tree.  But in actuality it isn't VI Server calls doing the work, but class property nodes, that can call VI Server and it can do the house keeping too.

 

Oh and as for constant row height.  I think having a constant row height for all rows is a good thing, I just think the height used could be read at the start, and then have that be stored instead of the constant.  Because the number of rows in my use case are much smaller, I tend to increase the size of UI elements so they are easier to see.

0 Kudos
Message 17 of 17
(1,600 Views)