Skip to main content

ScalableIcon Overview

This document is intended to give a detailed overview (if possible) of the ScalableIcon interface in the org.jdesktop.swingx.icon package. While the JavaDoc for that package and sub packages are mostly complete and in depth, this document is meant as a tutorial-esque runthrough of the features available in these classes and APIs.

To continue learning about the rest of the org.jdesktop.swingx.icon package and scalable icons see these other pages for information (they will be filled in over time):
  • Dynamic icons
  • Decorating icons
  • Composing icons
  • Lazy icons


Before reading this document it is probably a good idea to be fairly knowlegable about the javax.swing.Icon interface and also know about Java2D and images.


Icons in java are generally of a fixed size. In fact the documentation states that the Icon is
A small fixed size picture, typically used to decorate components.
The ScalableIcon interface and its accompanying APIs are designed to extend this definintion to essentially remove the 'fixed size' bit and as such increase the number of use-cases that the icon can be applied to.

Hopefully by the end of this document you will be in a position where you wonder how you ever got along without scalable icons (ok, well maybe not but they should come in useful sometimes) and should be able to write your own.

What is a Scalable Icon

There is really only one way to answer this question, it's an Icon that can be scaled. Or to elaberate a bit it's a number of painting commands (a picture or painter) that has no fixed size, unlike a non-scalable icon. Now that is not to say that it doesn't have a size that it prefers (default size) but it doesn't mind being shown in other sizes too.

Now, there are three ways to look at providing this functionality; and off the top of my head I can think of examples where each have been implemented, one of them in the core JRE. I'm going to talk about them all so that you have a general understanding of the decisions made in the API and why I felt they were the best choice for the job.

Scaling Icons - Graphics2D

The first method of scaling icons is possibly the simplest but also the hardest (for me at least) to get your head around, this is also the one that has examples in the JRE. The basic principle goes like this:
Graphics2D has a transform, so why not use that to scale the icon, I mean an icon is basically just a bunch of Graphics2D calls anyway.

There are a number of problems with this approach.
  1. Buffering - if you use images to buffer your painting (which is reccommended) then there is a chance that you will get artifacts if you scale up the icon
  2. Rounding - when rounded, up drawing primitives don't tend to behave as you first think unless you're using RenderingHints.VALUE_STROKE_PURE
  3. Transforms - if any other transforms are applied to the graphics then you can get into some serious problems when doing advanced scalable graphics that need to know about the scale factor
You can see an example of this in the JRE if you look at the$ScalableIconUIResource class which gets around the Buffering problem above by painting scaled icons that cancel out when the graphics transform is applied.

Scaling Icons - Setters

This approach is probably the most common (and was the first approach adopted when I first wrote the ScalableIcon interface) and involves providing essentially extra setter methods on top of Icons getIconWidth and getIconHeight getters. These setters allow you to change the dimensions of the icon which can then paint itself at the required dimensions when called to do so.

One of the big advanteges of this approach is that it is very simple to implement and adds minimal conceptual overhead to what you already know in the Icon class. In fact this approach is extreemly competent for the simple common case we use almost every day, where an Icon is used in only one place. Unfortunately this approach does not scale particularly well, imagine the series of steps needed to paint the same icon in two different places and at two different sizes.
  1. get icon
  2. set the size of the icon to size1
  3. paint the icon
  4. set the size of the icon to size2
  5. paint the icon
Now while that looks fairly simple, bear in mind that by setting the size of the icon you are changing it everywhere so really you should be resetting the size back when your done with it:
  1. get icon
  2. save icon size
  3. set the size of the icon to size1
  4. paint the icon
  5. reset the image size
  6. save the size of the icon
  7. set the size of the icon to size2
  8. paint the icon
  9. reset the size of the icon
Still not that bad? Now try to add notification of changes in the size of the icon, you'll have to add steps like disable/enable notification support. Or try adding decoration to the icon, want a border around your icon, it gets really complicated. The more steps there are the more likely you are that you'll forget something and then all sort of errors can pop in.

Scaling Icons - Painting

The final approach is similar to the Setters approach above but does not require that the icons size be changed. In fact the Icons size should never be changed, the size becomes decoupled from the painting logic of the icon and instead becomes more of a guideline or a preferred size. The painting logic of the Icon instead receives the bounding rectangle that the icon should be painted into, including the width and height, and it's up to the icon to honour these parameters.

