Swing Drucken von JPanel

  • Themenstarter Themenstarter Camino
  • Beginndatum Beginndatum
C

Camino

Gast
Hallo,

ich hab in meiner Anwendung eine Klasse zusammengefrickelt, mit der ich Components (z.B. JPanel) ausdrucken kann:

Java:
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;

import javax.swing.RepaintManager;

public class PrintUtilities implements Printable {
	
    private Component componentToBePrinted;

    public static void printComponent( Component c ) {
      new PrintUtilities(c).print();
    }
   
    public PrintUtilities( Component componentToBePrinted ) {
      this.componentToBePrinted = componentToBePrinted;
    }
   
    public void print() {
    	
      PrinterJob printJob = PrinterJob.getPrinterJob();
      
      PageFormat pageFormat = printJob.defaultPage();  //new PageFormat();
      //pageFormat.setOrientation( PageFormat.LANDSCAPE );   //Längs- oder Querformat (Standard: längs)
      
      Paper a4PortraitPaper = new Paper();
      final double cm2inch = 0.3937;  // 1in = 2.54cm
      double paperHeight = 29.7 * cm2inch;
      double paperWidth = 21.0 * cm2inch;
      double margin = 1.5 * cm2inch;
       
      a4PortraitPaper.setSize( paperWidth * 72.0, paperHeight * 72.0 );
      a4PortraitPaper.setImageableArea( margin * 72.0, margin * 72.0,
                          ( paperWidth - 2 * margin ) * 72.0,
                          ( paperHeight - 2 * margin ) * 72.0 );

      pageFormat.setPaper( a4PortraitPaper );
      
      printJob.setPrintable( this, pageFormat );
      
      if ( printJob.printDialog() )
        try {
          printJob.print();
        } catch( PrinterException pe ) {
          System.out.println( "Error printing: " + pe );
          System.out.println( "Error printing (Message): " + pe.getMessage() );
          System.out.println( "Error printing (Localized Message): " + pe.getLocalizedMessage() );
          System.out.println( "Error printing (Cause): " + pe.getCause() );
        }
        
    }

    
    public int print( Graphics g, PageFormat pageFormat, int pageIndex ) {
    	
    	double gBreite, gHoehe;
    	int b, h;
    	double skalierung = 0.0;
	
      if ( pageIndex > 0 ) {
        return( NO_SUCH_PAGE );
      } else {
    	  
    	//Skalierung*******************************
          gBreite = pageFormat.getImageableWidth();
          gHoehe = pageFormat.getImageableHeight();
          b = componentToBePrinted.getWidth();
          h = componentToBePrinted.getHeight();
          
          skalierung = gBreite / b;
          
          System.out.println(gBreite +" " + b + " " + gHoehe + " " + h + " " + skalierung);
        //Ende Skalierung***************************
    	  
        Graphics2D g2d = (Graphics2D)g;
        g2d.translate( pageFormat.getImageableX(), pageFormat.getImageableY() );
        
        g2d.scale( skalierung, skalierung );
        
        disableDoubleBuffering( componentToBePrinted );
        componentToBePrinted.paint( g2d );
        enableDoubleBuffering( componentToBePrinted );
        return( PAGE_EXISTS );
      }
    }

    
    public static void disableDoubleBuffering( Component c ) {
      RepaintManager currentManager = RepaintManager.currentManager( c );
      currentManager.setDoubleBufferingEnabled( false );
    }

    
    public static void enableDoubleBuffering( Component c ) {
      RepaintManager currentManager = RepaintManager.currentManager( c );
      currentManager.setDoubleBufferingEnabled( true );
    }
  }

Aufgerufen wird das dann so:

Java:
...
	public void printPanel( Component comp ) {
		
		PrintUtilities myPrintJob = new PrintUtilities( comp );
                myPrintJob.print();
		
	}
...

Das klappt auch so einigermassen. Nach Ausführung der Methode printPanel (durch Klick auf Button) öffnet sich der Druckerdialog und ich kann da noch Sachen auswählen. Jetzt hab ich aber noch Fragen.

1.) Ist die Klasse PrintUtilities denn so ok? Oder gibt es da noch Fehler oder Verbesserungsmöglichkeiten?

2.) Ich möchte manchmal auch 2 unterschiedliche JPanel gleichzeitig ausdrucken. Im Moment rufe ich dann mit 1 Buttonklick die Methode printPanel auch zweimal auf, wobei sich dann aber auch der Druckerdialog zweimal öffnet und ich zweimal bestätigen muss. Gibt es die Möglichkeit, dass ich dann nur einmal auf den Button klicke, und beide JPanel ausgedruckt werden? Also, dass die dann wie ein zweiseitiges Dokument gehandhabt werden?

