Drag and drop a TreeViewItem with auto-scroll problem


#1

Hi,

I want to drag and drop TreeViewItems that have custom components. Since my tree may be very large, I want an auto-scroll feature. I implemented this with a Timer that repeatedly calls setViewPosition on the Viewport of the TreeView.

The problem is the following one: scrolling in the tree may delete the component being dragged (as soon as it’s source position becomes invisible). DragImageComponent then detects the Components’ deletion and drag and drop is aborted (without any callback being called).

In order to fix this problem, I tried to clone the TreeViewItem’s component before passing it to startDragging(). This still leads to strange results and it is not trivial how to delete this cloned component once dragging is finished.

Any idea for a better solution ? Should this not be handled by TreeView internally ?

Thanks for your help,

Francis.


#2

That is kind of tricky… Can’t think of any quick fixes, I suppose there’d need to be some smarter logic in the treeview itself so that when it’s deciding which comps to re-use, it’d give priority to the one that the mouse is currently down on.


#3

+1 on this! Tnx to francis for pointing out its a component deletion problem, I was wondering why the scrolling was just stopping all of a sudden :slight_smile:


#4

In fact it already has something to do this - have a look at juce_TreeView.cpp line 221.

If it’s not working for you, perhaps that’s because it’s a sub-component of your treeview item that’s getting the drag? The logic probably needs beefing up a bit to handle those cases too…

Maybe this (I’ve not tried this yet):

if ((itemsToKeep[i] || (Component::isMouseButtonDownAnywhere() && (comp == Component::getComponentUnderMouse() || comp->isParentOf (Component::getComponentUnderMouse())))) && isParentOf (comp)) {

?


#5

…actually, just re-examining that block of code, the logic looks completely broken. I think what I meant was this:

[code] for (int i = rowComponentItems.size(); --i >= 0;)
{
Component* const comp = (Component*) (rowComponents.getUnchecked(i));

        bool keep = false;

        if (isParentOf (comp))
        {
            if (itemsToKeep[i])
            {
                const TreeViewItem* const item = (TreeViewItem*) rowComponentItems.getUnchecked(i);

                Rectangle pos (item->getItemPosition (false));
                pos.setSize (pos.getWidth(), item->itemHeight);

                if (pos.getBottom() >= visibleTop && pos.getY() < visibleBottom)
                {
                    keep = true;
                    comp->setBounds (pos);
                }
            }
            
            if ((! keep) 
                 && Component::isMouseButtonDownAnywhere()
                 && (comp == Component::getComponentUnderMouse()
                      || comp->isParentOf (Component::getComponentUnderMouse())))
            {
                keep = true;
                comp->setSize (0, 0);
            }
        }

        if (! keep)
        {
            delete comp;
            rowComponents.remove (i);
            rowComponentIds.remove (i);
            rowComponentItems.remove (i);
        }
    }[/code]

#6

Indeed, it is a sub-component of the TreeViewItem that gets the drag.

The fix works perfectly for me !

Thank you :smiley:


#7

Works for me too :smiley: Thanks Jules