using repaint() method with actionPerformed
Asked Answered
C

4

5

How to use the repaint() method when a button is pressed and Graphics p has to re-paint everything from scratch?

Thanks.

  import javax.swing.Box;
  import javax.swing.JButton;
  import javax.swing.JTextField;
  import java.awt.*;
  import java.awt.event.*;
  import javax.swing.*;

  class fares extends JPanel{

    private static final long serialVersionUID = 1L;
    public static int xaxis1,xaxis2,yaxis3,yaxis4;

public ControlsB(square) {

    final JButton btn1 = new JButton("Resize");

    final Box b = Box.createHorizontalBox();
    b.add(new JLabel("Please enter range:  "));
    Box b0 = Box.createVerticalBox();//create a vertical box to stack the controls

    Box b1 = Box.createHorizontalBox(); // create a horizontal box for the x-axis

    //x-axis
    b1.add(new JLabel("mark "));
    b1.add(new JLabel("for"));

    f1.setMaximumSize(new Dimension(100,30));

    b1.add(f1);
    b1.add(new JLabel("till"));

    f2.setMaximumSize(new Dimension(100,30));
    b1.add(f2);

    //y-axis
    //this code is not in use at the moment

    f4.setMaximumSize(new Dimension(100,30));
    b2.add(f4);

    b0.add(b1);

    add(b);

    btn1.addActionListener(new ActionListener(){

        public void actionPerformed(ActionEvent event){

            f = Integer.parseInt(f1.getText());

            invalidate();
            validate();
            paint(p);//this is not working...
        }
    });
 b.add(btn1);
  }
}

This is the code that has to be called and repainted:

import java.awt.*;

import javax.swing.*;

class Graph extends JPanel {

public static Graphics p;
private static final long serialVersionUID = 1L;
public static int f;
public static int g;

@Override
public Dimension getPreferredSize()
{   
    return (new Dimension(560,560));
}

public void paintComponent(Graphics p) {

    super.paintComponent(p);

    Graphics2D graph = (Graphics2D)p;

    Dimension appletSize = this.getSize();
    int appletHeight = (int)(appletSize.height);
    int appletWidth = appletSize.width;

    //change -ve num to +ve
    int g3 = Math.abs(g);

    int a1 = g3 + f;
    int b1 = a1;


    int d = (appletWidth / a1);
    int e = (appletHeight / b1);

    //draw y-axis numbers 
    //(+ve)
    while(f != 0){
        String s = String.valueOf(f);

        m = m + b;
        f = f - 1;
    }
    //(-ve)
    m2 = y;
    while(f2 != g-1)
        m2 = m2 + b;
        f2 = f2 - 1;
    }
    //draw x-axis numbers.
    //(-ve)
    while(g != 0){
        String hy = String.valueOf(g);

        n = n + a;
        g = g + 1;
    }
    //(+ve)
    n2 = x + a;
    while(g2 != g3+1){
        String w = String.valueOf(g2);
        n2 = n2 + a;
        g2 = g2 + 1;
    }

    BasicStroke aLine2 = new BasicStroke(1.0F,
                                         BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
    graph.setStroke(aLine2);

    //notch on numbers and grid lines
    //left to right, top to bottom notches
    int v2 = -5;
    int v5 = 0;
    while(i <= a1-1){
        p.setColor(Color.lightGray);//lightgray line
        a = a + d;
        b = b + e;
        i = i + 1;
    }

  }
}

At the moment the resize button works, but I need to resize my window in order for the graph to respond to the inputs given. Basically when resizing the graph is being redrawn / repainted... now I need this to be done automatically.

Cosenza answered 20/6, 2012 at 23:28 Comment(1)
Get rid of your Graphics variable, p, as you should never try to hold on to a component's Graphics object and paint with it. If it doesn't cause a NullPointerException to occur, it will simply not work. If you don't get a decent answer soon, consider creating and posting an sscce.Carolinecarolingian
C
6

