使用 MS Windows 10 服务将其打印为 pdf 时出现的乱图

Messy diagram derives when it comes to printing it on pdf by using MS Windows 10 service

我一直在编写 Java SE 8 桌面应用程序。我在 MS Windows 10 OS.

上使用 Eclipse IDE、Oracle 的 JDK 和 运行

简而言之,我的应用程序绘制图表。我在 JPanel 上绘制了一个图表,它成为 JTabbedPane 的一部分。它在 GUI 上显示得很好,而且反应非常灵敏。当我通过打印服务图表时,问题出现了。但我没有在打印机上打印,而是选择 "Microsoft print to PDF" 服务。接下来会发生什么,如果图表很大,当你向下滚动它时,你会发现它的质量下降了。也就是说,网格开始消失,出现新行等。

图片在这里。

如您所见,最终垂直网格消失,对角线逐渐出现,然后变得更糟。那是不受欢迎的。

相关代码在这里:

public final class GanttChartDiagram extends TopDiagram{
@Override  
    public void paintComponent(Graphics graph){
        super.paintComponent(graph);

        Graphics2D g2D = (Graphics2D)graph; 

        g2D.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
...........

@Override
    public Dimension getPreferredSize(){
        return new Dimension(this.diagramWidth + 20, this.diagramHeight + 20);
    }
}
}

getPreferredSize() 方法标识图表的大小,以便应用程序知道如何相应地调整滚动条以适合图表。否则默认情况下它 return 0,如果不是覆盖。 也就是我画图的class

这里的超级class:

public abstract class TopDiagram extends JPanel implements Printable {
    private static final long serialVersionUID = 1469816888488484L;

    @Override
    public void paintComponent(Graphics graph){
        super.paintComponent(graph);
    };

    /**
     * Prints selected diagram
     */
    @Override
    public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {

        Graphics2D dimension = (Graphics2D)graphics;
        dimension.translate(pageFormat.getImageableX(), pageFormat.getImageableY());

        if(pageIndex < PrintingImageBuffer.getImageBuffer().size()){
           dimension.drawImage(PrintingImageBuffer.getImageBuffer().get(pageIndex), null, 0, 0);
           return PAGE_EXISTS;
        }
        else{
            return NO_SUCH_PAGE;
        }               
    }   
}

现在这是我打印图表的地方:

 public static void printDiagram(){
     new Thread(new Runnable(){

    public void run(){

    TopDiagram diagram = null;
                    if(id.equalsIgnoreCase("GanttChart")){
                        diagram = ganttChartDiagram;
    }

        final PrinterJob printer = PrinterJob.getPrinte

rJob();
                        printer.setJobName("Printing the "+id+" Diagram");  
                        PageFormat format = printer.pageDialog(page);

                        int nowWidth = (int)diagram.getPreferredSize().getWidth();
                        int nowHeight = (int)diagram.getPreferredSize().getHeight();

                        BufferedImage buffImg = new BufferedImage(nowWidth, nowHeight, BufferedImage.TYPE_INT_ARGB);//default type

                        Graphics2D d = (Graphics2D)buffImg.getGraphics();

    ....etc..................
    }

    }).start();
    }

现在有趣的部分是:

int nowWidth = (int)diagram.getPreferredSize().getWidth();
                        int nowHeight = (int)diagram.getPreferredSize().getHeight();

在同一个图表实例中,在多次调用 print 时(或在方法中),它可能会或可能不会 return 不同的值。所以它导致我出现某种光栅异常。但我设法通过仅调用一次 size 方法并在整个方法中重复使用该 size 值来摆脱该异常。因此,大小值保持不变,因为它只被读取一次。 糟糕的解决方案,但它有效。

我也想解决这个问题。首先,为什么这个调用 diagram.getPreferredSize().getWidth() 是在图 obj 的同一个实例上。 return大小值不同?还有一件事是,我覆盖了上面介绍的这种方法。而且图表对象只创建一次,没有重新计算。

这是我创建图表对象的地方。每个应用程序的生命周期仅在 Swing Worker 上使用一次。

GanttChartSwingWorker ganttSwingWorker = new GanttChartSwingWorker(GanttChartDiagram::new, tabbedPane, showPerformanceDiagramTab, ganttChartDiagramTabReady);
        ganttSwingWorker.execute();

        new Thread(() -> {      
            try{
                ganttChartDiagramTabReady.await();              
                ganttChartDiagram = ganttSwingWorker.getGanttChartDiagram();                

            }catch(InterruptedException ie){ie.printStackTrace();}
        }
        ).start();

Swing Worker部分:

diagram = this.get();

              JScrollPane scrollPaneChart = addScrollPane(diagram);              
              tabbedPane.addTab("Gantt Chart", null, scrollPaneChart, "Displays Gantt Chart Diagram");

有些图表对象的创建可能很耗时,会造成延迟,所以我使用 Swing Worker 来做到这一点。

所以,总结一下:

  1. 当我按照我解释的方式 print/save 它在 pdf 文件中时,如何使图表看起来干净?
  2. 如何使图表大小根据多次调用一致计算?是什么导致不同的图表大小值在多次调用时从同一个图表对象实例中检索它?

我刚刚弄明白是什么问题了。

我观察到在绘制图表时, paintComponent(Graphics g) 方法已被重复调用。它一遍又一遍地重新绘制图表。它由系统隐式调用,但我的实现已触发它。

并且该触发器以派生 JPanel 对象上的 this.setSize(width, height) 方法的形式出现。因此,每次 paintComponent(Graphics g) 重新执行时,它都会在 JPanel 上设置大小,这会触发 painComponent 方法的额外执行。最后就是死循环

无限执行是问题的根源;它在 pdf 文件上生成扭曲的图表图像。

解决方法:只在需要的时候执行setSize方法;在初始面板设置上,或调整大小。