我運行該打印示例怎麼樣告訴我找不到main class java.lang.UnsupportedClassVersionError: javax/print/DocFlavor (Unsupported major.minor version 48.0) at java.lang.ClassLoader.defineClass0(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:486) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:111) at java.net.URLClassLoader.defineClass(URLClassLoader.java:248) at java.net.URLClassLoader.access$100(URLClassLoader.java:56) at java.net.URLClassLoader$1.run(URLClassLoader.java:195) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:297) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:286) at java.lang.ClassLoader.loadClass(ClassLoader.java:253) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:313)Exception in thread "main" "运行该程序时,请确保在命令行上输入了 PNG 图像文件的名称"。 PNG 图像文件的名称是指什麼。能說清楚一些嗎?謝謝!
Merlin 的魔力:在 JDK 1.4 中打印,第 1 部分 英文原文
内容:
定位一个打印机
指定输出格式
指定打印属性
设置内容
打印
打印机对话框
一个可运行的示例
参考资料
关于作者
对本文的评价
相关内容:
Design patterns 101
Merlin 的魔力归档
Java 专区中还有:
教学
工具与产品
代码与组件
所有文章
实用技巧
John Zukowski([email protected])
总裁,JZ Ventures 公司
2002 年 3 月从版本 1.1 以后,好像 Java 平台的每个新发行版都更改了平台的打印支持框架。Merlin 也不例外。在这个月的 Merlin 的魔力中,John Zukowski 开始分两部分对最新功能进行讨论。请单击文章顶部或底部的讨论在讨论论坛与作者和其他读者分享您对本文的心得。
如果您已经使用过一段时间 Java 平台,您可能会象我一样因打印 API 的无休止更改而感到沮丧。Merlin 已经为 Java 平台带来了另一套打印功能和技术。这个被称为“Java 打印服务 API”(Java Print Service API)的最新的再版从 1999 起就已经应用于 Java Community Process 了。幸运的是,新 API 是积极的补充,应该在一段时间里代表对打印支持的最终重要修改。 使用新的“打印服务 API”进行打印的过程包括三部分:发现、规范和打印。第四部分是当打印任务有进展时进行通知,这部分是可选的。本文中将用到的所有类和接口都在 javax.print 包,或者它的其中一个子包中(请参阅参考资料)。定位一台打印机
执行打印作业的第一步是识别您想用来打印的一个或一组打印机。打印机对象被称为打印服务,识别过程被称为查找。支持查找任务的类被恰如其分地命名为 PrintServiceLookup。要查找打印服务,您需要使用清单 1 中所示的三个方法的其中之一。清单 1. 查找一个打印服务 public static final PrintService
lookupDefaultPrintService()
public static final PrintService[]
lookupPrintServices(DocFlavor flavor, AttributeSet attributes)
public static final MultiDocPrintService[]
lookupMultiDocPrintServices(DocFlavor[] flavors,
AttributeSet attributes) 清单 1 中所示的这三个方法中的每一个都被用于不同的任务:lookupDefaultPrintService() 返回缺省的打印服务。
lookupPrintServices() 返回支持打印特定文档类型(比如 GIF)的打印机集,和一个特定的属性集(比如双面打印)。
lookupMultiDocPrintServices() 支持一次打印多个文档。
定位了自己想使用的打印服务后,您需要创建一个打印作业。 稍后,您将向这个作业发送输出。查找过程返回的 PrintService 可以用其 createPrintJob() 方法创建作业,如下所示:
PrintService printService =
PrintServiceLookup.lookupDefaultPrintService();
DocPrintJob job = printService.createPrintJob(); 指定输出格式
除了指定要打印到什么地方之外,您还必须指定打印文档的格式。这时,使用 DocFlavor 类(或它的其中一个子类)就很方便。DocFlavor 类被用于识别您要打印的对象的 MIME(Multipurpose Internet Mail Extensions,多用途因特网邮件扩展)类型。MIME 类型描述应该如何解释电子数据。在处理电子邮件和附件时,您可能已经遇到过 MIME 类型,但 MIME 规范描述了识别数据格式的更通用的机制。Merlin 提供了 DocFlavor 的七个子类,作为它自身用来定义格式的内部类。这些类可以分为三个 MIME 类型子集:面向字节的、面向字符的和面向服务的。面向字节的风格有:BYTE_ARRAY
INPUT_STREAM
URL
面向字符的有:CHAR_ARRAY
READER
STRING
面向服务的内部类是 SERVICE_FORMATTED。内部类中的内部类
每种风格类型支持它自己的 MIME 类型集。这些 MIME 类型也被定义为内部类。有 19 种面向字节的风格,如下所示:AUTOSENSE
GIF
JPEG
PCL
PDF
PNG
POSTSCRIPT
TEXT_HTML_HOST
TEXT_HTML_US_ASCII
TEXT_HTML_UTF_16
TEXT_HTML_UTF_16BE
TEXT_HTML_UTF_16LE
TEXT_HTML_UTF_8
TEXT_PLAIN_HOST
TEXT_PLAIN_US_ASCII
TEXT_PLAIN_UTF_16
TEXT_PLAIN_UTF_16BE
TEXT_PLAIN_UTF_16LE
TEXT_PLAIN_UTF_8
面向字符的流比较单调,只提供两种格式:TEXT_HTML
TEXT_PLAIN
面向服务的流包含三种格式:PAGEABLE
PRINTABLE
RENDERABLE_IMAGE
您可以象下面这样配置风格(在这个示例中,将其配置为 PNG 图像):
DocFlavor flavor = DocFlavor.INPUT_STREAM.PNG; 指定打印属性
打印时,您可以指定一些属性来描述您想如何打印文档。示例属性包括副本数目、要打印哪一页和文档图像类型(例如横向和纵向)。要指定属性,您需要使用下面两个类的其中之一:DocAttributeSet 为单个文档指定特性。
PrintRequestAttributeSet 指定单个打印作业的特性。
要为打印运行指定属性,您需要创建一个适当的属性集(DocAttributeSet 或 PrintRequestAttributeSet)的实例并用您期望的打印运行属性填充它。对于未指定的那些属性,还要为其配置合理的缺省值。javax.print.attribute 包拥有大约 70 个不同的属性,每个属性都被定义为单独的类。每个属性都使用一个或多个属性集。除本文中描述的两个属性集外,另外还有两个属性集可用于查询信息。javax.print.attribute 包提供一个公共空间用来查找所有的类型。下面我们将看到一个打印运行,它使用 PrintRequestAttributeSet 并把对象打印五份:
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
pras.add(new Copies(5)); 请务必看一下 javax.print.attribute 包中所有可用属性的列表。设置内容
Doc 接口为打印作业提供数据。该接口的实现者是 SimpleDoc 类。使用一个构造函数,提供内容作为第一个参数,风格作为第二个参数,属性作为第三个参数。该构造函数如下所示:
public SimpleDoc(Object printData, DocFlavor flavor,
DocAttributeSet attributes) 这就为我们留下了数据问题。答案取决于 DocFlavor。如果您指定了 DocFlavor.INPUT_STREAM 这种风格,那么数据将由它的 InputStream 识别。如果您的风格是 DocFlavor.BYTE_ARRAY,那么数据就是一个字节数组(byte [ ])。所以,要打印 PNG 图像文件,您需要使用清单 2 中所示的语法。清单 2. 设置内容 DocFlavor flavor = DocFlavor.INPUT_STREAM.PNG;
String filename = ...;
FileInputStream fis = new FileInputSteam(filename);
DocAttributeSet das = new HashDocAttributeSet();
Doc doc = new SimpleDoc(fis, flavor, das); 打印
一旦您识别了打印机,并指定了输出格式、属性和内容,那么只要打印一下就行了。实际的打印作业是通过 DocPrintJob(是从 PrintService 检索到的)的 print() 来执行,如清单 3 所示。清单 3. 一个打印作业 DocPrintJob job = ...;
PrintRequestAttributeSet pras = ...;
Doc doc = ...;
job.print(doc, pras);
通过调用 print(),您触发了一个机制,该机制在一个单独的线程中向打印服务发送内容。打印机对话框
很明显,目前为止我们还没有提到打印对话框。该对话框是由系统弹出的,允许您通过图形方式配置打印机属性。图 1 显示新“Java 打印服务 API”的打印对话框。图 1. 打印机对话框
有趣的是,打印机对话框的缺省行为已经用新的 API 更改了:缺省情况下对话框不显示。所以我们必须使用 ServiceUI 类创建如上面所示的打印对话框。ServiceUI 类提供一个单独的方法来显示打印机选择对话框:
printDialog(GraphicsConfiguration gc, int x, int y,
PrintService[] services, PrintService defaultService,
DocFlavor flavor, PrintRequestAttributeSet attributes) 然后您使用返回的 PrintService 获取打印要用的 DocPrintJob,如清单 4 所示。清单 4. 使用对话框打印 String filename = ...;
PrintRequestAttributeSet pras = ...;
DocFlavor flavor = ...;
PrintService printService[] =
PrintServiceLookup.lookupPrintServices(flavor, pras);
PrintService defaultService =
PrintServiceLookup.lookupDefaultPrintService();
PrintService service = ServiceUI.printDialog(null, 200, 200,
printService, defaultService, flavor, pras);
if (service != null) {
DocPrintJob job = service.createPrintJob();
FileInputStream fis = new FileInputStream(filename);
DocAttributeSet das = new HashDocAttributeSet();
Doc doc = new SimpleDoc(fis, flavor, das);
job.print(doc, pras);
}
一个可运行的示例
我们将以一个可运行的示例结束本文,该示例将让您试验新的“打印服务 API”的功能。下面的代码本质上是由先前所有的代码示例组合而成的一个可运行程序。运行该程序时,请确保在命令行上输入了 PNG 图像文件的名称。如果您更倾向于打印一种不同的格式,只需更改 DocFlavor 即可。清单 5. 一个打印示例 import javax.print.*;
import javax.print.attribute.*;
import java.io.*;public class Printing {
public static void main(String args[]) throws Exception {
String filename = args[0];
PrintRequestAttributeSet pras =
new HashPrintRequestAttributeSet();
DocFlavor flavor = DocFlavor.INPUT_STREAM.PNG;
PrintService printService[] =
PrintServiceLookup.lookupPrintServices(flavor, pras);
P
java.lang.UnsupportedClassVersionError: javax/print/DocFlavor (Unsupported major.minor version 48.0) at java.lang.ClassLoader.defineClass0(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:486) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:111) at java.net.URLClassLoader.defineClass(URLClassLoader.java:248) at java.net.URLClassLoader.access$100(URLClassLoader.java:56) at java.net.URLClassLoader$1.run(URLClassLoader.java:195) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:297) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:286) at java.lang.ClassLoader.loadClass(ClassLoader.java:253) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:313)Exception in thread "main"
"运行该程序时,请确保在命令行上输入了 PNG 图像文件的名称"。
PNG 图像文件的名称是指什麼。能說清楚一些嗎?謝謝!
同时也非常感谢cqli2002()的指引。
希望大家继续支持,谢谢!
[email protected]
import java.awt.event.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.awt.print.*;
import java.util.*;
import javax.swing.*;public class PrintTest
{ public static void main(String[] args)
{ JFrame frame = new PrintTestFrame();
frame.show();
}
}class PrintTestFrame extends JFrame
implements ActionListener
{ public PrintTestFrame()
{ setTitle("PrintTest");
setSize(300, 300);
addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent e)
{ System.exit(0);
}
} ); Container contentPane = getContentPane();
canvas = new PrintPanel();
contentPane.add(canvas, "Center"); JPanel buttonPanel = new JPanel();
printButton = new JButton("Print");
buttonPanel.add(printButton);
printButton.addActionListener(this); pageSetupButton = new JButton("Page setup");
buttonPanel.add(pageSetupButton);
pageSetupButton.addActionListener(this); contentPane.add(buttonPanel, "North");
} public void actionPerformed(ActionEvent event)
{ Object source = event.getSource();
if (source == printButton)
{ PrinterJob printJob = PrinterJob.getPrinterJob();
if (pageFormat == null)
pageFormat = printJob.defaultPage();
printJob.setPrintable(canvas, pageFormat);
if (printJob.printDialog())
{ try
{ printJob.print();
}
catch (PrinterException exception)
{ JOptionPane.showMessageDialog(this, exception);
}
}
}
else if (source == pageSetupButton)
{ PrinterJob printJob = PrinterJob.getPrinterJob();
if (pageFormat == null)
pageFormat = printJob.defaultPage();
pageFormat = printJob.pageDialog(pageFormat);
}
} private JButton printButton;
private JButton pageSetupButton; private PrintPanel canvas;
private PageFormat pageFormat;
}class PrintPanel extends JPanel
implements Printable
{ public void paintComponent(Graphics g)
{ super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
drawPage(g2);
} public int print(Graphics g, PageFormat pf, int page)
throws PrinterException
{ if (page >= 1) return Printable.NO_SUCH_PAGE;
Graphics2D g2 = (Graphics2D)g;
g2.setPaint(Color.black);
g2.translate(pf.getImageableX(), pf.getImageableY());
g2.draw(new Rectangle2D.Double(0, 0,
pf.getImageableWidth(), pf.getImageableHeight())); drawPage(g2);
return Printable.PAGE_EXISTS;
} public void drawPage(Graphics2D g2)
{ FontRenderContext context = g2.getFontRenderContext();
Font f = new Font("Serif", Font.PLAIN, 72);
GeneralPath clipShape = new GeneralPath(); TextLayout layout = new TextLayout("Hello", f, context);
AffineTransform transform
= AffineTransform.getTranslateInstance(0, 72);
Shape outline = layout.getOutline(transform);
clipShape.append(outline, false); layout = new TextLayout("World", f, context);
transform
= AffineTransform.getTranslateInstance(0, 144);
outline = layout.getOutline(transform);
clipShape.append(outline, false); g2.draw(clipShape);
g2.clip(clipShape); final int NLINES =50;
Point2D p = new Point2D.Double(0, 0);
for (int i = 0; i < NLINES; i++)
{ double x = (2 * getWidth() * i) / NLINES;
double y = (2 * getHeight() * (NLINES - 1 - i))
/ NLINES;
Point2D q = new Point2D.Double(x, y);
g2.draw(new Line2D.Double(p, q));
}
}
}
这个程序是可以实现打印的,但是我不明白class PrintPanel 的
工作原理,paintComponent、print、drawPage三个方法我都看不懂,
不知道它们内部怎么自动调用的,特别是方法paintComponent,
希望高手指点,让我可以修改此程序变成打印报表。因为我不懂
Graphics2D 所以看这程序有困难,请指点指点。
非常感激!!!
[email protected]