Java Swing 中的图形绘制仅绘制点

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17536229/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 02:15:04  来源:igfitidea点击:

Graph plotting in Java Swing only draws points

javaswinggraph

提问by user1209014

I'm currently working on a program where certain numerical variables, which evolve over time, have their value displayed on each iteration. That works well enough, but now I want to plot a graph that shows their evolution over time. So, I looked into an example of code for plotting graphs in Swing. My final code looks like this:

我目前正在开发一个程序,其中某些随时间演变的数值变量在每次迭代中都显示其值。这很有效,但现在我想绘制一个图表来显示它们随时间的演变。所以,我研究了一个在 Swing 中绘制图形的代码示例。我的最终代码如下所示:

public class Populus3 extends JPanel
{
    public static void main(String[] args) throws IOException {

        final Populus3 pop = new Populus3();

        JFrame f = new JFrame(); //where I want to plot the graph
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new GraphingData());
        f.setSize(400,400);
        f.setLocation(200,200);
        f.setVisible(true);


        frame = new JFrame("Animation Frame"); //where I'm running animation for another element of the program
        frame.add(pop, BorderLayout.CENTER);
        frame.setSize(graphSize, graphSize);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //insert all sort of things

    }


    public void paint(Graphics g) 
    {
        super.paint(g);
        paintCell(g, 1);
        Toolkit.getDefaultToolkit().sync(); // necessary for linux users to draw  and animate image correctly
        g.dispose();
    }


      public void actionPerformed(ActionEvent e) {
        repaint();
    }



    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        for(int i = 0; i < particleType.length; i++)
            paintCell(g, i);  //a method that draws a small circle for the animation panel
    }



    public static class GraphingData extends JPanel {
        int[] data = {
            21, 14, 18, 03, 86, 88, 74, 87, 54, 77,
            61, 55, 48, 60, 49, 36, 38, 27, 20, 18
        };
        final int PAD = 20;

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D)g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                RenderingHints.VALUE_ANTIALIAS_ON);
            int w = getWidth();
            int h = getHeight();
            // Draw ordinate.
            g2.draw(new Line2D.Double(PAD, PAD, PAD, h-PAD));

            // Draw abcissa.
            g2.draw(new Line2D.Double(PAD, h-PAD, w-PAD, h-PAD));
            double xInc = (double)(w - 2*PAD)/(data.length-1);
            double scale = (double)(h - 2*PAD)/getMax();
            // Mark data points.
            g2.setPaint(Color.red);
            for(int i = 0; i < data.length; i++) {
                double x = PAD + i*xInc;
                double y = h - PAD - scale*data[i];
                g2.fill(new Ellipse2D.Double(x-2, y-2, 4, 4));
            }
        }

        private int getMax() {
            int max = -Integer.MAX_VALUE;
            for(int i = 0; i < data.length; i++) {
                if(data[i] > max)
                    max = data[i];
            }
            return max;
        }
    }
}

Now, the animation panel works just fine. The graph panel, on the other hand...when I run the program, it displays a bunch of red dots, without lines to connect them. What am I doing wrong?

现在,动画面板工作正常。另一方面,图形面板......当我运行程序时,它显示一堆红点,没有线来连接它们。我究竟做错了什么?

回答by trashgod

In addition to @Hovercraft's helpful suggestions, also consider these other approaches:

除了@Hovercraft 的有用建议之外,还可以考虑以下其他方法:

  • Accumulate the points in a GeneralPaththat may be rendered as required, for example.
  • 累积 aGeneralPath中可以根据需要渲染的点,例如

lissajou image

丽莎茹图像

  • Connect the points using repeated calls to drawLine()using a suitable coordinate system, outlined here.
  • 使用重复调用将点连接到drawLine()使用合适的坐标系,此处概述。

sine image

正弦图像

回答by Hovercraft Full Of Eels

Your code confuses me:

你的代码让我困惑:

  • You override both paint and paintComponent for your Populus3 JPanel -- why? You should only override paintComponent unless you absolutely have to have your drawing affect a component's children and borders.
  • You dispose of the Graphics object passed into paint -- a verydangerous thing to do. You should never dispose of a Graphics object given to you by the JVM, only Graphics objects that you yourself create.
  • You repeatedly call a method not defined here for us, paintCell(...).
  • I've never heard of the need for Toolkit.getDefaultToolkit().sync();for Swing applications. Do you have a reference for this need?
  • You mention "animation" but I see no animation code.
  • In your GraphingData class's paintComponent method you fill ellipses in your for loop, but you don't connect them with lines ever, so it shouldn't be surprising that you're only seeing dots in your graph and no lines.
  • 您为 Populus3 JPanel 覆盖了paint 和paintComponent -- 为什么?您应该只覆盖paintComponent,除非您绝对必须让您的绘图影响组件的子项和边框。
  • 您处理了传递给paint 的Graphics 对象——这是一件非常危险的事情。您永远不应该处理 JVM 提供给您的 Graphics 对象,只能处理您自己创建的 Graphics 对象。
  • 您反复调用此处未为我们定义的方法,paintCell(...)
  • 我从未听说过需要Toolkit.getDefaultToolkit().sync();Swing 应用程序。你有这个需求的参考吗?
  • 你提到了“动画”,但我看不到动画代码。
  • 在您的 GraphingData 类的 paintComponent 方法中,您在 for 循环中填充椭圆,但您永远不会用线将它们连接起来,因此您在图形中只看到点而没有线也就不足为奇了。

Consider isolating your problem more and posting an sscce, a minimal test program that we can compile, run, modify and correct and that shows us your problem, but has no extra code not related to the problem or required for demonstration.

考虑更多地隔离您的问题并发布sscce,这是一个我们可以编译、运行、修改和更正的最小测试程序,它向我们展示了您的问题,但没有与问题无关或演示所需的额外代码。

回答by herrtim

The following code demonstrates a real-time Java chart using XChartwhere the line is updated as the data evolves over time. Creating real-time charts is as simple as calling updateXYSeriesfor one or more series objects through the XYChartinstance and triggering a redraw of the JPanelcontaining the chart. This works for all chart types including XYChart, CategoryChart, BubbleChartand PieChart, for which example source code can be found here: https://github.com/timmolter/XChart/tree/develop/xchart-demo/src/main/java/org/knowm/xchart/demo/charts/realtime. Examples demonstrate using the SwingWrapperwith repaintChart()method as well as XChartPanelwith revalidate()and repaint(). Disclaimer, I'm the main developer of the XChart library.

以下代码演示了一个使用XChart的实时 Java 图表,其中线条随着数据的变化而更新。创建实时图表就像updateXYSeries通过XYChart实例调用一个或多个系列对象并触发JPanel包含图表的重绘一样简单。这适用于所有图表类型包括XYChartCategoryChartBubbleChartPieChart,对此示例源代码可以在这里找到:https://github.com/timmolter/XChart/tree/develop/xchart-demo/src/main/java/org/knowm /xchart/demo/charts/realtime。示例演示如何使用SwingWrapperwithrepaintChart()方法以及XChartPanelwithrevalidate()repaint()。免责声明,我是 XChart 库的主要开发者。

public class SimpleRealTime {

  public static void main(String[] args) throws Exception {

    double phase = 0;
    double[][] initdata = getSineData(phase);

    // Create Chart
    final XYChart chart = QuickChart.getChart("Simple XChart Real-time Demo", "Radians", "Sine", "sine", initdata[0], initdata[1]);

    // Show it
    final SwingWrapper<XYChart> sw = new SwingWrapper<XYChart>(chart);
    sw.displayChart();

    while (true) {

      phase += 2 * Math.PI * 2 / 20.0;

      Thread.sleep(100);

      final double[][] data = getSineData(phase);

      chart.updateXYSeries("sine", data[0], data[1], null);
      sw.repaintChart();

    }

  }

  private static double[][] getSineData(double phase) {

    double[] xData = new double[100];
    double[] yData = new double[100];
    for (int i = 0; i < xData.length; i++) {
      double radians = phase + (2 * Math.PI / xData.length * i);
      xData[i] = radians;
      yData[i] = Math.sin(radians);
    }
    return new double[][] { xData, yData };
  }
}

This results in the following Java Swing real-time chart app: enter image description here

这将产生以下 Java Swing 实时图表应用程序: 在此处输入图片说明