简体   繁体   English

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

[英]Graph plotting in Java Swing only draws points

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. 所以,我查看了一个用于在Swing中绘制图形的代码示例。 My final code looks like this: 我的最终代码如下所示:

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? 我究竟做错了什么?

In addition to @Hovercraft's helpful suggestions, also consider these other approaches: 除了@ Hovercraft的有用建议,还要考虑以下其他方法:

  • Accumulate the points in a GeneralPath that may be rendered as required, for example . 在累积点GeneralPath可以呈现为需要的, 例如

lissajou图片

  • Connect the points using repeated calls to drawLine() using a suitable coordinate system, outlined here . 连接使用重复调用点drawLine()使用合适的坐标系,概括这里

正弦图像

Your code confuses me: 你的代码让我困惑:

  • You override both paint and paintComponent for your Populus3 JPanel -- why? 你为Populus3 JPanel覆盖了paint和paintComponent - 为什么? You should only override paintComponent unless you absolutely have to have your drawing affect a component's children and borders. 您应该只覆盖paintComponent,除非您必须让绘图影响组件的子项和边框。
  • You dispose of the Graphics object passed into paint -- a very dangerous thing to do. 你处理掉传递给paint的Graphics对象 - 这是一件非常危险的事情。 You should never dispose of a Graphics object given to you by the JVM, only Graphics objects that you yourself create. 您永远不应该处理JVM提供给您的Graphics对象,只能处理您自己创建的Graphics对象。
  • You repeatedly call a method not defined here for us, paintCell(...) . 你为我们重复调用一个没有定义的方法, paintCell(...)
  • I've never heard of the need for Toolkit.getDefaultToolkit().sync(); 我从未听说过需要Toolkit.getDefaultToolkit().sync(); for Swing applications. 用于Swing应用程序。 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. 在你的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 ,一个我们可以编译,运行,修改和纠正的最小测试程序,它向我们展示你的问题,但是没有与问题无关或演示所需的额外代码。

The following code demonstrates a real-time Java chart using XChart where the line is updated as the data evolves over time. 以下代码演示了使用XChart的实时Java图表,其中随着数据随时间的推移而更新行。 Creating real-time charts is as simple as calling updateXYSeries for one or more series objects through the XYChart instance and triggering a redraw of the JPanel containing the chart. 创建实时图表就像通过XYChart实例调用一个或多个系列对象的updateXYSeries并触发包含图表的JPanel的重绘一样简单。 This works for all chart types including XYChart , CategoryChart , BubbleChart and 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 . 这适用于所有的图表类型,包括XYChartCategoryChartBubbleChartPieChart ,为此示例源代码可以在这里找到: https://github.com/timmolter/XChart/tree/develop/xchart-demo/src/main/java / org / knowm / xchart / demo / charts / realtime Examples demonstrate using the SwingWrapper with repaintChart() method as well as XChartPanel with revalidate() and repaint() . 示例演示了SwingWrapperSwingWrapperrepaintChart()方法一起使用,以及将XChartPanelrevalidate()repaint() Disclaimer, I'm the main developer of the XChart library. 免责声明,我是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: 这导致以下Java Swing实时图表应用程序: 在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM