B4J Code Snippet [JavaFX] - Metro Style CSS

Hello, I will show you how to install this Metro skin in your projects.
It is a JavaFX css style that allows you to modify the controls, giving it a metro effect.

I use JMetro CSS files from:



Some Issues you have to know.
Thanks to @tchart

  • There are some definitions for jfx controls that are specified under "sun.com.javafx..." these need to be relabelled to just "javafx..." (for open jdk).
  • I had to comment out any definitions with "impl.jfxtras.styles."
  • Some of the B4J controls dont seem to be defined (eg slider) so I had to remove those from the demo form

DEMO:

DEFAULT B4J:

Screenshot_1.png


METRO STYLE LIGHT:

Screenshot_9.png


METRO STYLE DARK:


Screenshot_10.png



STEP 1:

Download [B4J] - METRO STYLE attach ZIP and Unzip.


NOTE: The screenshot lang its spanish, but are the same options.


STEP 2:

Screenshot_3.png


Add a new group on Files tab.

Screenshot_4.png


Add all CSS file of the zip file.

Screenshot_5.png


You should have all these files added in the list.


STEP 3:


Screenshot_6.png


Now go to the modules tab, and right click on Main and click on Add Existing Module.
Select the .bas file on the zip.

Screenshot_7.png


Select "Copy to project folder" and click OK

You should have this code.

Screenshot_8.png


Now just use this code:

B4X:
' For the Light style
Metro.ApplyTheme(MainForm,"Light")

B4X:
' For the Dark style
Metro.ApplyTheme(MainForm,"Dark")


I hope it will be you useful.
Regards!
 

Attachments

  • [B4J] - METRO STYLE.zip
    27.1 KB · Views: 964
  • [B4J] - METRO STYLE DEMO.zip
    440.3 KB · Views: 938
Last edited:

Jmu5667

Well-Known Member
Licensed User
Longtime User
Hi @Brian Michael

Nice work ! When I run your demo I get the following in the logs, however the app does not crash and does display the Themed form.

B4X:
Waiting for debugger to connect...
Program started.
Mar 18, 2020 4:46:21 PM javafx.scene.control.Control loadSkinClass
SEVERE: Failed to load skin 'impl.jfxtras.styles.jmetro.FluentButtonSkin' for control Button@90b06ed[styleClass=button]'Button Enabled'
java.lang.ClassNotFoundException: impl.jfxtras.styles.jmetro.FluentButtonSkin
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at javafx.scene.control.Control.loadClass(Control.java:112)
    at javafx.scene.control.Control.loadSkinClass(Control.java:701)
    at javafx.scene.control.Control$4.invalidated(Control.java:661)
    at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:109)
    at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
    at javafx.css.StyleableStringProperty.set(StyleableStringProperty.java:83)
    at javafx.scene.control.Control$4.set(Control.java:653)
    at javafx.css.StyleableStringProperty.applyStyle(StyleableStringProperty.java:69)
    at javafx.css.StyleableStringProperty.applyStyle(StyleableStringProperty.java:45)
    at javafx.scene.CssStyleHelper.transitionToState(CssStyleHelper.java:774)
    at javafx.scene.Node.impl_processCSS(Node.java:9189)
    at javafx.scene.Parent.impl_processCSS(Parent.java:1249)
    at javafx.scene.control.Control.impl_processCSS(Control.java:868)
    at javafx.scene.Parent.impl_processCSS(Parent.java:1280)
    at javafx.scene.Node.processCSS(Node.java:9056)
    at javafx.scene.Scene.doCSSPass(Scene.java:545)
    at javafx.scene.Scene.access$3600(Scene.java:159)
    at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2392)
    at com.sun.javafx.tk.Toolkit.lambda$runPulse$29(Toolkit.java:398)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:397)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:424)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:518)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:498)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:491)
    at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$408(QuantumToolkit.java:319)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$152(WinApplication.java:177)
    at java.lang.Thread.run(Thread.java:748)
