很是不幸,打印时没有几多工作是可以自动举办的。相反,为完成打印,我们必需经验大量机器的、非OO(面向工具)的步调。但打印一个图形化的组件时,大概几多有点儿自动化的意思:默认环境下,print()要了解挪用paint()来完本钱身的事情。大大都时候这都已经足够了,但如果还想做一些出格的工作,就必需知道页面的几许尺寸。
下面这个例子同时演示了文字和图形的打印,以及打印图形时可以采纳的差异要领。另外,它也对打印支持举办了测试:
//: PrintDemo.java // Printing with Java 1.1 import java.awt.*; import java.awt.event.*; public class PrintDemo extends Frame { Button printText = new Button("Print Text"), printGraphics = new Button("Print Graphics"); TextField ringNum = new TextField(3); Choice faces = new Choice(); Graphics g = null; Plot plot = new Plot3(); // Try different plots Toolkit tk = Toolkit.getDefaultToolkit(); public PrintDemo() { ringNum.setText("3"); ringNum.addTextListener(new RingL()); Panel p = new Panel(); p.setLayout(new FlowLayout()); printText.addActionListener(new TBL()); p.add(printText); p.add(new Label("Font:")); p.add(faces); printGraphics.addActionListener(new GBL()); p.add(printGraphics); p.add(new Label("Rings:")); p.add(ringNum); setLayout(new BorderLayout()); add(p, BorderLayout.NORTH); add(plot, BorderLayout.CENTER); String[] fontList = tk.getFontList(); for(int i = 0; i < fontList.length; i++) faces.add(fontList[i]); faces.select("Serif"); } class PrintData { public PrintJob pj; public int pageWidth, pageHeight; PrintData(String jobName) { pj = getToolkit().getPrintJob( PrintDemo.this, jobName, null); if(pj != null) { pageWidth = pj.getPageDimension().width; pageHeight= pj.getPageDimension().height; g = pj.getGraphics(); } } void end() { pj.end(); } } class ChangeFont { private int stringHeight; ChangeFont(String face, int style,int point){ if(g != null) { g.setFont(new Font(face, style, point)); stringHeight = g.getFontMetrics().getHeight(); } } int stringWidth(String s) { return g.getFontMetrics().stringWidth(s); } int stringHeight() { return stringHeight; } } class TBL implements ActionListener { public void actionPerformed(ActionEvent e) { PrintData pd = new PrintData("Print Text Test"); // Null means print job canceled: if(pd == null) return; String s = "PrintDemo"; ChangeFont cf = new ChangeFont( faces.getSelectedItem(), Font.ITALIC,72); g.drawString(s, (pd.pageWidth - cf.stringWidth(s)) / 2, (pd.pageHeight - cf.stringHeight()) / 3); s = "A smaller point size"; cf = new ChangeFont( faces.getSelectedItem(), Font.BOLD, 48); g.drawString(s, (pd.pageWidth - cf.stringWidth(s)) / 2, (int)((pd.pageHeight - cf.stringHeight())/1.5)); g.dispose(); pd.end(); } } class GBL implements ActionListener { public void actionPerformed(ActionEvent e) { PrintData pd = new PrintData("Print Graphics Test"); if(pd == null) return; plot.print(g); g.dispose(); pd.end(); } } class RingL implements TextListener { public void textValueChanged(TextEvent e) { int i = 1; try { i = Integer.parseInt(ringNum.getText()); } catch(NumberFormatException ex) { i = 1; } plot.rings = i; plot.repaint(); } } public static void main(String[] args) { Frame pdemo = new PrintDemo(); pdemo.setTitle("Print Demo"); pdemo.addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); pdemo.setSize(500, 500); pdemo.setVisible(true); } } class Plot extends Canvas { public int rings = 3; } class Plot1 extends Plot { // Default print() calls paint(): public void paint(Graphics g) { int w = getSize().width; int h = getSize().height; int xc = w / 2; int yc = w / 2; int x = 0, y = 0; for(int i = 0; i < rings; i++) { if(x < xc && y < yc) { g.drawOval(x, y, w, h); x += 10; y += 10; w -= 20; h -= 20; } } } } class Plot2 extends Plot { // To fit the picture to the page, you must // know whether you're printing or painting: public void paint(Graphics g) { int w, h; if(g instanceof PrintGraphics) { PrintJob pj = ((PrintGraphics)g).getPrintJob(); w = pj.getPageDimension().width; h = pj.getPageDimension().height; } else { w = getSize().width; h = getSize().height; } int xc = w / 2; int yc = w / 2; int x = 0, y = 0; for(int i = 0; i < rings; i++) { if(x < xc && y < yc) { g.drawOval(x, y, w, h); x += 10; y += 10; w -= 20; h -= 20; } } } } class Plot3 extends Plot { // Somewhat better. Separate // printing from painting: public void print(Graphics g) { // Assume it's a PrintGraphics object: PrintJob pj = ((PrintGraphics)g).getPrintJob(); int w = pj.getPageDimension().width; int h = pj.getPageDimension().height; doGraphics(g, w, h); } public void paint(Graphics g) { int w = getSize().width; int h = getSize().height; doGraphics(g, w, h); } private void doGraphics( Graphics g, int w, int h) { int xc = w / 2; int yc = w / 2; int x = 0, y = 0; for(int i = 0; i < rings; i++) { if(x < xc && y < yc) { g.drawOval(x, y, w, h); x += 10; y += 10; w -= 20; h -= 20; } } } } ///:~
#p#分页标题#e#
这个措施答允我们从一个选择列表框中选择字体(而且我们会留意到许多有用的字体在Java 1.1版中一直受到严格的限制,我们没有任何可以操作的优秀字体安装在我们的呆板上)。它利用这些字体去打出粗体,斜体和差异巨细的文字。别的,一个新型组件挪用过的画图被建设,以用来示范图形。当打印图形时,画图拥有的ring将显示在屏幕上和打印在纸上,而且这三个衍生类Plot1,Plot2,Plot3用差异的要领去完成任务以便我们可以看到我们选择的事物。同样,我们也能在一个画图中改变一些ring——这很有趣,因为它证明白Java 1.1版中打印的懦弱。在我的系统里,当ring计数显示“too high”(毕竟这是什么意思?)时,打印机给堕落误信息而且不能正确地事情,而当计数给出“low enough”信息时,打印机又能事情得很好。我们也会留意到,当打印到看起来实际巨细不相符的纸时页面的巨细便发生了。这些特点大概被装入到未来刊行的Java中,我们可以利用这个措施来测试它。
这个措施为促进反复利用,岂论何时都可以封装成果到内部类中。譬喻,岂论何时我想开始打印事情(岂论图形或文字),我必需建设一个PrintJob打印事情工具,该工具拥有它本身的连同页面宽度和高度的图形工具。建设的PrintJob打印事情工具和提取的页面尺寸一起被封装进PrintData class打印类中。
1. 打印文字
打印文字的观念简朴明白:我们选择一种字体和巨细,抉择字符串在页面上存在的位置,而且利用Graphics.drawSrting()要领在页面上画出字符串就行了。这意味着,不管奈何我们必需准确地计较每行字符串在页面上存在的位置并确定字符串不会超出页面底部可能同其它行斗嘴。假如我们想举办字处理惩罚,我们将举办的事情与我们很相配。ChangeFont封装进少量从一种字体到其它的字体的改观要领并自动地建设一个新字体工具和我们想要的字体,技俩(粗体和斜体——今朝还不支持下划线、空心等)以及点阵巨细。它同样会简朴地计较字符串的宽度和高度。当我们按下“Print text”按钮时,TBL吸收器被激活。我们可以留意到它通过重复建设ChangeFont工具和挪用drawString()来在计较出的位置打印出字符串。留意是否这些计较发生预期的功效。(我利用的版本没有堕落。)
2. 打印图形
按下“Print graphics”按钮时,GBL吸收器会被激活。我们需要打印时,建设的PrintData工具初始化,然后我们简朴地为这个组件挪用print()打印要领。为强制打印,我们必需为图形工具挪用dispose()处理惩罚要领,而且为PrintData工具挪用end()竣事要领(或改变为为PrintJob挪用end()竣事要领。)
这种事情在画图工具中继承。我们可以看到基本类画图是很简朴的——它扩展画布而且包罗一其间断挪用ring来指明几多个会合的ring需要画在这个非凡的画布上。这三个衍生类展示了可到达一个目标的差异的要领:画在屏幕上和打印的页面上。
Plot1回收最简朴的编程要领:忽略绘画和打印的差异,而且过载paint()绘画要领。利用这种事情要领的原因是默认的print()打印要领简朴地改变事情要领转而挪用Paint()。可是,我们会留意到输出的尺寸依赖于屏幕上画布的巨细,因为宽度和高度都是在挪用Canvas.getSize()要领时抉择是,所以这是公道的。假如我们图像的尺寸一值都是牢靠稳定的,其它的环境都可接管。当画出的外观的巨细如此的重要时,我们必需深入相识的尺寸巨细的重要性。不凑巧的是,就像我们将在Plot2中看到的一样,这种要领变得很棘手。因为一些我们不知道的好的来由,我们不能简朴地要求图形工具以它本身的巨细画出外观。这将使整个的处理惩罚事情变得十分的优良。相反,假如我们打印而不是绘画,我们必需操作RTTI instanceof要害字(在本书11章中有相应描写)来测试PrintGrapics,然后下溯造型并挪用这奇特的PrintGraphics要领:getPrintJob()要领。此刻我们拥有PrintJob的句柄而且我们可以发明纸张的高度和宽度。这是一种hacky的要领,但也许这对它来说是公道的来由。(在其它方面,到如今我们看到一些其它的库设计,因此,我们大概会获得设计者们的想法。)
我们可以留意到Plot2中的paint()绘画要领对打印和画图的大概性举办审查。可是因为当打印时Print()要领将被挪用,那么为什么不利用那种要领呢?这种要领同样也在Plot3中也被利用,而且它消除了对instanceof利用的需求,因为在Print()要领中我们可以假设我们能对一个PrintGraphics工具造型。这样也不坏。这种环境被安排民众绘画代码到一个疏散的doGraphics()要领的步伐所改造。
2. 在措施片内运行帧
假如我们想在一个措施片中打印会怎以样呢?很好,为了打印任何事物我们必需通过东西组件工具的getPrintJob()要领拥有一个PrintJob工具,配置独一的一个帧工具而不是一个措施片工具。于是它好像大概从一个应用措施中打印,而不是从一个措施片中打印。可是,它变为我们可以从一个措施片中建设一个帧(相反的到今朝为止,我在措施片或应用措施例子中所做的,都可以生成措施片并安顿帧。)。这是一个很有用的技能,因为它答允我们在措施片中利用一些应用措施(只要它们不故障措施片的安详)。可是,当应用措施窗口在措施片中呈现时,我们会留意到WEB欣赏器插入一些告诫在它上面,个中一些发生“Warning:Applet Window.(告诫:措施片窗口)”的字样。
我们会看到这种技能十分直接的安顿一个帧到措施片中。独一的事是当用户封锁它时我们必需增加帧的代码(取代挪用System.exit()):
//: PrintDemoApplet.java // Creating a Frame from within an Applet import java.applet.*; import java.awt.*; import java.awt.event.*; public class PrintDemoApplet extends Applet { public void init() { Button b = new Button("Run PrintDemo"); b.addActionListener(new PDL()); add(b); } class PDL implements ActionListener { public void actionPerformed(ActionEvent e) { final PrintDemo pd = new PrintDemo(); pd.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e){ pd.dispose(); } }); pd.setSize(500, 500); pd.show(); } } } ///:~
#p#分页标题#e#
陪伴Java 1.1版的打印支持成果而来的是一些杂乱。一些宣传好像声明我们能在一个措施片中打印。但Java的安详系统包括了一个特点,可遏制一个正在初始化打印事情的措施片,初始化措施片需要通过一个Web欣赏器或措施片欣赏器来举办。在写作这本书时,这看起来像留下了一个未定的争议。当我在WEB欣赏器中运行这个措施时,printdemo(打印样本)窗口正好呈现,但它却基础不能从欣赏器中打印。