I’ve been getting quite a bit of time lately to my own hobbies. I finally got around to implementing some user-friendliness with PersonalFinancier, involving a status-bar at the bottom of the application for supplying a little user guidance.
Unfortunately, part of what I wanted to do was have a custom message per tab appear as I hovered the mouse over a tab. Like in the screenshot below.
Note the inflation tab, and the status bar at the bottom of the application with a custom message showing for the tab.
You’re seeing this post because it took me a while to crack. I spent quite a bit of time out at stackexchange and pouring over Java Swing documentation and examples. I’ve learned the following things in my failure to find a working solution:
- Tabs within JTabbedPane are not their own distinct objects. You can’t interact directly with a particular tab object, and add your own mouse handler.
- You can supply another Swing component instead of plain text for rendering the tab title (useful if I ever want to add a close button per tab).
- You can add a mouse handler to that “title component”.
- The “title component” does not take up the entire tab title screen real-estate.
- Mouse events won’t fire until you shift out of the tab “title” area, and into the “title component” area, making the response of the tab in terms of the behaviour you want less than ideal.
- If your look & feel does something funky like highlight a tab, expect broken behaviour as mouse events suddenly stop hilighting the tab, and instead, does whatever you’ve told to happen for the “title component” via those mouse events.
Finally, I’ve found an approach that works. In essence, I tie a MouseMovementListener to the parent JTabbedPane. The event handler loops through the installed tabs, comparing the screen real-estate they occupy against the mouse location. If the event handler finds the mouse is “over” the tab, it reacts with my desired behaviour.
Ultimately, this works because the only piece of the tab identified as being under the mouse position is the tab title itself because the tab “body” is either a) mostly under another tab, stopping mouse events firing, or b) under the component we install for the tab to render, again stopping mouse events from firing (so long as the child component has be told to occupy all of the tab body’s space).
Here’s the gist of it below, using a Runnable for the custom behaviour for a tab. For my particular problem, I ended up adding client properties to each tab child component, and using them in the mouse event handler to populate my application status bar.