Mar 18, 2020 4:46:21 PM javafx.scene.control.Control loadSkinClass
SEVERE: Failed to load skin 'impl.jfxtras.styles.jmetro.FluentButtonSkin' for control Button@14a11f82[styleClass=button]'Button Disabled'
java.lang.ClassNotFoundException: impl.jfxtras.styles.jmetro.FluentButtonSkin
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at javafx.scene.control.Control.loadClass(Control.java:112)
    at javafx.scene.control.Control.loadSkinClass(Control.java:701)
    at javafx.scene.control.Control$4.invalidated(Control.java:661)
    at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:109)
    at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
    at javafx.css.StyleableStringProperty.set(StyleableStringProperty.java:83)
    at javafx.scene.control.Control$4.set(Control.java:653)
    at javafx.css.StyleableStringProperty.applyStyle(StyleableStringProperty.java:69)
    at javafx.css.StyleableStringProperty.applyStyle(StyleableStringProperty.java:45)
    at javafx.scene.CssStyleHelper.transitionToState(CssStyleHelper.java:774)
    at javafx.scene.Node.impl_processCSS(Node.java:9189)
    at javafx.scene.Parent.impl_processCSS(Parent.java:1249)
    at javafx.scene.control.Control.impl_processCSS(Control.java:868)
    at javafx.scene.Parent.impl_processCSS(Parent.java:1280)
    at javafx.scene.Node.processCSS(Node.java:9056)
    at javafx.scene.Scene.doCSSPass(Scene.java:545)
    at javafx.scene.Scene.access$3600(Scene.java:159)
    at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2392)
    at com.sun.javafx.tk.Toolkit.lambda$runPulse$29(Toolkit.java:398)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:397)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:424)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:518)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:498)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:491)
    at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$408(QuantumToolkit.java:319)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$152(WinApplication.java:177)
    at java.lang.Thread.run(Thread.java:748)
Mar 18, 2020 4:46:21 PM javafx.scene.control.Control loadSkinClass
SEVERE: Failed to load skin 'impl.jfxtras.styles.jmetro.ProgressBarSkin' for control ProgressBar@7f8aca1b[styleClass=progress-bar]
java.lang.ClassNotFoundException: impl.jfxtras.styles.jmetro.ProgressBarSkin
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at javafx.scene.control.Control.loadClass(Control.java:112)
    at javafx.scene.control.Control.loadSkinClass(Control.java:701)
    at javafx.scene.control.Control$4.invalidated(Control.java:661)
    at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:109)
    at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
    at javafx.css.StyleableStringProperty.set(StyleableStringProperty.java:83)
    at javafx.scene.control.Control$4.set(Control.java:653)
    at javafx.css.StyleableStringProperty.applyStyle(StyleableStringProperty.java:69)
    at javafx.css.StyleableStringProperty.applyStyle(StyleableStringProperty.java:45)
    at javafx.scene.CssStyleHelper.transitionToState(CssStyleHelper.java:774)
    at javafx.scene.Node.impl_processCSS(Node.java:9189)
    at javafx.scene.Parent.impl_processCSS(Parent.java:1249)
    at javafx.scene.control.Control.impl_processCSS(Control.java:868)
    at javafx.scene.Parent.impl_processCSS(Parent.java:1280)
    at javafx.scene.Node.processCSS(Node.java:9056)
    at javafx.scene.Scene.doCSSPass(Scene.java:545)
    at javafx.scene.Scene.access$3600(Scene.java:159)
    at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2392)
    at com.sun.javafx.tk.Toolkit.lambda$runPulse$29(Toolkit.java:398)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:397)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:424)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:518)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:498)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:491)
    at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$408(QuantumToolkit.java:319)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$152(WinApplication.java:177)
    at java.lang.Thread.run(Thread.java:748)
