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


DEMO:

DEFAULT B4J:



METRO STYLE LIGHT:



METRO STYLE DARK:





STEP 1:

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


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


STEP 2:



Add a new group on Files tab.



Add all CSS file of the zip file.



You should have all these files added in the list.


STEP 3:




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



Select "Copy to project folder" and click OK

You should have this code.



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: 840
  • [B4J] - METRO STYLE DEMO.zip
    440.3 KB · Views: 833
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


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: 430
Last edited:
Cookies are required to use this site. You must accept them to continue using the site. Learn more…