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