Mouse enter / leave callbacks for a TableListBox row


#1

I would like to show / hide a few buttons of a custom component that is displayed inside a TableListBox when the mouse enters / leaves the row of the custom component but I can't find a way to do this.

Related, it seems there is no way to paint or animate a row background when the mouse enters/leaves a row. So there is no possibility to indicate over which row the mouse is currently hovering.

I have looked at the TableListBox implementation but see no way to add this. TableListBox::RowComp is private and can't be overwritten. It seems the only way to add a row hovering state is to change internal JUCE code, or am I missing something?

I really would love to have:

1. Row enter / leave callbacks for the TableListBoxModel
2. paintRowBackground should indicate if the mouse is hovering, maybe even if the mouse is down, very much like buttons.
3. Allow custom components as RowComp somehow. This way even animations on mouse enter/leave would be possible.

Jules, do you think this is something that makes sense to be added to TableListBox?


#2

You can already give it custom cell components - see refreshComponentForCell() - surely that'd do the trick?


#3

That will work if you want to react to hovering above a single cell, not above a row. Imagine the mouse enters on the last column. Now the whole row should be repainted with a different background color. Also the custom component in the first column of the row the mouse is over should make a few buttons visible that were hidden previously.

If this can somehow be done with the existing TableListBox it would be great!


#4

I can't start adding things like that to the model, or it leads to feature-creep.. e.g. after adding a mouseEnter callback then someone would want a mouse-wheel callback, and then something else, etc etc, and you'd end up with a whole bunch of stuff that can already be done in other ways.

If you have some special behaviour that works on the basis of a whole row, then you could certainly find ways to do that with a custom component, or even skip the TableListBox entirely and just use a ListBox directly.


#5

If it can be done in other ways without adding anything to the TableListBox or TableListBoxModel I would be very happy.

To get any mouse enter / leave notifications in a custom component it needs to call setInterceptsMouseClicks(true, true) The problem is all mouse handling in TableListBox is lost then. Row selection will no longer work.

A solution could be to add a mouse listener to RowComp but that is not possible because there is no way to access or subclass it. Its private to TableListBox.

I may suffer mental block but I see no way to achieve any row based behaviour.

PS: In my opinion support for row based behaviour (a row enter / leave notification and maybe a row repaint callback with the row hovering state indicated) in a table component isn't special behaviour but pretty much standard for modern ui. Tables in DropBox, MySpace, Windows 8 and even iTunes do this. But opinions differ and I respect your decision of course.


#6

Jules:

Please find attached a changed TableListBox that allows the TableListBox::RowComp and TableListBox::Header classes to be subclassed. I also added getters to some of the private properties subclasses may need.

The existing public interface has not changed at all.

With these changes it is very easy to add hover based actions, animations and drawing to TableListBox. AnimatedTableListBox.h shows how simple it would be.

Is it possible to add these changes to the JUCE TableListBox? Or is it still a bad idea even though it does not affect existing code at all?


#7

Bump.

Can these changes be applied to the JUCE TableListBox or is it a bad idea?


#8

Yeah.. I just don't like the idea of those classes being public. Exposing that much of the implementation detail creates too much potential for coupling of user code to the internal implementation.

If all you're trying to do is to catch a few mouse-enters, why not just attach a MouseListener? If you make it listen to all child events, you'll be told every time an event hits one of the row components, and you can just repaint the table.


#9

Hmmm. Where can I attach the MouseListener to catch mouse enter and exit of a row? The row component is not visible at all in the original implementation.

Also without making it possible to subclass the row component there is no way to make row based animations. For example I could create a subclass of the row component that will fade in and out a child component that adds a different background color to the whole row.

The public interface of the row component and header component could probably be reduced by using pimpl idiom.

But if you think its a bad idea to expose the row and header components I'll work with my own copy of the table classes.


#10

Like I said, you can attach the listener to the table itself, and get all the events in all the subcomponents. That's how I'd do it.


#11

Is there an elegant way of doing this?

I just wanted to highlight each row as the mouse is over it on the TableListBox.

My code seems clunky, but it works.

I have a component with a child TableListBox and TableListBoxModel derived class.
On the component I have a mouseMove method, then I check the event.eventComponent to determine how many times I’m calling getParentComponent on event.eventComponent, which gives me the ListBox::RowComponent, which I call getY() on, then divide by the row height. I then call a new method on my TableListBoxModel derived class to set the current hovered row number.
Finally in the paintCell or paintRowBackground methods I can compare the passed in rowNumber against the current hovered row.

This seems like a lot of pain when I’m sure it would solve most people’s use cases for the paintCell and paintRowBackground calls to be passed one more bool : rowIsHovered

Unless of course I missed some simpler method to achieving this fairly standard UI presentation?