user3325799
user3325799

Reputation: 21

How to create a JPanel for graphing

I'm making a function grapher that take 4 parameters and size for the Panel, but I don't know how to create a Panel class that will draw the information from the Grapher class. Can some one help please?(The parameters are not important, I just want to learn how to make a Graph Panel for later use)

Panel Class

import java.awt.BorderLayout;

public class Panel extends JFrame {

    private JPanel contentPane;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {

    }

    /**
     * Create the frame.
     */
    public Panel(int w, int h) {
        setVisible(true);
        setSize(w,h);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, w, h);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setBackground(Color.WHITE);
        setContentPane(contentPane);
        contentPane.setLayout(null);

        JPanel panel = new JPanel();
        panel.setBackground(Color.WHITE);
        panel.setBorder(new EmptyBorder(0, 0, 0, 0));
        panel.setBounds(0, 0, w, h);
        contentPane.add(panel);
    }


    public void paint(Graphics g) {
        super.paint(g);
        //g.drawLine(110, 112,129, 132);
    }

    public Graphics getGraphics(Graphics g){
        return g;
    }

}

Grapher class

import java.awt.EventQueue;


public class Grapher {

    private int panelWidth;
    private int panelHeight;
    int x1;
    int x2;
    int y1;
    int y2;
    int a;
    int b;
    int c;
    int d;
    private JFrame frmChinhsFunctionGrapher;
    private JTextField textFieldXMin;
    private JTextField textFieldXMax;
    private JTextField textFieldYMin;
    private JTextField textFieldYMax;
    private JTextField textFieldA;
    private JTextField textFieldB;
    private JTextField textFieldC;
    private JTextField textFieldD;
    private JLabel lblPeriod;
    private JLabel lblYIntercept;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    Grapher window = new Grapher();
                    window.frmChinhsFunctionGrapher.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     */
    public Grapher() {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frmChinhsFunctionGrapher = new JFrame();
        frmChinhsFunctionGrapher.setTitle("Chinh's function grapher\r\n");
        frmChinhsFunctionGrapher.setBounds(100, 100, 450, 300);
        frmChinhsFunctionGrapher.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmChinhsFunctionGrapher.getContentPane().setLayout(null);

        textFieldXMin = new JTextField();
        textFieldXMin.setText("-200");
        textFieldXMin.setBounds(66, 8, 86, 20);
        frmChinhsFunctionGrapher.getContentPane().add(textFieldXMin);
        textFieldXMin.setColumns(10);

        JLabel lblXMin = new JLabel("X min");
        lblXMin.setBounds(10, 11, 46, 14);
        frmChinhsFunctionGrapher.getContentPane().add(lblXMin);

        JLabel lblXMax = new JLabel("X max");
        lblXMax.setBounds(10, 42, 46, 14);
        frmChinhsFunctionGrapher.getContentPane().add(lblXMax);

        textFieldXMax = new JTextField();
        textFieldXMax.setText("200");
        textFieldXMax.setBounds(66, 39, 86, 20);
        frmChinhsFunctionGrapher.getContentPane().add(textFieldXMax);
        textFieldXMax.setColumns(10);

        textFieldYMin = new JTextField();
        textFieldYMin.setText("-200");
        textFieldYMin.setBounds(66, 70, 86, 20);
        frmChinhsFunctionGrapher.getContentPane().add(textFieldYMin);
        textFieldYMin.setColumns(10);

        textFieldYMax = new JTextField();
        textFieldYMax.setText("200");
        textFieldYMax.setBounds(66, 101, 86, 20);
        frmChinhsFunctionGrapher.getContentPane().add(textFieldYMax);
        textFieldYMax.setColumns(10);

        JLabel lblYMin = new JLabel("Y min");
        lblYMin.setBounds(10, 73, 46, 14);
        frmChinhsFunctionGrapher.getContentPane().add(lblYMin);

        JLabel lblYMax = new JLabel("Y max");
        lblYMax.setBounds(10, 104, 46, 14);
        frmChinhsFunctionGrapher.getContentPane().add(lblYMax);

        JLabel lblParameters = new JLabel("Parameters");
        lblParameters.setBounds(320, 11, 93, 14);
        frmChinhsFunctionGrapher.getContentPane().add(lblParameters);

        textFieldA = new JTextField();
        textFieldA.setText("100");
        textFieldA.setBounds(360, 39, 64, 20);
        frmChinhsFunctionGrapher.getContentPane().add(textFieldA);
        textFieldA.setColumns(10);

        JLabel lblNewLabel = new JLabel("Graph's Height");
        lblNewLabel.setBounds(263, 42, 72, 14);
        frmChinhsFunctionGrapher.getContentPane().add(lblNewLabel);

        textFieldB = new JTextField();
        textFieldB.setText("10");
        textFieldB.setBounds(360, 70, 64, 20);
        frmChinhsFunctionGrapher.getContentPane().add(textFieldB);
        textFieldB.setColumns(10);

        textFieldC = new JTextField();
        textFieldC.setText("100");
        textFieldC.setBounds(360, 101, 64, 20);
        frmChinhsFunctionGrapher.getContentPane().add(textFieldC);
        textFieldC.setColumns(10);

        textFieldD = new JTextField();
        textFieldD.setText("1");
        textFieldD.setBounds(360, 132, 64, 20);
        frmChinhsFunctionGrapher.getContentPane().add(textFieldD);
        textFieldD.setColumns(10);

        JButton btnGraph = new JButton("Graph");
        btnGraph.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {


                getInput();

                Panel pn = new Panel(panelWidth, panelHeight);

                Graphics gs = pn.getGraphics();
                gs.drawLine(100, 100, 200, 200);



            }
        });
        btnGraph.setBounds(10, 228, 89, 23);
        frmChinhsFunctionGrapher.getContentPane().add(btnGraph);

        lblPeriod = new JLabel("Period");
        lblPeriod.setBounds(263, 73, 46, 14);
        frmChinhsFunctionGrapher.getContentPane().add(lblPeriod);

        lblYIntercept = new JLabel("Vertical shift");
        lblYIntercept.setBounds(263, 104, 72, 14);
        frmChinhsFunctionGrapher.getContentPane().add(lblYIntercept);

        JLabel lblHorizontalShift = new JLabel("Horizontal shift");
        lblHorizontalShift.setBounds(263, 135, 86, 14);
        frmChinhsFunctionGrapher.getContentPane().add(lblHorizontalShift);
    }


    public void getInput(){
        x1 = Integer.parseInt(textFieldXMin.getText());
        x2 = Integer.parseInt(textFieldXMax.getText());
        y1 = Integer.parseInt(textFieldYMin.getText());
        y2 = Integer.parseInt(textFieldYMax.getText());
        a = Integer.parseInt(textFieldA.getText());
        b = Integer.parseInt(textFieldB.getText());
        c = Integer.parseInt(textFieldC.getText());
        d = Integer.parseInt(textFieldD.getText());

        panelWidth = Math.abs(x2 - x1);
        panelHeight = Math.abs(y2 - y1);
    }
}

