Why I don't use Swing hacks (continuation)
here I want to explain my point by brifely commenting some of the techinques he covered.
Implementing validation overlaysFirst of all I want to mention my requirements to the validation overlays implementation:
- Solution shouldn't change global settings, it has to be as compatible with any other projects as possible
- It should work well inside JScrollPane
- Validation icons should respect Z-order of sibling components
RepaintManagerWhen a component requires a custom RepaintManager to be installed
it sounds for me as strange as if I require to customize your operating system for my application.
RepaintManager is a global resouce and changing it to support a particular component is not just awkward but it may cause problems if another component wants to install its own RepaintManager at the same time.
Since Swing repaints components asynchronously it is impossible to fix this potential conflict by saving and restoring the old RM after repaint() is called. Note: SwingX
uses custom RM for their needs but it's a special case.
SwingX is a project which contains extentions for the Swing GUI toolkit which may become a part of the JDK.
If we decide to include e.g. translucency to Swing, the default RM will be the best choice to add support for this feature and no doubt, in this case their experience will be very useful.
Since a custom RepaintManager works well if you are sure that no one else will change it,
I take RepaintManagerX as the only recommended alternative implementation
GlassPaneFor me it is quite obvious that GlassPane is not the best solution for validation overlays.
I know that with GlassPane it is impossible to write a robust code which will quickly and correctly:
- move/hide/show validation icon when its component is moved/hidden/shown
- crop the icon when its component is overlapped by another component
JLayeredPaneIt is the most interesting hack and it deserves special attention because of two remarkable projects.
Long time ago I came across the Decorating/Overpainting Swing Components blog with an impressive demo by Timothy Wall.
He transparently adds all kinds of custom components to the frame's default JLayeredPane to decorate existing components. The demo is really cool, but...
It fails to meet my second requirement about quick painting inside JScrollPane
(I can see the labels' flickering when I scroll the JScrollPane in the demo, sorry about that)
It also fail to meet the third requrement because
if two sibling non-opaque components are overlapped it is impossible to detect which component's pixels are transparent to correctly mix their decorations
(I'll give an example later on)
- you can make it work for a demo, but it will never be completely ready for production use The IconFeedbackPanel by Karsten Lentzsch is another tricky solution. I wrote a simple test with a JTextField inside IconFeedbackPanel with a validation icon,
then I wrapped the JTextField with JScrollPane and the icon unexpectedly was gone.
My first though was that IconFeedbackPanel doesn't support inner scrollPanes at all but then I read this note from its constructor javaDoc:
When I tried the magic getWrappedComponentTree method the validation icon appeared in the inner JScrollPane and were repainted very quickly during scrolling.
Note: Typically you should wrap component trees with getWrappedComponentTree(ValidationResultModel, JComponent)}, not this constructor.
After a few minitues I found the reason - this method traverses the component's hierarchy and wraps JScrollPane's views with additional IconFeedbackPanels!
This is an important detail, I'll return to it later The Karsten's code is clear and well-written as usual, only a few things about IconFeedbackPanel caught my attention
- It removes all validation icons, adds them again and repaints the whole panel during every layout change, which is pretty expensive
- Quote from javadoc:
you must ensure that the wrapped content
provides enough space to display the overlaid components.
Since the current implementation positions the overlay components
in the lower left, just make sure that there are about 6 pixel to the left
and bottom of the input components that can be marked.
But what if I don't want to think about 6 pixel to the left and bottom and like to have a solution which will make it right?
to make it work you have to wrap every JTextField with a kind of an IconFeedbackPanel Nevertheless, among all mentioned techniques, IconFeedbackPanel is probably the best one
JXLayerIn his comments Kirill mentioned an interesting term - "component-level techniques", comparing JXLayer with GlassPanes and LayeredPanes.
Actually if you need to decorate an existing component you have only three recommended choices:
- Subclass a component
- Make a custom UI delegate
- Wrap it with a special decorator
- It doesn't change any global resources
- Its decorations are painted quickly and correctly inside JScrollPane
- It respects Z-order of sibling components
(move the decorated component and note that decorations correctly overlaps with the top circular component)
That what I meant when I said that solutions like GlassPanes or LayeredPanes are not good enough for me.
I want to be sure that my components will work well with all existing layouts, like StackLayout Try to make a component which is decorated with JLayeredPane, correctly overlap a non-opaque sibling component In the previous blog I showed two examples of validation decorations:
when it is completely within the bounds of wrapped component, and JXLayer has the same size as its inner component;
the second variant is when decorations are partially outside (the little red icon on the corner). I personally like the first one, because it doesn't affect component's layout and doesn't require a bunch of listeners to be added to the TextField's document.
If I needed to support that fancy outer icon for some TextFields I would use Karsten's trick - he automatically wraps JScrollPane's views only when I'd wrap all TextFields to set them identical insets
ConclusionSometimes the "no-hacks rule" is not easy to follow and may require some extra work,
but use it or not is always up to you Thanks