Zio*_*yte 8 css resources stylesheet embedded-resource javafx-8
是否可以将整个样式表包装在字符串中并将其应用于某个节点?用例是为PseudoClass添加特定(非变化)行为.我知道我可以使用pane.getStylesheets().add(getClass().getResource("mycss.css").toExternalForm());,但我想知道是否有某种方法可以直接将其嵌入源代码中; 一些事情:
pane.getStylesheets().add(
".button:ok { -fx-background-color: green; }\n"+
".button:ko { -fx-background-color: red; }");
Run Code Online (Sandbox Code Playgroud)
Zio*_*yte 10
我通过定义新的URL连接找到了一种方法:
private String css;
public void initialize() {
...
// to be done only once.
URL.setURLStreamHandlerFactory(new StringURLStreamHandlerFactory());
...
}
private void updateCss(Node node) {
// can be done multiple times.
css = createCSS();
node.getStylesheets().setAll("internal:"+System.nanoTime()+"stylesheet.css");
}
private class StringURLConnection extends URLConnection {
public StringURLConnection(URL url){
super(url);
}
@Override public void connect() throws IOException {}
@Override public InputStream getInputStream() throws IOException {
return new StringBufferInputStream(css);
}
}
private class StringURLStreamHandlerFactory implements URLStreamHandlerFactory {
URLStreamHandler streamHandler = new URLStreamHandler(){
@Override protected URLConnection openConnection(URL url) throws IOException {
if (url.toString().toLowerCase().endsWith(".css")) {
return new StringURLConnection(url);
}
throw new FileNotFoundException();
}
};
@Override public URLStreamHandler createURLStreamHandler(String protocol) {
if ("internal".equals(protocol)) {
return streamHandler;
}
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
显然,协议"内部"可以是任何(非冲突)格式良好的字符串,并且(在这个简单的示例中)文件路径被强制忽略.
我用它来设置全局.css,所以我不需要记住多个字符串.似乎Stream只打开了一次,但我不知道在所有情况下是否都适用.
随意根据需要使代码复杂化;)
这种方法可以归功于Jasper Potts(参见本例)
这是我基于ZioBytre答案的CSS更新器类(+1效果很好)。
这是一个自包含类,可以轻松将其复制到项目并按原样使用。
它依赖于commons IO IOUtils类以返回Stream基于的a String。但是,如果需要,可以很容易地内联或替换为另一个库。
我在一个项目中使用该类,在该项目中,可以在服务器端的应用程序内部动态编辑CSS,并将其推送到JavaFX客户端。它可以用于CSS字符串不是来自文件或URL而是来自另一个来源(服务器应用程序,数据库,用户输入...)的任何情况。
它具有绑定字符串属性的方法,以便CSS更改在发生更改后立即自动应用。
/**
* Class that handles the update of the CSS on the scene or any parent.
*
* Since in JavaFX, stylesheets can only be loaded from files or URLs, it implements a handler to create a magic "internal:stylesheet.css" url for our css string
* see : https://github.com/fxexperience/code/blob/master/FXExperienceTools/src/com/fxexperience/tools/caspianstyler/CaspianStylerMainFrame.java
* and : http://stackoverflow.com/questions/24704515/in-javafx-8-can-i-provide-a-stylesheet-from-a-string
*/
public class FXCSSUpdater {
// URL Handler to create magic "internal:stylesheet.css" url for our css string
{
URL.setURLStreamHandlerFactory(new StringURLStreamHandlerFactory());
}
private String css;
private Scene scene;
public FXCSSUpdater(Scene scene) {
this.scene = scene;
}
public void bindCss(StringProperty cssProperty){
cssProperty.addListener(e -> {
this.css = cssProperty.get();
Platform.runLater(()->{
scene.getStylesheets().clear();
scene.getStylesheets().add("internal:stylesheet.css");
});
});
}
public void applyCssToParent(Parent parent){
parent.getStylesheets().clear();
scene.getStylesheets().add("internal:stylesheet.css");
}
/**
* URLConnection implementation that returns the css string property, as a stream, in the getInputStream method.
*/
private class StringURLConnection extends URLConnection {
public StringURLConnection(URL url){
super(url);
}
@Override
public void connect() throws IOException {}
@Override public InputStream getInputStream() throws IOException {
return IOUtils.toInputStream(css);
}
}
/**
* URL Handler to create magic "internal:stylesheet.css" url for our css string
*/
private class StringURLStreamHandlerFactory implements URLStreamHandlerFactory {
URLStreamHandler streamHandler = new URLStreamHandler(){
@Override
protected URLConnection openConnection(URL url) throws IOException {
if (url.toString().toLowerCase().endsWith(".css")) {
return new StringURLConnection(url);
}
throw new FileNotFoundException();
}
};
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
if ("internal".equals(protocol)) {
return streamHandler;
}
return null;
}
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
StringProperty cssProp = new SimpleStringProperty(".root {-fx-background-color : red}");
FXCSSUpdater updater = new FXCSSUpdater(scene);
updater.bindCss(cssProp);
//new style will be applied to the scene automatically
cssProp.set(".root {-fx-background-color : green}");
//manually apply css to another node
cssUpdater.applyCssToParent(((Parent)popover.getSkin().getNode()));
Run Code Online (Sandbox Code Playgroud)