3.) Im Druckerdialog hab ich bei "Druckbereich" die Auswahlmöglichkeiten "Alles" oder "Seiten ... von ... bis ...", wobei dort "von 1 bis 9999" eingetragen ist. Kann ich dort reinschreiben, wieviele Seiten das Dokument hat? Also, bei 1 JPanel "von 1 bis 1" und wenn es 2 JPanel sind "von 1 bis 2"?
 
Vermutlich werden die meisten es so machen wie ich: JPanel Drucken? Hab' ich nie gemacht, da kann ich bestimmt nicht helfen... :bahnhof: Aber es geht ja weniger um eine FRAGE dazu, als eher um die LÖSUNG.

Die Klasse ist jetzt eben sehr minimalistisch: Man kann sie erstellen, und dann drucken. Je mehr Konfigurationsmöglichkeiten man bieten will ("...mein Drucker hat einen schmaleren Rand!") umso komplexer wird sie u.U., und im schlimmsten Fall landet man bei etwas, was genauso kompliziert ist, wie die "original-API".

Wie auch immer, und wie schon gesagt: Ahnung hab' ich davon keine, aber spontan würde ich sagen, dass man mehrere Seiten (d.h. mehrere Panels) durch eine geeignete Implementierung der print-Methode erschlagen müßte. D.h. die Klasse könnte z.B. eine List<Component> componentsToPrint haben, und bei der print-Methode abhängig vom pageIndex die jeweilige component aus dieser Liste verwenden.
 
Die Klasse ist jetzt eben sehr minimalistisch: Man kann sie erstellen, und dann drucken. Je mehr Konfigurationsmöglichkeiten man bieten will ("...mein Drucker hat einen schmaleren Rand!") umso komplexer wird sie u.U., und im schlimmsten Fall landet man bei etwas, was genauso kompliziert ist, wie die "original-API".
Na ja, ich hab halt zwei JPanels (Formulare), in denen was ausgefüllt und berechnet werden soll. Und es soll möglich sein, diese auszudrucken. Entweder nur die erste Seite oder Seite 1+2. Den Code für die Klasse oben hab ich aus dem Internet zusammengesucht und abgeändert. Wichtig war mir auch dabei, dass ich die JPanel skalieren kann, zumindest in der Breite auf die DINA4-Seite angepasst. Das funktioniert so ja auch, bis auf meine obigen Fragen. Es gibt bestimmt noch mehr Einstellungen, die man da vornehmen kann. Aber wozu, wenn es auch so (minimalistisch) geht.

Wie auch immer, und wie schon gesagt: Ahnung hab' ich davon keine, aber spontan würde ich sagen, dass man mehrere Seiten (d.h. mehrere Panels) durch eine geeignete Implementierung der print-Methode erschlagen müßte. D.h. die Klasse könnte z.B. eine List<Component> componentsToPrint haben, und bei der print-Methode abhängig vom pageIndex die jeweilige component aus dieser Liste verwenden.
Hmmm, versteh ich noch nicht so ganz, wie das mit dem pageIndex gehen soll...

Ach ja, was mich auch noch interessieren würde: Kann mir jemand den Unterschied zwischen PageFormat und Paper erklären?
 
