Java PrintJob 到 DocPrintJob 不工作?

Java PrintJob to DocPrintJob Not Working?

我有一个从 Printable 扩展而来的 class,它使用标准 PrintJob 可以很好地打印,但我想转到 DocPrintJob,这样我就可以听到打印状态(成功打印等)。

我当前的代码如下所示,用于创建打印作业并打印

// define printer
AttributeSet attributes = new HashAttributeSet();
attributes.add(new Copies(1));

// get printerJob
PrinterJob printJob = PrinterJob.getPrinterJob();
PageFormat pageFormat = printJob.defaultPage();

// sizing (standard is 72dpi, so multiple inches by this)
Double height = 8d * 72d;
Double width = 3d * 72d;
Double margin = 0.1d * 72d;

// set page size
Paper paper = pageFormat.getPaper();

paper.setSize(width, height);
paper.setImageableArea(margin, margin, width - (margin * 2), height - (margin * 2));

// set orientation and paper
pageFormat.setOrientation(PageFormat.PORTRAIT);
pageFormat.setPaper(paper);

// create a book for printing
Book book = new Book();
book.append(new EventPrint(args.getEvent()), pageFormat);

// set book to what we are printing
printJob.setPageable(book);

// set print request attributes
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
aset.add(OrientationRequested.PORTRAIT);

// now print
try {
    printJob.print();
} catch (PrinterException e) {
    e.printStackTrace();
}   

现在要将其转换为 DocPrintJob,我按照 this link 了解如何将 PrintJob 转换为 DocPrintJob。所以现在我的代码变成了这个

PrintService[] services = PrinterJob.lookupPrintServices(); //list of printers
PrintService printService = services[0];
DocFlavor[] flavours = printService.getSupportedDocFlavors();

// may need to determine which printer to use
DocPrintJob printJob = printService.createPrintJob();

// get out printable
EventPrint eventPrint = new EventPrint(args.getEvent());

// convert printable to doc
Doc doc = new SimpleDoc(eventPrint, DocFlavor.SERVICE_FORMATTED.PRINTABLE, null);

// add eventlistener to printJob
printJob.addPrintJobListener(new PrintJobListener() {

    @Override
    public void printDataTransferCompleted(PrintJobEvent pje) {
        Console.Log("Print data sent successfully");
    }

    @Override
    public void printJobCompleted(PrintJobEvent pje) {
        Console.Log("Print successful");
    }

    @Override
    public void printJobFailed(PrintJobEvent pje) {
        Console.Log("Print failed");
    }

    @Override
    public void printJobCanceled(PrintJobEvent pje) {
        Console.Log("Print cancelled");                     
    }

    @Override
    public void printJobNoMoreEvents(PrintJobEvent pje) {
        Console.Log("No more printJob events");
    }

    @Override
    public void printJobRequiresAttention(PrintJobEvent pje) {
        Console.Log("printJob requires attention");                     
    }

});

PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
aset.add(new Copies(1));

try {
    printJob.print(doc, aset);
} catch (Exception e) {

}

现在由于某种原因,我的打印一直在执行(400 多次直到我关闭应用程序)。我不确定是不是因为我没有设置纸张尺寸,就像我在使用 PrintJob 时所做的那样?那会导致吗?如果是这样,我该如何设置 DocPrintJob 的 paperSize,因为它没有普通 printJob 所具有的方法?

以前有其他人遇到过这个问题吗?

编辑:这是我的 eventPrint class 和它继承自

的 class

PRINTABLEBASE.JAVA

public class PrintableBase {

    public Graphics2D g2d;
    public float x, y, imageHeight, imageWidth, maxY;
    public enum Alignment { LEFT, RIGHT, CENTER };

    public void printSetup(Graphics graphics, PageFormat pageFormat) {
        // user (0,0) is typically outside the imageable area, so we must translate
        // by the X and Y values in the pageFormat to avoid clipping
        g2d = (Graphics2D) graphics;
        g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());

        // get starter X and Y
        x = 0;//(float)pageFormat.getImageableX();

        // do not offset vertical as pushes ticket down too much
        y = 0;//(float)pageFormat.getImageableY();

