【问题标题】:CrosshairOverlay throws NullpointerException with CombinedXYPlot (jfreechart)CrosshairOverlay 使用 CombinedXYPlot (jfreechart) 抛出 NullpointerException
【发布时间】:2017-09-11 18:51:37
【问题描述】:

我想从 jFreeCharts 库CrosshairOverlay 添加到我的CombinedXYPlot。在第一步中,我绘制了一个 XYPlot 并将其添加到我的组合 XYPlot 中。就像在几个演示和教程中一样,我创建了 crosshairOverlay 并将其添加到 chartPanel 以及相应的 combineXYPlot。

这是我的示例代码,它会产生 NullPointerException:

import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.panel.CrosshairOverlay;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.Crosshair;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RectangleEdge;

import javax.swing.*;
import java.awt.*;

public class stack implements ChartMouseListener{

    CombinedDomainXYPlot combinedDomainXYPlot;
    XYPlot myPlot1;

    Crosshair xCrosshair;
    Crosshair yCrosshair;

    public static void main(String[] args){

        stack s = new stack();


    }

    public stack(){

        ApplicationFrame app = new ApplicationFrame("Example");
        myPlot1 = createPlot();
        combinedDomainXYPlot = createCombinedXYPlot();
        JFreeChart chart = new JFreeChart("Example", combinedDomainXYPlot);
        ChartPanel chartPanel = new ChartPanel(chart);

        chartPanel.addChartMouseListener(this);

        CrosshairOverlay crosshairOverlay = new CrosshairOverlay();
        this.xCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
        this.xCrosshair.setLabelVisible(false);
        this.yCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
        this.yCrosshair.setLabelVisible(false);

        crosshairOverlay.addDomainCrosshair(xCrosshair);
        crosshairOverlay.addRangeCrosshair(yCrosshair);

        //chartPanel.addOverlay(crosshairOverlay);

        LegendTitle legend = chart.getLegend();
        legend.setPosition(RectangleEdge.RIGHT);
        legend.setBackgroundPaint(Color.BLACK);
        legend.setItemPaint(Color.GRAY);
        legend.setItemFont(new Font("Arial", 1, 9));

        app.getContentPane().add(chartPanel);
        app.pack();
        app.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        app.setVisible(true);

    }

    private XYPlot createPlot(){
        XYDataset data1 = createDataset();
        XYItemRenderer renderer1 = new StandardXYItemRenderer();
        NumberAxis rangeAxis1 = new NumberAxis("Range 1");
        XYPlot myPlot = new XYPlot(data1,null,rangeAxis1,renderer1);
        myPlot.setRangeAxisLocation(AxisLocation.BOTTOM_OR_LEFT);
        return myPlot;
    }

    private CombinedDomainXYPlot createCombinedXYPlot(){
        CombinedDomainXYPlot combinedDomainXYPlot = new CombinedDomainXYPlot(new NumberAxis());
        combinedDomainXYPlot.setGap(5);
        combinedDomainXYPlot.add(myPlot1,11);
        return combinedDomainXYPlot;
    }

    private XYDataset createDataset() {

        // create dataset 2...
        final XYSeries series2 = new XYSeries("Series 2");

        series2.add(10.0, 16853.2);
        series2.add(20.0, 19642.3);
        series2.add(30.0, 18253.5);
        series2.add(40.0, 15352.3);
        series2.add(50.0, 13532.0);
        series2.add(100.0, 12635.3);
        series2.add(110.0, 13998.2);
        series2.add(120.0, 11943.2);
        series2.add(130.0, 16943.9);
        series2.add(140.0, 17843.2);
        series2.add(150.0, 16495.3);
        series2.add(160.0, 17943.6);
        series2.add(170.0, 18500.7);
        series2.add(180.0, 19595.9);

        return new XYSeriesCollection(series2);

    }

    @Override
    public void chartMouseClicked(ChartMouseEvent event) {
        // would be happy to get this called without exception
        System.out.print("Test");
    }

    @Override
    public void chartMouseMoved(ChartMouseEvent event) {
        // would be happy to get this called  without exception
        System.out.print("Test");
    }
}