It's hard to tell what's wrong based on snippets of code, but it appears that your graph is drawn on the Graph object, called graph (please correct me if I'm wrong), and you appear to be trying to repaint (or paint -- never call that directly!) your ControlsB panel. If so, then you may be calling methods on the wrong object. Perhaps you need to do something like:

// graph is final so it may be used in an inner class
public ControlsB(Box box2, final Graph graph) {

     // .....

      btn1.addActionListener(new ActionListener(){

        public void actionPerformed(ActionEvent event){

            f = Integer.parseInt(f1.getText());
            g = Integer.parseInt(f2.getText());
            System.out.println(f + "  " + g);

            // invalidate();
            // validate();
            //  paint(p); ***** NEVER do this

            graph.repaint();
        }
    });
}

Also:

  • Never call paint(...) directly on a component except in very special circumstances (this isn't it).
  • Never try to hold on to a components Graphics object and draw with it as this will often lead to a NullPointerException occurring, and it surely won't work.
  • Do read up on how to do drawing in Swing in the standard Swing tutorials. You would likely learn much from doing this.
  • Again, if you don't get a decent answer soon, consider creating and posting an sscce.
Carolinecarolingian answered 21/6, 2012 at 2:18 Comment(0)
H
5

HELPING DIAGRAM

Changes made :

- Inside the GraphApplet class, these two lines have been changed

Box box2 = new Box(BoxLayout.Y_AXIS); // Changed
// Added one more argument, while making Object.
ControlsB b = new ControlsB(box2, graph);//horizontal
  • Inside Graph Class, setValues(...) method has been added.

-

public void setValues(int x, int y)
{
    xstart = x;
    ystart = y;
    repaint();
}
  • Inside Graph class, scope of variables xstart and ystart has been changed to Instance/Class

- Inside ControlB Class

refineButton = new JButton("Refine");
buttonBox.add(refineButton);
refineButton.addActionListener(new ActionListener()
{
    public void actionPerformed(ActionEvent ae)
    {
        int x = Integer.parseInt(f1.getText());
        int y = Integer.parseInt(f3.getText());
        /*
         * Calling a method of Graph Class (setValues)
         * and passing the values that we had got from
         * the respective JTextFields.
         */
        graph.setValues(x, y);          }
    });
}

Here watch this code example, modified your previous example a bit to give you one idea how to make this work. Have a look at the image attached, only use these three thingies, enter some integer values in the pointed JTextFields and then click on Refine JButton, you will see how to repaint. Since I really don't know how the logic works, hence won't be able to say how you can optimize your code, though to give you one idea, here it is :

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

public class GraphApplet extends JApplet
{
    private static final long serialVersionUID = 1L;

    public void init(){

        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                Container conn = getContentPane();
                conn.setLayout(new BorderLayout());

                Graph graph = new Graph();//graph
                conn.add(graph,BorderLayout.CENTER);

                Box box1 = new Box(BoxLayout.X_AXIS);
                ControlsA a = new ControlsA(box1);//vertical
                conn.add(a,BorderLayout.EAST);

                Box box2 = new Box(BoxLayout.Y_AXIS); // Changed
                // Added one more argument, while making Object.
                ControlsB b = new ControlsB(box2, graph);//horizontal
                conn.add(b,BorderLayout.SOUTH);
            }
        });
    }
}

class Graph extends JPanel {

    private static final long serialVersionUID = 1L;
    private int xstart;
    private int ystart;

    public Graph(){
        this.setBackground(Color.yellow);
    }

    @Override
    public Dimension getPreferredSize()
    {   
        return (new Dimension(460,560));
    }

    /*
     * Added this method, which will call
     * repaint(), everytime it is been
     * called from anywhere. Moreover
     * the variables used inside 
     * paintComponent(...) method xstart
     * and ystart, have been changed to 
     * instance variables of the Graph Class.
     */
    public void setValues(int x, int y)
    {
        xstart = x;
        ystart = y;
        repaint();
    }

