Globale Variable (Font)

Status
Nicht offen für weitere Antworten.

Turkey1976

Mitglied
Ich möchte in meiner Main ein Font laden. Darauf möchte ich von allen anderen Objekten zugreifen können. Also im Sinne einer globalen Variablen oder Konstanten.

Wie mache ich das?

Gruß

Heiko

Jaja, ich weiß, dies widerspricht den Idealen der objektorientierten Programmierung....
 
getter und setter Methoden einbauen? Dann gibts auch kein Problem mit der Objektorientierung.
 
Codebeispiel? Wenn das Font der Main bekannt ist kannst du es mit einer getter Methode auch für andere Klassen abrufbar machen.
 
Ein Codebeispiel ist zu aufwendig... ich ergänze ein altes Projekt.

wie ist der Aufruf aus einem beliebigen Objekt? Wie heißt meine Main? 🙂
 
Du meinst, du willst den Klassen, die den Font brauchen, nicht immer Referenzen (zur Main) mitgeben? Hast du darüber nachgedacht, den Font einfach static zu machen? (Wahrscheinlich werden hier jetzt Kommentare folgen, die das als Misshandlung objektorientierter Programmierung geißeln werden, aber hey; übertreibt nicht 😉 )
 
Ja, genau! In verschiedenen Klassen steht bei mir Folgendes:


Code:
Font font;
ClassLoader cl =ClassLoader.getSystemClassLoader();     
InputStream in = this.getClass().getResourceAsStream("font.TTF");      	  	
try {font = Font.createFont(java.awt.Font.TRUETYPE_FONT, in);}catch(Exception e){ font = null;}
font=font.deriveFont(Font.PLAIN,size);
g.setFont(font);


Und wenn ich mehrere Objekte aus diesen Klassen erzeuge, wird bei einem vollständigen RePaint das Applet sehr sehr langsam. Verständlicherweise, da ja das Font immer wieder neu geladen wird!

Wenn ich jetzt aber in die Main folgenden Code eingebe:


Code:
    public static Font myfont() {
		Font font;
		ClassLoader cl =ClassLoader.getSystemClassLoader();     
		InputStream in = this.getClass().getResourceAsStream("font.TTF");      	  	
		try {font = Font.createFont(java.awt.Font.TRUETYPE_FONT, in);}catch(Exception e){ font = null;}
		font=font.deriveFont(Font.PLAIN,10);
		return font;	  
    }

erhalte ich beim Compilieren folgende Fehlermeldung:


compile:
[javac] Compiling 1 source file to /Applications/xampp/xamppfiles/htdocs/wb_e7/build
[javac] /Applications/xampp/xamppfiles/htdocs/wb_e7/source/Main.java:12: non-static variable this cannot be referenced from a static context
[javac] InputStream in = this.getClass().getResourceAsStream("font.TTF");
[javac] ^
[javac] Note: /Applications/xampp/xamppfiles/htdocs/wb_e7/source/Main.java uses or overrides a deprecated API.
[javac] Note: Recompile with -Xlint:deprecation for details.
[javac] 1 error

BUILD FAILED

Wie kann ich das Problem umschiffen? Das "font.TTF" liegt im JAR.


Gruß Heiko
 
Ich habe noch ein wenig rumprobiert, komme aber einfach nicht weiter! Wer kann mir helfen?

Heiko
 
Code:
public static Font myfont() { 
      Font font; 
      ClassLoader cl =ClassLoader.getSystemClassLoader();      
      InputStream in = cl.getResourceAsStream("font.TTF");               
      try {font = Font.createFont(java.awt.Font.TRUETYPE_FONT, in);}catch(Exception e){ font = null;} 
      font=font.deriveFont(Font.PLAIN,10); 
      return font;     
    }

musst nur dran denken, die font auch wirklich nur einmal zu laden. also nicht einfach nur in eine statische methode auslagern, sondern auch noch in einer statischen variable speichern und wirklich nur einmal laden.
 
Du kannst es auch so machen:
Code:
public class FontHolder{

  private static Font font = null;

