Class StyleSheet

java.lang.Object
swingtree.style.StyleSheet

public abstract class StyleSheet extends Object
An abstract class intended to be extended to create custom CSS look-alike source code based style sheets for your Swing application.

A style sheet object is in essence merely a collection of StyleTraits and corresponding Styler lambdas which are used by the SwingTree style engine to calculate component StyleConf configurations in a functional and side effect free manner.
Implement the configure() method and use the add(StyleTrait, Styler) method to add StyleTraits and corresponding Styler lambdas to the style sheet. There are also various factory methods for creating StyleTraits in the form of id(String), group(String), group(Enum), type(Class). This is designed to make your style sheet code more readable and maintainable.

Here an example of how this class is typically used to create a custom style sheet:


  class MyStyleSheet extends StyleSheet {
    {@literal @}Override
    protected void configure() {
      add(group("MyButton"), it -> it
        .margin(12)
        .padding(16)
        .backgroundColor(Color.YELLOW)
      );
      add(type(JLabel.class).id("Foo"), it-> it
        .borderRadius(5)
        .gradient("Bar", ... )
      );
      add(group(Group.ERROR), it -> it
        .backgroundColor(Color.RED)
        .borderColor(Color.YELLOW)
        .borderWidth(2)
      );
    }
  }
  
This API design is inspired by the CSS styling language, and the use of immutable objects is a key feature of the style API, which makes it possible to safely compose Styler lambdas into any kind of style inheritance hierarchy without having to worry about side effects.

