2008-10-21 8 views
27

¿Hay alguna manera en SWT de obtener una fuente monoespaciada simplemente, que funcione en varios sistemas operativos?SWT: forma agnóstica del sistema para obtener la fuente monoespaciada

Por ejemplo. esto funciona en Linux, pero no Ventanas:

 

Font mono = new Font(parent.getDisplay(), "Mono", 10, SWT.NONE); 
 

o tengo que tener un método que trata de fuentes de carga variable (Consolas, Terminal, Mónaco, Mono) hasta que uno no es 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.

Respuesta

15

De acuerdo con el apartado de Font Configuration Files en la documentación del JDK de Internationalization Support API relacionados con la PI, el concepto de Logical Font s se usa para definir ciertas fuentes independientes de la plataforma, que se asignan a las fuentes físicas en los archivos de configuración de fuente por defecto:

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.

Así, en su caso, que iba a tratar

Font mono = new Font(parent.getDisplay(), "Monospaced", 10, SWT.NONE);

para obtener un identificador de la fuente solo espacio físico de la plataforma actual su código se está ejecutando.

Editar: Parece que SWT no sabe nada sobre fuentes lógicas (Bug 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 puede recuperarse de una fuente AWT ...

+3

Esto también debe estar disponible como java.awt.Font.MONOSPACED – nos

+0

Parece que proporcionaron una clase [SWTFontUtils] (https://bugs.eclipse.org/bugs/attachment.cgi?id=238603) para esto ahora. – Campa

4

Por lo que yo sé, la API AWT 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 fuentes en un par de directorios JRE lib, puedo ver que no están definidos de manera consistente.

Puede cargar sus propias fuentes, pero parece un desperdicio dado que sabe que la plataforma viene con lo que necesita.

Este es un truco que carga una fuente de 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(); 
     } 
    } 

} 

Esto probablemente no es un buen enfoque, ya que puede dejar expuesto a cuestiones locale. 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 basada en 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 del FontDialog.

+0

Gracias por la respuesta detallada. Creo que la mejor opción es la que usted diga: un predeterminado predeterminado como Courier, que está disponible en todas las plataformas, y le permite al usuario cambiar esta propiedad con un cuadro de diálogo de configuración de fuentes. – JeeBee

+0

¿Hay alguna manera de cargar 'Fuente' del recurso Java o 'InputStream' en lugar de la ruta del archivo en SWT? – parxier

+0

@parxier - no que yo sepa. Esto sería mejor como una nueva pregunta. – McDowell

1

Si sólo desea una utilización de la fuente de espacio sencillo "Courier" =>new Font(display, "Courier", 10, SWT.NORMAL)

35

pasé un tiempo golpeando la cabeza contra éste hasta que me di cuenta de que, obviamente, eclipsar debe tener acceso a una fuente de espacio sencillo para su uso en su texto campos, consola, etc. Un poco de investigación se presentó:

Font terminalFont = JFaceResources.getFont(JFaceResources.TEXT_FONT); 

que funciona si todo lo que te interesa es apoderarse de alguna fuente de espacio sencillo.

Editar: Or basado en comentario de @ ctron:

Font font = JFaceResources.getTextFont(); 
+1

¡Muy bonito! Esta es la única respuesta utilizable aquí – pmf

+6

O incluso un poco más simple: Font font = JFaceResources.getTextFont(); – ctron

+1

** Esto no será necesariamente una fuente monoespaciada. ** Por ejemplo, en una aplicación Eclipse será cualquier fuente que el usuario haya configurado en * Preferencias> General> Colores y fuentes> Básico> Fuente de texto *. Es la misma fuente que utiliza el editor de texto básico en Eclipse. Casi todos los usuarios tendrán una fuente monoespacial, por supuesto, pero no puede estar seguro. – Lii

3

Para las personas que tienen el mismo problema, se puede descargar cualquier archivo TTF, ponerlo en la carpeta de recursos (en mi caso/font/* * .ttf) y añada 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; } 
+0

Esto funcionó para mí en Ubuntu 12.04 + Eclipse 3.7, pero en Windows 7 + Eclipse 4.3 loadFont() devuelve falso cuando su argumento es un paquete de URL en lugar de un archivo. –

+0

Debe saber que la ruta relativa dada "/fonts/DS-DIGI.TTF" está en el directorio de recursos, ¿está utilizando maven? – freesniper

Cuestiones relacionadas