The Source for Java Technology Collaboration
User: Password:



Alexander Potochkin

Alexander Potochkin's Blog

Why I don't use Swing hacks (continuation)

Posted by alexfromsun on October 09, 2007 at 04:50 AM | Comments (7)

In one of my previous blogs I answered to Kirill's comment that some of techniques he described in his Swing painting pipeline overview are "not good enough for me",
here I want to explain my point by brifely commenting some of the techinques he covered.

Implementing validation overlays

First of all I want to mention my requirements to the validation overlays implementation:

  1. Solution shouldn't change global settings, it has to be as compatible with any other projects as possible
  2. It should work well inside JScrollPane
  3. Validation icons should respect Z-order of sibling components

RepaintManager

When 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

GlassPane

For 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:

  1. move/hide/show validation icon when its component is moved/hidden/shown
  2. crop the icon when its component is overlapped by another component

I don't even need to repeat that GlassPane is a global resource etc, because all mentioned issues together with the popups issue make GlassPane unusable for validation overlays implementation

JLayeredPane

It 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)

In addition in the AbstractComponentDecorator.java code I found a bunch of FIXME and TODO notes which reminds the situation with my JXTransformer
- 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:

Note: Typically you should wrap component trees with getWrappedComponentTree(ValidationResultModel, JComponent)}, not this constructor.

When I tried the magic getWrappedComponentTree method the validation icon appeared in the inner JScrollPane and were repainted very quickly during scrolling.
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?

Anyway, IconFeedbackPanel works well with JScrollPane, what about the second requirement?

Okay, you can already guess that this solution doesn't work well for overlapped sibling components either,
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

JXLayer

In 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

All of them are "component-level techniques" and there is no other valid tecniques in Swing, because only in that cases your components will work in predictable way for all common cases

JXLayer is a component's wrapper, which meets all my requirements:

  1. It doesn't change any global resources
  2. Its decorations are painted quickly and correctly inside JScrollPane

  3. It respects Z-order of sibling components
    (move the decorated component and note that decorations correctly overlaps with the top circular component)

Decorated components behave exactly like any other Swing components and there are no unexpected "special cases" where something might go wrong.
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

Conclusion

Sometimes 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
alexp


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment


  • Alex,
    I remember u once saying that jxlayer doesnt use a glass pane or layered pane , but i tried to have a look at the jxlayer sources and found a jxglasspane class etc..
    Please can u explain in one of ur future posts the design of the jxlayer(ie how it actually performs the layering diagramatically) so that we can get a better understanding of what is happening underneath. I understand jxlayer is very powerful but explaining the internals would increase its use among the many swing developers for sure

    Posted by: psychostud on October 11, 2007 at 11:28 PM

  • Hello Psychostud

    it's my pleasure to explain how it works
    As you correctly said there is a JXGlassPane class in my sources,
    but there it doesn't contradict my statement about frame's GlassPane

    JXLayer really doesn't change the GlassPane from the frame
    because it has its own one, you can find the JXLayer.set/getGlassPane() methods
    which have nothing to do with JFrame.set/getGlassPane()

    You can also refer to Kirill's and mine presentation for the last JavaOne where we are discussing several advanced painting techniques, including JXLayer
    Thanks
    alexp

    Posted by: alexfromsun on October 12, 2007 at 04:00 AM

  • follow up:

    for the infromation about the general idea
    please refer to the previous blogs:

    first,
    second
    and third

    Thanks
    alexp

    Posted by: alexfromsun on October 12, 2007 at 04:06 AM

  • Thanks Alex, will have a look at them and get back to u for any further clarifications.

    Posted by: psychostud on October 12, 2007 at 09:54 AM

  • So it's not so much "no hacks" as "no code that doesn't have the same requirements as mine" :) Which is a sensible philosophy. Make sure you know the requirements and limits of the code you're using, because a truck engine isn't necessarily appropriate to use in a back hoe.

    Does JXLayer work transparently with any layout? Will any layout work identically with and without the JXLayer wrapper?

    What about putting decorations outside the wrapped component bounds? Will they be clipped? Do you have to wrap an outer component instead to achieve this?

    Posted by: twalljava on October 13, 2007 at 07:56 AM

  • Hello Timothy

    > So it's not so much "no hacks" as "no code that doesn't have the same requirements as mine" :)

    I wouldn't put it this way,
    when I look at a custom component I always think:
    Does it work as relieble as Swing components do ?Can I invent any test cases where this component fails ?
    So actually if a component works as good as simple JButton or JLabel I don't ask for more than that
    "My requirements" are not something very special,
    because all core Swing components meet them

    By the way, I didn't say that JXLayer is the best component in the world and that it can do any effect you can imagine
    If the effect can't be implemented in Swing with recommended practices, JXLayer won't help either
    so It's not a silver bullet, the main idea that it follows the recomended patternsand it makes it more robust

    > Does JXLayer work transparently with any layout?
    JXLayer will work with any layout, because it is a component
    which contains all its decorations inside itself like all other components

    > Will any layout work identically with and without the JXLayer wrapper?
    I didn't find any example where JXLayer breaks existing layout
    please let me know if you find one

    > What about putting decorations outside the wrapped component bounds? Will they be clipped? Do you have to wrap an outer component instead to achieve this?
    As all core Swing components JXLayer doesn't allow painting outside its boundsit is possible to paint outside the bounds of the wrapped component with help of a custom border for its layer
    please see Validation overlays with JXLayer - The outer decorations paragraph

    Thanks
    alexp

    Posted by: alexfromsun on October 14, 2007 at 07:43 AM

  • Using the JXTransformer in the applets causes flickering. In order to avoid it, it should be nice to have double buffering implemented in JXTransformer itself.


    Another thing is resizing the fonts. This is the problem I am trying to solve. If you put several labels, texts in the JPanel and wrap it, after the scaling the fonts get very ugly. I want to implement a method that will wrap all the children components automatically.


    Archie

    Posted by: avaliani_360t on April 23, 2008 at 06:59 AM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds