Dragging tree items that use createItemComponent()


#1

I have implemented createItemComponent() to create Labels for my TreeViewItem derived items so that I can edit them in place which works great.

Can someone point me to an example of implementing drag/drop with this type of tree item? I need to drag within the tree, and also from the tree to another component ( a component whose owner is a TabbedComponent ) .


#2

anyone?


#3

Just implement:

getDragSourceDescription()
isInterestedInDragSource()
itemDropped()

in your TreeViewItem.


#4

Thanks valley! It turns out that the Label was intercepting the mouseDown, up and drag. It’s working now that I am passing those on.


#5

I am having a problem passing things on. My class extends Label and overrides mouseDown, mouseUp and mouseDrag like this.


void EditableTreeTextCustomComponent::mouseDown(const MouseEvent& event)
{
    owner.treeView.mouseDown(event);
    owner.itemClicked(event);
    Label::mouseDown(event);
}
void EditableTreeTextCustomComponent::mouseUp(const MouseEvent& event)
{
    owner.treeView.mouseUp(event);
}
void EditableTreeTextCustomComponent::mouseDrag(const MouseEvent& event)
{
    owner.treeView.mouseDrag(event);
}

This isn't working. I noticed that getDragSourceDescription is never called in the class that originally extended TreeViewItem but now extends the new EditableTreeInterface.

Any ideas or do I need to show more code. I know it a little complicated.


#6

Do you need to translate the co-ordinates there? 

For example when passing an event to a parent component:

void mouseDrag(const MouseEvent & e) override { auto parent = getParentComponent(); parent->mouseDrag(e.getEventRelativeTo(parent)); }
 


#7

Just a general tip:

It's a really bad idea to ever call mouseDrag, mouseUp etc directly on a component.

Behind the scenes there a hugely complex mouse-event direction system that tries to make sure these are always delivered in a consistent order to each component. By invoking the functions directly you'll probably mess that up and things can go subtly wrong.

I've often seen people attempting to pass events up the hierarchy like you're doing above, but I've never had to do anything like that in code I've written (and I've written a lot of strange component layouts!) so you might want to re-think what you're trying to do.


#8

So does this code suck a bit? :) It implements, in a TreeView, the behaviour:

- Click to select.
- Click again to edit after a tiny delay 
- Unless you start dragging first

I don't think it's trivially possible another way? I could add the features to a custom TreeView/TreeViewItem if my current approach is likely to break stuff. 



class LabelComponent
    :
    public Component,
    public Label::Listener,
    public Timer
{
    //...
        void mouseDown(const MouseEvent & e) override
        {
            if (e.mods.isPopupMenu())
            {
                doPopupMenu();
                return; /* as may have resulted in object being deleted. */ 
            }
            else if (! owner->isSelected())
            {
                auto parent = getParentComponent();
                auto newEvent = e.getEventRelativeTo(parent);
                parent->mouseDown(newEvent);
            }
            else
            {
                startTimer(500); 
            }
        }
        void timerCallback() override
        {
            stopTimer();
            label.showEditor();
        }
    void mouseUp(const MouseEvent & e) override
        {
            if (! owner->isSelected())
            {
                auto parent = getParentComponent();
                auto newEvent = e.getEventRelativeTo(parent);
                parent->mouseUp(newEvent);
            }
        }
        
        void mouseDrag(const MouseEvent & e) override
        {
            stopTimer();
            auto parent = getParentComponent();
            auto newEvent = e.getEventRelativeTo(parent);
            parent->mouseDrag(newEvent);
        }
};
class UserTreeItem
:
public TreeViewItem
{
    //...
    Component * createItemComponent() override
    {
        return new LabelComponent(this);
    }
};




 

 


#9

It may work in this case, but classes like the TreeView will expect their mouseMove/Down/Drag/Up/Enter/Exit methods to always be called in the correct order.

So unless you're 100% sure that you'll never send a mouseDrag without having sent a mouseDown first, or a mouseMove without a mouseEnter, etc, then you're risking confusing it. Probably nothing fatal would ever happen, but there could be edge-cases where things get stuck or misbehave.


#10

All I am trying to do is create a tree that allows drag and drop within itself AND allows for editing the text. I had the drag and drop part working fine. To add the editing I changed my TreeItem class to extend EditableTreeInterface instead of TreeViewInterface (similar to how it is done on the table code in the Juce Demo). EditableTreeInterface keeps a copy of the TreeView. In TreeItem  I override createItemComponent to return an EditableTreeTextCustomComponent. EditableTreeTextCustomComponent extend Label and overrides mouseDown (like the Juce Demo). So now the label editing works fine but the drag and drop no longer works. I assumed the Label was eating the drag events which is why I thought I needed to pass them back to the TreeView.

As I said this is not working. Based on this how should I be doing it?

Thanks

 


#11

Bob - that's almost exactly what I'm doing, only with a delay before the text editing jumps in.  Have a look at the code I posted.


#12

Thanks. Based on Jules response I was hoping there was a more direct way than using a timer. I am hoping he will straighten this out. If not I will take a closer look.


#13

So Jules, is there are better way to accomplish this or should I give bazrush's code a try?


#14

If it works, go with it! There could be a better way, but I've no time to think about it right now.


#15

The only better solution I could think of was to roll a new version of TreeView which exposed additioanl virtual function calls for this stuff...