Java 打印JFrame及其组件

Java 打印JFrame及其组件,java,swing,graphics,printing,jframe,Java,Swing,Graphics,Printing,Jframe,我一直在一个大程序中工作,它的功能之一应该是打印主窗口的内容。我检查了API,发现了以下示例: 这非常有帮助,我尝试在我的程序中使用该代码,将其放在打印按钮的actionperformed方法中: PrinterJob job = PrinterJob.getPrinterJob(); job.setPrintable(this); boolean ok = job.printDialog(); if (ok) { try {

我一直在一个大程序中工作,它的功能之一应该是打印主窗口的内容。我检查了API,发现了以下示例:

这非常有帮助,我尝试在我的程序中使用该代码,将其放在打印按钮的actionperformed方法中:

PrinterJob job = PrinterJob.getPrinterJob();
     job.setPrintable(this);
     boolean ok = job.printDialog();
     if (ok) {
         try {

             job.print();
         } catch (PrinterException ex) {
          /* The job did not successfully complete */
         }
     }
如果我点击打印按钮,我会看到一个打印机对话框,当我告诉它打印时,它只打印一个空白文档。我知道上面的代码并不是我所需要的全部,正如我在API的示例中所看到的,有一个print()方法,但显然他们从未调用过它,所以它非常混乱。我试过多次打电话和使用它,但都没有成功

另外,我认为当我最终打印时,我的窗口需要横向打印,甚至可能需要一些缩放。有什么办法吗


我想要任何有用的帮助来帮助我成功地实现这段代码。我知道我应该能够自己做这件事,只要检查一下文档(我已经尝试了将近两天了),但我无法让它工作。我通过互联网学会了所有我知道的编程。任何帮助都将不胜感激。

这里有一个简单的解决方案。我有一个实现printable的Printer类,它将处理打印作业:

public static class Printer implements Printable {
    final Component comp;

    public Printer(Component comp){
        this.comp = comp;
    }

    @Override
    public int print(Graphics g, PageFormat format, int page_index) 
            throws PrinterException {
        if (page_index > 0) {
            return Printable.NO_SUCH_PAGE;
        }

        // get the bounds of the component
        Dimension dim = comp.getSize();
        double cHeight = dim.getHeight();
        double cWidth = dim.getWidth();

        // get the bounds of the printable area
        double pHeight = format.getImageableHeight();
        double pWidth = format.getImageableWidth();

        double pXStart = format.getImageableX();
        double pYStart = format.getImageableY();

        double xRatio = pWidth / cWidth;
        double yRatio = pHeight / cHeight;


        Graphics2D g2 = (Graphics2D) g;
        g2.translate(pXStart, pYStart);
        g2.scale(xRatio, yRatio);
        comp.paint(g2);

        return Printable.PAGE_EXISTS;
    }
}
接下来,要打印它:

JFrame yourComponent = new JFrame();
PrinterJob pjob = PrinterJob.getPrinterJob();
PageFormat preformat = pjob.defaultPage();
preformat.setOrientation(PageFormat.LANDSCAPE);
PageFormat postformat = pjob.pageDialog(preformat);
//If user does not hit cancel then print.
if (preformat != postformat) {
    //Set print component
    pjob.setPrintable(new Printer(yourComponent), postformat);
    if (pjob.printDialog()) {
        pjob.print();
    }
}

这是我对这个想法的看法

打印以适合

打印以填充

public class TestPrinting {

    public static void main(String[] args) {    
        try {
            printComponentToFile(new PrintForm(), true);
            printComponentToFile(new PrintForm(), false);
        } catch (PrinterException exp) {
            exp.printStackTrace();
        }
    }

    public static void printComponent(JComponent comp, boolean fill) throws PrinterException {
        PrinterJob pjob = PrinterJob.getPrinterJob();
        PageFormat pf = pjob.defaultPage();
        pf.setOrientation(PageFormat.LANDSCAPE);

        PageFormat postformat = pjob.pageDialog(pf);
        if (pf != postformat) {
            //Set print component
            pjob.setPrintable(new ComponentPrinter(comp, fill), postformat);
            if (pjob.printDialog()) {
                pjob.print();
            }
        }    
    }

    public static void printComponentToFile(Component comp, boolean fill) throws PrinterException {    
        Paper paper = new Paper();
        paper.setSize(8.3 * 72, 11.7 * 72);
        paper.setImageableArea(18, 18, 559, 783);

        PageFormat pf = new PageFormat();
        pf.setPaper(paper);
        pf.setOrientation(PageFormat.LANDSCAPE);

        BufferedImage img = new BufferedImage(
                        (int) Math.round(pf.getWidth()),
                        (int) Math.round(pf.getHeight()),
                        BufferedImage.TYPE_INT_RGB);

        Graphics2D g2d = img.createGraphics();
        g2d.setColor(Color.WHITE);
        g2d.fill(new Rectangle(0, 0, img.getWidth(), img.getHeight()));
        ComponentPrinter cp = new ComponentPrinter(comp, fill);
        try {
            cp.print(g2d, pf, 0);
        } finally {
            g2d.dispose();
        }

        try {
            ImageIO.write(img, "png", new File("Page-" + (fill ? "Filled" : "") + ".png"));
        } catch (IOException ex) {
            ex.printStackTrace();
        }        
    }

    public static class ComponentPrinter implements Printable {

        private Component comp;
        private boolean fill;

        public ComponentPrinter(Component comp, boolean fill) {
            this.comp = comp;
            this.fill = fill;
        }

        @Override
        public int print(Graphics g, PageFormat format, int page_index) throws PrinterException {

            if (page_index > 0) {
                return Printable.NO_SUCH_PAGE;
            }

            Graphics2D g2 = (Graphics2D) g;
            g2.translate(format.getImageableX(), format.getImageableY());

            double width = (int) Math.floor(format.getImageableWidth());
            double height = (int) Math.floor(format.getImageableHeight());

            if (!fill) {

                width = Math.min(width, comp.getPreferredSize().width);
                height = Math.min(height, comp.getPreferredSize().height);

            }

            comp.setBounds(0, 0, (int) Math.floor(width), (int) Math.floor(height));
            if (comp.getParent() == null) {
                comp.addNotify();
            }
            comp.validate();
            comp.doLayout();
            comp.printAll(g2);
            if (comp.getParent() != null) {
                comp.removeNotify();
            }

            return Printable.PAGE_EXISTS;
        }

    }

}

一些范围更广的问题

  • 您将或多或少地负责已打印组件的布局。至少你会想确保它们或者合适,或者你有某种溢出机制
  • 您可能需要“欺骗”尚未在屏幕上显示的组件,使其认为它们是……因此,使用
    addNotify
    /
    验证
    /
    doLayout
    会产生所有的问题。即使在屏幕上显示,如果修改它们的边界,也可能需要调用这些方法

您的JFrame是否有
公共int打印(图形g、页面格式pf、int i)
方法覆盖?如果没有,考虑创建一个。在该方法的内部,考虑调用<代码> PrimaLoad(…)<代码>来打印JFrm及其所有组件。在打印方法中,我不使用<代码> COMP.Prase<代码>,我将使用<代码>打印< /代码>或<代码> PrimaLase>代码>除了它禁用双缓冲之外,我个人认为如果组件没有在屏幕上实现,这个方法会抛出一个空指针异常……IHMOHey非常感谢,它成功了。但是,它太大了,无法适应页面,我尝试在打印对话框中更改比例,但结果是相同的大小。你知道我该如何改变它吗?你可以翻译的方式,你甚至可以使用g2来缩放它。缩放(,)是的,这很有效,我自己想出来了,但是嘿,非常感谢你的帮助。@user1401250有没有办法修改这段代码来打印JFrames以外的内容?我试着把变量yourComponent改成一个表,但它只是打印一个空白页。这是一个很好的解决方案。在读这篇文章之前,我想了另一种方法。你知道,只是用g2.scale和ta-da,比我想象的要容易。谢谢,伙计。@AlexTerreaux,这就是为什么我不使用scaling;)