文档

Java™教程
隐藏目录
如何打印表格
路径: 使用 Swing 创建 GUI
课程: 使用其他 Swing 特性

如何打印表格

JTable类提供对表格的打印支持。 JTable打印API包括了允许您实现基本和高级打印任务的方法。 对于常见的打印任务,当您只需要打印一个表格时,直接使用print方法即可。 print方法有多种形式,具有不同的参数集。 该方法准备您的表格,获取相应的Printable对象,并将其发送到打印机。

如果Printable对象的默认实现不符合您的需求,您可以通过重写getPrintable方法来自定义打印布局,以包装默认的Printable对象或完全替换它。

打印表格的最简单方法是调用没有参数的print方法。 请参阅下面的代码示例。

try {
    boolean complete = table.print();
    if (complete) {
        /* 显示成功消息 */
        ...
    } else {
        /* 显示打印被取消的消息 */
        ...
    }
} catch (PrinterException pe) {
    /* 打印失败,向用户报告 */
    ...
}

当您调用没有参数的print方法时,将显示打印对话框,然后以FIT_WIDTH模式交互式打印您的表格,不包括页眉和页脚。 以下代码示例显示了带有完整参数集的print方法签名。

boolean complete = table.print(JTable.PrintMode printMode,
                               MessageFormat headerFormat,
                               MessageFormat footerFormat, 
                               boolean showPrintDialog,
                               PrintRequestAttributeSet attr,
                               boolean interactive,
                               PrintService service);

当您使用所有参数调用print方法时,您可以明确选择打印功能,例如打印模式、页眉和页脚文本、打印属性、目标打印服务,以及是否显示打印对话框,以及是否交互式打印。 要确定哪些参数最适合您的需求,请参阅下面可用功能的描述。

JTable打印API提供以下功能:

交互式或非交互式打印

在交互模式下,将显示一个带有中止选项的进度对话框,用于打印的持续时间。 下面是一个进度对话框的示例。

打印进度对话框的截图

该对话框允许用户跟踪打印进度。进度对话框是模态的,这意味着在显示对话框时,用户无法与表格进行交互。在打印期间,重要的是您的表格保持不变,否则打印行为将是未定义的。然而,交互式打印不会阻止其他开发者的代码修改表格。例如,还有另一个线程使用SwingUtilities.invokeLater方法发布更新。因此,为确保正确的打印行为,您应确保在打印期间您自己的代码不会修改表格。

或者,您可以以非交互方式打印表格。在这种模式下,打印立即在事件调度线程上开始,并完全阻塞任何待处理的事件。一方面,这种模式可以确保在打印完成之前,表格不会发生任何更改。另一方面,这种模式完全剥夺了用户与GUI的任何交互。这就是为什么只有在从非可见GUI的应用程序打印时才推荐使用非交互打印。

打印对话框

您可以显示一个标准的打印对话框,允许用户执行以下操作:

打印对话框的截图

您可能会注意到打印对话框中没有指定打印输出的总页数。这是因为表格打印实现使用了Printable API,打印时无法预先知道总页数。

向打印布局添加页眉或页脚(或两者)

页眉和页脚由MessageFormat参数提供。这些参数允许对页眉和页脚进行本地化。请阅读MessageFormat类的文档,因为一些字符(例如单引号)是特殊字符,需要避免使用。页眉和页脚都居中。您可以使用{0}插入页码。

MessageFormat footer = new MessageFormat("Page - {0}");

由于在打印时不知道输出的总页数,因此无法指定像“第1页/共5页”这样的编号格式。

打印模式

打印模式负责缩放输出并将其分布在页面上。您可以以以下任一模式打印表格:

NORMAL模式下,表格以其当前大小打印。如果列无法适应一页,它们将根据表格的ComponentOrientation分布在其他页面上。在FIT_WIDTH模式下,如果需要,表格的大小会缩小以适应每页的所有列。请注意,宽度和高度都会按比例缩放,以提供相同比例的输出。在这两种模式下,行会依次跨多个页面展开,每页尽可能多的行。

自动布局和分页

使用JTable打印API,您无需关心布局和分页。您只需要为print方法指定适当的参数,例如打印模式和页脚文本格式(如果您想在页脚插入页码)。如前所示,您可以在页脚字符串中包含"{0}"来指定页码。在打印输出中,{0}将被当前页码替换。

表格打印示例