        // get height and width of the printable image
        imageWidth = (float)pageFormat.getImageableWidth();
        imageHeight = (float)pageFormat.getImageableHeight();

        // maximum that we can go vertically
        maxY = y;

        Console.Log("imageWidth:" + imageWidth);
        Console.Log("imageHeight: " + imageHeight);
        Console.Log("X: " + x);
        Console.Log("Y: " + y);
    }

    public void setFont(Font font) {
        g2d.setFont(font);
    }

    public float addSeparatorLine(float y, float imageWidth) {
        String fontName = g2d.getFont().getName();
        int fontStyle = g2d.getFont().getStyle();
        int fontSize = g2d.getFont().getSize();

        g2d.setFont(new Font("Arial", Font.PLAIN, 10));

        y = drawFirstLine(g2d, "---------------------------------------------------------------------------------------", imageWidth, 0, y, Alignment.LEFT);

        // revery font
        g2d.setFont(new Font(fontName, fontStyle, fontSize));

        return y + 5;
    }

    public BufferedImage scaleImage(BufferedImage sbi, int dWidth, int dHeight) {
        BufferedImage dbi = null;
        if(sbi != null) {
            // calculate ratio between standard size and scaled
            double wRatio = (double)dWidth / (double)sbi.getWidth();
            double hRatio = (double)dHeight / (double)sbi.getHeight();

            // use wRatio by default
            double sWidth = (double)sbi.getWidth() * wRatio;
            double sHeight = (double)sbi.getHeight() * wRatio;

            // if hRation is small, use that, as image will be reduced by more
            if (hRatio < wRatio) {
                sWidth = (double)sbi.getWidth() * hRatio;
                sHeight = (double)sbi.getHeight() * hRatio;             
            }

            double sRatio = (wRatio < hRatio) ? wRatio : hRatio;

            // now create graphic, of new size
            dbi = new BufferedImage((int)sWidth, (int)sHeight, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g = dbi.createGraphics();

            AffineTransform at = AffineTransform.getScaleInstance(sRatio, sRatio);
            g.drawRenderedImage(sbi, at);
        }
        return dbi;
    }

    // This function will only add the first line of text and will not wrap
    // useful for adding the ticket title.  
    // Returns the height of the text
    public float drawFirstLine(Graphics2D g2, String text, float width, float x, float y, Alignment alignment) {
        AttributedString attstring = new AttributedString(text);
        attstring.addAttribute(TextAttribute.FONT, g2.getFont());
        AttributedCharacterIterator paragraph = attstring.getIterator();
        int paragraphStart = paragraph.getBeginIndex();
        int paragraphEnd = paragraph.getEndIndex();
        FontRenderContext frc = g2.getFontRenderContext();
        LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, frc);

        // Set break width to width of Component.
        float breakWidth = width;
        float drawPosY = y;
        // Set position to the index of the first character in the paragraph.
        lineMeasurer.setPosition(paragraphStart);

        // Get lines until the entire paragraph has been displayed.
        if (lineMeasurer.getPosition() < paragraphEnd) {
            // Retrieve next layout. A cleverer program would also cache
            // these layouts until the component is re-sized.
            TextLayout layout = lineMeasurer.nextLayout(breakWidth);
            // Compute pen x position. 
            float drawPosX;

            switch (alignment){         
                case RIGHT:
                    drawPosX = (float) x + breakWidth - layout.getAdvance();
                    break;
                case CENTER:
                    drawPosX = (float) x + (breakWidth - layout.getAdvance())/2;
                    break;
                default: 
                    drawPosX = (float) x;
            }
            // Move y-coordinate by the ascent of the layout.
            drawPosY += layout.getAscent();

            // Draw the TextLayout at (drawPosX, drawPosY).
            layout.draw(g2, drawPosX, drawPosY);

            // Move y-coordinate in preparation for next layout.
            drawPosY += layout.getDescent() + layout.getLeading();
        }
        return drawPosY;
    }

    /**
     * Draw paragraph.
     *
     * @param g2 Drawing graphic.
     * @param text String to draw.
     * @param width Paragraph's desired width.
     * @param x Start paragraph's X-Position.
     * @param y Start paragraph's Y-Position.
     * @param dir Paragraph's alignment.
     * @return Next line Y-position to write to.
     */
    protected float drawParagraph (String text, float width, float x, float y, Alignment alignment){
        AttributedString attstring = new AttributedString(text);
        attstring.addAttribute(TextAttribute.FONT, g2d.getFont());
        AttributedCharacterIterator paragraph = attstring.getIterator();
        int paragraphStart = paragraph.getBeginIndex();
        int paragraphEnd = paragraph.getEndIndex();
        FontRenderContext frc = g2d.getFontRenderContext();
        LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, frc);

        // Set break width to width of Component.
        float breakWidth = width;
        float drawPosY = y;
        // Set position to the index of the first character in the paragraph.
        lineMeasurer.setPosition(paragraphStart);

        // Get lines until the entire paragraph has been displayed.
        while (lineMeasurer.getPosition() < paragraphEnd) {
            // Retrieve next layout. A cleverer program would also cache
            // these layouts until the component is re-sized.
            TextLayout layout = lineMeasurer.nextLayout(breakWidth);
            // Compute pen x position. 
            float drawPosX;
            switch (alignment){         
                case RIGHT:
                    drawPosX = (float) x + breakWidth - layout.getAdvance();
                    break;
                case CENTER:
                    drawPosX = (float) x + (breakWidth - layout.getAdvance())/2;
                    break;
                default: 
                    drawPosX = (float) x;
            }
            // Move y-coordinate by the ascent of the layout.
            drawPosY += layout.getAscent();

            // Draw the TextLayout at (drawPosX, drawPosY).
            layout.draw(g2d, drawPosX, drawPosY);

            // Move y-coordinate in preparation for next layout.
            drawPosY += layout.getDescent() + layout.getLeading();
        }
        return drawPosY;
    }

}