Upvotes: 2

Views: 4009

Answers (2)

Marco13
Marco13

Reputation: 54631

There are quite some issues with your code

You should not use the null layout. You should not extent JFrame and even if you do it, you should not override the paint method of JFrame. You should create the GUI on the Event Dispatch Thread. You should have an idea of how you are going to define which area of the function is plotted into which area of the panel. (Plotting a function like sin(x) will result in a straight, horizontal line, because the values will alternate between -1 and 1, and thus, span a range of only 3 pixels...)

However, once I created a https://stackoverflow.com/help/mcve showing a very simple plotter that can be used to plot arbitrary functions. Maybe you find parts of it "inspiring".

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * Main class of the simple function plotter. Contains the
 * main method and creates the GUI
 */
public class SimplePlotMain
{
    /**
     * Entry point
     *
     * @param args not used
     */
    public static void main(String[] args)
    {
        // Create the GUI on the Event-Dispatch-Thread
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    /**
     * Creates the frame containing the simple plotter
     */
    private static void createAndShowGUI()
    {
        // Create the main frame
        JFrame frame = new JFrame("SimplePlot");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(new BorderLayout());
        frame.setSize(800,600);

        // Create the SimplePlotPanel and add it to the frame
        SimplePlotPanel plotPanel = new SimplePlotPanel();
        frame.getContentPane().add(plotPanel, BorderLayout.CENTER);

        // Create the Function that should be plotted, and assign
        // it to the SimplePlotPanel
        Function function = new Function()
        {
            @Override
            public double compute(double argument)
            {
                return Math.sin(argument)*argument;
            }
        };
        plotPanel.setFunction(function);

        // Create a simple control panel and add it to the frame
        JComponent controlPanel = createControlPanel(plotPanel);
        frame.getContentPane().add(controlPanel, BorderLayout.EAST);

        // As the last action: Make the frame visible
        frame.setVisible(true);
    }

    /**
     * Creates a panel containing some Spinners that allow defining
     * the area in which the function should be shown
     *
     * @param plotPanel The SimplePlotPanel, to which the settings
     * will be transferred
     * @return The control-panel
     */
    private static JComponent createControlPanel(
        final SimplePlotPanel plotPanel)
    {
        JPanel controlPanel = new JPanel(new BorderLayout());
        JPanel panel = new JPanel(new GridLayout(0,2));
        controlPanel.add(panel, BorderLayout.NORTH);

        // Create spinners for the minimum and maximum
        // X- and Y-values
        final JSpinner minXSpinner = new JSpinner(
            new SpinnerNumberModel(-1.0, -1000.0, 1000.0, 0.1));
        final JSpinner maxXSpinner = new JSpinner(
            new SpinnerNumberModel( 1.0, -1000.0, 1000.0, 0.1));
        final JSpinner minYSpinner = new JSpinner(
            new SpinnerNumberModel(-1.0, -1000.0, 1000.0, 0.1));
        final JSpinner maxYSpinner = new JSpinner(
            new SpinnerNumberModel( 1.0, -1000.0, 1000.0, 0.1));

        // Add the spinners and some labels to the panel
        panel.add(new JLabel("minX"));
        panel.add(minXSpinner);
        panel.add(new JLabel("maxX"));
        panel.add(maxXSpinner);
        panel.add(new JLabel("minY"));
        panel.add(minYSpinner);
        panel.add(new JLabel("maxY"));
        panel.add(maxYSpinner);

        // Create a ChangeListener that will be added to all spinners,
        // and which transfers the settings to the SimplePlotPanel
        ChangeListener changeListener = new ChangeListener()
        {
            @Override
            public void stateChanged(ChangeEvent event)
            {
                double minX = ((Double)minXSpinner.getValue()).doubleValue();
                double maxX = ((Double)maxXSpinner.getValue()).doubleValue();
                double minY = ((Double)minYSpinner.getValue()).doubleValue();
                double maxY = ((Double)maxYSpinner.getValue()).doubleValue();
                plotPanel.setRangeX(minX, maxX);
                plotPanel.setRangeY(minY, maxY);
            }
        };
        minXSpinner.addChangeListener(changeListener);
        maxXSpinner.addChangeListener(changeListener);
        minYSpinner.addChangeListener(changeListener);
        maxYSpinner.addChangeListener(changeListener);

        // Set some default values for the Spinners
        minXSpinner.setValue(-10.0);
        maxXSpinner.setValue( 10.0);
        minYSpinner.setValue(-10.0);
        maxYSpinner.setValue( 10.0);

        return controlPanel;
    }
}


/**
 * Interface for a general function that may be plotted with
 * the SimplePlotPanel
 */
interface Function
{
    /**
     * Compute the value of the function for the given argument
     *
     * @param argument The function argument
     * @return The function value
     */
    double compute(double argument);
}



/**
 * The panel in which the function will be plotted
 */
class SimplePlotPanel extends JPanel
{
    private static final long serialVersionUID = -6588061082489436970L;