让我们来看一个名为TablePrintDemo1的示例。该程序的完整代码可以在TablePrintDemo1.java中找到。这个演示的丰富GUI是由NetBeans IDE GUI构建器自动构建的。这是TablePrintDemo1应用程序的截图。

TablePrintDemo1的截图

请尝试以下操作:
  1. 点击"启动"按钮,使用Java™ Web Start 运行TablePrintDemo1(下载JDK 7或更高版本)。或者,如果你想要自己编译和运行示例,请参考示例索引启动TablePrintDemo1应用程序
  2. 应用程序窗口底部的每个复选框都有工具提示。将鼠标悬停在复选框上,以了解其用途。
  3. 编辑“头部”或“底部”复选框中的文本,或同时编辑两者,以提供不同的页眉或页脚。
  4. 清除“头部”或“底部”复选框中的选中状态,以关闭页眉或页脚。
  5. 清除“显示打印对话框”复选框,以关闭打印对话框。
  6. 清除“适应打印页面宽度”复选框,以选择在“NORMAL”模式下打印。
  7. 清除“交互式(显示状态对话框)”复选框,以关闭打印对话框。
  8. 点击“打印”按钮,根据所选选项打印表格。

每当一个通过Web启动的应用程序尝试进行打印时,Java Web Start会弹出一个安全对话框,询问用户是否允许打印。要继续打印,用户必须接受请求。

请注意,当你清除“交互式”复选框时,会出现一个警告消息,提醒用户打印非交互式的劣势。你可以在PrintGradesTable方法中找到打印代码。当调用此方法时,首先从GUI组件中获取选定选项的集合,然后调用print方法,如下所示。

boolean complete = gradesTable.print(mode, header, footer,
                                     showPrintDialog, null,
                                     interactive, null);

print方法返回的值被用来显示成功消息或用户取消打印的消息。

另一个重要的功能是表格打印API使用表格渲染器。通过使用表格的渲染器,API提供了一个打印输出,其外观与屏幕上的表格相同。看一下屏幕上表格的最后一列。它包含了每个学生的通过或不通过状态的自定义图像。现在看一下打印结果。你会发现,勾号和叉号看起来是一样的。

下面是TablePrintDemo1在FIT_WIDTH模式下的打印结果的图片。

TablePrintDemo1示例的打印输出
此图片已缩小以适应页面。
点击图片以查看其原始大小。

TablePrintDemo2示例

TablePrintDemo2示例是基于上一个示例的,并且具有相同的界面。唯一的区别在于打印输出结果。如果你仔细观察TablePrintDemo1的打印结果,你可能会注意到勾号和X号模糊不清。TablePrintDemo2示例展示了如何自定义表格以使图像在表格打印中更加清晰可辨。在此示例中,重写的getTableCellRendererComponent方法判断表格是否正在打印,并返回更清晰的黑白图像。如果表格没有在打印,它返回在屏幕上可见的彩色图像。

点击“启动”按钮使用Java™ Web Start下载JDK 7或更高版本)运行TablePrintDemo2。或者,要自己编译和运行示例,请参考示例索引

启动TablePrintDemo2应用程序

JComponent类中定义的isPaintingForPrint方法允许我们根据打印和屏幕显示的差异来自定义打印内容。下面是自定义单元格渲染器的代码,取自TablePrintDemo2.java。这段代码根据isPaintingForPrint方法的返回值选择使用哪些图像。

    /**
     * 一个自定义单元格渲染器,继承自TablePrintDemo1的渲染器,用于在打印时使用更清晰的黑白图标。
     */
    protected static class BWPassedColumnRenderer extends PassedColumnRenderer {
            public Component getTableCellRendererComponent(JTable table,
                                                           Object value,
                                                           boolean isSelected,
                                                           boolean hasFocus,
                                                           int row,
                                                           int column) {

            super.getTableCellRendererComponent(table, value, isSelected,
                                                hasFocus, row, column);

            /* 如果当前正在打印,则使用黑白图标 */
            if (table.isPaintingForPrint()) {
                boolean status = (Boolean)value;
                setIcon(status ? passedIconBW : failedIconBW);
            } /* 否则,使用父类(彩色)图标 */

            return this;
        }
    }

这是TablePrintDemo2打印结果的图片,使用FIT_WIDTH模式。

TablePrintDemo2示例的打印输出
这张图片已经缩小以适应页面。
点击图片以查看其原始大小。

TablePrintDemo3示例

