在JavaFX+中加载自定义字体;Clojure

在JavaFX+中加载自定义字体;Clojure,java,css,fonts,clojure,javafx,Java,Css,Fonts,Clojure,Javafx,作为背景,我意识到还有大约5篇关于堆栈溢出的文章,但我已经看了回复,研究了无数个小时,没有真正的解决方案。否则我就不会在这里发帖了 我是JavaFX新手,我喜欢Clojure,所以我使用来自Github的chrisx的CLJJavaFX项目作为JavaFX的Clojure包装器。大多数操作都非常有效,例如在场景/舞台上放置组件,并使用CSS设置它们的样式。只有一个问题:我想导入自定义字体,但到目前为止我还无法导入 我试过多种方法。我尝试的第一件事的Java版本是: Font.loadFont(&

作为背景,我意识到还有大约5篇关于堆栈溢出的文章,但我已经看了回复,研究了无数个小时,没有真正的解决方案。否则我就不会在这里发帖了

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

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

Font.loadFont(<myClass>.class.getResource("mpsesb.ttf").toExternalForm(), 14);
它可以很好地打印.ttf文件的URL。 然后我尝试使用该URL并将其用作Font.loadFont方法中的参数,但没有成功。在认真研究了100种点运算符和Java方法及类的排列之后,我得到了以下结果,与我尝试的其他组合不同,我没有打印任何错误:

(Font/loadFont "fonts/ttf/mpsesb.ttf")
但是它只返回nil,根据javafxapi,这意味着字体没有实际加载。我甚至尝试了假路径名,它们也返回了无错误的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';
}
大多数JavaFX引用代码都能工作,但现在整个JavaFX.scene.control包都不能工作,这意味着没有标签、按钮、文本字段等等

> (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)
有关这些错误的可能参考信息,请访问。基本上,要点是JavaFX8只是测试版,所以我们不能期望它100%工作。嗯

我打开了一个关于JIRA的问题:。一旦这个问题得到解决,我可以更全面地探讨@jewelsea的其他建议。

这些建议大多是建议,而不是最终的解决方案

@font-face上的

如果可以,请使用。它支持(JavaFX的早期版本如2.2不支持)。它还有一个经过改进的字体系统,可能会更健壮一些。因为字体可以通过Java8中的css加载,所以可能不需要解决与类位置相关的加载资源问题

在Font.loadFont上

您应该能够在尝试使用时使用
Font.loadFont
方法。javafx2.x在其初始版本中就支持自定义字体。在纯Java中加载JavaFX中的字体有一些步骤:。我知道你已经看过了,但没有帮助——只是把它放在这里作为参考,这样真正了解clojure但不了解JavaFX的人可能会帮助解决这个问题

检查目标字体是否兼容

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

您可能需要进一步帮助


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

更新:正如所指出的,原始答案没有直接回答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中有一件事一直让我感到困惑,那就是它需要
双参数,比如
Font/loadFont
。我习惯于Java将整型参数提升为双精度。在Clojure中,如果使用需要双精度的整数,程序将失败,并显示一条不太有用的错误消息。

对于Java 8,JavaFX类位于标准默认类路径上,因此不应将它们导入maven存储库。我不知道SublimeREPL是如何工作的,但我认为只要使用Java8JRE启动它,它就能够自动找到JavaFX类。您链接的论坛线程与您遇到的类未找到问题无关。Java8是早期的访问方式,但大体上来说,创建按钮之类的基本功能是没有问题的。关于让JavaFX 8与Clojure一起使用,您可能需要创建一个单独的StackOverflow问题。我认为alex正在尝试加载Windows上未安装但其应用程序附带的字体(JavaFX文本教程的一节)。@jewelsea:是的,原始答案并不适用。我删除了它,写了一些更适用的东西。
> (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)
(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))