-
Enhancement
-
Resolution: Unresolved
-
P3
-
jfx15
-
generic
-
generic
ADDITIONAL SYSTEM INFORMATION :
Windows 10, Java 14.0.2
A DESCRIPTION OF THE PROBLEM :
In JavaFX 8 there was the possibility to change the user agent stylesheet of a Node at runtime and then call impl_reapplyCSS() or reapplyCss() with reflection and the control style would be updated.
In the next versions the behaviour has been changed, impl_reapplyCSS() has been removed because deprecated and if I call reapplyCss() with reflection the control's style is not updated anymore.
The only way to change the control style now is to force it by calling getStylesheets().setAll(STYLESHEET)
I think this regression may be related toJDK-8088253.
Please fix it as this should not be the intended behavior.
REGRESSION : Last worked in version 8u281
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Execute the first example with Java 8 and JavaFX 8 and then the second example with newer versions.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The control's style should update if the user agent stylesheet is updated
ACTUAL -
The CSS is not reloaded and the control's style is not updated.
---------- BEGIN SOURCE ----------
EXAMPLE 1
import custombutton.DynamicButton;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import static custombutton.DynamicButton.Styles.STYLE1;
import static custombutton.DynamicButton.Styles.STYLE2;
public class Test extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
StackPane pane = new StackPane();
DynamicButton dynamicButton = new DynamicButton("TO CHANGE");
Button button = new Button("CHANGE!");
button.setOnAction(event -> {
dynamicButton.setDynamicStyle(
dynamicButton.getDynamicStyle() == STYLE1 ? STYLE2 : STYLE1
);
});
VBox box = new VBox(40, dynamicButton, button);
box.setAlignment(Pos.TOP_CENTER);
box.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
pane.getChildren().add(box);
primaryStage.setScene(new Scene(pane, 800, 600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
package custombutton;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.Button;
public class DynamicButton extends Button {
private final String STYLE_CLASS = "dynamic-button";
private String STYLESHEET = getClass().getResource("dynamic1.css").toString();
public static enum Styles {
STYLE1,
STYLE2
}
private final ObjectProperty<Styles> style = new SimpleObjectProperty<>(Styles.STYLE1);
public DynamicButton() {
initialize();
}
public DynamicButton(String text) {
super(text);
initialize();
}
private void initialize() {
getStyleClass().add(STYLE_CLASS);
style.addListener((observable, oldValue, newValue) -> {
if (newValue == Styles.STYLE1) {
STYLESHEET = getClass().getResource("dynamic1.css").toString();
} else {
STYLESHEET = getClass().getResource("dynamic2.css").toString();
}
impl_reapplyCSS();
System.out.println("Style Changed");
});
}
public Styles getDynamicStyle() {
return style.get();
}
public ObjectProperty<Styles> dynamicStyleProperty() {
return style;
}
public void setDynamicStyle(Styles style) {
this.style.set(style);
}
@Override
public String getUserAgentStylesheet() {
System.out.println("getUserAgentStylesheet Called");
return STYLESHEET;
}
}
EXAMPLE 2
import custombutton.DynamicButton;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import static custombutton.DynamicButton.Styles.STYLE1;
import static custombutton.DynamicButton.Styles.STYLE2;
public class Test extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
StackPane pane = new StackPane();
DynamicButton dynamicButton = new DynamicButton("TO CHANGE");
Button button = new Button("CHANGE!");
button.setOnAction(event -> {
dynamicButton.setDynamicStyle(
dynamicButton.getDynamicStyle() == STYLE1 ? STYLE2 : STYLE1
);
});
VBox box = new VBox(40, dynamicButton, button);
box.setAlignment(Pos.TOP_CENTER);
box.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
pane.getChildren().add(box);
primaryStage.setScene(new Scene(pane, 800, 600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
package custombutton;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Node;
import javafx.scene.control.Button;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class DynamicButton extends Button {
private final String STYLE_CLASS = "dynamic-button";
private String STYLESHEET = getClass().getResource("dynamic1.css").toString();
public static enum Styles {
STYLE1,
STYLE2
}
private final ObjectProperty<Styles> style = new SimpleObjectProperty<>(Styles.STYLE1);
public DynamicButton() {
initialize();
}
public DynamicButton(String text) {
super(text);
initialize();
}
private void initialize() {
getStyleClass().add(STYLE_CLASS);
style.addListener((observable, oldValue, newValue) -> {
if (newValue == Styles.STYLE1) {
STYLESHEET = getClass().getResource("dynamic1.css").toString();
} else {
STYLESHEET = getClass().getResource("dynamic2.css").toString();
}
try {
Method method = Node.class.getDeclaredMethod("reapplyCss");
method.setAccessible(true);
Object call = method.invoke(this);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
System.out.println("Style Changed");
});
}
public Styles getDynamicStyle() {
return style.get();
}
public ObjectProperty<Styles> dynamicStyleProperty() {
return style;
}
public void setDynamicStyle(Styles style) {
this.style.set(style);
}
@Override
public String getUserAgentStylesheet() {
System.out.println("getUserAgentStylesheet Called");
return STYLESHEET;
}
}
CSS FILES
dynamic1.css
.dynamic-button {
-fx-border-color: blue;
}
dynamic2.css
.dynamic-button {
-fx-border-color: red;
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Since the CSS file is cached in STYLESHEET, the only way to update the control's style is to call getStylesheets().setAll(STYLESHEET);
FREQUENCY : always
Windows 10, Java 14.0.2
A DESCRIPTION OF THE PROBLEM :
In JavaFX 8 there was the possibility to change the user agent stylesheet of a Node at runtime and then call impl_reapplyCSS() or reapplyCss() with reflection and the control style would be updated.
In the next versions the behaviour has been changed, impl_reapplyCSS() has been removed because deprecated and if I call reapplyCss() with reflection the control's style is not updated anymore.
The only way to change the control style now is to force it by calling getStylesheets().setAll(STYLESHEET)
I think this regression may be related to
Please fix it as this should not be the intended behavior.
REGRESSION : Last worked in version 8u281
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Execute the first example with Java 8 and JavaFX 8 and then the second example with newer versions.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The control's style should update if the user agent stylesheet is updated
ACTUAL -
The CSS is not reloaded and the control's style is not updated.
---------- BEGIN SOURCE ----------
EXAMPLE 1
import custombutton.DynamicButton;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import static custombutton.DynamicButton.Styles.STYLE1;
import static custombutton.DynamicButton.Styles.STYLE2;
public class Test extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
StackPane pane = new StackPane();
DynamicButton dynamicButton = new DynamicButton("TO CHANGE");
Button button = new Button("CHANGE!");
button.setOnAction(event -> {
dynamicButton.setDynamicStyle(
dynamicButton.getDynamicStyle() == STYLE1 ? STYLE2 : STYLE1
);
});
VBox box = new VBox(40, dynamicButton, button);
box.setAlignment(Pos.TOP_CENTER);
box.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
pane.getChildren().add(box);
primaryStage.setScene(new Scene(pane, 800, 600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
package custombutton;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.Button;
public class DynamicButton extends Button {
private final String STYLE_CLASS = "dynamic-button";
private String STYLESHEET = getClass().getResource("dynamic1.css").toString();
public static enum Styles {
STYLE1,
STYLE2
}
private final ObjectProperty<Styles> style = new SimpleObjectProperty<>(Styles.STYLE1);
public DynamicButton() {
initialize();
}
public DynamicButton(String text) {
super(text);
initialize();
}
private void initialize() {
getStyleClass().add(STYLE_CLASS);
style.addListener((observable, oldValue, newValue) -> {
if (newValue == Styles.STYLE1) {
STYLESHEET = getClass().getResource("dynamic1.css").toString();
} else {
STYLESHEET = getClass().getResource("dynamic2.css").toString();
}
impl_reapplyCSS();
System.out.println("Style Changed");
});
}
public Styles getDynamicStyle() {
return style.get();
}
public ObjectProperty<Styles> dynamicStyleProperty() {
return style;
}
public void setDynamicStyle(Styles style) {
this.style.set(style);
}
@Override
public String getUserAgentStylesheet() {
System.out.println("getUserAgentStylesheet Called");
return STYLESHEET;
}
}
EXAMPLE 2
import custombutton.DynamicButton;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import static custombutton.DynamicButton.Styles.STYLE1;
import static custombutton.DynamicButton.Styles.STYLE2;
public class Test extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
StackPane pane = new StackPane();
DynamicButton dynamicButton = new DynamicButton("TO CHANGE");
Button button = new Button("CHANGE!");
button.setOnAction(event -> {
dynamicButton.setDynamicStyle(
dynamicButton.getDynamicStyle() == STYLE1 ? STYLE2 : STYLE1
);
});
VBox box = new VBox(40, dynamicButton, button);
box.setAlignment(Pos.TOP_CENTER);
box.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
pane.getChildren().add(box);
primaryStage.setScene(new Scene(pane, 800, 600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
package custombutton;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Node;
import javafx.scene.control.Button;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class DynamicButton extends Button {
private final String STYLE_CLASS = "dynamic-button";
private String STYLESHEET = getClass().getResource("dynamic1.css").toString();
public static enum Styles {
STYLE1,
STYLE2
}
private final ObjectProperty<Styles> style = new SimpleObjectProperty<>(Styles.STYLE1);
public DynamicButton() {
initialize();
}
public DynamicButton(String text) {
super(text);
initialize();
}
private void initialize() {
getStyleClass().add(STYLE_CLASS);
style.addListener((observable, oldValue, newValue) -> {
if (newValue == Styles.STYLE1) {
STYLESHEET = getClass().getResource("dynamic1.css").toString();
} else {
STYLESHEET = getClass().getResource("dynamic2.css").toString();
}
try {
Method method = Node.class.getDeclaredMethod("reapplyCss");
method.setAccessible(true);
Object call = method.invoke(this);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
System.out.println("Style Changed");
});
}
public Styles getDynamicStyle() {
return style.get();
}
public ObjectProperty<Styles> dynamicStyleProperty() {
return style;
}
public void setDynamicStyle(Styles style) {
this.style.set(style);
}
@Override
public String getUserAgentStylesheet() {
System.out.println("getUserAgentStylesheet Called");
return STYLESHEET;
}
}
CSS FILES
dynamic1.css
.dynamic-button {
-fx-border-color: blue;
}
dynamic2.css
.dynamic-button {
-fx-border-color: red;
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Since the CSS file is cached in STYLESHEET, the only way to update the control's style is to call getStylesheets().setAll(STYLESHEET);
FREQUENCY : always
- links to
-
Review openjdk/jfx/525