TablePrintDemo3示例基于前两个演示。此示例展示了如何通过包装默认的Printable来提供自定义的Printable实现。此演示具有类似的界面,但标题和页脚的复选框被禁用,因为自定义的可打印对象将提供自己的标题和页脚。

点击“启动”按钮使用Java™ Web Start 运行TablePrintDemo3(下载JDK 7或更高版本)。或者,要自己编译和运行示例,请参考示例索引

启动TablePrintDemo3应用程序

此示例将表格打印在剪贴板的图像内。这是TablePrintDemo3示例的打印结果的图片,使用FIT_WIDTH模式。

TablePrintDemo3示例的打印输出
这张图片已经缩小以适应页面。
点击图片以查看其原始大小。

此程序的完整代码可以在TablePrintDemo3.java中找到。在此演示中,使用了一个名为FancyPrintingJTableJTable类的自定义子类。这个FancyPrintingJTable类重写了getPrintable方法,返回一个自定义的可打印对象,该对象包装了默认的可打印对象,并带有自己的装饰、标题和页脚。下面是getPrintable方法的实现。

public Printable getPrintable(PrintMode printMode,
                              MessageFormat headerFormat,
                              MessageFormat footerFormat) {

     MessageFormat pageNumber = new MessageFormat("- {0} -");

     /* 获取默认的可打印对象 */
     Printable delegate = super.getPrintable(printMode, null, pageNumber);

     /* 返回一个包装默认可打印对象的精美可打印对象 */
     return new FancyPrintable(delegate);
}

FancyPrintable类负责将默认的可打印对象包装成另一个可打印对象,并设置剪贴板图像。当实例化这个类的一个实例时,它会加载组装剪贴板图像所需的图像,计算剪贴板图像所需的区域,计算表格的缩小区域,将表格打印到较小的区域,并组装和打印剪贴板图像。

请注意,组装剪贴板图像的代码对于页面大小的灵活性。代码考虑了实际页面的尺寸,并组合辅助图像,根据需要拉伸其中一些图像,以使最终的剪贴板图像适合实际页面大小。下图显示了辅助图像并指示这些图像如何组成最终的输出。

显示辅助图像如何用于打印输出的图表
此图已缩小以适应页面。
点击图片查看其原始大小。

表格打印API

本节列出了JTable类中定义的允许您打印表格的方法。

方法 目的
boolean print()
boolean print(printMode)
boolean print(printMode, MessageFormat, MessageFormat)
boolean print(printMode, MessageFormat, MessageFormat, boolean, PrintRequestAttributeSet, boolean)
boolean print(printMode, MessageFormat, MessageFormat, boolean, PrintRequestAttributeSet, boolean, PrintService)
当不带参数调用时,显示一个打印对话框,然后以FIT_WIDTH模式打印此表格,不包含页眉和页脚文本。如果用户继续打印,则返回true,如果用户取消打印,则返回false
当使用完整的参数列表调用时,根据指定的参数打印此表格。第一个参数指定打印模式。两个MessageFormat参数指定页眉和页脚文本。第一个布尔参数定义是否显示打印对话框。另一个布尔参数指定是否进行交互式打印。使用另外两个参数,您可以指定打印属性和打印服务。
每当省略一个PrintService参数时,将使用默认打印机。
Printable getPrintable(PrintMode, MessageFormat, MessageFormat) 返回用于打印表格的Printable对象。重写此方法以获取自定义的Printable对象。您可以将一个Printable对象包装在另一个中以获得各种布局。

使用表格打印的示例

这个表格列出了使用表格打印的示例,并指向了这些示例所描述的位置。

示例 描述位置 注释
TablePrintDemo 如何使用表格 演示了表格打印的基本功能,例如显示打印对话框,然后以FIT_WIDTH模式进行交互式打印,并将页码作为页眉。
TablePrintDemo1 本页面 演示了表格打印的基础知识,并提供了一个丰富的GUI。允许用户指定页眉或页脚文本,选择打印模式,打开或关闭打印对话框,以及选择交互式或非交互式打印。
TablePrintDemo2 本页面 基于TablePrintDemo1,此示例具有相同的界面。此演示演示了如何自定义表格,使打印结果与屏幕上显示的表格不同。
TablePrintDemo3 本页面 此演示显示了高级表格打印功能,例如将默认表格可打印对象包装到另一个可打印对象中,以获得不同的布局。

上一页:如何在对话框中使用模态
下一页:如何打印文本