java - que - ateísmo agnóstico
SWT: forma agnóstica de OS de obtener una fuente de espacio único (5)
¿Hay alguna manera en SWT de obtener una fuente monoespaciada simplemente, que funcione en varios sistemas operativos?
Por ejemplo. esto funciona en Linux, pero no en Windows:
Font mono = new Font(parent.getDisplay(), "Mono", 10, SWT.NONE);
o ¿necesito tener un método que intente cargar fuentes variables (Consolas, Terminal, Monaco, Mono) hasta que uno no sea nulo? Alternativamente, podría especificarlo en un archivo de propiedades al inicio.
Intenté obtener la fuente del sistema desde la pantalla, pero no estaba monoespaciado.
De acuerdo con la sección sobre archivos de configuración de fuentes en la documentación JDK de las API relacionadas con Internationalization Support , el concepto de fuentes lógicas se usa para definir ciertas fuentes independientes de plataforma que se asignan a fuentes físicas en los archivos de configuración de fuente predeterminados:
La Plataforma Java define cinco nombres de fuentes lógicas que cada implementación debe admitir: Serif, SansSerif, Monospaced, Dialog y DialogInput. Estos nombres de fuentes lógicas se asignan a fuentes físicas de formas dependientes de la implementación.
Entonces en tu caso, probaría
Font mono = new Font(parent.getDisplay(), "Monospaced", 10, SWT.NONE);
para obtener un control sobre la fuente física monoespaciada de la plataforma actual en la que se está ejecutando su código.
Editar : Parece que SWT no sabe nada sobre fuentes lógicas (el error 48055 en eclipse.org describe esto en detalle). En este informe de error se sugirió una solución provisional, donde el nombre de la fuente física se puede recuperar de una fuente AWT ...
Según mi leal saber y entender, la AWT API no expone la información de fuente subyacente. Si puede acceder a ella, esperaría que dependa de la implementación. Ciertamente, comparando los archivos de mapeo de fuentes en un par de directorios JRE lib, puedo ver que no están definidos de manera consistente.
Puede cargar sus propias fuentes, pero eso parece un desperdicio dado que sabe que la plataforma viene con lo que necesita.
Este es un truco que carga una fuente JRE:
private static Font loadMonospacedFont(Display display) {
String jreHome = System.getProperty("java.home");
File file = new File(jreHome, "/lib/fonts/LucidaTypewriterRegular.ttf");
if (!file.exists()) {
throw new IllegalStateException(file.toString());
}
if (!display.loadFont(file.toString())) {
throw new IllegalStateException(file.toString());
}
final Font font = new Font(display, "Lucida Sans Typewriter", 10,
SWT.NORMAL);
display.addListener(SWT.Dispose, new Listener() {
public void handleEvent(Event event) {
font.dispose();
}
});
return font;
}
Funciona en IBM / Win32 / JRE1.4, Sun / Win32 / JRE1.6, Sun / Linux / JRE1.6, pero es un enfoque bastante frágil. Dependiendo de sus necesidades de I18N, podría ser un problema allí también (no lo he comprobado).
Otro truco sería probar las fuentes disponibles en la plataforma:
public class Monotest {
private static boolean isMonospace(GC gc) {
final String wide = "wgh8";
final String narrow = "1l;.";
assert wide.length() == narrow.length();
return gc.textExtent(wide).x == gc.textExtent(narrow).x;
}
private static void testFont(Display display, Font font) {
Image image = new Image(display, 100, 100);
try {
GC gc = new GC(image);
try {
gc.setFont(font);
System.out.println(isMonospace(gc) + "/t"
+ font.getFontData()[0].getName());
} finally {
gc.dispose();
}
} finally {
image.dispose();
}
}
private static void walkFonts(Display display) {
final boolean scalable = true;
for (FontData fontData : display.getFontList(null, scalable)) {
Font font = new Font(display, fontData);
try {
testFont(display, font);
} finally {
font.dispose();
}
}
}
public static void main(String[] args) {
Display display = new Display();
try {
walkFonts(display);
} finally {
display.dispose();
}
}
}
Probablemente este no sea un buen enfoque, ya que puede exponerte a problemas de configuración regional. Además, no se sabe si la primera fuente monoespaciada que se encuentra no es un conjunto de iconos de devanados.
El mejor enfoque puede ser simplemente tomar su mejor estimación en base a una lista blanca de mapeo de fuentes / locale y asegurarse de que los usuarios puedan reconfigurar fácilmente la IU a su gusto a través de FontDialog .
Para las personas que tienen el mismo problema, puede descargar cualquier archivo ttf de fuentes, ponerlo en la carpeta de recursos (en mi caso / font / * * .ttf) y agregar este método a su aplicación. Es trabajo 100%.
public Font loadDigitalFont(int policeSize) {
URL fontFile = YouClassName.class
.getResource("/fonts/DS-DIGI.TTF");
boolean isLoaded = Display.getCurrent().loadFont(fontFile.getPath());
if (isLoaded) {
FontData[] fd = Display.getCurrent().getFontList(null, true);
FontData fontdata = null;
for (int i = 0; i < fd.length; i++) {
if (fd[i].getName().equals("DS-Digital")) {
fontdata = fd[i];
break;
}}
if (fontdata != null) {
fontdata.setHeight(policeSize);
fontdata.setStyle(SWT.BOLD);return new Font(getDisplay(), fontdata));}
}return null; }
Si solo quiere una fuente de Monospaced, use "Courier" => new Font(display, "Courier", 10, SWT.NORMAL)
Pasé un tiempo golpeando mi cabeza contra este hasta que me di cuenta de que obviamente el eclipse debe tener acceso a una fuente monoespacial para usar en sus campos de texto, consola, etc. Apareció un poco de excavación:
Font terminalFont = JFaceResources.getFont(JFaceResources.TEXT_FONT);
Lo cual funciona si todo lo que le interesa es obtener alguna fuente monoespacial.
Editar: O basado en el comentario de @ ctron:
Font font = JFaceResources.getTextFont();