SWT: forma agnóstica de OS de obtener una fuente de espacio único

¿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 fonts 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 fonts en la documentación JDK de las API relacionadas con Internationalization Support , el concepto de fonts lógicas se usa para definir ciertas fonts independientes de plataforma que se asignan a fonts físicas en los archivos de configuración de fuente predeterminados:

La Plataforma Java define cinco nombres de fonts lógicas que cada implementación debe admitir: Serif, SansSerif, Monospaced, Dialog y DialogInput. Estos nombres de fonts lógicas se asignan a fonts 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 fonts 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 …

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

Editar: Advertencia (basado en el comentario de @Lii): obtendrá la Fuente de texto configurada, que puede ser modificada por el usuario y puede no ser una fuente monoespaciada. Sin embargo, será coherente con, por ejemplo, la fuente utilizada en el editor y la consola, que es probablemente lo que desea.

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, al comparar los archivos de mapeo de fonts en un par de directorios JRE lib, puedo ver que no están definidos de manera consistente.

Puedes cargar tus propias fonts, pero eso parece un poco inútil dado que sabes que la plataforma viene con lo que necesitas.

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 fonts 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 icons de devanados.

El mejor enfoque puede ser simplemente tomar su mejor estimación en base a una lista blanca de mapeo de fonts / 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 fuente, 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)