Imprimir JPanel/JFrame a escala en Java

Bueno aqui va una adaptación de la primera versión para imprimr un JPanel / JFrame a escala:

  1. Implementar la interfaz Printable en la clase que contiene el JPanel/JFrame que deseamos imprimir:
     public class PrintJFrameScaled extends javax.swing.JFrame implements Printable 
  2. Sobreescribir el método print en la clase que queremos imprimir:
        public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
    
            if (pageIndex > 0)
              return NO_SUCH_PAGE;
    
            Graphics2D g2d = (Graphics2D)graphics;
            g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
    
            // set dimension to scale panel to print
            g2d.scale( ((Number) campo_escala.getValue()).doubleValue()
                    , ((Number) campo_escala.getValue()).doubleValue());
    
            jPanel1.printAll(graphics);
    
            return PAGE_EXISTS;
        }
    

    Como se puede ver el método scale(X,Y) del objeto g2d es el que realiza el trabajo, recibe como parámetros dos valores de tipo Double que representan la escala para el alto (X) y el ancho (Y), por ejemplo el 1.00 equivale al 100%.

    100% == 1.00
    80% == 0.80

    Para imprimir panel en una escala del 70% se tienen que utilizar los siguientes valores:

    g2d.scale(0.70,0.70);
    
  3. Y para ejecutar la impresión utilizas las siguientes líneas de código:
    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
            try {
    
                // Open printer dialog and pass JPanel to print
                    PrinterJob job = PrinterJob.getPrinterJob();
                    job.setPrintable(this);
    
                    if(job.printDialog()) job.print();
    
            } catch (PrinterException ex) {
                Logger.getLogger(PrintJFrameScaled.class.getName()).log(Level.SEVERE, null, ex);
            }
    
        }
    

Aquí la captura del ejemplo con el código.

Actualización 12/04/2017, he recuperado el código de un respaldo y he creado un repositorio en github:

https://github.com/jaehoo/oz-ex-swing/blob/master/src/main/java/org/oz/swing/examples/jpanel/PrintJFrameScaled.java

Saludos

Anuncios

