# Probleme beim drucken



## Seppel (13. Sep 2011)

Hallo, ich möchte den Inhalt eines JFrames drucken besser gesagt alles was im scrollpane ist. Menü und Rahmen sowie scrollbar sollen weggealassen werden.
Als erstes habe ich mich an einfache Beispiele gewagt--> Text ausdrucken und das ging problemlos
dann habe ich mich an mein fenster gemacht und ausgedruckt. 
Folgendes läuft da aber ne so wie es soll:
1. Wie kann man automatisch auf Querformat stellen?
2. Der Rechner zeigt mir zig mal das Druckenfenster an --> wo liegt hier das Problem?
3. warum druckt er immer nur eine Seite und das was nicht darauf past auf die nächste?

richtig gedruckt habe ig nicht, nur an OneNote geschickt um Papier zusparen.

Da der Code zulang war wollte ich ihn kürzen, dabei scheint mir aber ein Fehler unterlaufen zu sein und jetzt geht der code nicht mehr, deshalb hier mal die langform.

```
import java.awt.*; 
import java.awt.event.*;
import java.awt.print.*;
import java.awt.Container;
import java.awt.Graphics;
import javax.swing.*;
import java.awt.Font;

public class Chronik2 extends JFrame   { //implements AdjustmentListener
 private static final long serialVersionUID = 1L;

  StammbaumFenster NeueCronik_stammbaum;
  //####################################################################################################################

  
  public static void main(String[] args) {
	Chronik2 fenster = new Chronik2 ("FamilienChronik2");	
    fenster.pack();
    fenster.setSize(965,900);
    fenster.setResizable(false);
    fenster.setVisible(true); 
  }
   
  Chronik2 (String titel) {
    super(titel);

    GridBagLayout gbl = new GridBagLayout();
    JPanel panel1 = new JPanel();
    panel1.setLayout(gbl);   
    
    class CMeinActionLauscher implements ActionListener {
      public void actionPerformed(ActionEvent e)  {
          String label;
          label = e.getActionCommand();
          if (label.equals("Stammbaum anzeigen")) {
        	  NeueCronik_stammbaum =new StammbaumFenster ("");          	  
        	  NeueCronik_stammbaum.pack();          	 
        	  NeueCronik_stammbaum.setSize(855,900);
        	  NeueCronik_stammbaum.setResizable(false);        	  
        	  NeueCronik_stammbaum.setVisible(true);         	  
          }	
      }        
    }  
    //Menü  #####################################################################################################
    JMenuBar menueleiste =new JMenuBar();
    JMenu menu3 =new JMenu("Datenbank");
    
    
    JMenuItem item = new JMenuItem("Stammbaum anzeigen");
    item.addActionListener(new CMeinActionLauscher());
    menu3.add(item);
    menueleiste.add(menu3);
    setJMenuBar(menueleiste);

    add(panel1);     
    setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
  }
 
  
  public class StammbaumFenster extends JFrame implements Printable{
	  JButton Personen[] = new JButton[33];	 
	  
	  JScrollPane scrollpane;
	  JPanel panel1 = new JPanel();	
	  
	  private static final long serialVersionUID = 1L;
		
		public int print( Graphics g, PageFormat pageFormat, int pageIndex ) {
			Toolkit tk = Toolkit.getDefaultToolkit();
			PrintJob pj = tk.getPrintJob(NeueCronik_stammbaum, "", null );
		
			if ( pj == null ) 
		        return Printable.NO_SUCH_PAGE;
		        
			scrollpane.printComponents( g );
		    g.dispose();
		    pj.end();
		    return Printable.PAGE_EXISTS;
		 }
  
		void addComponent( Container cont, GridBagLayout gbl,Component c,int x, int y,int width, int height,double weightx, double weighty,int typ , int schriftgroese){
			 GridBagConstraints gbc = new GridBagConstraints();
			 gbc.fill = GridBagConstraints.BOTH;
			 gbc.gridx = x; gbc.gridy = y; gbc.gridwidth = width; gbc.gridheight = height; gbc.weightx = weightx; gbc.weighty = weighty;
			 
				 if (typ==1) {
					 ((JButton) c).setMargin(new Insets(0, 0, 0, 0));				 
					 ((JButton) c).setFont(new Font("Arial", Font.PLAIN,schriftgroese));				
				 }							 
				 gbl.setConstraints(c, gbc );	
				 cont.add( c );
		 }
		
		StammbaumFenster(String titel){
			  super(titel); 	
			  class CMeinActionLauscher implements ActionListener {
			      public void actionPerformed(ActionEvent e)  {
			          String label;					  
			          label = e.getActionCommand();            
			          if (label.equals("Drucken")) {  
			        	  PrinterJob pjob = PrinterJob.getPrinterJob();
			        	    if ( pjob.printDialog() == false )
			        	      return;			        	   
			        	    try {
			        	    	pjob.setPrintable(NeueCronik_stammbaum );
								pjob.print();
							} catch (PrinterException e1) {e1.printStackTrace();}
				      }        
			      }        
			    }  
			  
			  JMenuBar menueleiste =new JMenuBar();
			  JMenu menu1 =new JMenu("Drucken");	
			  JMenuItem item = new JMenuItem("Drucken");
		      item.addActionListener(new CMeinActionLauscher());
		      menu1.add(item);		
			  menueleiste.add(menu1);
			  setJMenuBar(menueleiste);
			    
			  GridBagLayout gbl = new GridBagLayout();
			  		  			  			  	
			  panel1.setLayout(gbl);	  

			  int i=0;
	          for ( i=0;i<32;i++){  Personen[i]=new JButton("<html>Max<br> Muster</html>");}    
	          for ( i=1;i<34;i++){  addComponent( panel1, gbl, new JLabel("<--->"), i , 0, 1, 1, 0 , 0 ,0,8);}   
	          for (i=0 ;i<8 ;i++){ 
	              addComponent( panel1, gbl, Personen[i*2]   , 4*i+2 , 1+i*2, 3, 1, 0 , 0 ,1  ,9 );
	              addComponent( panel1, gbl, Personen[i*2+1] , 4*i+2 , 2+i*2, 3, 1, 0 , 0 ,1  ,9 );               
	          }     
	          scrollpane = new JScrollPane(panel1);   
	          add(scrollpane);  	  
		  }	  	
  }
}
```

