3

作为背景,我意识到 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 的其他建议。

4

2 回答 2

3

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

在@font-face

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

在字体.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

于 2013-08-06T20:35:28.967 回答
3

更新:正如所指出的,原始答案没有直接回答 OP 的问题。如果有人感兴趣,我已经创建了一篇关于原始技术的博客文章。

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

(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 中,如果在需要双精度的情况下使用整数,程序将失败并显示不太有用的错误消息。

于 2013-08-07T17:53:42.307 回答