ListBox and ListBox's 10 million unnamed children


#1

I’ve got several ListBoxes in an app. I have it setup that double-clicking an item in a ListBox will add it to another ListBox. The way I did this was simply using the mouseDoubleClick event in the main component. It checks if myListBox->isParentOf( MouseEvent.eventComponent ). It has to do this because the eventComponent isn’t pointing to myListBox – it’s pointing to the item which is the child of the child of the child of the child of the actual ListBox object. None of these items actually have names, so I can’t even use getName() to see what was clicked on. If I wanted to give the items names, that would be a big hassle because they are dynamically created and destroyed by JUCE.

Anyway, that was working fine, except if an item is selected, double-clicking on the ListBox’s scrollbar would also add the item. My code was simply looking for a double-click in any of the children of the ListBox then adding the selected items. I don’t want to have to deselect everything in the ListBox when the scrollbar is clicked on, so I thought, “OK, I have to make sure you’re actually clicking on the item in the double-click event.”

This is pretty complicated since the ListBox item objects have no names, and using typeid( MouseEvent.eventComponent ) just returns a generic Component.

What I ended up doing was making a constant LISTBOX_ITEM_HEIGHT, then I just added this to the beginning of the mouseDoubleClick event:

if( e.eventComponent->getHeight() != LISTBOX_ITEM_HEIGHT ) return;

So that way it only processes the double-click event if you’re actually clicking on a ListBox item. This seems like a pretty bogus solution to me, though, and I can see in the future something changing in my application that caused LISTBOX_ITEM_HEIGHT to be the same value as the height of the up/down scroll buttons on the scrollbar.

I really think I must be missing something obvious that exists in JUCE to make this much simpler otherwise ListBoxes just seem kinda ridiculous. I’m sure there’s a better way to determine what I’m clicking on.


#2

… ListBoxModel::listBoxItemDoubleClicked() perhaps?


#3

That could probably be helpful in some way, but it doesn’t really fit in with having mouseDoubleClick in the main component handle things. All the buttons in the app are handled in the main component, and all the double-clicks are handled in the main component, so overloading listBoxItemDoubleClicked to handle double-clicks from within the objects isn’t going to work. If listBoxItemDoubleClicked just returned a bool of whether or not an item was double-clicked that’d be useful, but as it is I’d have to overload listBoxItemDoubleClicked to set a flag in the object, then have the change listener in the main component look for that flag.

I could probably come up with a way to rewrite everything that made that fairly simple, but as it is I don’t think that’s going to work as a substitute for being able to figure out if MouseEvent.eventComponent is a ListBox item or not.


#4

You sound pretty confused about what you’re doing there, and are definitely approaching the whole thing backwards.

If you have a bunch of listboxes, just make each one catch the double-click event in its listboxmodel, and do something appropriate. Trying to have one place where all your events end up and then trying to put all your app logic in there is the opposite of good object-oriented programming.


#5

That’s certainly true to some extent, but you yourself made the Jucer, and it sticks a billion things right there in buttonClicked. So I’ve got all my button handling stuff right there in the main component, although it really just consists of simple calls to objects, and likewise I have a changeListenerCallback, mouseDown, mouseDoubleClick, and mouseWheelMove right there in the main component. It looked to me like that’s the way you designed it.


#6

well you could expand it all yourself to do exactly that if you wanted… (i.e. make a “listboxitemlistener” and make all your listboxmodels call some ‘master’ listboxitemdoubleclicked function. if that’s really the way you have to do it.


#7

Haydxn speaketh the truth. In a case where you have many lists, all using the same model class but doing different things, that might actually be a good way to implement it. But going down to the mouse-event level and catching raw double-clicks is bad practice - the listbox needs to be allowed to tell you when it has been double-clicked, you mustn’t try to duplicate that logic elsewhere.


#8

Well I did sort of a lame middle-ground fix … I just made my listbox class’s listBoxItemDoubleClicked set a flag, then I made a function that checks if the listbox was double-clicked, and the main component mouseDoubleClick looks at those. It’s a little weird, but it seems to fit pretty well with all the “if (buttonThatWasClicked == buttonExit)”-type stuff in the main component.


#9

Sounds like the worst of both worlds, made even worse because you’re adding flags that will inevitably end up in the wrong state.


#10

I don’t see how that would happen … the listBoxItemDoubleClicked function sets the flag to true, and then my function to check the flag always sets it to false.


#11

It’s just a really really bad solution. Don’t think I could have thought of a hackier one if I tried.

What if I changed something so that the mouse events started arriving before the list event? Of if the list started consuming the mouse event rather than letting your handler get it? Or if lists changed so that they used a different mechanism to detect the clicks? Or if the user wants to press “return” rather than click the mouse? Or if the user triple-clicks and two double-click events happen for one list event? Or if they click somewhere in a list that’s not on a row? Etc etc…

Your listboxes should know enough about their own contexts, so that when an itemDoubleClicked() method gets called, it can do the appropriate thing. Simple as that!