EVENTPRINT.JAVA

public class EventPrint extends PrintableBase implements Printable {

    private Event event;

    public EventPrint(Event event) {
        this.event = event; 
    }

    @Override
    public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
            throws PrinterException {

        // setup
        super.printSetup(graphics, pageFormat);

        // title
        super.setFont(new Font("Tahoma", Font.BOLD, 16));
        y = super.drawParagraph(event.getTitle(), imageWidth, x, y, Alignment.LEFT);

    RETURN PAGE_EXISTS;                 
}

我在从 PrinterJob 切换到 DocPrintJob 时也遇到了一些问题。你的代码对我来说似乎很好,所以也许你对页面大小是正确的。您可以这样设置页面大小:

aset.add(new MediaPrintableArea(0, 0, width, height, MediaPrintableArea.MM));

但这取决于您的可打印对象如何设置。我用 iText 创建了一个 bytearray (PDF) 并在那里设置了页面大小。然后,我将上面代码中的宽度和高度设置为Integer.MAX_VALUE

我回家后可以 post 我的全部代码。希望对您有所帮助!

我会说你的问题是你从来没有告诉 API 没有更多的页面....

public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
        throws PrinterException {

    // setup
    super.printSetup(graphics, pageFormat);

    // title
    super.setFont(new Font("Tahoma", Font.BOLD, 16));
    y = super.drawParagraph(event.getTitle(), imageWidth, x, y, Alignment.LEFT);

    RETURN PAGE_EXISTS;                 
}

所以,假设您只想打印一页,您可以使用类似...

public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
        throws PrinterException {
    int result = NO_SUCH_PAGE;
    if (pageIndex == 0) {

        // setup
        super.printSetup(graphics, pageFormat);

        // title
        super.setFont(new Font("Tahoma", Font.BOLD, 16));
        y = super.drawParagraph(event.getTitle(), imageWidth, x, y, Alignment.LEFT);
        result = PAGE_EXISTS;
    }

    RETURN result;                 
}

否则API不知道什么时候停止打印

Bookable 使用不同的方法,因为书的每一页只打印一次,并且会一直打印到所有页面都打印完。 Printable不同,它会一直打印直到你告诉它停止

查看 A Basic Printing Program 了解更多详情