【问题标题】:JavaFx Could not load @font-face font because of com.sun.javafx.css.StyleManager loadStylesheetUnPrivileged由于 com.sun.javafx.css.StyleManager loadStylesheetUnPrivileged,JavaFx 无法加载 @font-face 字体
【发布时间】:2016-03-06 07:24:24
【问题描述】:

我已经问过一个类似的问题here,但似乎不清楚,因为我在项目中有很多代码,无法在这里发布所以不要标记为重复。

因此,我决定创建一个新项目,其中只有一个标签,以使代码小而干净,并消除其他潜在的嫌疑人我得到的错误。

这是我的Java源代码

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        Group root = new Group();

        Label label = new Label("Sample Label");
        label.setId("sampleLabel");
        root.getChildren().add(label);

        Scene scene = new Scene(root, 300, 275);
        scene.getStylesheets().add(getClass().getResource("applicationStyles.css").toExternalForm());
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

这是我的css文件

/**/
@font-face {
    font-family:'Roboto';
    src:url("Roboto-Thin.ttf");
}
#sampleLabel{
    -fx-font-family: Roboto ;
}

这是我在 Intellij Idea 中遇到的错误

Dec 02, 2015 9:16:34 AM com.sun.javafx.css.StyleManager loadStylesheetUnPrivileged
INFO: Could not load @font-face font [file:/C:/Users/UserName/Desktop/Java8%20projects/TeamViewer/out/production/TeamViewer/sample/Roboto-Thin.ttf]

所有项目文件都在一个包中,字体文件也存在于 out>production>TeamViewer>sample>Roboto-Thin.ttf 中。我也从 jdk-8u65 升级到 jdk-8u66

谢谢,非常感谢任何帮助。

【问题讨论】:

  • 你在使用maven资源过滤吗?我刚刚遇到了同样的问题,结果证明是由 Maven 过滤引起的,因为我忘记将它们排除在过滤之外。
  • @MajedAbdulaziz 非常感谢您的回复,但我没有使用 maven,我认为这不是我的原因。
  • Roboto-Thin.ttf 相对于您的源文件和编译的类文件位于何处?
  • @hotzst 他们都在同一个文件夹out>production>TeamViewer>sample>Main.classout>production>TeamViewer>sample>Roboto-Thin.ttf
  • 如果您将项目移动到其他位置,其中没有包含空格的路径 (Java8%20projects),这会有所不同吗?如果您将应用程序打包到一个 jar 文件中并运行该文件会怎样?

标签: java javafx java-8 javafx-2 javafx-8


【解决方案1】:

我找到了可能的原因和解决方法: 在后台,css-loader 使用函数 Font.loadFont 在 CSS 中加载字体。 Font.loadFont 如果失败则简单地返回 null,这会给出“警告”。

这个函数似乎不适用于%20 它的路径/url 字符串。 所以你需要解析路径,然后用空格替换它。 这意味着您将不得不使用代码而不是 CSS(目前)加载字体。

在 Clojure 中,我的解决方法如下所示:

(require '[clojure.java.io :as cio])
(require '[clojure.string :as s])
(-> "fonts/SourceCodePro-Regular.ttf" 
  cio/resource 
  str 
  (s/replace "%20" " ") 
  (javafx.scene.text.Font/loadFont  10.))

;-)

【讨论】:

  • 我已经通过删除空间来摆脱 %20 来解决它,但这也解决了问题。非常感谢 +1
【解决方案2】:

我正在为 Eclipse 使用 e(fx)clipse 插件,它无法将您的 CSS 文件识别为有效的 JavaFX CSS。但是,当我启动程序时,我没有遇到异常,它只是使用默认字体。

通过以下更改,正在加载和显示字体。

/**/
@font-face {
    font-family: Roboto; /* removed '' */
    src: url("Roboto-Thin.ttf");
}
#sampleLabel{
    -fx-font-family: Roboto ; /* added -fx- prefix */
}

【讨论】:

  • 感谢您的回复,但我仍然遇到同样的错误,也很抱歉我忘记了 -fx- 前缀但我刚刚添加了它
  • 可能是 Intellij Idea 的问题
  • 您是否尝试过在没有 IDE 的情况下使用纯 javac/java 编译/运行它?刚刚自己尝试过,甚至你原来的 CSS 也能正常工作。
  • 我想,即使是 eclipse 也可以工作,但我需要 IntelliJ Idea 的解决方案,而且它最初工作得很好,但突然停止了。
  • 我今天遇到了这个问题。即使多年后我可以添加我的一点。如果您使用的是 Maven 和 IntelliJ Idea,我发现在导入字体文件后手动重新导入 maven 项目很有帮助。在那之后它起作用了。
