【问题标题】:JavaFX 8 scale node for printing without changing displayed nodeJavaFX 8 缩放节点用于打印而不更改显示节点
【发布时间】:2017-07-11 15:55:04
【问题描述】:

在 JavaFX 8 中,我正在使用 printerJob.printPage() 打印一个节点(例如 ScatterChart)。没有缩放,打印的节点被裁剪。如果我缩放打印,则打印的节点正确适合页面,但显示的节点被缩放。一个简单的解决方案是复制/克隆节点,但似乎不支持。有没有比缩放节点然后移除缩放更好的解决方案(这会导致显示的节点短暂地重新缩放,这很难看)?看起来打印图表将是 JavaFX 的基本操作。

【问题讨论】:

  • 打印时隐藏显示节点。完成后带回来。
  • 我确实尝试了 setVisible(false),但它没有打印出来。我想我可以将它从父节点中删除,打印,然后将其放回父节点,但这与重新缩放一样难看。我仍然希望有一个更清洁的解决方案。
  • 您是否尝试过使用Snapshot API?然后打印生成的图像。 SnapeShot 例子。

标签: javafx


【解决方案1】:

你可以玩这个应用程序。它创建图表的PNG。然后打印图表。我没有缩放图像。实际图像位于您的源文件夹中。您也可以使用 Paint 打开它并从那里打印。您还可以对打印机设置进行编码,以便在打印之前显示打印机对话框。

import java.awt.Graphics;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import static java.awt.print.Printable.NO_SUCH_PAGE;
import static java.awt.print.Printable.PAGE_EXISTS;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.IOException;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javax.imageio.ImageIO;

/**
 *
 * @author blj0011
 */
public class JavaFXApplication145 extends Application
{

    final static String itemA = "A";
    final static String itemB = "B";
    final static String itemC = "F";
    @Override
    public void start(Stage stage) {
        final NumberAxis xAxis = new NumberAxis();
        final CategoryAxis yAxis = new CategoryAxis();
        final BarChart<Number, String> bc = new BarChart<Number, String>(xAxis, yAxis);
        bc.setTitle("Summary");
        xAxis.setLabel("Value");
        xAxis.setTickLabelRotation(90);
        yAxis.setLabel("Item");

        XYChart.Series series1 = new XYChart.Series();
        series1.setName("2003");
        series1.getData().add(new XYChart.Data(2, itemA));
        series1.getData().add(new XYChart.Data(20, itemB));
        series1.getData().add(new XYChart.Data(10, itemC));

        XYChart.Series series2 = new XYChart.Series();
        series2.setName("2004");
        series2.getData().add(new XYChart.Data(50, itemA));
        series2.getData().add(new XYChart.Data(41, itemB));
        series2.getData().add(new XYChart.Data(45, itemC));

        XYChart.Series series3 = new XYChart.Series();
        series3.setName("2005");
        series3.getData().add(new XYChart.Data(45, itemA));
        series3.getData().add(new XYChart.Data(44, itemB));
        series3.getData().add(new XYChart.Data(18, itemC));

        Button button = new Button("Print Chart");
        button.setOnAction((event)->{printImage(saveAsPng(bc));});//Create the image and print it.

        VBox vbox = new VBox();
        vbox.getChildren().add(bc);

        StackPane stackPane = new StackPane();
        stackPane.getChildren().add(button);
        vbox.getChildren().add(stackPane);

        Scene scene = new Scene(vbox, 800, 600);
        bc.getData().addAll(series1, series2, series3);
        stage.setScene(scene);
        stage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        launch(args);
    }

    public File saveAsPng(BarChart barChart) {
        WritableImage image = barChart.snapshot(new SnapshotParameters(), null);

        // TODO: probably use a file chooser here
        File file = new File("chart.png");

        try {
            ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", file);
        } catch (IOException e) {
            // TODO: handle exception here
        }

        return file;
    }

    private void printImage(File file) {
        Image image = new Image(file.toURI().toString());
        java.awt.image.BufferedImage bufferedImage = SwingFXUtils.fromFXImage(image, null);
        PrinterJob printJob = PrinterJob.getPrinterJob();
        printJob.setPrintable(new Printable() {
            @Override
            public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException                    {
                // Get the upper left corner that it printable
                int x = (int) Math.ceil(pageFormat.getImageableX());
                int y = (int) Math.ceil(pageFormat.getImageableY());
                if (pageIndex != 0) {
                    return NO_SUCH_PAGE;
                }
                graphics.drawImage(bufferedImage, x, y, bufferedImage.getWidth(), bufferedImage.getHeight(), null);

                return PAGE_EXISTS;
            }
        });
        try {
            printJob.print();
        } catch (PrinterException e1) {
            e1.printStackTrace();
        }
    }
}

【讨论】:

  • 我喜欢 this 打印作业的方式。他们拿走了 PNG 并将其添加到 ImageView。然后他们使用JavaFX打印API打印ImageView
  • 当我回到它时我会看看这个。在发布之前,我确实尝试过使用 JavaFX ScatterPlot 快照的类似方法,但是我的代码产生的质量不如缩放和打印图表本身产生的质量。我确实尝试使用基于打印机分辨率的非常高分辨率的图像,但结果(打印到 PDF)较差。可能,我在创建图像时没有使用最佳参数。似乎最好的方法是让 JavaFX 为 PrinterJob 提供可选的缩放参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-31
  • 2015-11-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多