Note that the configure() method, here the Styler lambdas are intended to be registered, is not called eagerly in the constructor of the style sheet, but rather lazily when the style sheet is first used to calculate the style configuration for a particular component, which happens through the computeStyleFrom(JComponent) or computeStyleFrom(JComponent, StyleConf) methods.
The intended way to use a StyleSheet is by configuring it globally through SwingTree.initialiseUsing(SwingTreeConfigurator), or if you want to apply ste sheets to specific scopes through UIFactoryMethods.use(StyleSheet, Supplier). The second argument is a supplier lambda for your SwingTree GUI declaration where each component will be bound to the StyleSheet you supplied!
  • Field Details

    • log

      protected final org.slf4j.Logger log
  • Constructor Details

    • StyleSheet

      protected StyleSheet()
    • StyleSheet

      protected StyleSheet(StyleSheet parentStyleSheet)
      Use this method to inherit styles from the supplied parentStyleSheet. All styles in the parent will be reused in this style, but you may overwrite parent styles in the local configure() method...
      Parameters:
      parentStyleSheet - Another StyleSheet from which this one should inherit all styles!
  • Method Details

    • none

      public static StyleSheet none()
      A factory method for getting the empty style sheet representing no style whatsoever. It is especially useful instead of null.
      Returns:
      A style sheet without any traits and stylers.
    • observable

      public final sprouts.Observable observable()
      Creates and returns an Observable on an internal Event which is triggered after every time this StyleSheet is being configured through the configure() method.
      Components created from SwingTree use this observable to recompute and apply their style from this style sheet...
      Note that the instance returned by this method is weakly referenced by the source Event. This means that when a call-site no longer holds on to their observer, then it will be garbage collected alongside all of the Observer (event listeners) registered on it!
      Returns:
      A weakly referenced Observable which can be used to react to StyleSheet re-configurations...
    • reconfigure

      public final void reconfigure()
      Essentially (re)initiates the style sheet by clearing all previously registered StyleTraits and Stylers, and then calling the configure() method again to establish a potentially completely new style.
      You can use this method to build highly dynamic styling behavior. For example, during the new configuration you may want to add switch to a completely a different set of traits with different Stylers depending on the current theme of the application, which you also want the user to change at runtime (but don't forget to repaint the components to see the effect).
    • id

      protected StyleTrait<JComponent> id(String id)
      A factory method for a StyleTrait targeting components with the given id/name (see Component.setName(String)). This is intended to be used in the configure() method of the style sheet. Note that this method does not set the id/name of the component, it expects there to be a component with the given id/name already in the component hierarchy so that a corresponding Styler lambda can be applied to it.

      This is intended to be used in the configure() method of the style sheet.
      Here an example of how to use this method in the configure() method:
      
            add(id("myButton"), it -> it.backgroundColor(Color.CYAN));
        
      Parameters:
      id - The id/name of the component to target.
      Returns:
      A StyleTrait targeting components with the given id/name.
    • group

      protected StyleTrait<JComponent> group(String group)
      A factory method for a StyleTrait targeting components belonging to the given string group (see UIForAnySwing.group(String...). A group is conceptually similar to a CSS class, meaning that you can add a group to any component and then target all components belonging to that group with a single StyleTrait. Note that this method does not add the group to any component, it expects there to be a component with the given group already in the component hierarchy so that a corresponding Styler lambda can be applied to it.

      This is intended to be used in the configure() method of the style sheet.
      Here an example of how to use this method in the configure() method:
      
            add(group("myGroup"), it -> it.backgroundColor(Color.RED));
        
      Although using Strings is a convenient way of grouping components, it is not ideal with respect to compile time safety. Please use group(Enum) and UIForAnySwing.group(Enum[]) instead...
      Parameters:
      group - The group to target in the form of a string.
      Returns:
      A StyleTrait targeting components belonging to the given group.
    • group

      protected <E extends Enum<E>> StyleTrait<JComponent> group(E group)
      A factory method for a StyleTrait targeting components belonging to the given enum group (see UIForAnySwing.group(Enum...). A group is conceptually similar to a CSS class, meaning that you can add a group to any component and then target all components belonging to that group with a single StyleTrait. Note that this method does not add the group to any component, it expects there to be a component with the given group already in the component hierarchy so that a corresponding Styler lambda can be applied to it.

      This is intended to be used in the configure() method of the style sheet.
      Here an example of how to use this method in the configure() method:
      
            add(group(Group.ERROR), it -> it.backgroundColor(Color.RED));
        
      Type Parameters:
      E - The type of the enum defining the group to target.
      Parameters:
      group - The group to target in the form of an enum.
      Returns:
      A StyleTrait targeting components belonging to the given group.
    • type

      protected <C extends JComponent> StyleTrait<C> type(Class<C> type)
      A factory method for a StyleTrait targeting components which are of a given type (see Object.getClass(). Note that this method does not set the type of any component, it expects there to be a component of the given type already in the component hierarchy so that a corresponding Styler lambda can be applied to it.

      This is intended to be used in the configure() method of the style sheet.
      Here an example of how to use this method in the configure() method:
      
            add(type(JButton.class), it -> it.backgroundColor(Color.RED));
        
      Type Parameters:
      C - The type of the components to target for styling.
      Parameters:
      type - The type of the component to target.
      Returns:
      A StyleTrait targeting components of the given type.
    • add

      protected <C extends JComponent> void add(StyleTrait<C> trait, Styler<C> traitStyler)
      Use this to register style rules in you configure() implementation by providing a StyleTrait targeting the components you want to style (see id(String), group(String), group(Enum), type(Class)), and a corresponding Styler lambda which will be applied to the components targeted by the StyleTrait.

      Here an example of how to use this method in the configure() method:
      
        @Override
        protected void configure() {
            add(id("arial-button"), it -> it.font(new Font("Arial", Font.BOLD, 12)));
            add(type(JButton).group("FooBar"), it -> it.borderRadius(5));
            add(group(Group.ERROR), it -> it.backgroundColor(Color.RED));
            // ...
        }
        
      Type Parameters:
      C - The type of the components targeted by the StyleTrait.
      Parameters:
      trait - The StyleTrait targeting the components you want to style.
      traitStyler - The Styler lambda which will be applied to the components targeted by the StyleTrait.
    • configure

      protected abstract void configure()
      Override this method to configure the style sheet by adding StyleTraits and corresponding Styler lambdas to the style sheet through the add(StyleTrait, Styler) method.

      Example:
      
        @Override
        protected void configure() {
            add(type(JComponent.class), it -> it
              .backgroundColor(new Color(0.7f, 0.85f, 1f))
              .padding(4)
              .margin(5)
            );
            add(type(JButton.class), it -> it
               .padding(12)
               .margin(16)
               .gradient("default", shade -> shade
                   .strategy(ShadingStrategy.TOP_LEFT_TO_BOTTOM_RIGHT)
                   .colors(it.component().getBackground().brighter(), Color.CYAN)
               )
            );
            // ...
         }
       
    • computeStyleFrom

      public final StyleConf computeStyleFrom(JComponent toBeStyled)
      Uses this style sheet to compute the StyleConf for a component derived from the StyleConf.none() constant as a basis. Note that the style sheet is expected to already be configured at this point, because the configure() method is called in the constructor of the style sheet.

      Example:
      
            MyStyleSheet styleSheet = new MyStyleSheet();
            JComboBox<String> comboBox = new JComboBox<>();
            var style = styleSheet.computeStyleFrom(comboBox);
       
      Note that this method does NOT install the style on the supplied component! Style installation is intended to happen when you SwingTree UI declarations are bound to a particular StyleSheet through the UIFactoryMethods.use(StyleSheet, Supplier) method.
      Parameters:
      toBeStyled - The component to apply the style sheet to.
      Returns:
      The StyleConf that was applied to the component.
    • computeStyleFrom

      public final StyleConf computeStyleFrom(JComponent toBeStyled, StyleConf startingStyle)
      Uses this style sheet to compute the StyleConf for a component derived from the supplied StyleConf as a basis. Note that the style sheet must already be configured at this point, because the configure() method needs to be called before in the constructor of the style sheet to bei able to compute the style.

      Example:

      
            MyStyleSheet styleSheet = new MyStyleSheet();
            JComboBox<String> comboBox = new JComboBox<>();
            var style = styleSheet.computeStyleFrom(comboBox, Style.none());
       
      Note that this method does NOT install the style on the supplied component! Style installation is intended to happen when you SwingTree UI declarations are bound to a particular StyleSheet through the UIFactoryMethods.use(StyleSheet, Supplier) method.
      Parameters:
      toBeStyled - The component for which a style ought to be computed and returned.
      startingStyle - The StyleConf to start with when applying the style sheet.
      Returns:
      The StyleConf that was applied to the component.
      Throws:
      NullPointerException - If either argument is null.