  static{
      Font font;
      ClassLoader cl =ClassLoader.getSystemClassLoader();     
      InputStream in = cl.getResourceAsStream("font.TTF");               
      try {
        font = Font.createFont(java.awt.Font.TRUETYPE_FONT, in);
        font=font.deriveFont(Font.PLAIN,10);
      }catch(Exception e){
        font = null;
      }
  }

  public static Font getFont(){
    return font;
  }

}

Hier wird der Font beim Laden der Klasse erzeugt und du brauchst dich um nichts mehr kümmern.
 
Habe ich das jetzt richtig verstanden: Das Font wird beim erstmaligen Laden der Klasse geladen und nicht bei jedesmal wenn ich ein Objekt daraus erzeuge?
 
Ja. Trotzdem (!) sollte man die FontHolder-Klasse ergänzen um einen privaten Konstruktor
Code:
public class FontHolder
{
   /* private constructor to avoid instantiation */
   private FontHolder() {}

   private static Font font = null; 
   static{
      Font font; 
      ...
}
damit niemand auf die Idee kommt, sich Objekte einer Klasse zu erzeugen, von der es eigentlich keine Objekte geben muss (und darum auch nicht geben sollte oder darf)
 
Kurz zur Erklärung:
Code:
static{

}

ist ein statischer Initialisierungsblock, der eben nur einmalig beim erstmaligen Laden der Klasse aufgerufen wird.
Es gibt auch normale Initialisierungsblöcke:
Code:
public class Initializer{

  //init
  {
    System.out.println("init");
  }

  public Initializer(){
    super();
    System.out.println("Konstruktor");
  }
}

Bei diesem Beispiel wird jedes mal beim Erzeugen eines neuen Objektes der Block ausgeführt, und zwar gleich nach dem super Aufruf des Konstruktors (oder this).
Also würde
Code:
 new Initializer();
diese Ausgabe produzieren:
Code:
init
Konstruktor

statische Initialisierungsblöcke werden sehr gerne beim Einbinden von C-Bibliotheken verwendet:
Code:
static{
  System.load("lib_name");
}
 
Also ich habe jetzt die Klasse:


Code:
import java.io.*;
import java.awt.font.*;
import java.awt.*;

public class FontHolder{ 

 private FontHolder() {} 

 private static Font font = null; 
  
  

  static{ 
      Font font;
      ClassLoader cl =ClassLoader.getSystemClassLoader();      
      InputStream in = cl.getResourceAsStream("font.TTF");                
      try { 
        font = Font.createFont(java.awt.Font.TRUETYPE_FONT, in); 
        font=font.deriveFont(Font.PLAIN,10); 
      }catch(Exception e){ 
        font = null; 
      } 
  } 

  public static Font getFont(){ 
     return font;
  
  } 

}


Wenn ich aus anderen Klassen den Aufruf


Code:
	FontHolder fh = new FontHolder();
	Font font = fh.getFont();

mache, erhalte ich lediglich das NULL Objekt zurück :-(



---------------


Die Ergänzung der FontHolder Klasse um


Code:
 private FontHolder() {}
bringt mir beim Compilieren folgenden Fehlercode:


[javac] /Applications/xampp/xamppfiles/htdocs/wb_e7/source/TextTool.java:110: FontHolder() has private access in FontHolder
[javac] FontHolder fh = new FontHolder();
 
Code:
new FontHolder();
ist auch falsch, du musst so den Font holen:
Code:
FontHolder.getFont();
da getFont ja statisch ist.

gib mal im catch-Block den Stacktrace der Exception aus:
Code:
  static{     
      ClassLoader cl =ClassLoader.getSystemClassLoader();     
      InputStream in = cl.getResourceAsStream("font.TTF");               
      try {
        font = Font.createFont(java.awt.Font.TRUETYPE_FONT, in);
        font=font.deriveFont(Font.PLAIN,10);
      }catch(Exception e){
        e.printStackTrace();
        font = null;
      }
  }

//Edit, du musst natürlich Font font; weg lassen! (im initializer-Block)
 
Das gibt mir die JAVA Console aus:

java.io.IOException: Stream closed
at java.io.BufferedInputStream.getInIfOpen(BufferedInputStream.java:134)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:254)
at java.io.BufferedInputStream.read(BufferedInputStream.java:313)
at java.awt.Font$1.run(Font.java:746)
at java.security.AccessController.doPrivileged(Native Method)
at java.awt.Font.createFont(Font.java:732)
at FontHolder.<clinit>(FontHolder.java:18)
 
Ich darf noch hinzufügen, dass das Laden des Fonts innerhalb der Objekte, in denen die Schrift benötigt wird, auch problemlos funktionierte.


Meine Klasse sieht im Moment so aus:


Code:
import java.io.*;
import java.awt.font.*;
import java.awt.*;

public class FontHolder{ 