Das meiste ist ja nur für das Erstellen des Fensters. Das Drucken ist erst im zweiten Fenster möglich. Wenn ich über one Note ausgebe muss ich min 3-4 ja klicken und dann erst paar mal auf nein damit überhaupt was angezeigt wird.
Leider konnte ich kein Beispie finden was mir helfen konnte.


----------



## Michael... (14. Sep 2011)

Das Drucken unter Java ist m.M. eine Sache für sich.
Dein Code ist ja ganz schön wagemutig - um's mal vorsichtig auszudrücken.
Dass bei Dir andauernd der Druckdialog hochkommt liegt daran, dass Du in dauernd aufrufst.
Nämlich in der print(...) der Klasse StammbaumFenster - und da hat das gar nichts verloren.
Schon mal ein Tutorial dazu angeschaut?
Etwas komplizierter wird es bei mehrseitigen Ausdrucken, da muss man ein bisschen selbst rechnen.
Hier mal eine Demo - ohne Gewähr, da ich mich selbst nie wirklich mit dem Drucken auseinandergesetzt habe:

```
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;

import javax.swing.JComponent;

public class PrintingDemo {
	
	class PrintableComponent extends JComponent implements Printable {
		BufferedImage img;
		
		public PrintableComponent() {
			img = new BufferedImage(1300, 1000, BufferedImage.TYPE_INT_ARGB);
			Graphics2D g = img.createGraphics();
			g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
			g.setColor(Color.BLUE);
			g.setStroke(new BasicStroke(50));
			g.drawLine(0, 0, img.getWidth(), img.getHeight());
			g.setColor(Color.RED);
			g.drawLine(0, img.getHeight(), img.getWidth(), 0);
			g.setColor(Color.GREEN);
			g.drawRect(0, 0, img.getWidth(), img.getHeight());
			g.drawRect(img.getWidth()/4, img.getHeight()/4, img.getWidth()/2, img.getHeight()/2);
			g.setColor(Color.BLACK);
			g.rotate(Math.PI/6);
			g.setFont(new Font("Arial", Font.BOLD, 170));
			g.drawString("PRINTDEMO", 250, 250);
			g.dispose();
			this.setSize(img.getWidth(), img.getHeight());
		}
		
		public void paintComponent(Graphics g) {
			super.paintComponent(g);
			if(img!=null)
				g.drawImage(img, 0, 0, null);
		}
		
		public int print(Graphics g, PageFormat pf, int page)
				throws PrinterException {
			int w = (int)pf.getImageableWidth();
			int h = (int)pf.getImageableHeight();
			int maxRow = this.getHeight()/h +1;
			int maxColumn = this.getWidth()/w +1;
			int row = page%maxRow;
			int col = page/maxRow;
			
			if (page >= maxRow*maxColumn)
				return NO_SUCH_PAGE;
			
			Graphics2D g2 = (Graphics2D) g;
			g2.translate(pf.getImageableX(), pf.getImageableY());
			g2.translate(-col*w, -row*h);
			g2.setClip(col*w, row*h, w, h);
			this.paintComponent(g2);
			
			return PAGE_EXISTS;
		}
	}

	public void printDemo() {
		PrintableComponent comp = new PrintableComponent();
		PrinterJob pj = PrinterJob.getPrinterJob();
		if (pj.printDialog()) {
			try {
				pj.setPrintable(comp);
				pj.print();
			} catch (PrinterException exc) {
				System.out.println(exc);
			}
		}

	}

	public static void main(String[] s) {
		new PrintingDemo().printDemo();
	}
}
```


