On 24/01/2014 22:28, David Grieve wrote:
On Jan 24, 2014, at 4:02 PM, John Hendrikx<hj...@xs4all.nl>  wrote:

I've got an update on this.

I've rewritten the code now to make use of multiple skins, and doing some 
trickery with Factories to make them easily switchable.

The main reason I've rewritten them is because I think I will not be able to provide CSS 
properties that are accessible if they are not specifically defined on a Skin class (or 
Control class) -- but that may be lack of understanding how CSS properties are discovered 
(I don't see how they could get discovered if they're defined on a "delegated 
skin").
A control returns the CssMetaData of its skin (provided the skin extends from SkinBase).  
Also, if a node is in the scene-graph, then CSS will "discover" it.
Yes, and a Skin could return the CssMetaData for a Skin it delegates to... my problem is, if I change the delegate (by changing a property) while the main Skin itself remains the same, can I inform the CSS engine of potential changes in the CssMetaData? Each delegate Skin may have additional CSS properties. When changing a Skin on a Control that's probably automatic, but I'm not so sure how that would work with a delegate skin.

--John


Anyway, the solution works, but I found some odd issues, for which I filed two 
JIRA's:

https://javafx-jira.kenai.com/browse/RT-35528
https://javafx-jira.kenai.com/browse/RT-35529

One deals with anonymously created Skins (my Skins have protected methods that 
can be easily overriden to customize the appearance).  Unfortunately, JavaFX 
doesn't like it when a Skin is an anonymous inner class with one or more 
methods overriden with small customizations.  The setting of the Skin itself 
works, it just complains about it later when a CSS pass occurs (I think).
The second issue deals with something odd that I noticed when a Skin is 
specified in CSS (with -fx-skin) and when I later override it with setSkin().  
JavaFX seems to reset it back to the skin defined by CSS when a CSS pass 
occurs.  I'm not aware of any other properties that behave like that.

All in all, it works, but it feels somewhat fragile.

--John

On 7/01/2014 17:04, Richard Bair wrote:
Could you write a single skin that delegates to one or more reusable skins?

On Jan 7, 2014, at 7:26 AM, John Hendrikx<hj...@xs4all.nl>   wrote:

On 7/01/2014 14:50, Tomas Mikula wrote:
Interesting ideas. I'm wondering, do you switch skins often enough that you are 
worried about performance (and thus care about reusability of skins)? Because I 
don't see how reusability of skins saves you lines of code - whether the code 
is in the constructor or in the initialize() method, it is there somewhere. In 
my opinion, reusing objects is more complicated than creating fresh instances 
and the only justification for it is performance.
To address your last point first, if you already are required to write a proper 
dispose method, then fresh instances should be just as easy/hard to write as 
reusable ones.  Everything is already in place, just rename the constructor.  
Of course, if you did not write a proper dispose method, then your object will 
stick around or cause other trouble.  With fresh instances you won't notice 
this so readily -- in JavaFX for example, the problem of having objects that 
are no longer actively reachable through the SceneGraph, but are still 
participating in Event handling (because they registered non-weak listeners) 
can be a nice source of surprises.  With reusable objects, you'll notice the 
bugs in your cleanup code likely the first time you reuse it.

Anyway, for me, making Skins reusable makes them easier to use with bindings, and it 
ofcourse saves creating a factory.  I see the "skin" of an object as the same 
as say its background color.  There is no reason (anymore I think) that one should be 
treated so differently from the other.

   private final Skin someExistingSkin = new SkinA();
   private final Skin someExistingSkin2 = new SkinB();

   void changeToSquareLook() {
      myControl.setSkin(someExistingSkin);
   }

   void changeToRoundLook() {
      myControl.setSkin(someExistingSkin2);
   }

vs.

  private final SkinFactory skinFactory = new SkinFactory() {
     public Skin createSkin(Control control) {
         return new SkinA(control);
     }
  };

  private final SkinFactory skinFactory2 = new SkinFactory() {
     public Skin createSkin(Control control) {
         return new SkinB(control);
     }
  };

  void changeToSquareLook() {
     myControl.setSkin(skinFactory.createSkin(myControl));
  }

   void changeToRoundLook() {
     myControl.setSkin(skinFactory2.createSkin(myControl));
   }

It's not really about performance, but ease of use.  The binding case requires 
a ChangeListener instead of just bind().

I agree with you on the problem of separation of skin initialization from 
setSkin(). Another way to address this could be deprecating the original 
setSkin() method and introducing

    setSkin(SkinProvider<C>   skinProvider);

where SkinProvider is a SAM interface and thus the above method could be called 
like this:

    setSkin(control ->   new MySkin(control));

I know this defeats reusability of skins altogether, so you (and others) may 
disagree.
Maybe if there was a "skinProviderProperty"... then I could bind to that 
atleast.  Still introduces lots of factories (or functions).

--John


Reply via email to