例外:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at org.jfree.chart.panel.CrosshairOverlay.paintOverlay(CrosshairOverlay.java:257)
    at org.jfree.chart.ChartPanel.paintComponent(ChartPanel.java:1658)
    at javax.swing.JComponent.paint(JComponent.java:1056)
    at javax.swing.JComponent.paintChildren(JComponent.java:889)
    at javax.swing.JComponent.paint(JComponent.java:1065)
    at javax.swing.JComponent.paintChildren(JComponent.java:889)
    at javax.swing.JComponent.paint(JComponent.java:1065)
    at javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
    at javax.swing.JComponent.paintChildren(JComponent.java:889)
    at javax.swing.JComponent.paintToOffscreen(JComponent.java:5217)
    at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1579)
    at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1502)
    at javax.swing.RepaintManager.paint(RepaintManager.java:1272)
    at javax.swing.JComponent.paint(JComponent.java:1042)
    at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)
    at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:79)
    at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:116)
    at java.awt.Container.paint(Container.java:1975)
    at java.awt.Window.paint(Window.java:3904)
    at javax.swing.RepaintManager$4.run(RepaintManager.java:842)
    ...

我可以在语句中找到(在 CrosshairOverlay.java 中)

double yy = yAxis.valueToJava2D(y, dataArea, yAxisEdge);

抛出 NullPointerException 因为yAxis 为空。这个变量在上面的语句中赋值:

ValueAxis yAxis = plot.getRangeAxis();

来自 XYPlot.java 的函数 RangeAxis()

public ValueAxis getRangeAxis(int index) {
    ValueAxis result = this.rangeAxes.get(index);
    if (result == null) {
        Plot parent = getParent();
        if (parent instanceof XYPlot) {
            XYPlot xy = (XYPlot) parent;
            result = xy.getRangeAxis(index);
        }
    }
    return result;
}

这里的 parent 不是 XYPlot 的实例,而是 nullgetParent() 函数的评论说:

返回父图(或null,如果此图不是部分 的组合图)。

此时我不明白为什么它返回null(可能是因为我在CombinedXYPlot 中并且它没有父级?)。谁能帮助我并解释为什么父情节为空,以及如何解决我的问题?

【问题讨论】:

    标签: java plot jfreechart


    【解决方案1】:

    我找到了问题的答案。我必须通过修改paintOverlay 函数来编写自己的CrosshairOverlay。现在(仅)为添加到 CombinedXYPlot 的第一个图绘制了十字准线

    我不得不向下转换为CombinedXYPlot 才能获得一个函数,该函数为我提供了 XYPlot 子图的列表。从那以后,我选择了第一个子图,让十字线画用这个来计算。

        @Override
        public void paintOverlay(Graphics2D g2, ChartPanel chartPanel) {
            Shape savedClip = g2.getClip();
            Rectangle2D dataArea = chartPanel.getScreenDataArea();
            g2.clip(dataArea);
            JFreeChart chart = chartPanel.getChart();
            XYPlot plot = (XYPlot) chart.getPlot();
    
            ValueAxis xAxis = plot.getDomainAxis();
            RectangleEdge xAxisEdge = plot.getDomainAxisEdge();
            Iterator iterator = getDomainCrosshairs().iterator();
            while (iterator.hasNext()) {
                Crosshair ch = (Crosshair) iterator.next();
                if (ch.isVisible()) {
                    double x = ch.getValue();
                    double xx = xAxis.valueToJava2D(x, dataArea, xAxisEdge);
                    if (plot.getOrientation() == PlotOrientation.VERTICAL) {
                        drawVerticalCrosshair(g2, dataArea, xx, ch);
                    }
                    else {
                        drawHorizontalCrosshair(g2, dataArea, xx, ch);
                    }
                }
            }
    
            // get subplots
            List<XYPlot> subplots = ((CombinedDomainXYPlot) plot).getSubplots();
    
            //take yAxis from first plot
            ValueAxis yAxis = subplots.get(0).getRangeAxis();
    
            RectangleEdge yAxisEdge = plot.getRangeAxisEdge();
            iterator = this.getRangeCrosshairs().iterator();
            while (iterator.hasNext()) {
                Crosshair ch = (Crosshair) iterator.next();
                if (ch.isVisible()) {
                    double y = ch.getValue();
                    double yy = yAxis.valueToJava2D(y, dataArea, yAxisEdge);
                    if (plot.getOrientation() == PlotOrientation.VERTICAL) {
                        drawHorizontalCrosshair(g2, dataArea, yy, ch);
                    }
                    else {
                        drawVerticalCrosshair(g2, dataArea, yy, ch);
                    }
                }
            }
            g2.setClip(savedClip);
        }
    

    该解决方案的问题是,如果我将子图添加到CombinedXYPlot十字线位置将按每个子图的大小移动。 我必须找到一种方法来获取子图的大小(每个图应该相同)并将其添加到yy 位置的计算中。

    这个问题与我原来的问题没有任何关系,所以我会等待一段时间的帮助或潜在的更好的答案,并将此帖子标记为解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-11
      • 2013-09-07
      • 2013-06-18
      • 2016-07-07
      • 2014-10-02
      • 2012-05-21
      • 2014-08-15
      相关资源
      最近更新 更多