 private FontHolder() {} 

 private static Font font = null; 
  
  

  static{ 
    //  Font font;
      ClassLoader cl =ClassLoader.getSystemClassLoader();      
      InputStream in = cl.getResourceAsStream("font.TTF");                
      try { 
        font = Font.createFont(java.awt.Font.TRUETYPE_FONT, in); 
        font=font.deriveFont(Font.PLAIN,10); 
      }catch(Exception e){ 
       
       e.printStackTrace();
       font = null; 
      } 
      if (font==null) {System.out.println("Font wurde NICHT geladen");}
  } 
  public static Font getFont(){ 
     return font;
  } 
}

In der 6letzen Zeile Frage ich ab, ob font==null ist. Und genau diesen Output erhalte ich in der Javakonsole.
 
auf statische methoden greift man anders zu.

Code:
FontHolder.getFont();

könnte nicht schaden, mal ein buch für java anfänger zu lesen.
 
könnte nicht schaden, mal ein buch für java anfänger zu lesen.

Lesen schadet selten. :meld:


Was ich als Ungebildeter nicht versehe, wie schaffe ich es denn das Font aus FontHolder in meine Klasse einzubinden?

Code:
FontHolder.getFont();

und dann?

ich hätte jetzt erwartet:

Code:
Font myFont = FontHolder.getFont();
g.setFont(myFont);

aber das funktioniert halt nicht...
 
Hm. Der Aufruf ist schon richtig. Wo genau die IOException herkommt ... ???:L hm.

Wenn du 100% (nicht 99.9% sondern 100%) sicher bist, dass er die "font.TTF" auch wirklich findet, könnte ich mir höchstens vorstellen, dass er bei der statischen Initialisierung irgendwie mit dem ClassLoader durcheinanderkommt. Du könntest die Klasse ggf. auch mal schreiben als
Code:
import java.io.*;
import java.awt.font.*;
import java.awt.*;

public class FontHolder{

private FontHolder() {}

   private static Font font = null;
 
  public static Font getFont()
  {
    if (font == null)
    {
      //  Font font;
      ClassLoader cl =ClassLoader.getSystemClassLoader();     
      InputStream in = cl.getResourceAsStream("font.TTF");               
      try {
        font = Font.createFont(java.awt.Font.TRUETYPE_FONT, in);
        font=font.deriveFont(Font.PLAIN,10);
      }catch(Exception e){
       
       e.printStackTrace();
       font = null;
      }
      if (font==null) {System.out.println("Font wurde NICHT geladen");}
    }

     return font;
  }
}

Aber das ist nur ins blaue geraten :? vielleicht hat jemand noch eine bessere Idee...
 
forulieren wir es mal so:

als sich der Code zum Laden des Fonts noch in der eigentlichen Klasse befand, funktionierte alles gut - bis auf dass bei 100 Instanzen das Applet äußerst zäh war 🙂

Also der folgende Code funktionierte definitiv:


Code:
Font font;
ClassLoader cl =ClassLoader.getSystemClassLoader();     
InputStream in = this.getClass().getResourceAsStream("font.TTF");      
try {font = Font.createFont(java.awt.Font.TRUETYPE_FONT, in);}catch(Exception e){ font = null;}
font=font.deriveFont(Font.PLAIN,size);
g.setFont(font);
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben