Search code examples
javaswingplotjframepaintcomponent

Java JFrame Plotting Multiple Lines


So the crux of my problem is plotting multiple components into one JFrame in Java. I'm trying to use the same component twice to plot two different lines, but only one appears. I'm working across three separate classes in separate files, which might be making it more difficult for me. I have tried possible solutions to no avail here, here, here, here, and elsewhere. I suspect I am doing multiple things wrong, as I'm still trying to fully understand JFrame, JPanel, and LayoutManagers. Can anyone show where I went wrong?

My tester class is as follows:

import javax.swing.JFrame;

public class TransportSlabTester
{
    public static void main(String[] args)
    {
        System.out.println("Estimation at 100 sections: ");
        TransportSlab slab1 = new TransportSlab(10000,1,5,100);
        System.out.println();

        JFrame frame = new JFrame("Attenuated Profile");
        frame.setSize(600,600);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        TransportSlabGraph component = new TransportSlabGraph();
        //analytical is a method from a 3rd class that returns double[]
        component.attProfileArray(slab1.analytical(),slab1.getThickness());
        frame.add(component);
        component = new TransportSlabGraph();
        //euler is a method from a 3rd class that returns double[]
        component.attProfileArray(slab1.euler(),slab1.getThickness());
        frame.add(component);
        frame.setVisible(true);
    }
}

Now, the class that extends JPanel:

import java.awt.*;
import java.awt.geom.Line2D;
import java.math.*;
import javax.swing.JPanel;

public class TransportSlabGraph extends JPanel
{
    double[] N, xAxes, yAxes;
    final int edge = 100; //Distance from edge of frame
    String[] xlabel = new String[11];
    String[] ylabel = new String[11];

    /**
     *
     * @param inputN Data array of type {@code double[]}
     * @param thickness Thickness set by the original constructor
     */
    public void attProfileArray(double[] inputN, double thickness)
    {
        N = new double[inputN.length];
        //Create labels for the tick marks of the x and y axis from rounded #'s
        BigDecimal bd1, bd2;
        for (int i = 0; i <= 10; i++)
        {
            bd1 = new BigDecimal((thickness/10)*i);
            MathContext mc = new MathContext(2); //Round to one decimal place
            bd2 = bd1.round(mc);
            xlabel[i] = String.valueOf(bd2.doubleValue());
            ylabel[i] = String.valueOf((inputN[0]*i)/(inputN.length-1));
        }
        //Set up data array and the axes
        for (int i = 0; i < N.length; i++)
        {
            N[i]=inputN[i];
            xAxes = new double[N.length];
            yAxes = new double[N.length];
        }
    }
    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        //Get frame dimensions to scale drawn components
        int w = getWidth();
        int h = getHeight();
        double xInc = (double)(w-2*edge)/(N.length-1);
        double scale = (double)(h-2*edge)/N[0];
        g2.draw(new Line2D.Double(edge, h-edge, w-edge, h-edge)); //draw x axis
        g2.draw(new Line2D.Double(edge, edge, edge, h-edge)); // draw y axis
        //Create evenly spaced tick marks for both axes and label them
        for (int i = 0; i <= 10; i++)
        {
            g2.draw(new Line2D.Double(edge+((w-edge-edge)/10.0)*i, h-edge-10, edge+((w-edge-edge)/10.0)*i, h-edge+10)); //x ticks
            g2.draw(new Line2D.Double(edge-10, h-edge-((h-edge-edge)/10.0)*i, edge+10, h-edge-((h-edge-edge)/10.0)*i)); //y ticks
            g2.drawString(xlabel[i],(int)(edge+((w-edge-edge)/10.0)*i),h-edge+20);
            g2.drawString(ylabel[i],edge-30,(int)(h-edge-((h-edge-edge)/10.0)*i));
        }
        //Scale data and convert to pixel coordinates
        for (int i = 0; i < N.length; i++)
        {
            xAxes[i] = edge+i*xInc;
            yAxes[i] = h-edge-scale*N[i];
        }
        //Only set the data line's color
        g2.setPaint(Color.BLUE);
        //Draw the data as a series of line segments
        for (int i = 1; i < N.length; i++)
        {
            g2.draw(new Line2D.Double(xAxes[i-1],yAxes[i-1],xAxes[i],yAxes[i]));
        }
    }
}

Solution

  • Problem #1

    An instance of a Component may only reside within a single Container (once).

    You will need to create a new instance of each Component you want to add. I would recommend a factory pattern...

    Problem #2

    JFrame, but default, uses a BorderLayout, which will only allow a single component to reside at each of it's 5 available layout positions.

    You will also have problems because your TransportSlabGraph class doesn't override it's getPreferredSize method, which means that, by default, instance of the component will be provided with a default size of 0x0 by many of the layout managers.

    Consider changing the layout manager to something like GridLayout to start with.

    Take a look at Laying Out Components Within a Container for more details