----------



## Seppel (14. Sep 2011)

Erst mal vielen vielen Dank.
Dein Beispiel hat das gemacht was ich brauchte. Das mit dem Berechnen war mir in dem Umfang unbewusst. Nach dem ich den inhalt deiner Print() übernohmen und angepasst habe lief es wie geschmiert. 

Lediglich zwei Dinge sind es jetzt noch.
Das mit dem Querformat, aber da werde ich heute noch mal suchen gehen.
Und dann "nur" das ungescrollte Fenster gedruckt wird. also das was nicht ohne Scollen zusehen ist wird nicht ausgedruckt.
Wie könnte man das in den Griff bekommen.

Bin garade dabei ein umfangreiches Druck tutorial dazu zulesen, wollte aber nicht deswegen das ganze Projekt zum stillstand kommen lassen.

In wie fern wagemutig? meist du damit das mit dem Drucken oder gibts beim  Rest was zu optimieren, wäe für Tipps immer erfreut.

Noch mal danke


----------



## Michael... (14. Sep 2011)

Seppel hat gesagt.:


> In wie fern wagemutig? meist du damit das mit dem Drucken oder gibts beim  Rest was zu optimieren, wäe für Tipps immer erfreut.


Naja, es sind da so ein paar Kleinigkeiten:
- das mit dem getPrintJob in der print habe ich ja schon erläutert
- warum implementiert 
	
	
	
	





```
StammbaumFenster
```
 das Interface 
	
	
	
	





```
Printable
```
, obwohl eigentlich doch nur ein ganz bestimmter Teil (die Komponente im Viewport der JScrollpane) daraus gedruckt werden soll.
besser eine eigene Komponente schreiben, da kommt man auch besser an die notwendigen Informationen ran.
- in 
	
	
	
	





```
StammbaumFenster
```
 wird des Öfteren die Instanzvariable 
	
	
	
	





```
NeueCronik_stammbaum
```
 aus der Klasse Chronik2 genutzt, um an die Referenz auf sich selbst zu kommen. Hier wäre 
	
	
	
	





```
this
```
 oder 
	
	
	
	





```
StammbaumFenster.this
```
 besser - zumal es zu Problemen kommen könnte, wenn 
	
	
	
	





```
NeueCronik_stammbaum
```
 plötzlich - aus welchen Gründen auch immer - auf ein anderes Objekt referenziert.