【解决方案3】:

所以,差不多 2 年后,我遇到了自己对我仍然遇到的同样问题的回应。

但是,在研究了com.sun.javafx.css.StyleManager 的源代码之后,现在我有了一个更酷、更优雅的解决方案:只需自己解析样式表并加载字体。

在此处查看相关源代码:lines 932-662

(是的,这一切都在 Clojure 中,但我相信你能弄明白。)

我从这个开始:

(defn add-stylesheet [^Scene scene path]
  (let [logger (Logging/getCSSLogger)
        level (.level logger)]
    (.setLevel logger PlatformLogger$Level/OFF)  ;; turn off logger
    (-> scene .getStylesheets (.add path))  ;; set stylesheet
    (.setLevel logger level) ;; turn logger back on
    (-> path stylesheet-parsed load-fonts))) ;; parse and load fonts

(由于某种原因,关闭日志记录不起作用)。

样式表是这样解析的:

(defn stylesheet-parsed [path]
  (.parse (CSSParser.) (cio/resource path)))

最后字体是这样加载的:

(defn- load-fonts [^Stylesheet stylesheet]
  (doseq [^FontFace fontface (.getFontFaces stylesheet)]
    (doseq [^FontFace$FontFaceSrc ffsrc (.getSources fontface)]
      (let [src (-> ffsrc .getSrc (cs/replace "%20" " "))] ;; <- sanitizing path for Font/getFont
        (println "Loading font:" src)
        (let [f (Font/loadFont src 10.)]
          (println "Font loaded:" f))))))

这很好用,看起来很像原版。一个优点是这里我们不只检查类型 URL,所以理论上我们可以扩展它以更广泛地处理 @font-face。

这里是 load-fonts 的更 Clojure-y 实现,它返回所有已加载字体的列表:

(defn- load-fontface-src [^FontFace$FontFaceSrc ffsrc]
  (-> ffsrc .getSrc (cs/replace "%20" " ") (Font/loadFont 10.)))

(defn- load-fontface [^FontFace ff]
  (map load-fontface-src (.getSources ff)))

(defn- load-fonts [^Stylesheet stylesheet]
  (vec (flatten (map load-fontface (.getFontFaces stylesheet)))))

以及所需的进口:

(import
  '[com.sun.javafx.css.parser CSSParser]
  '[com.sun.javafx.css Stylesheet FontFace FontFace$FontFaceSrc]
  '[com.sun.javafx.util Logging]
  '[sun.util.logging PlatformLogger$Level])

待办事项:
1. 记录日志。 (这很烦人,虽然只是开发中的一个问题。)
2. 测试看看是否有字体没有被加载,然后才进行替代解析加载。但是,简单的检查可能需要与实际加载字体一样多的处理时间。

修复: 在flatten左侧添加vec,保证实现惰性seqs。

【讨论】:

    【解决方案4】:

    对于那些 - 像我一样 - 仍然有这个问题并且不想或不知道如何使用 Clojure 的人,这里是如何在 Java 中做到这一点:
    在将样式表添加到您的场景之前,请使用 Font.loadFont(getClass().getResourceAsStream([fontpath...]), [Some font-size, for example 12]);
    然后字体将在 JavaFX 中注册,您可以将 -fx-font-family css-Property 与加载的字体一起使用。

    【讨论】:

      【解决方案5】:

      在我的情况下,这是由字体文件名中的“-”字符产生的,用“_”替换它就可以了。

      我确定字体系列必须是相同的文件名,但替换所有特殊字符“”(空格)并拆分驼峰式单词。

      所以:

      之前(不工作):

      @font-face {
          font-family: 'RifficFree Bold';
          src: url("../fonts/RifficFree-Bold.ttf");
      }
      .bingo-number, .label{
          -fx-font-family: 'RifficFree Bold';
      }
      

      之后(工作):

      @font-face {
          font-family: 'Riffic Free Bold';
          src: url("../fonts/RifficFree_Bold.ttf");
      }
      .bingo-number, .label{
          -fx-font-family: 'Riffic Free Bold';
      }
      

      【讨论】:

        猜你喜欢
        • 2016-03-02
        • 2016-12-24
        • 1970-01-01
        • 2010-11-22
        • 2013-01-15
        • 1970-01-01
        • 2016-02-07
        • 2019-06-02
        • 2011-05-02
        相关资源
        最近更新 更多