【问题标题】:Load Custom Fonts in JavaFX + Clojure在 JavaFX + Clojure 中加载自定义字体
【发布时间】:2013-08-07 23:52:53
【问题描述】:

作为背景,我意识到 Stack Overflow 上还有大约 5 篇关于此的其他帖子,但我查看了回复并研究了无数小时,但没有真正的解决方案。否则我不会在这里发帖。

我是 JavaFX 新手,我喜欢 Clojure,所以我使用 Github 的 chrisx 的 clj-javafx 项目作为 JavaFX 的 Clojure 包装器。大多数操作都很好用,例如将组件放置在场景/舞台上并使用 CSS 对其进行样式设置。只有一个问题:我想导入自定义字体,但目前还没有。

我尝试了多种方法。我尝试的第一件事的Java版本是:

Font.loadFont(<myClass>.class.getResource("mpsesb.ttf").toExternalForm(), 14);

我尝试在 Clojure 中使用 Java 互操作来做到这一点,但我不确定 Clojure 如何处理 Java 类。相反,我使用了 clojure.java.io.resource:

(use '[clojure.java.io :only [resource]])
(resource "mpsesb.tff")

它可以很好地打印 .ttf 文件的 URL。 然后我尝试使用该 URL 并将其用作 Font.loadFont 方法中的参数,但没有成功。在玩弄了 100 种点运算符和 Java 方法和类的排列之后,我得到了以下结果,不会打印任何错误,这与我尝试过的其他组合不同:

(Font/loadFont "fonts/ttf/mpsesb.ttf")

但它只返回 nil,根据 JavaFX API,这意味着字体实际上并未加载。我什至尝试了假路径名,它们也没有错误地返回 nil,所以 Font/loadFont 函数似乎没有我想象的那么有希望。

我终于尝试使用 CSS 来加载字体,而不是使用 Java 来导入它:

@font-face {
    font-family: 'MyrProSemiExtBold';
    src: url('file:/Users/<restOfPath>/mpsesb.ttf');
}
.label {
    -fx-font-size: 14px;
    -fx-font-weight: normal;
    -fx-font-family: 'MyrProSemiExtBold';
}

但没有运气。标签仅显示为 14 pt 的默认字体 (Lucida Grande)。

提前感谢您提出的任何建议。

编辑:

谢谢,@jewelsea。阅读您所写的内容后,我做的第一件事是获取 Java 8 + JDK 8(构建 b101)。我正在使用 Sublime Text,所以我让 SublimeREPL 在终端中使用 Maven 识别 JavaFX:

$ mvn deploy:deploy-file -DgroupId=local.oracle -DartifactId=javafxrt -Dversion=8.0 -Dpackaging=jar -Dfile=/System/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/l‌​ib/ext/jfxrt.jar -Durl=file:/Users/vaniificat/.m2/repository

大部分 JavaFX 引用代码都可以工作,但现在整个 javafx.scene.control 包都不能工作,这意味着没有标签、没有按钮、没有 TextFields 等......:

> (import javafx.scene.control.Button)
: NoClassDefFoundError Could not initialize class javafx.scene.control.Button
  java.lang.Class.forName0 (Class.java:-2)
> (import javafx.scene.control.Label)
: NoClassDefFoundError javafx.scene.control.Labeled
  java.lang.Class.forName0 (Class.java:-2)
> (import javafx.scene.control.TextField)
: NoClassDefFoundError javafx.scene.control.Control
  java.lang.Class.forName0 (Class.java:-2)
> (import '(javafx.scene.control Button Label PasswordField TextField))
: NoClassDefFoundError Could not initialize class javafx.scene.control.Button  
  java.lang.Class.forName0 (Class.java:-2)

可以在https://forums.oracle.com/thread/2526150 找到对这些错误的可能参考。基本上要点是 JavaFX 8 仅处于测试阶段,所以我们不能指望它 100% 工作。嗯!

我在 JIRA 上打开了一个问题:https://bugs.openjdk.java.net/browse/JDK-8093894。一旦这个问题得到解决,我就可以更全面地探索@jewelsea 的其他建议。

【问题讨论】:

  • 在 Java 8 中,JavaFX 类位于标准的默认类路径中,因此不应将它们导入 maven 存储库。我不知道 SublimeREPL 是如何工作的,但我认为只要使用 Java 8 JRE 启动它,它就能够自动找到 JavaFX 类。您链接的论坛主题与您遇到的未找到的课程问题无关。 Java8 是早期访问,但总的来说主要是功能性的——创建按钮之类的基本东西是没有问题的。您可能想要创建一个单独的 StackOverflow 问题,以让 JavaFX 8 与 Clojure 一起使用。

标签: java css fonts clojure javafx


【解决方案1】:

更新:正如所指出的,原始答案并未直接回答 OP 的问题。我创建了一个关于原始技术的blog post,以防有人感兴趣。

这是一个简短的程序,可以满足您的需求。

(ns demo.core
  (:gen-class
   :extends javafx.application.Application)
  (:import
   [javafx.application Application]
   [javafx.event EventHandler]
   [javafx.scene Scene]
   [javafx.scene.control Button]
   [javafx.scene.layout StackPane]
   [javafx.scene.text Font])
  (:require [clojure.java.io :as jio]))

(defn- get-font-from-resource
  "Load the named font from a resource."
  [font-name]
  (let [prefix "demo/resources/"
        url (jio/resource (str prefix font-name))
        fnt (Font/loadFont (.toExternalForm url) 20.0)]
    fnt))

(defn -start
  "Build the application interface and start it up."
  [this stage]
  (let [root (StackPane.)
        scene (Scene. root 600 400)
        fnt (get-font-from-resource "ITCBLKAD.TTF")
        btn (Button. "Press Me!")]

     (.setOnAction btn
                   (reify EventHandler
                     (handle [this event]
                       (doto btn
                         (.setText (str "This is " (.getName fnt)))
                         (.setFont fnt)))))

    (.add (.getChildren root) btn)

    (doto stage
      (.setTitle "Font Loading Demo")
      (.setScene scene)
      (.show))))

(defn -main
  [& args]
  (Application/launch demo.core args))

在这个项目中,我将字体文件放在resources 中,这是demo 的子目录——Clojure 源存储的地方——因此是函数get-font-from-resource 中的“前缀”。

看起来您在使用 loadFont 时可能遇到的问题是在您从 URL 转换为 String 表单时。外部形式是从驱动器根目录开始的绝对路径。

提示:您可能知道这一点,但一直困扰我的一件事是 JavaFX 中需要 double 参数的方法,例如 Font/loadFont。我习惯于 Java 只是将整数参数提升为 double。在 Clojure 中,如果在需要双精度的情况下使用整数,则程序会失败并显示不太有用的错误消息。

【讨论】:

  • 我认为 alex 正在尝试加载 Windows 上未安装但随他的应用程序一起提供的字体(JavaFX 文本教程的 Using Custom Fonts 部分)。
  • @jewelsea:是的,原来的答案并不适用。我把它删了,写了一些更适用的东西。
【解决方案2】:

这些大多是建议而不是确定的解决方案

在@font-face

如果可以,请使用Java 8。它支持@font-face css notation(JavaFX 的早期版本,例如 2.2 不支持)。它还具有改进的字体系统,可能会更加强大。因为在 Java 8 中可以通过 css 加载字体,所以您可能不需要解决加载资源与类位置相关的问题。

在 Font.loadFont 上

您应该能够在尝试使用Font.loadFont 方法时使用它。 JavaFX 2.x 从其初始版本开始就支持自定义字体。在纯 Java 中加载 JavaFX 中的字体有一些步骤:How to embed .ttf fonts is JavaFx 2.2?。我知道您已经看过它,但它并没有帮助 - 只是将其包含在此处以供参考,以便真正了解 clojure 但不了解 JavaFX 的人可以帮助解决问题。

检查您的目标字体是否兼容

仔细检查您使用的特定字体是否已加载并在基于 Java 的常规 JavaFX 应用程序中使用(只是为了确保字体文件与您平台上的 JavaFX 系统之间没有不兼容的内容)。

您可能需要更多帮助

我也不知道在 clojure 中加载相关资源是如何工作的(或者您的代码可能存在其他问题) - 但也许 clojure 专家可以发布另一个允许它工作的答案。您可能需要编辑您的问题以包含sscce

【讨论】:

    猜你喜欢
    • 2015-07-04
    • 2016-01-25
    • 2016-07-11
    • 1970-01-01
    • 2018-02-23
    • 2011-09-14
    • 2020-12-10
    • 1970-01-01
    相关资源
    最近更新 更多