Meines Wissens kann pro Printable nur ein Druckauftrag erzeugt werden. Wenn eine Komponente in einem Druckauftrag auf die erste Seite und eine weitere Komponente gedruckt werden soll, kann man ja in der
Code:
public int print( Graphics g, PageFormat pageFormat, int pageIndex ) {
den pageIndex abfragen und entsprechend das erste oder das zweite Panel drucken.
 
Meines Wissens kann pro Printable nur ein Druckauftrag erzeugt werden. Wenn eine Komponente in einem Druckauftrag auf die erste Seite und eine weitere Komponente gedruckt werden soll, kann man ja in der
Code:
public int print( Graphics g, PageFormat pageFormat, int pageIndex ) {
den pageIndex abfragen und entsprechend das erste oder das zweite Panel drucken.

Hmm, die Panels einzeln drucken krieg ich ja hin. Ich müsste aber irgendwie die beiden Panels (Seite 1 + 2) verbinden , so dass sie in einem Druckauftrag gedruckt werden können.
 
Ein Hinweis auf den Originalautor wäre nett gewesen... (zumindets zu erwähnen, dass man das gefunden und weiterentwickelt hat).

Zumal ich das in meinem Thread vor ca. 1 Woche getan habe. http://www.java-forum.org/java-basics-anfaenger-themen/126569-drucken-z-b-jframe-ueber-graphics-g.html#post823010

Finds nicht OK sich mit fremden Loorbeeren zu schmücken.
Dachte schon, irgendwie kommt mir der Code bekannt vor.


Zur Erläuterung was ich meine (und wie ich festgestellt habe auch schon Marco13 mit seinem Listenvorschlag gemeint hat):
Java:
public int print( Graphics g, PageFormat pageFormat, int pageIndex ) {
    if (pageIndex==0) {
        //hier Panel1 "drucken"
        return PAGE_EXISTS;
    }
    else if (pageIndex==1) {
        //hier Panel2 "drucken"
        return PAGE_EXISTS;
    }
    else
        return NO_SUCH_PAGE;
 }
 
Ein Hinweis auf den Originalautor wäre nett gewesen... (zumindets zu erwähnen, dass man das gefunden und weiterentwickelt hat).

Zumal ich das in meinem Thread vor ca. 1 Woche getan habe. http://www.java-forum.org/java-basics-anfaenger-themen/126569-drucken-z-b-jframe-ueber-graphics-g.html#post823010

Finds nicht OK sich mit fremden Loorbeeren zu schmücken.

Ich hab mich nirgendwo mit fremden Lorbeeren geschmückt.
Den Code für die Klasse oben hab ich aus dem Internet zusammengesucht und abgeändert.
Das hab ich in meinem 2. Posting hier geschrieben. Ich hab den Code tatsächlich im Internet gefunden, zumindest Teile davon. Weiss aber nicht mehr wo. Und ich hatte daran auch schon einiges hinzugefügt und verändert. Und ich hatte auch viele von meinen falschen und sinnlosen Änderungen wieder gelöscht, bevor ich das hier reingestellt hatte.

EDIT: Ausserdem hab ich den Code NICHT von deinem Posting, sondern ich hatte den auch schon viel früher gefunden und damit weitergearbeitet. Aber trotzdem danke für deinen Link. Schau ich mir gleich mal genauer an.
 
Zuletzt bearbeitet von einem Moderator:
Zur Erläuterung was ich meine (und wie ich festgestellt habe auch schon Marco13 mit seinem Listenvorschlag gemeint hat):
Java:
public int print( Graphics g, PageFormat pageFormat, int pageIndex ) {
    if (pageIndex==0) {
        //hier Panel1 "drucken"
        return PAGE_EXISTS;
    }
    else if (pageIndex==1) {
        //hier Panel2 "drucken"
        return PAGE_EXISTS;
    }
    else
        return NO_SUCH_PAGE;
 }

OK, danke. Werde ich mal versuchen und melde mich dann wieder.
 
Ich hab mich nirgendwo mit fremden Lorbeeren geschmückt.

Zitat:
Den Code für die Klasse oben hab ich aus dem Internet zusammengesucht und abgeändert.

Das hab ich in meinem 2. Posting hier geschrieben.

Sorry den 2. Posting hatte ich nicht ganz gelesen. Dir sei hiermit verziehen ^^

Du gibst mir aber sicherlich Recht, dass man eben darauf hinweisen sollte wenn man bestehenden Code verbessert hat. Da es nicht im ersten Post stand hab ichs übersehen.

Trotz allem: Durch den ergänzten Link + deine Verbesserungen sollte das dem ein oder anderen auf jeden Fall helfen! Und das ist letzendlich die Hauptsache!
 
Ja, sorry, ich hätte es vielleicht gleich genauer in mein erstes Posting schreiben sollen, damit es gleich jedem auffällt. Mir geht es nicht darum, mich mit fremden Federn zu schmücken. Aber ich weiss tatsächlich auch nicht mehr, wo ich das her hatte. Hab das vor längerer Zeit im Internet gefunden und ein bisschen verändert. Falls ich meine Fragen/Probleme gelöst bekomme, werde ich das hier auf jeden Fall auch dazu schreiben... Danke für die Hilfe...
 
Wie gesagt, bei dir wars ja wirklich ein Missverständnis. Es gibt halt in Foren leider viele die sich eben mit fremden Loorbeeren schmücken und das kannn ich einfach nicht haben. Du hast das ja wiklich nicht gewollt von daher forget it 🙂
 
Juhu, nach mehreren Test und Ausdrucken hab ich es jetzt wohl hingekriegt. :toll:

Also, erstmal die jetzt abgewandelte Klasse PrintUtilities:
Java:
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.util.List;

import javax.swing.RepaintManager;

public class PrintUtilities implements Printable {
    
    private List<Component> componentsToPrint;

  
    public static void printComponents( List<Component> componentsToPrint ) {
        new PrintUtilities( componentsToPrint ).print();
	}
   
    
    public PrintUtilities( List<Component> componentsToPrint ) {
        this.componentsToPrint = componentsToPrint;
	}
   
    
    public void print() {
    	
      PrinterJob printJob = PrinterJob.getPrinterJob();
      
      PageFormat pageFormat = printJob.defaultPage();  //new PageFormat();
      //pageFormat.setOrientation( PageFormat.LANDSCAPE );   //Längs- oder Querformat (Standard: längs)
      
      Paper a4PortraitPaper = new Paper();
      final double cm2inch = 0.3937;  // 1in = 2.54cm
      double paperHeight = 29.7 * cm2inch;
      double paperWidth = 21.0 * cm2inch;
      double margin = 1.5 * cm2inch;
       
      a4PortraitPaper.setSize( paperWidth * 72.0, paperHeight * 72.0 );
      a4PortraitPaper.setImageableArea( margin * 72.0, margin * 72.0,
                          ( paperWidth - 2 * margin ) * 72.0,
                          ( paperHeight - 2 * margin ) * 72.0 );

      pageFormat.setPaper( a4PortraitPaper );
      
      printJob.setPrintable( this, pageFormat );
      
      
      if ( printJob.printDialog() )
        try {
          printJob.print();
        } catch( PrinterException pe ) {
          System.out.println( "Error printing: " + pe );
          System.out.println( "Error printing (Message): " + pe.getMessage() );
          System.out.println( "Error printing (Localized Message): " + pe.getLocalizedMessage() );
          System.out.println( "Error printing (Cause): " + pe.getCause() );
        }
        
    }

    
    public int print( Graphics g, PageFormat pageFormat, int pageIndex ) {
    	
    	double gBreite, gHoehe;
    	int b, h;
    	double skalierung = 0.0;
    	
    	System.out.println("page index: " + pageIndex);

    	Graphics2D g2d = (Graphics2D)g;
    	g2d.translate( pageFormat.getImageableX(), pageFormat.getImageableY() );
    		
    	gBreite = pageFormat.getImageableWidth();
    	gHoehe = pageFormat.getImageableHeight();
    	

    	if ( pageIndex < componentsToPrint.size() ) {
    		
    		Component c = componentsToPrint.get( pageIndex );
    		
    		// ***** Skalierung *****
    		
        	b = c.getWidth();
        	h = c.getHeight();
                
        	skalierung = gBreite / b;
                
        	g2d.scale( skalierung, skalierung );
                
        	// ***** Ende Skalierung *****

    		disableDoubleBuffering( componentsToPrint.get( pageIndex ) );
    		componentsToPrint.get( pageIndex ).paint( g2d );
    		enableDoubleBuffering( componentsToPrint.get( pageIndex ) );
    		return PAGE_EXISTS;
                
    	}
    	else
    		return NO_SUCH_PAGE;

    	
    }

    
    public static void disableDoubleBuffering( Component c ) {
      RepaintManager currentManager = RepaintManager.currentManager( c );
      currentManager.setDoubleBufferingEnabled( false );
    }

    
    public static void enableDoubleBuffering( Component c ) {
      RepaintManager currentManager = RepaintManager.currentManager( c );
      currentManager.setDoubleBufferingEnabled( true );
    }
  }

Und so wird das dann jetzt aufgerufen:
Java:
...
	List<Component> componentsToPrint = new ArrayList<Component>();
	componentsToPrint.add( panel1 );
	componentsToPrint.add( panel2 );
		
	PrintUtilities myPrintJob = new PrintUtilities( componentsToPrint );
        myPrintJob.print();
...

Ich stelle also eine LIste mit den Components zusammen und übergeb das den PrintUtilities. Dort wird solange gedruckt und PAGE_EXISTS zurückgegeben, bis pageIndex die Grösse der Liste erreicht hat. So ist es flexibel und es ist egal, wie gross die Liste der Components ist.
Ist das so OK, oder hab ich noch Fehler drin?
 

Zurück
Oben