Mar 18, 2020 4:46:21 PM javafx.scene.control.Control loadSkinClass
SEVERE: Failed to load skin 'impl.jfxtras.styles.jmetro.SliderSkin' for control Slider@26848705[styleClass=slider]
java.lang.ClassNotFoundException: impl.jfxtras.styles.jmetro.SliderSkin
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at javafx.scene.control.Control.loadClass(Control.java:112)
    at javafx.scene.control.Control.loadSkinClass(Control.java:701)
    at javafx.scene.control.Control$4.invalidated(Control.java:661)
    at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:109)
    at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
    at javafx.css.StyleableStringProperty.set(StyleableStringProperty.java:83)
    at javafx.scene.control.Control$4.set(Control.java:653)
    at javafx.css.StyleableStringProperty.applyStyle(StyleableStringProperty.java:69)
    at javafx.css.StyleableStringProperty.applyStyle(StyleableStringProperty.java:45)
    at javafx.scene.CssStyleHelper.transitionToState(CssStyleHelper.java:774)
    at javafx.scene.Node.impl_processCSS(Node.java:9189)
    at javafx.scene.Parent.impl_processCSS(Parent.java:1249)
    at javafx.scene.control.Control.impl_processCSS(Control.java:868)
    at javafx.scene.Parent.impl_processCSS(Parent.java:1280)
    at javafx.scene.Node.processCSS(Node.java:9056)
    at javafx.scene.Scene.doCSSPass(Scene.java:545)
    at javafx.scene.Scene.access$3600(Scene.java:159)
    at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2392)
    at com.sun.javafx.tk.Toolkit.lambda$runPulse$29(Toolkit.java:398)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:397)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:424)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:518)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:498)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:491)
    at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$408(QuantumToolkit.java:319)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$152(WinApplication.java:177)
    at java.lang.Thread.run(Thread.java:748)
Mar 18, 2020 4:46:21 PM javafx.scene.control.Control loadSkinClass
SEVERE: Failed to load skin 'impl.jfxtras.styles.jmetro.TextFieldSkin' for control TextField@e27e473[styleClass=text-input text-field]
java.lang.ClassNotFoundException: impl.jfxtras.styles.jmetro.TextFieldSkin
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at javafx.scene.control.Control.loadClass(Control.java:112)
    at javafx.scene.control.Control.loadSkinClass(Control.java:701)
    at javafx.scene.control.Control$4.invalidated(Control.java:661)
    at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:109)
    at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
    at javafx.css.StyleableStringProperty.set(StyleableStringProperty.java:83)
    at javafx.scene.control.Control$4.set(Control.java:653)
    at javafx.css.StyleableStringProperty.applyStyle(StyleableStringProperty.java:69)
    at javafx.css.StyleableStringProperty.applyStyle(StyleableStringProperty.java:45)
    at javafx.scene.CssStyleHelper.transitionToState(CssStyleHelper.java:774)
    at javafx.scene.Node.impl_processCSS(Node.java:9189)
    at javafx.scene.Parent.impl_processCSS(Parent.java:1249)
    at javafx.scene.control.Control.impl_processCSS(Control.java:868)
    at javafx.scene.Parent.impl_processCSS(Parent.java:1280)
    at javafx.scene.Node.processCSS(Node.java:9056)
    at javafx.scene.Scene.doCSSPass(Scene.java:545)
    at javafx.scene.Scene.access$3600(Scene.java:159)
    at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2392)
    at com.sun.javafx.tk.Toolkit.lambda$runPulse$29(Toolkit.java:398)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:397)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:424)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:518)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:498)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:491)
    at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$408(QuantumToolkit.java:319)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$152(WinApplication.java:177)
    at java.lang.Thread.run(Thread.java:748)
