viernes, 30 de abril de 2010

(Parentesis. II Parte) Compartiendo el código Applet

Ahora si llegó la hora de seguir en la onda java, ahora para presentar (como lo prometí en un post anterior), el código del Applet que me permite imprimir un reporte HTML, que me da la ventaja de capturar si el usuario del sistema hizo click en "Imprimir" o "Cancelar" para que se puedan hacer los cambios en la base de datos después que se procedió a imprimir.

Este código también muestra como cambiar la configuración de impresión o también llamado atributos de impresión, por ejemplo los márgenes, todo esto desde código Java, también se utiliza el paquete java.net (la clase URL) que me permite buscar en una dirección remota un recurso, en este caso un archivo, que fue generado y grabado en el servidor.

Como lo expliqué en el post anterior: este código me quedó de una experiencia en mi trabajo para la impresión de cheque, pero que no fue implementado por cambio en los requerimientos del sistema, pero pienso que les puede servir como ejemplo o ayuda a todo aquel que busque información en lo que se refiere a todos los elementos que actúan en el código que ya he mencionado en los párrafos anteriores.

Bueno empecemos con el archivo HTML que contiene el contenido del cheque, este archivo debe ser creado por el programa en el servidor y por lo tanto estar en un directorio del mismo.
el Código es:


package cheque;

import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.MediaPrintableArea;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.print.*;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessControlException;