While the size of the icon has become seperate from the painting logic there still needs to be a connection, the icon still needs a way to say "I need to be this aspect ratio" or "I cant go smaller than this" or "I only scale horizontally." These use-cases are provided by a secondary API that allows the icon to define what its preferred size would be if it were given a certain domain area. The conversation looks something like this:
Hey Icon, I have this area (100x100), whats the maximum area you could take up in there?
Aspect ratio icon:
Err, well, I have an aspect ratio of 4:3 so that would be 100x75.
How about you?
Banner icon:
Well, I have a fixed height of 32 but can strech horizontally so that would be 100x32 then.
Anyway, you get the point.

This is the approach used in this ScalableIcon framework.

ScalableIcon interface

The ScalableIcon interface provides the API required to implement the Painting scale method listed above; it provides two extra methods on top of the default Icon interface, one for painting and one for size constraints:

   public interface ScalableIcon extends Icon {
      public void paintIcon(Component c, Graphics g, int x, int y, int width, int height);
      public Dimension fitInto(Component c, int width, int height);
The first one provides the painting support and the second one the scaling hints, that's it.

An example use would be to create a component that simply painted an icon over it's contents:

    * This component paints the icon in the top left corener if size constraints apply
   public class IconComponent extends JComponent {
      private ScalableIcon icon;
      public IconComponent(ScalableIcon icon) {
         this.icon = icon;

      protected void paintComponent(Graphics g) {
         Dimension paintAtSize = icon.fitInto(this, getWidth(), getHeight());
         icon.paintIcon(this, g, 0, 0, paintAtSize.width, paintAtSize.height);
As you can see it should be a relatively easy task to center the icon in the area or position it in the bottom right or anywhere as required. It should also be easy to spot that you can restrict the size for the icon to any size you choose by changing the width and height passed to the fitInto method while still respecting the icons wishes for size constraints. The use of ScalableIcons is generally the same for every use, there is no save-state-set-state-paint-reset-state process, only what you see above.

Implementing the interface

Well as using the interface is so simple lets get on to how to implement your own scalable icons. There are three things that you need to think about when implementing this interface
  1. What will your icon look like - the picture or paintIcon method
  2. What is the default size of the icon - this is the getIconWidth and getIconHeight methods
  3. How will it scale - are there restrictions on how you want to be scaled; the fitInto method
When you decide that you need a new Scalable Icon the thing you generally think of the first is the picture that the icon will represent, this is the reason for having the icon in the first place after all. This will be made up of mostly your own painting logic and is mostly left up to you.

The second thing to think about is the preferred size of the icon, now a lot of the time you won't have a preferred size as you've written the icon to be truly scalable, however the API requires it so generally I find supplying a constructor that takes the preferred width and height as arguments is a reasonable approach to defining these.

The third thing to think about is the scale constraints that the icon may have. Does it grow to fill all available space, does it keep it's aspect ratio, does it have a maximum or minimum size? These are all questions that can be answered by implementing the fitInto method. Lukily for us there are also helper classes to aid with these implementations.

Introducing ScalePolicy

todo: maybe move this into it's own document

As most icons follow a finite set of scaling rules the ScalePolicy class has been designed to provide these rules for you. If you think of a scale constraint as a combination of dimension constraints and size constraints then you can define the vast majority of usecases very easily. The ScalePolicy class does this for you in the form of the enums DimensionPolicy and ResizePolicy.


This enum defines the constraints that can be applied to dimensions, the width and height, of an area. It defines:
Scale the width only, the height will remain unchanged
Scale the height only, the width will remain unchanged
Scale both the width and height independently
Scale both the width and height but keep the same aspect ratio


This enum defines how to scale within the area and can be used as an aid to define minimum and maximum sizes. It defines:
The area can only get bigger, not smaller
The area can only get smaller, not bigger
The area can get bigger or smaller
Do not scale in any direction

The ScalePolicy class also provides some simple caching mechanism for the different combinations of scale constraints via the ScalePolicy.valueOf(DimensionPolicy, ResizePolicy) method. For example we can define the following scale constraints:
Fill all available space
ScalePolicy.valueOf(DimensionPolicy.BOTH, ResizePolicy.BEST_FIT)
ScalePolicy.BOTH - a static variable for this common case
Fill all available space but keep the aspect ratio
ScalePolicy.valueOf(DimensionPolicy.FIXED_RATIO, ResizePolicy.BEST_FIT)
ScalePolicy.FIXED_RATIO - static variable for the common case
Scale horizontally but not vertically with a minimum size, like a header/banner
ScalePolicy.valueOf(DimensionPolicy.HORIZONTAL, ResizePolicy.GROW)
Note that every call to valueOf with the same parameters will result in the same instance of the ScalePolicy class.


The api for using the ScalePolicy class is very similar to the ScalableIcon.fitInto API. There are slight differences though as the ScalePolicy is essentially stateless and has no size. The primary API is Dimension fitInto(Dimension source, Dimension target, Dimension result) where the source is the area we are attempting to scale, the target is the area we are trying to scale into and result is an optional Dimension where the results can be placed for performance reasons. The result will be the source area scaled into the target area restricted by the DimensionPolicy and ResizePolicy passed on the construction of the ScalePolicy.

If we take the examples from the ScalableIcon.fitInto above we have the following:
Fixed aspect ratio of 4:3 - gives a Dimension with size 100x75
ScalePolicy.valueOf(DimensionPolicy.FIXED_RATIO, ResizePolicy.BEST_FIT).fitInto(new Dimension(4, 3), new Dimension(100, 100), null)
ScalePolicy.FIXED_RATIO.fitInto(new Dimension(4, 3), new Dimension(100, 100), null) // using static var
Fixed height of 32, scalable width - gives a dimension of 100x32
ScalePolicy.valueOf(DimensionPolicy.HORIZONTAL, ResizePolicy.BEST_FIT).fitInto(new Dimension(0, 32), new Dimension(100, 100), null)
As you can imagine the ScalePolicy class can come in very useful when trying to define how your icon will scale and takes away much of the repeated code that is common when scaling icons and images.


The AbstractScalableIcon is designed to take the common use cases for Icons and require that the user write the least code to get done what they want to get done. If you extend the AbstractScalableIcon class instead of implementing the ScalableIcon interface directly you will be reuired to implement exatly 3 methods, exatcly the same number as if you were writing a standard Icon. You are required to implement you painting logic via paintIconImpl and provide the preferred size for the icon via getIconHeight and getIconWidth, that's it.

There are other benifits to using the AbstractScalableIcon class too, you get PropertyChangeListener support, Graphics configuration for properties like anti-aliasing and interpolation and all you have to do to change the scaling constraints is provide a new ScalePolicy instance for AbstractScalableIcon to work with.

Implementing the first icon - ScalableImageIcon

Ok, so enough background and API descriptions, you should be able to get most of that from the JavaDoc anyway; lets build our first ScalableIcon.

The icon we are going to build is a simple ImageIcon replacement called ScalableImageIcon, it's not going to be as hi-tech as ImageIcon in that it will require the image be loaded beforehand but it will show off the basics of how to create scalable icons.

Getting Started

To create our Icon we will extend the AbstractScalableIcon interface and implement the basic APIs required of us.

 * Simple scalable image icon class.
public class ScalableImageIcon extends AbstractScalableIcon {
    private BufferedImage image;

    public ScalableImageIcon(BufferedImage image) {
        super(ScalePolicy.FIXED_RATIO); // optional as AbstractScalableIcon defaults to FIXED_RATIO anyway
        this.image = image;

    protected void paintIconImpl(Component c, Graphics2D g2, int x, int y, int width, int height) {
        g2.drawImage(image, x, y, width, height, null);

    public int getIconWidth() {
        return image.getWidth();

    public int getIconHeight() {
        return image.getHeight();
To be honest that's it, there's no more to it. Sure you could add getters, setters, property change support to the image and null checking but that's it, you now have a scalable icon that respects the images aspect ratio; it can't get much simpler than that.


Hopefully by this point you will have a (mostly) clear understanding of what the ScalableIcon APIs are about and why certain decisions have been made. You should be able to create your own implementations of simple scalable icons and should be able to use these icons in your own components.

In other articles the knowledge is built upon to make it easier to do other common but more complicated icon tasks like animation, decoration, composition and lazy loading (todo: fill with links as the articles become available).

Please Confirm