    @Override
    public void paintComponent(Graphics p) 
    {

        super.paintComponent(p);

        Graphics2D graph = (Graphics2D)p;

        Dimension appletSize = this.getSize();
        int appletHeight = (int)(appletSize.height);
        int appletWidth = appletSize.width;

        this.setBackground(Color.yellow);//set background color.

        int x,y,y1,x1,a,b,p1x,p1y,p2x,p2y;

        //line co-ordinates
        //the numbers represent the number of boxes on the graph
        // Made these two variables as Instance Variables
        //int xstart = 10;
        //int ystart = 5;

        int xfinish = 2;
        int yfinish = 8;

        //other variables
        int i = 0;
        int i2 = 0;
        int m = 0;
        int n = 0;
        int m2 = 0;
        int n2 = 0;
        int f2 = 0;
        int g2 = 1;

        //ranges
        int f = 5;
        int g = -5;

        //change -ve num to +ve
        int g3 = Math.abs(g);

        int a1 = g3 + f;
        int b1 = a1;

        y1 = (appletHeight);
        x1 = (appletWidth);
        y = (appletHeight / 2);
        x = (appletWidth / 2);
        a = (appletWidth / a1);
        b = (appletHeight / b1);

        int d = (appletWidth / a1);
        int e = (appletHeight / b1);

        /**
        to determine the
        ammount of pixles there
        is in each box of the
        graph, both y-axis and 
        x-axis
        */
        int xbox = x1 / 10;
        int ybox = y1 / 10;

        //line variables
        //the xstart, ystart, etc represent the number of boxes

        //top point of the line on the graph
        p1x = xbox * xstart;//start x
        p1y = ybox * ystart;//start y

        //lowwer point of the line on the graph
        p2x = xbox * xfinish;//finish x
        p2y = ybox * yfinish;//finish y

        //draw y-axis numbers 
        //(+ve)
        while(f != 0){
            String s = String.valueOf(f);
            p.drawString(s,(x + 5),m + 13);
            m = m + b;
            f = f - 1;
        }
        //(-ve)
        m2 = y;
        while(f2 != g-1){
            String u = String.valueOf(f2);
            p.drawString(u,(x + 5),m2 - 3);
            m2 = m2 + b;
            f2 = f2 - 1;
        }
        //draw x-axis numbers.
        //(-ve)
        while(g != 0){
            String t = String.valueOf(g);
            p.drawString(t,n,y - 5);
            n = n + a;
            g = g + 1;
        }
        //(+ve)
        n2 = x + a;
        while(g2 != g3+1){
            String vw = String.valueOf(g2);
            p.drawString(vw,n2 -10,y - 5);
            n2 = n2 + a;
            g2 = g2 + 1;
        }

        BasicStroke aLine2 = new BasicStroke(1.0F,
                 BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
        graph.setStroke(aLine2);

        //notch on numbers and grid lines
        //left to right, top to bottom notches
        int v2 = -5;
        int v5 = 0;
        while(i <= a1-1){
            p.setColor(Color.lightGray);//lightgray line
            p.drawLine(a,0,a,y1);//vertical lightgray
            p.drawLine(0,b,x1,b);//horizontal lightgray
            a = a + d;
            b = b + e;
            i = i + 1;
        }
        //notches
        while(i2 <= a1){
            p.setColor(Color.blue);//notch color
            p.drawString("x",v2+2,y+3);//xaxis
                p.drawString("x",x-4,v5+4);//yaxis
            v5 = v5 + e;
            v2 = v2 + d;
            i2 = i2 + 1;
        }

        //draws the border of the graph
        p.setColor(Color.black);
        Rectangle2D.Float rect = new Rectangle2D.Float(0,0,x1,y1);
        BasicStroke aLine = new BasicStroke(2.5F, 
                BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        graph.setStroke(aLine);
        graph.draw(rect);

        //draw cross
        BasicStroke aLine3 = new BasicStroke(2.5F,
                BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        graph.setStroke(aLine3);
        p.drawLine(x,0,x,y1); //vertical line
        p.drawLine(0,y,x1,y); //horizontal line

        //display the value of graph width and graph height
        String aw = String.valueOf(x1);
        p.drawString("Graph Width = ", 50,90);
        p.drawString(aw,150,90);
        p.drawString("Graph Height = ", 50,110);
        String ah = String.valueOf(y1);
        p.drawString(ah,156,110);

        //draw line on graph

        BasicStroke aLine4 = new BasicStroke(1.5F,
            BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        graph.setStroke(aLine4);
        p.setColor(Color.red);

        if(p1x <= x1 && p2x <= x1 && p1y <= y1 && p2y <= y1){
            p.drawLine(p1x,p1y,p2x,p2y);
            Color c = new Color(0,0,0);
            p.setColor(c);
            p.drawString("X", p1x-4,p1y+4);
            p.drawString("X", p2x-4,p2y+4);
        }           
        else{
            p.setColor(Color.black);
            p.drawRect(48,34,223,35);
            p.setColor(Color.white);
            p.fillRect(49,35,222,34);
            p.setColor(Color.red);
            p.drawString("Wrong co-ordinates!!!", 50,50);
            p.drawString("Values exceede applet dimensions.", 50,65);
        }
    }
}

class ControlsA extends JPanel
{

    private static final long serialVersionUID = 1L;

    public ControlsA (Box a) 
    {

        a = Box.createVerticalBox();
        a.add(new JLabel("Please enter the values below:"));
        a.add(new JLabel("a"));
        JTextField g1 = new JTextField("0.0");
        g1.setMaximumSize(new Dimension(100,30));
        a.add(g1);
        a.add(new JLabel("b"));
        JTextField g2 = new JTextField("0.0");
        g2.setMaximumSize(new Dimension(100,30));
        a.add(g2);
        a.add(new JLabel("c"));
        JTextField g3 = new JTextField("0.0");
        g3.setMaximumSize(new Dimension(100,30));
        a.add(g3);
        a.add(new JLabel("d"));
        JTextField g4 = new JTextField("0.0");
        g4.setMaximumSize(new Dimension(100,30));
        a.add(g4);
        a.add(new JButton("Plot"));
        a.add(new JButton("Refine"));
        add(a);
    }

    @Override
    public Dimension getPreferredSize()
    {   
        return (new Dimension(200,100));
    }
}

class ControlsB extends JPanel
{

    private static final long serialVersionUID = 1L;
    private Graph graph;
    private JButton refineButton;

    public ControlsB (Box b, Graph g) {

        graph = g;
        b = Box.createVerticalBox();
        Box boxUpper = new Box(BoxLayout.X_AXIS);
        boxUpper.add(new JLabel("Please enter range:  "));
        b.add(boxUpper);
        Box boxX = new Box(BoxLayout.X_AXIS);
        boxX.add(new JLabel(" x-axis "));
        boxX.add(new JLabel("from"));
        // Added final keyword.
        final JTextField f1 = new JTextField("-5");
        f1.setMaximumSize(new Dimension(100,30));
        boxX.add(f1);
        boxX.add(new JLabel(" to "));
        JTextField f2 = new JTextField("5");
        f2.setMaximumSize(new Dimension(100,30));
        boxX.add(f2);
        b.add(boxX);
        //b.add(new JLabel(".   "));
        Box boxY = new Box(BoxLayout.X_AXIS);
        boxY.add(new JLabel("y-axis "));
        boxY.add(new JLabel("from"));
        // Added final keyword.
        final JTextField f3 = new JTextField("5");
        f3.setMaximumSize(new Dimension(100,30));
        boxY.add(f3);
        boxY.add(new JLabel("to"));
        JTextField f4 = new JTextField("-5");
        f4.setMaximumSize(new Dimension(100,30));
        boxY.add(f4);
        b.add(boxY);
        Box buttonBox = new Box(BoxLayout.X_AXIS);
        buttonBox.add(new JButton("Plot"));
        /* 
         * Made this an instance variable,
         * and added ActionListener to it.
         */
        refineButton = new JButton("Refine");
        buttonBox.add(refineButton);
        refineButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent ae)
            {
                int x = Integer.parseInt(f1.getText());
                int y = Integer.parseInt(f3.getText());
                /*
                 * Calling a method of Graph Class (setValues)
                 * and passing the values that we had got from
                 * the respective JTextFields.
                 */
                graph.setValues(x, y);
            }
        });
        b.add(buttonBox);       
        add(b);
    }

    @Override
    public Dimension getPreferredSize()
    {   
        return (new Dimension(200,100));
    }
}
Heteromorphic answered 21/6, 2012 at 3:51 Comment(0)
C
2

Congrats, you just stumbled upon the subtleties of repaint :) There is a quite nice explanation at http://www.oracle.com/technetwork/java/painting-140037.html#paint_process . Here is the summary:

  • If you call repaint() on a heavyweight component like JFrame or JApplet, it will repaint immediately.
  • If you call repaint() on a JComponent, it will "schedule" the repainting to occur at some point in the future as decided by the Repaint Manager (which means, you have no control over it).

So, call the repaint() method in JApplet and you should see the changes as soon as you click the button.

Camass answered 21/6, 2012 at 2:39 Comment(0)
F
1

Have you tried instead of paint(p) to use p.repaint() or p.update(p.getGraphics())?

I have not done Swing for ages and I can't remember exactly how it's behaving. One sure thing is that you have to be aware of when it is the good time to call paint, update or validate and how to use correctly the EventDispatcherThread (EDT). Otherwise your application will look like a lot of java swing applications : a crap filled of UI bugs...

I don't say Swing is crap, I say that if you don't know how it works, your UI will be a crap.

Filtrate answered 20/6, 2012 at 23:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.