- bei der Darstellung des Stammbaums mit GridLayout und Buttons, würde ich mir überlegen sowas eventuell selbst zu zeichnen oder eine externe Lib einzubinden. Je nach dem wie komplex das ganze noch wird.

Noch ein Hinweis auf die Java Code Conventions: in Java ist es üblich variablenNamen mit einem kleinBuchstaben beginnen zu lassen.


----------



## Seppel (14. Sep 2011)

Michael... hat gesagt.:


> - in
> 
> 
> 
> ...


 stimmt muss ich eindeutig noch mal bissel mehr drauf achten



Michael... hat gesagt.:


> - bei der Darstellung des Stammbaums mit GridLayout und Buttons, würde ich mir überlegen sowas eventuell selbst zu zeichnen oder eine externe Lib einzubinden. Je nach dem wie komplex das ganze noch wird.



ist schon sehr umfangreich, habe dir nur eine sehr kurze version gegeben
mit selber zeichnen meist du sicherlich die exakten Koordinaten angeben oder?


Michael... hat gesagt.:


> Noch ein Hinweis auf die Java Code Conventions: in Java ist es üblich variablenNamen mit einem kleinBuchstaben beginnen zu lassen.



ich weis, hat man mir bereits schon gesagt, aber ich fang damit erst im nächsten Projekt an, zum einen will ich nicht alles hier ändern und zum zweiten ließt sich es sich schlecht wenn ich in einem projekt zwei methoden anwende.

und die zwei Probleme die ich noch hatte, habe bs jetzt heute noch nichts zum zweiten Problem gefunden, das mit dem Querformat habe ich noch nicht gesucht


----------



## Michael... (14. Sep 2011)

Seppel hat gesagt.:


> mit selber zeichnen meist du sicherlich die exakten Koordinaten angeben oder?


Meinte damit die Benutzung der 2D API wie ich es in meinem Bsp zum Zeichnen auf das BufferedImage bzw. mit der überschriebenen paintComponent(Graphics g) meiner Komponente genutzt habe.


----------



## Michael... (14. Sep 2011)

Seppel hat gesagt.:


> und die zwei Probleme die ich noch hatte, habe bs jetzt heute noch nichts zum zweiten Problem gefunden, das mit dem Querformat habe ich noch nicht gesucht


man kann dem PrinterJob auch ein PageFormat mit übergeben - weiss nicht, ob das Dein Problem löst:
PrinterJob (Java Platform SE 6)
Und was ist das andere offene Problem?


----------



## Seppel (14. Sep 2011)

Habs grad so gelöst:

```
if (label.equals("Drucken")) {  
			        	  PrinterJob pjob = PrinterJob.getPrinterJob();
			        	  HashPrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
			  			  aset.add(MediaSizeName.ISO_A4);
			  			  //170, 257
			  	          aset.add(new MediaPrintableArea(10, 10, 200, 290, MediaPrintableArea.MM));
			      	      aset.add(OrientationRequested.LANDSCAPE);
			  	          aset.add(PrintQuality.NORMAL);
			  	          aset.add(Chromaticity.MONOCHROME);
			  	          pjob.setPrintable(NeueCronik_stammbaum);
			        	  boolean ok = pjob.printDialog(aset);
			                if(ok) {
			                	try{pjob.print(aset);}
			                    catch(Exception ex){ex.printStackTrace();}
			                }
				      }
```

Damit hätte ich mein Querformat, allerdings wüsste ich gern wie viel Platz ein Drucker so als Rand braucht, da jetzt nicht mehr viel Platz da ist
Das andere Problem war, das er nicht alles gedruckt hat, ist aber nun Geschichte.
dennoch danke für deine letzte Nachricht

Edit: Das Gridbag niehmt einen aber doch dennoch einiges ab, was die Breite von Objekten angeht zb


----------



## Michael... (14. Sep 2011)

Seppel hat gesagt.:


> Edit: Das Gridbag niehmt einen aber doch dennoch einiges ab, was die Breite von Objekten angeht zb


Stimmt, im Falle von Selberzeichnen müsste man das auch selbst kalkulieren ;-)


----------



## Seppel (15. Sep 2011)