    /**
     * The function that will be plotted
     */
    private Function function;

    /**
     * The minimal x value that is shown
     */
    private double minX = -1.0f;

    /**
     * The maximal x value that is shown
     */
    private double maxX = 1.0f;

    /**
     * The minimal y value that is shown
     */
    private double minY = -1.0f;

    /**
     * The maximal y value that is shown
     */
    private double maxY = 1.0f;

    /**
     * Set the Function that should be plotted
     *
     * @param function The Function that should be plotted
     */
    public void setFunction(Function function)
    {
        this.function = function;
        repaint();
    }

    /**
     * Set the x-range that should be plotted
     *
     * @param minX The minimum x-value
     * @param maxX The maximum y-value
     */
    public void setRangeX(double minX, double maxX)
    {
        this.minX = minX;
        this.maxX = maxX;
        repaint();
    }

    /**
     * Set the y-range that should be plotted
     *
     * @param minY The minimum y-value
     * @param maxY The maximum y-value
     */
    public void setRangeY(double minY, double maxY)
    {
        this.minY = minY;
        this.maxY = maxY;
        repaint();
    }

    /**
     * Overridden method from JComponent: Paints this panel - that
     * is, paints the function into the given graphics object
     */
    @Override
    protected void paintComponent(Graphics gr)
    {
        super.paintComponent(gr);
        Graphics2D g = (Graphics2D)gr;
        g.setColor(Color.WHITE);
        g.fillRect(0,0,getWidth(),getHeight());
        g.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);