34 comentarios en “Imprimir JPanel/JFrame a escala en Java

  1. Miguel Jose dijo:

    Te agradezco broder por toda tu ayuda, no sabes cuanto me han ayudado tus ejemplos de impresion en el desarrollo de mi proyecto.

    Sigue enviando tus ejemplos porque son de gran utilidad. Gracias por tu ayuda, estamos en contacto.

    • jaehoo dijo:

      De nada, me da gusto que te hayan servido…
      Aun me falta darle un poco de orden a los temas y unos enlaces pero espero poder seguir escribiendo (si es que me da tiempo) para que poco a poco esto pueda convertirse en un sitio de referencia o por lo menos un catalogo de consulta, saludos

  2. leonardo dijo:

    el codigo esta muy bueno no lo habia encontrado en ningun lado mi consulta es la siguiente yo puse el codigo en la ventana que quiero imprimir y no me sale nada para imprimir no soy muy entendido en esto que puedo hacer?
    este es mi codigo

    … COMENTE TODO TU CODIGO =P

    • jaehoo dijo:

      Hola n_n, lo siento comente todo el código que pusiste, para tu problema veo que hay dos cosas:

      1. La clase ventana no implementa la interfaz Serializable.
      2. Te falta sobre sobre-escribir el método print().

      Con esas dos cosas ya debe funcionar, ya modifique el código e imprime la ventana, solo checa los puntos que puse en la entrada.

      Saludos.

  3. marbin dijo:

    hola jaehoo ,primero que nada felicitarte por el blog esta super y agradecerte por los posteos que haces bien completos la verdad.
    veras tengo una pregunta y no se como resolverla,la cuestion es que tengo un frame y un jlabel con una imagen debajo tengo un jlabel con texto y al costado un jtxtfield,debajo de los anteriores tengo un jtable con muchas filas y deco imprimirlas todas con el misma composicion del frame osea con los jlabels y jtxtfield,como el jtable es largo mas de una hoja diria yo como podria resolver ese problema.
    espero puedas ayudarme con tu infinita sbiduria jajaja.
    gracias de antemano.
    atentamente Marbin

    • jaehoo dijo:

      Hola, deberias de poder imprimir todo el contenido del frame sin problemas siempre y cuando todos los componentes que estas mandando estan dentro del panel principal.

      Saludos

  4. fredy dijo:

    hay dios no le entiendo a tu codigo!!

    =(

    como le puedo hacer para que no me escale la ventana??
    y agregar mas componentes como labels, jtables , combo , chck?

    contestame porfavor

    gracias!!

    • jaehoo dijo:

      jaja es chistoso, primero escribes un comentario donde me pides que escriba mas y luego este =P…

      Pero haber no es tan dificil, si ves mucho codigo raro es porque el frame lo cree con la herramienta visual de netbeans por eso hay mucho codigo raro, pero a eso no le hagas caso.

      Hasta abajo al final del post deje el codigo fuente completo por si quieres bajarlo y modificarlo.

      Bueno como puedes ver la clase tiene :
      1 constructor = PrintMeScale(), inicializa la clase.
      4 metodos:
      initComponents() = lo genera netbeans en automatico, a este NO le hagas caso, lo unico que tiene son los botones los labels, etc… todo lo que forma el frame.
      jButton1ActionPerformed(java.awt.event.ActionEvent evt)”: Este metodo es la acción que manda a imprimir el frame
      main(String args[]): Es el metodo con el que ejecutamos la clase.
      print(Graphics graphics, PageFormat pageFormat, int pageIndex): el metodo que sobreescribimos de la interfaz printable para poder imprimir.

      Y eso es todo en realidad como vez no es nada complicado, ahora si no quieres que la impresion salga a escala solo comenta la linea:

      //g2d.scale( ((Number) campo_escala.getValue()).doubleValue(), ((Number) campo_escala.getValue()).doubleValue());

      Y si quieres agregar mas cosas pues… no se tendrias que aventartelo a mano, pero yo te sugeriria que probaras el NetBeans, por lo menos para las aplicaciones swing (y a mi punto de vista) es el más completo.

      Espero te sriva saludos

  5. edstapia dijo:

    Gracias…. muy buen aporte…
    desde hace tiempo estuve buscando algo similar, ahora se me facilitaran mucho las cosas.
    Segun revisaba tu codigo es muy facil imprimir cualquier componente swing, el unico requisito es que tenga el metodo printAll()….

    Si a alguien le sirve yo lo implemento de esta manera:

    public class DocumentoAImprimir implements Printable{
    private JTextArea ComponenteSwing;
    private double escalaX,escalaY;
    public DocumentoAImprimir(JTextArea texto,double escalax, double escalay){
    ComponenteSwing=texto;
    escalaX = escalax;
    escalaY = escalay;
    }
    public int print(Graphics g, PageFormat pf, int page){
    if (page > 0) {
    return NO_SUCH_PAGE;
    }
    Graphics2D g2d = (Graphics2D)g;
    g2d.translate(pf.getImageableX(), pf.getImageableY());
    g2d.scale(escalaX, escalaY);
    ComponenteSwing.printAll(g2d);
    return PAGE_EXISTS;
    }
    }

    Luego lo llamo desde otro lado pasandole el componente que deseo imprimir (jtable, jframe, jtextarea, etc) junto con las escalas de X y Y. Luego llamamos a un Printerob comun…

    PrinterJob printJob = PrinterJob.getPrinterJob();
    Book libro = new Book();
    libro.append(new DocumentoAImprimir(txtResumen, 1.0, 1.0),
    printJob.defaultPage());
    printJob.setPageable(libro);
    if (printJob.printDialog()) {
    try {
    printJob.print();
    } catch (Exception PrinterException) {
    javax.swing.JOptionPane.showMessageDialog(null, PrinterException.getMessage());
    }
    }

    • edstapia dijo:

      por cierto para mi ejemplo yo imprimo un JTextArea… si se desea imprimir otro tipo de componente se debe de reemplazar por un JTable, JTextPane,etc….

      • Jokin de julian dijo:

        Buenas Tardes, estoy implementando algo muy parecido a lo que planteaste tu en su tiempo;
        Necesito imprimir 4 paneles, el caso es que lo consigo pero me sale cada panel en una pagina distinta y lo que necesito es imprimir los paneles uno debajo de otro en una pagina a poder ser, me imagino que sucede por esto: printJob.setPageable(libro);

        ¿Como podría hacer para imprimir todas las ventanas en una misma pagina?

        Aquí dejo mi código por si alguien me puede ayudar….

        PrinterJob printJob = PrinterJob.getPrinterJob();
        Book libro = new Book();

        libro.append(new Imprimir_Documento(panel_1, 0.25, 0.75), printJob.defaultPage());
        libro.append(new Imprimir_Documento(panel_2, 0.25,0.75),printJob.defaultPage());
        libro.append(new Imprimir_Documento(panel_32, 0.25, 0.75), printJob.defaultPage());
        libro.append(new Imprimir_Documento(panel_13, 0.25, 0.75), printJob.defaultPage());
        printJob.setPageable(libro);
        if (printJob.printDialog()) {
        try {
        printJob.print();
        } catch (Exception PrinterException) {
        javax.swing.JOptionPane.showMessageDialog(null, PrinterException.getMessage());
        }
        }

    • Daniel Betancourt dijo:

      Aquí dejo el método y la clase que he utilizado para hacer la impresión !
      Que ademas me ha funconado perfectamente !

      public class Impresión implements Printable
      {
      private JPanel componente; //Cualquier Componente
      private double escalaX,escalaY;

      public Impresión(JPanel panelUno,double escalax, double escalay)
      {
      componente = panelUno;
      escalaX = escalax;
      escalaY = escalay;
      }

      public int print(Graphics graficar, PageFormat pageFormat, int pageIndex)
      {
      if (pageIndex > 0)
      return NO_SUCH_PAGE;

      Graphics2D graficar2D = (Graphics2D)graficar;

      graficar2D.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
      graficar2D.scale(escalaX, escalaY);

      componente.printAll(graficar2D);

      return PAGE_EXISTS;
      }
      }

      Este método se encontraba en otra clase, la clase Ejecutable o principal.

      public static void imprimir()
      {
      PrinterJob printJob = PrinterJob.getPrinterJob();

      Book libro = new Book();
      libro.append(new Impresión(panelUno, 0.9, 0.9),

      printJob.defaultPage());
      printJob.setPageable(libro);

      if (printJob.printDialog())
      try
      {
      printJob.print();
      }
      catch (Exception PrinterException)
      {
      JOptionPane.showMessageDialog(null, PrinterException.getMessage());
      }
      }

      • Daniel Betancourt dijo:

        Ahora la pregunta es:
        Tengo cuatro paneles para imprimir, como se hace para que cada uno se imprima en una hoja diferente ???
        y que sea de forma automática, es decir que no le aparezca 4 ventanas de solicitud de impresión al usuario !

        Alguien podría ayudarme ???

      • Daniel Betancourt dijo:

        Ya esta la solución para imprimir los paneles que se quiera, solo es quitar del método print(Graphics, PageFormat, int) de la clase Impresión las siguientes líneas:

        if (pageIndex > 0)
        return NO_SUCH_PAGE;

        y así, si se imprime las páginas que se quieran !

      • Daniel Betancourt dijo:

        Claro y tambien habria los otros paneles al objeto Book:

        libro.append(new Impresión(panelDos, 0.9, 0.9),printJob.defaultPage());

        libro.append(new Impresión(panelTres, 0.9, 0.9),printJob.defaultPage());

        libro.append(new Impresión(panelCuatro, 0.9, 0.9),printJob.defaultPage());


        ..
        .

  6. RoxCobain dijo:

    Si sirve, te daré un millón de dólares okno… sucede que tengo varios objetos graphics (del generalPath) en el panel, y hasta el momento solo me imprime el primer elemento que encuentre en el panel, veamos que sucede :s

  7. nanjimenez dijo:

    Viejo que buen aporte utilice el codigo que dejaste pero tengo un problema, estoy tratando de imprimir un panel pero es demaciado grande y se me sale de la hoja de impresion, no hay una obcion de ajustar el panel con la hoja de impresion?, si me puedes ayudar se lo agradeceria

  8. Emanuel dijo:

    Hola, disculpen yo hice un jframe (el JFrame se llama Personal)en donde por medio de un boton agrego una imagen en un jpanel y ademas texto en etiquetas, pero ademas el usuario ademas de agreagar la imagen al jpanel tambien pondra texto en varios textfieldt, mi pregunta es como le puedo hacer para mandar a imprimir todo el jframe con la imagen y el texto de los textfield o en el peor de los casos como exportarlo a PDF???

    • jaehoo dijo:

      hola, ps en todo caso se me ocurren estas ideas:
      1. Que generes un boton imprimir que te genere la vista previa de todo lo que quieres imprimir y en esa hoja (Jframe) aplicar este truco para imprimir.
      2. Existe un framework llamado Itext y POI, que te permiten generar archivos PDF, pero tendrias que investigar como acoplarla a tu proyecto.
      3. Hay otra herramienta llamada Jasper Reports, se utiliza para imprimir reportes que también puede ser una buena opción.

      Saludos

  9. drake dijo:

    tengo una pregunta disculpa pero no se mucho de programacion
    bueno al escalar la impresion utilizas una variable lammada campo_escala
    donde la inicializas o la creas en el formulario ?

  10. Jokin de julian dijo:

    Buenas Tardes, estoy implementando algo muy parecido a lo que planteaste tu en su tiempo;
    Necesito imprimir 4 paneles, el caso es que lo consigo pero me sale cada panel en una pagina distinta y lo que necesito es imprimir los paneles uno debajo de otro en una pagina a poder ser, me imagino que sucede por esto: printJob.setPageable(libro);

    ¿Como podría hacer para imprimir todas las ventanas en una misma pagina?

    Aquí dejo mi código por si alguien me puede ayudar….

    PrinterJob printJob = PrinterJob.getPrinterJob();
    Book libro = new Book();

    libro.append(new Imprimir_Documento(panel_1, 0.25, 0.75), printJob.defaultPage());
    libro.append(new Imprimir_Documento(panel_2, 0.25,0.75),printJob.defaultPage());
    libro.append(new Imprimir_Documento(panel_3, 0.25, 0.75), printJob.defaultPage());
    libro.append(new Imprimir_Documento(panel_4, 0.25, 0.75), printJob.defaultPage());
    printJob.setPageable(libro);
    if (printJob.printDialog()) {
    try {
    printJob.print();
    } catch (Exception PrinterException) {
    javax.swing.JOptionPane.showMessageDialog(null, PrinterException.getMessage());
    }
    }

    • jaehoo dijo:

      Hola, cuando escribí ese programa lo hice con la idea e capturar el contenido completo del panel.

      En tu caso me parece algo raro querer imprimir los cuatro en una hoja, pero talvez esta idea te pueda funcionar (es lo que yo probaría):

      • 1. Tienes que generar otro Jpanel (el 5to) y desde el código manipular sus dimensiones deacuerdo al tamaño que necesitas antes de imprimirlo
      • 2. Cada panel que quieres imprimir debe ser agregado desde el código al nuevo panel, para esto debes obtener las dimesiones de cada uno y agregarlo al nuevo panel, esto puede ser algo difícil ya que tienes que pensar como vas calcular las posiciones, su tamaño y como vas a posicionarlo dentro del nuevo panel
      • 3. Una vez que tengas todo en un solo panel, debes haerlo visible. Recuerdo que si esta oculto el panel no se imprime nada, digamos que vas a generar una pantalla como vista previa a la impresión

      Espero que la ídea te sea util y creo que es posible lo que estas buscando.

      Saludos

    • jaehoo dijo:

      Leyendo los comentarios veo que la respuesta a tu pregunta es parte de lo que ocmenta DANIEL BETANCOURT, ahí explica como imprimir en paginas.

      Y es exactamente como lo pensé tienes que manipular los tres puntos que te mencione, hice una prueba y funciona, el código lo puedes bajar de github:

      https://github.com/jaehoo/oz-ex-swing/blob/master/src/main/java/org/oz/swing/examples/jpanel/PrintJFramesInOnePage.java

      y si necesitas otro ejemplo similar :http://www.java2s.com/Code/Java/2D-Graphics-GUI/Book.htm

      Saludos

      • jOUK dijo:

        Lo primero de todo agradecerte el mero hecho de responderme y mas todavía con una idea muy valida como la que me has propuesto, que sepas que esa misma idea es la que he llevado a cabo, crear un JPanel contenedor como si fuese una vista previa de impresión, que se encarga de cargar los demás JPanels en un mismo JDialog.

        Ahora solo me queda hacer pruebas con la escala para poder mostrarlo completo ya que no llega a entrar ni de largo de ancho en la hoja, por los comentarios que he leído por aquí veo que es normal, a ver si lo consigo rápido, aunque ya queda poco.

        Gracias por la atención, un saludo

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s