Mar 18, 2020 4:46:21 PM javafx.scene.control.Control loadSkinClass
SEVERE: Failed to load skin 'impl.jfxtras.styles.jmetro.FluentToggleButtonSkin' for control ToggleButton@a769db6[styleClass=toggle-button]'ToogleButton'
java.lang.ClassNotFoundException: impl.jfxtras.styles.jmetro.FluentToggleButtonSkin
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at javafx.scene.control.Control.loadClass(Control.java:112)
    at javafx.scene.control.Control.loadSkinClass(Control.java:701)
    at javafx.scene.control.Control$4.invalidated(Control.java:661)
    at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:109)
    at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
    at javafx.css.StyleableStringProperty.set(StyleableStringProperty.java:83)
    at javafx.scene.control.Control$4.set(Control.java:653)
    at javafx.css.StyleableStringProperty.applyStyle(StyleableStringProperty.java:69)
    at javafx.css.StyleableStringProperty.applyStyle(StyleableStringProperty.java:45)
    at javafx.scene.CssStyleHelper.transitionToState(CssStyleHelper.java:774)
    at javafx.scene.Node.impl_processCSS(Node.java:9189)
    at javafx.scene.Parent.impl_processCSS(Parent.java:1249)
    at javafx.scene.control.Control.impl_processCSS(Control.java:868)
    at javafx.scene.Parent.impl_processCSS(Parent.java:1280)
    at javafx.scene.Node.processCSS(Node.java:9056)
    at javafx.scene.Scene.doCSSPass(Scene.java:545)
    at javafx.scene.Scene.access$3600(Scene.java:159)
    at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2392)
    at com.sun.javafx.tk.Toolkit.lambda$runPulse$29(Toolkit.java:398)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:397)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:424)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:518)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:498)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:491)
    at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$408(QuantumToolkit.java:319)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$152(WinApplication.java:177)
    at java.lang.Thread.run(Thread.java:748)

Regards

John.
 

tchart

Well-Known Member
Licensed User
Longtime User
So after some investigation.

#1 there are some definitions for jfx controls that are specified under "sun.com.javafx..." these need to be relabelled to just "javafx..." (for open jdk).

#2 I had to comment out any definitions with "impl.jfxtras.styles."

#3 Some of the B4J controls dont seem to be defined (eg slider) so I had to remove those from the demo form

After that, no more messages...
 

Jmu5667

Well-Known Member
Licensed User
Longtime User
So after some investigation.

#1 there are some definitions for jfx controls that are specified under "sun.com.javafx..." these need to be relabelled to just "javafx..." (for open jdk).

#2 I had to comment out any definitions with "impl.jfxtras.styles."

#3 Some of the B4J controls dont seem to be defined (eg slider) so I had to remove those from the demo form

After that, no more messages...


Great Info, anyone figured out how to get Material Icons to display correctly, currently I get a Square displayed. I am using the MI on buttons in a B4J UI app. This is obviously in relation to Metro Dark/Light themes.

Regards

John.
 

moster67

Expert
Licensed User
Longtime User
Great Info, anyone figured out how to get Material Icons to display correctly, currently I get a Square displayed. I am using the MI on buttons in a B4J UI app. This is obviously in relation to Metro Dark/Light themes.
Any luck in resolving this?
 

Revisable5987

Member
Licensed User
Great Info, anyone figured out how to get Material Icons to display correctly, currently I get a Square displayed. I am using the MI on buttons in a B4J UI app. This is obviously in relation to Metro Dark/Light themes.

Regards

John.
It appears to be the way CSS actually works.
From what I understand the metro CSS is conflicting with the style set by the designer, and the metro is winning either because:
1. It has a higher specificity
2. It is loaded after the style set in the designer

I have removed the following entries from the base.css which means that the size, colour and font are now handled by the Designer
-fx-font-family: "Segoe UI";
-fx-font-size: <font-size>
-fx-text-fill: text_color;

If you wish to keep the Segoe font but also use Material Icons you could try creating a Material CSS file and load it to the items that require it after loading metro?
Not tested, but seems like it could be a solution.

as @tchart said previously 'com.sun.jfxtras' needs changing to 'jfxtras'

impl.jfxtras.styles will be solved by using the following:

Download jmetro-11.6.11.jar https://github.com/JFXtras/jfxtras-styles/releases
Add it to your additional libraries folder and add to your project:
B4X:
#AdditionalJar: jmetro-11.6.11

This 'works', however my TextFields are now running away so your mileage may vary.
? EDIT: seems to cause more than that. Think i'll stay with the standard skin
 

Attachments

  • metro css.zip
    26.2 KB · Views: 515
Last edited:
Top