首页 文章

在JavaFX Clojure中加载自定义字体

提问于
浏览
2

作为背景,我意识到Stack Overflow上还有大约5篇关于此问题的文章,我已经查看了这些回复,并且在没有真正解决方案的情况下研究了无数个小时 . 否则我不会在这里发布 .

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

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

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

我尝试使用Java互操作在Clojure中做到这一点,但我不确定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磅的默认字体(Lucida Grande) .

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

编辑:

谢谢,@ jewelsea . 在阅读了你所写的内容后,我做的第一件事就是获得Java 8 JDK 8(build 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%工作 . 哼!

I opened an issue on JIRA: https://bugs.openjdk.java.net/browse/JDK-8093894. Once this gets addressed I can more fully explore @jewelsea 's other suggestions.

2 回答

  • 2

    这些主要是建议而不是明确的解决方案

    On @font-face

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

    On Font.loadFont

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

    Check that your target font is compatible

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

    You may need further help

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

  • 2

    Update: 正如所指出的那样,原来的答案没有直接回答OP 's question. I'已经创建了一个关于原始技术的情况,以防任何人感兴趣 .

    这是一个做你想要的短程序 .

    (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))
    

    在这个项目中,我将字体文件放在 resourcesdemo 的子目录中 - 存储了Clojure源 - 因此函数 get-font-from-resource 中的"prefix" .

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

    Tip :你可能知道这一点,但有一点不断让我困惑的是JavaFX中需要 double 参数的方法,比如 Font/loadFont . 我习惯于Java只是将整数参数提升为double . 在Clojure中,如果使用需要double的整数,程序将失败并显示一条不太有用的错误消息 .

相关问题