public class ReporteApplet extends JApplet
implements ActionListener, Printable{
private JEditorPane htmlPane;
private URL initialURL;
private String ipServer;
private String rutaArchivoHtml;
private JButton printButton;
private int margenSuperior, margenIzquierdo,
private int anchoPagina, altoPagina;
private PrintRequestAttributeSet atributosDeImpresion;
private int unidadMedidaImpresion;
public void init() {
super.init();
margenSuperior = (getParameter("margen-superior") != null)?
Integer.parseInt(getParameter("margen-superior")):20;
margenIzquierdo = (getParameter("margen-izquierdo") != null)?
Integer.parseInt(getParameter("margen-izquierdo")):20;
anchoPagina = (getParameter("ancho-pagina") != null)?
Integer.parseInt(getParameter("ancho-pagina")):210;
altoPagina = (getParameter("alto-pagina") != null)?
Integer.parseInt(getParameter("alto-pagina")):297;
ipServer = getParameter("ip-server");
rutaArchivoHtml = getParameter("ruta-archivo");
atributosDeImpresion =
new HashPrintRequestAttributeSet();
unidadMedidaImpresion = MediaPrintableArea.MM;
}
public void start(){
try {
//if ipServer == 127.0.0.1 invocar a localhost
//else invocar 192.168.0.91
if(ipServer != "192.168.0.91" &&
ipServer != null &&
ipServer.trim() != ""){
this.initialURL = new URL
("http://localhost/rutaProyecto/"+
rutaArchivoHtml);
}else{
this.initialURL = new URL
("http://192.168.0.91/rutaProyecto/"+
rutaArchivoHtml);
}
htmlPane = new JEditorPane(initialURL);
} catch (MalformedURLException e) {
warnUser("Ruta de archivo incorrecto");
} catch (AccessControlException e) {
warnUser("no se tiene permiso de abrir archivo");
}catch (IOException e) {
warnUser("Verifique el IP de la maquina.\n
Debe pasar por parámetro el IP correcto del servidor");
}
JPanel buttonPanel = new JPanel();
buttonPanel.setBackground(Color.lightGray);
printButton = new JButton("Imprimir");
printButton.addActionListener(this);
buttonPanel.add(printButton);
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
htmlPane.setEditable(false);
JScrollPane scrollPane = new JScrollPane(htmlPane);
getContentPane().add(scrollPane,
BorderLayout.CENTER);
Dimension screenSize =
Toolkit.getDefaultToolkit().getScreenSize();
int width = screenSize.width * 8 / 10;
int height = screenSize.height * 8 / 10;
setBounds(width/8, height/8, width, height);
setSize(500, 250);
setVisible(true);
}
public void actionPerformed(ActionEvent event){
String command = event.getActionCommand();
if (command.equals("Imprimir")){
this.printComponent();
}
}
private void warnUser(String message){
JOptionPane.showMessageDialog(null, message, "Error",
JOptionPane.ERROR_MESSAGE);
}

public void printComponent(){
print();
}

public void print(){
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(this);
atributosDeImpresion.add(new MediaPrintableArea
(margenIzquierdo, margenSuperior,
anchoPagina, altoPagina, unidadMedidaImpresion));
if (job.printDialog(atributosDeImpresion)){
try{
job.print();
}catch (Exception ex){
System.out.println(ex);
}
}else{
warnUser("Impresión cancelada");
}
}

public int print(Graphics g, PageFormat pf,
int pageIndex) throws PrinterException{
Graphics2D g2 = (Graphics2D)g;
Dimension d = htmlPane.getSize();
double panelWidth = d.width;
double panelHeight = d.height;
double pageHeight = pf.getImageableHeight();
double pageWidth = pf.getImageableWidth();
double scale = pageWidth/panelWidth;
int totalNumPages = (int)Math.ceil(scale *
panelHeight / pageHeight);
//Para asegurar que no imprime página vacía
if(pageIndex >= totalNumPages){
return Printable.NO_SUCH_PAGE;
}
g2.translate(pf.getImageableX()-19,
pf.getImageableY()-19);
g2.translate(0f, -pageIndex*pageHeight);
g2.scale(scale, scale);
htmlPane.paint(g2);
return Printable.PAGE_EXISTS;
}
}


Veamos que quiere decir todo este código. Entre los atributos de inteŕes de la clase ReporteApplet tenemos una referencia JEditorPane que es el que me sirve para mostrar el código HTML del cheque que se va a imprimir. Para definir los atributos de impresión se utilizan una interfaz (PrintRequestAttributeSet) que define los métodos para agregar o definir los atributos de impresión, una clase HashPrintRequestAttributeSet que implementa esta interfaz y una clase final MediaPrintableArea para definir el patrón de medida de los atributos así como usar finalmente estos atributos, aunque en el código esta disperso por cuestiones de orden del applet, la secuencia es:



private PrintRequestAttributeSet atributosDeImpresion;
atributosDeImpresion = new HashPrintRequestAttributeSet();
unidadMedidaImpresion = MediaPrintableArea.MM;
atributosDeImpresion.add(new MediaPrintableArea(
margenIzquierdo, margenSuperior, anchoPagina,
altoPagina, unidadMedidaImpresion));


Con el método add de la interfaz PrintRequestAttributeSet podemos agregar atributos de impresión utilizando la clase HashPrintRequestAttributeSet y MediaPrintableArea y con ello definir los márgenes, ancho y alto de la página así como la unidad de medida de la impresión (MM: milímetros o INCH para pulgadas).

Si se sigue observando el código del Applet se puede ver que éste recibe varios parámetros, estos son:



margenSuperior = (getParameter("margen-superior") != null)?
Integer.parseInt(getParameter("margen-superior")):20;
margenIzquierdo = (getParameter("margen-izquierdo") != null)?
Integer.parseInt(getParameter("margen-izquierdo")):20;
anchoPagina = (getParameter("ancho-pagina") != null)?
Integer.parseInt(getParameter("ancho-pagina")):210;
altoPagina = (getParameter("alto-pagina") != null)?
Integer.parseInt(getParameter("alto-pagina")):297;
ipServer = getParameter("ip-server");
rutaArchivoHtml = getParameter("ruta-archivo");


Todo estos parámetros los debo pasar a través del código del html que tiene el applet de la siguiente manera:



<applet code="cheque.ReporteApplet.class" width="500" height="150">

<param name="margen-superior" value="10">
<param name="margen-izquierdo" value="10">
<param name="ancho-pagina" value="180">
<param name="alto-pagina" value="275">
<param name="ip-server" value="127.0.0.1">
<param name="ruta-archivo" value="applets/cheque.html">

</applet>


Por último y no menos importante del código de ReportEApplet es que cuando se hace click en el botón "Imprimir" se llama al método PrintComponent() este a su vez llama al método print que contiene:


public void print(){
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(this);
atributosDeImpresion.add(new MediaPrintableArea
(margenIzquierdo, margenSuperior,
anchoPagina, altoPagina, unidadMedidaImpresion));
if (job.printDialog(atributosDeImpresion)){
try{
job.print();
//Aqui codigo para cambiar valores en Base de datos
}catch (Exception ex){
System.out.println(ex);
}
}else{
warnUser("Impresión cancelada");
}
}

Donde es creado un PrinterJob y luego llamo a printDialog (Ventana de diálogo de impresión) pasándole como parámetro los atributos de impresión para saber cuales atributos va a utilizar en la Impresión. Si en el diálogo se hace click en "Imprimir" se envía automáticamente a imprimir, de otra forma (si se hace click en cancelar) se muestra un mensaje con el motivo correspondiente.

Bueno por ahora sólo falta el código HTML del cheque se los anexo aquí:



<html>
<head>
<title></title>
<meta content="">
<style>
body {
padding: 0;
margin: 0;
}
.papel{
position: absolute;
width: 18.60cm;
height: 20.70cm;
background: #dddddd;
margin: 0;
padding: 0;
}
.cheque table{
cellspacing: 0;
cellpadding: 0;
}
.cheque *{
font-family: arial;
font-size: 8pt;
font-weight: bold;
}
.cheque{
position: relative;
float: left;
clear:left;
width: 17.60cm;
height: 100px;
font-family: arial;
font-size: 8pt;
font-weight: bold;
background: #ffffff;
border: 2px solid black;
}
</style>
</head>
<body>
<table cellpadding="0" cellspacing="0" >
<tr>
<td width="13.60cm"></td>
<td align="left" height="0.92cm" valign="bottom" style="font-size: 8pt; font-family: arial; font-weight: bold;">2.550,75</td>
</tr>
</table>
<table border="0" cellpadding="0" cellspacing="0" class="cheque">
<table >
<tr>
<td height="1.30cm"></td>
</tr>
<tr>
<td width="1.50cm" height="0.80cm"><td>BENEFICIARIO DEL CHEQUE DE PRUEBA</td></td>
</tr>
</table>
<table >
<tr>
<td width="1.80cm" height="0.75cm"><td>DOS MIL QUINIENTOS CINCUENTA CON 75/100</td></td>
</tr>
<tr><td height="0.60cm"></td></tr>
</table>
<table >
<tr>
<td width="1.00cm" height="0.90cm"></td><td width="6.00cm">MARACAIBO, 09 DE ABRIL</td><td width="0.50cm">2010</td>
</tr>
</table>

</table>

</body>
</html>

Esto es sólo un ejemplo, pero en la práctica debe crearse un HTML dinámico que cambie los valores para monto, beneficiario, y los demás datos que el cheque necesita.

El archivo anterior HTML, se debe llamar cheque.html y debe estar en una ruta especificada por la clase ReporteApplet. En este caso estamos pasando como ruta del archivo applets/cheque.html y debe estar en la carpeta del servidor:

Aquí esta este detalle de la clase ReporteApplet que indica esto que acabo de mencionar:


//if ipServer == 127.0.0.1 invocar a localhost
//else invocar 192.168.0.91
if(ipServer != "192.168.0.91" &&
ipServer != null &&
ipServer.trim() != ""){
this.initialURL = new URL
("http://localhost/rutaProyecto/"+
rutaArchivoHtml);
}else{
this.initialURL = new URL
("http://192.168.0.91/rutaProyecto/"+
rutaArchivoHtml);
}



Bueno, espero que este código les sirva de modelo para impresión de cheques o cualquier reporte donde deban imprimir mediante ciertos atributos de impresión. Hasta la Próxima.

1 comentario:

Eveyo3 dijo...

muy bueno tu ejemplo me ayudo mucho a despejar algunas dudas que tenia sobre los metodos de impresion gracias voy a seguir leyendo tus post estan excelentes