        paintAxes(g);
        paintFunction(g);
    }

    /**
     * Converts an x-coordinate of the function into an x-value of this panel
     *
     * @param x The x-coordinate of the function
     * @return The x-coordinate on this panel
     */
    private int toScreenX(double x)
    {
        double relativeX = (x-minX)/(maxX-minX);
        int screenX = (int)(getWidth() * relativeX);
        return screenX;
    }

    /**
     * Converts an y-coordinate of the function into an y-value of this panel
     *
     * @param y The y-coordinate of the function
     * @return The y-coordinate on this panel
     */
    private int toScreenY(double y)
    {
        double relativeY = (y-minY)/(maxY-minY);
        int screenY = getHeight() - 1 - (int)(getHeight() * relativeY);
        return screenY;
    }

    /**
     * Converts an x-coordinate on this panel into an x-coordinate
     * for the function
     *
     * @param x The x-coordinate on the panel
     * @return The x-coordinate for the function
     */
    private double toFunctionX(int x)
    {
        double relativeX = (double)x/getWidth();
        double functionX = minX + relativeX * (maxX - minX);
        return functionX;
    }


    /**
     * Paints some coordinate axes into the given Graphics
     *
     * @param g The graphics
     */
    private void paintAxes(Graphics2D g)
    {
        int x0 = toScreenX(0);
        int y0 = toScreenY(0);
        g.setColor(Color.BLACK);
        g.drawLine(0,y0,getWidth(),y0);
        g.drawLine(x0,0,x0,getHeight());
    }

    /**
     * Paints the function into the given Graphics
     *
     * @param g The graphics
     */
    private void paintFunction(Graphics2D g)
    {
        g.setColor(Color.BLUE);

        int previousScreenX = 0;
        double previousFunctionX = toFunctionX(previousScreenX);
        double previousFunctionY = function.compute(previousFunctionX);
        int previousScreenY = toScreenY(previousFunctionY);

        for (int screenX=1; screenX<getWidth(); screenX++)
        {
            double functionX = toFunctionX(screenX);
            double functionY = function.compute(functionX);
            int screenY = toScreenY(functionY);

            g.drawLine(previousScreenX, previousScreenY, screenX, screenY);
            previousScreenX = screenX;
            previousScreenY = screenY;
        }
    }


}

Upvotes: 4

Roy
Roy

Reputation: 984

First, I would say delete the main() method in the panel class. It has nothing to do with answering your question, but I think it'll cause problems and/or confusion.

What you need to do is 1) add a reference in the panel class to the Grapher class so that the panel paint method can call the Grapher class 2) set the reference to point to the instance of the Grapher class 3) have the Panel paint method invoke a method in the Grapher class to draw the graph.

1) Add a reference

public class Panel extends JFrame {

    private Grapher myGrapher = null;        //add this line
    private JPanel contentPane;

2) Set the reference

public Panel(Grapher graph, int w, int h) {   //change this line
    myGrapher = graph;                        //add this line
    setVisible(true);

and

public void actionPerformed(ActionEvent arg0) {


            getInput();

            Panel pn = new Panel(this, panelWidth, panelHeight);  //change this line

            //Graphics gs = pn.getGraphics();                     //remove this line
            //gs.drawLine(100, 100, 200, 200);                    //remove this line

        }

3) Invoke the method

  public void paint(Graphics g) {
        super.paint(g);
        //g.drawLine(110, 112,129, 132);
        if(myGrapher != null)                     //add this line
        {
            myGrapher.drawGraph(g);               //add this line
        }
    }

and in the Grapher class, add the method

void drawGraph(Graphics g) {
    g.drawLine(100, 100, 200, 200);
    //whatever else you need to draw the graph
}

Good luck!

Upvotes: 0

Related Questions