Hallo, nochmal.
ich habe festgestellt das das Ausgedruckte immer größer ist als das Fenster auf dem Bildschirm.
Ich denke das das sicherlich an der Uaflösung liegt das ein Drucker nicht die selbe hat wie ein Bildschirm.
Könnte noch mal hierbei Hilfe gebrauchen da ich das Problem ne recht in den Griff bekomme. danke


```
public int print( Graphics g, PageFormat pageFormat, int pageIndex ) {
			int w = (int)pageFormat.getImageableWidth();
            int h = (int)pageFormat.getImageableHeight();
            int maxRow = this.getHeight()/h +1;
            int maxColumn = this.getWidth()/w +1;
            int row = pageIndex%maxRow;
            int col = pageIndex/maxRow;
            
            if (pageIndex >= maxRow*maxColumn)
                return NO_SUCH_PAGE;
            
            Graphics2D g2 = (Graphics2D) g;
            g2.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
            g2.translate(-col*w, -row*h);
            g2.setClip(col*w, row*h, w, h);
            panel1.printComponents(g2);
            return PAGE_EXISTS;
		 }
```


```
public void actionPerformed(ActionEvent e)  {
			          String label;					  
			          label = e.getActionCommand();            
			          if (label.equals("Drucken")) {  
			        	  PrinterJob pjob = PrinterJob.getPrinterJob();
			        	  
			        	  HashPrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
			  			  aset.add(MediaSizeName.ISO_A4);//oben rand;rechts rand;Senkrecht;wagerecht
			  	          aset.add(new MediaPrintableArea(25, 20, 160, 257, MediaPrintableArea.MM));
			      	      aset.add(OrientationRequested.LANDSCAPE);
			  	          aset.add(PrintQuality.NORMAL);
			  	          aset.add(Chromaticity.MONOCHROME);
			  	          pjob.setPrintable(NeueCronik_stammbaum);
			        	  boolean ok = pjob.printDialog(aset);
			                if(ok) {
			                	try{pjob.print(aset);}
			                    catch(Exception ex){ex.printStackTrace();}
			                }
				      }
```


----------



## Michael... (15. Sep 2011)

Seppel hat gesagt.:


> ich habe festgestellt das das Ausgedruckte immer größer ist als das Fenster auf dem Bildschirm.


Größen auf dem Bildschirm sind relativ. Auf anderen Monitoren schaut Dein Fenster auch "größer/kleiner" aus ;-)


Seppel hat gesagt.:


> Ich denke das das sicherlich an der Uaflösung liegt das ein Drucker nicht die selbe hat wie ein Bildschirm.


Korrekt - zumindest teilweise. Siehe:


			
				API Doku hat gesagt.:
			
		

> public double getImageableHeight()Return the height, in 1/72nds of an inch, of the imageable area of the page. This method takes into account the orientation of the page.
> 
> Returns:
> the height of the page.


PageFormat (Java Platform SE 6)
Hier wir von einer Auflösung von 72 dpi ausgegangen. Dein Monitor hat vermutlich eine höhere Auflösung, dadurch erscheint das Fenster kleiner.

Wenn Du den Ausdruck kleiner haben willst musst Du skalieren.
Entweder die Größe der Komponente vor dem Drucken ändern. Oder die Komponente erst auf ein BufferedImage malen, dieses skalieren und dann Drucken.

Aber wie gesagt die Größe auf einem Monitor ist relativ und Dein Fenster schaut auf Monitoren mit einer anderen Auflösung anders aus.


----------



## Seppel (15. Sep 2011)

danke, war auch meine Vermutung, dann mach ich mich mal an die Arbeit


----------



## Seppel (15. Sep 2011)

sag mal bitte, mit scale() kann ich das ganze doch auch kleiner machen oder sollte man das nicht nehmen?


----------



## André Uhres (16. Sep 2011)

Die Methode "scale" kann man natürlich auch benutzen. Damit wird üblicherweise der Maßstab des Grafik-Objekts so angepasst, dass die gesamte Breite des Dokuments auf eine Seite passt ("fit to width"). Der Skalierungsfaktor ist in dem Fall die verfügbare Breite geteilt durch die Dokumentbreite.

Gruß,
André


----------

