-
Notifications
You must be signed in to change notification settings - Fork 235
How to use IconManager
Available since WebLaF v1.2.11 release, updated for WebLaF v1.2.12 release
Requires weblaf-ui module and Java 6 update 30 or any later to run
Managing icon resources is always a problem that requires some sort of solution. It might not be a problem initially or for very small projects, but once you get to the point of having hundreds of icons scattered across your codebase and/or resources - it becomes impossible to maintain.
WebLaF offers it's own solution for that problem - IconManager
that can be used to manage skin/extension-related or global icon sets. Each icon set can contain a list of icons with their own unique identifiers through which those icons can be easily referenced and retrieved in the code. Where you store actual icon resources, how you group them by icon sets and how you name them is completely up to you.
There is one more thing that IconManager
supports - overriding previously added icons. This is an important feature because it allows you to replace even icons that are used internally by WebLaF itself in various components like JFileChooser
.
There are a few important classes you will be working with:
-
IconSource
- interface that represents source for actualIcon
.
Currently there are two implementations available:ImageIconSource
andSvgIconSource
. -
IconSet
- interface that represent different available icon set implementations.
Currently there are two implementations available:XmlIconSet
andRuntimeIconSet
. -
IconManager
can be used to add/removeIconSet
s in runtime and retrieve actualIcon
s.
The whole thing is pretty simple - IconSource
s are grouped in IconSet
s which in turn are added to IconManager
which provides global access to any icons from those sets. Actual icons are only loaded on demand so you can add as many icons as you want and it won't affect performance in any noticeable way until you actually request or use them.
Now that you know the basics - let's move to more practical examples.
For creating IconSet
in runtime you can use RuntimeIconSet
implementation:
final IconSet iconSet = new RuntimeIconSet ( "my-custom-set" );
The only thing you need to provide in it is a custom identifier that can be used to find that set in IconManager
later on. Each IconSet
added to IconManager
must have unique identifier, otherwise you will receive an exception.
Next step - you can add IconSource
s to that IconSet
:
iconSet.addIcon ( new SvgIconSource (
"github-logo",
new UrlResource ( "https://github.com/mgarin/weblaf/raw/master/resources/github.svg" )
) );
iconSet.addIcon ( new SvgIconSource (
"firefox-logo",
new UrlResource ( "https://github.com/mgarin/weblaf/raw/master/resources/firefox.svg" )
) );
iconSet.addIcon ( new ImageIconSource (
"weblaf-logo",
new UrlResource ( "https://github.com/mgarin/weblaf/raw/master/resources/weblaf.png" )
) );
Note: I've used existing URL addresses:
https://github.com/mgarin/weblaf/raw/master/resources/github.svg
https://github.com/mgarin/weblaf/raw/master/resources/firefox.svg
https://github.com/mgarin/weblaf/raw/master/resources/weblaf.png
So you can actually use those icons for testing.
There two reasons why IconSet
contains IconSource
and not final Icon
s:
-
Performance - having an actual
Icon
in memory often means it has to be loaded - Convenience - in case you want to modify some icon you can load it as many times as needed through the source
Now that you have actual icons in your icon set - we can add it into the IconManager
:
IconManager.addIconSet ( iconSet );
That's it, now your icons are populated and available through LazyIcon
implementation anywhere in the code.
Note: You can still add new icons to your icon set after you've added it to IconManager
and they will become available as well, it's just a good practice to add icons first as this will cause less potential updates.
Now, there are a few ways how you can access your icons from code:
- Directly through
IconManager
:
final Icon icon = IconManager.getIcon ( "github-logo" );
- Through
LazyIcon
:
final Icon icon = new LazyIcon ( "firefox-logo" );
- In XML styles you can use it through
SetIcon
content:
(for more information on styling overall you might want to read this article first)
<SetIcon icon="weblaf-logo" />
You can also access original Icon
type:
final SvgIcon icon = IconManager.getIcon ( "github-logo" );
final SvgIcon icon = new LazyIcon ( "firefox-logo" ).getIcon ();
final ImageIcon icon = new LazyIcon ( "weblaf-logo" ).getIcon ();
Although generally it shouldn't be necessary in most cases when you are working with Swing and you can simply use LazyIcon
- it will be both easier to use and faster on performance side because it only loads actual Icon
when necessary.
Now let's say you want to have an IconSet
that is attached to existing Skin
or even your own custom Skin
. The reason for having one is pretty simple - it will be automatically added and removed as the application Skin
is changed. This allows you to swap between different icons for different skins quite easily - this is pretty much what WebLaF already does for it's own skins internally.
Let's look at each of two cases separately.
Attaching IconSet
to existing skin
In case you have a small application that doesn't have it's own skin (or maybe even custom styles), but you want to provide separate icon sets for existing WebLightSkin
and WebDarkSkin
- you will need to create two extensions that each include one of your custom IconSet
s.
To avoid a hassle of creating XmlSkinExtension
override class and empty XML for it with only icon set include(s) I've added new SkinExtension
implementation specifically for this case - IconSetExtension
. We will be using it:
final SkinExtension lightExtension = new IconSetExtension ( "my-custom-icon-set", "weblaf.light.skin", lightIconSet );
final SkinExtension darkExtension = new IconSetExtension ( "my-custom-icon-set", "weblaf.dark.skin", darkIconSet );
A few important thing to note here:
- I'm using the same identifier for both
IconSetExtension
s because they will never be used together since they support different skins that will never be crossed - I'm using only one skin supported for each
IconSetExtension
, but you can specify multiple ones - I'm using only one
IconSet
for eachIconSetExtension
, but you can specify multiple ones
Once we have these two extensions - all we need is to register them in StyleManager
:
StyleManager.addExtensions ( lightExtension, darkExtension );
They will be automatically used by the skins that are supported, either right away or when new supported skin is installed as current one in StyleManager
.
One important thing to mention here - you can still modify icons in your IconSet
s at any point and even if they are currently used - those changes will instantly become available.
Attaching IconSet
to custom Skin
or SkinExtension
If you aren't sure about how custom Skin
s and SkinExtension
s can be created - I strongly recommend reading Styling introduction wiki article first and then come back to this part.
So once you have your own Skin
and XML that comes with it - this is a rather simple task. You can specify any custom IconSet
class as include in your Skin
's XML, like the default one is specified in WebLightSkin
:
<iconSet>com.alee.iconset.LightIconSet</iconSet>
All you need for your custom MyIconSet
class to work as include - it needs to be of IconSet
type and it needs to have an empty constructor which will be used for it's loading when Skin
is initialized.
Once you have specified your custom IconSet
include in Skin
or SkinExtension
- it will be used automatically whenever those are active. So generally this is a better approach compared to specifying IconSet
s in the code, but only if you are expecting your project to grow in size, otherwise more simple previous approach might be worth it.
Now to the last topic that haven't been covered yet - how can existing icons be replaced? For instance WebLaF uses lots of custom icons (check Icons.java) for various UI elements and all of them can be replaced if you don't like or want to customize some of them.
To replace any existing icon all you need to do is provide another one with the same identifier - any "user"-added icon sets and their icons will have priority over skin and extension icon sets. Extension icon sets and their icons will have priority over skin icon sets. The rest is up to the order of icon set addition
For instance, here is a small example with RuntimeIconSet
use and DemoApplication
:
// Creating custom IconSet
final IconSet iconSet = new RuntimeIconSet ( "my-custom-set" );
// Adding replacement icon
iconSet.addIcon ( new SvgIconSource (
"github19",
new UrlResource ( "https://github.com/mgarin/weblaf/raw/master/resources/firefox.svg" ),
new Dimension ( 19, 19 )
) );
// Registering new IconSetExtension with our custom IconSet for default light skin
StyleManager.addExtensions ( new IconSetExtension (
"my-custom-icon-set",
"weblaf.light.skin",
iconSet
) );
DemoApplication
uses icon with github19
identifier which I am replacing and it forces IconManager
to provide a different Icon
for that particular use case in DemoApplication
:
Original icon:
This approach works for IconSet
s provided through Skin
s and SkinExtension
s as well.
If you found any mistakes or inconsistency in this article, feel that it is lacking explanation or simply want to request an additional wiki article covering some topic:
I will do my best to answer and provide assistance as soon as possible!