Search code examples
javaawtgraphics2d

Points not increasing on right away click but on subsequent click it increases


i have created a color guessing game where the square gets a random color (red or blue) from and array of 2 colors and there are 2 buttons one red and one blue. the game begins with either of the color already in the square and if we guess that the next color will be red we press the red button and if that guess is correct we get 1 point. but somehow that updating of point is not showing right away even when the guess is right and the updating appears only on second clicking of the same red button. in short update is delayed or waiting for next click.

import java.awt.Button;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.*;
import java.util.Random;

class apple1 extends Frame{
    private Button b;
    private Button b2;
    Graphics2D g2;
    TextField tf;
    TextArea lbl;
    int count = 1;
    public void paint(Graphics g) {
        g2 = (Graphics2D) g;
        Color[] clrs = {Color.red,Color.blue};
        Random rand = new Random();
        g2.setColor(clrs[rand.nextInt(clrs.length)]);
        g2.fillRect (60, 50, 200, 200);  
      }
    public apple1(){      
        tf = new TextField("Points: ");
        tf.setBounds(10, 30, 280, 20);

        //create components   
        b=new Button("RED");
        b.setBackground(Color.red);
        b.setBounds(80,260,80,30); 

        //register listener
        b.addActionListener(new ActionListener(){

            @Override
            public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub
                if(b.getBackground().equals(g2.getColor())){
                    tf.setText(String.valueOf(count++));

         }
                else{
                    tf.setText("Sorry your guess was wrong");       
                }
                repaint();
            }

        });//passing current instance 

        b2=new Button("BLUE");
        b2.setBackground(Color.blue);
        b2.setBounds(180,260,80,30); 

        b2.addActionListener(new ActionListener(){

            @Override
            public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub
                if(b2.getBackground().equals(g2.getColor())){
                    tf.setText(String.valueOf(count++));

         }
                else{
                    tf.setText("Sorry your guess was wrong");       
                }
                repaint();
            }

        });//passing current instance         
        //add components and set size, layout and visibility  
        add(b);add(b2);add(tf);  
        setSize(600,600);  
        setLayout(null);
        setVisible(true);
        }


public static void main(String args[]){  
new apple1();  
}  
}  

Please help I am feeling so down that I am not able to solve such a small problem.

===========================================================================

As per suggestions by @VGR made modifications to above code. Here is how it looks now and the problem is solved. Thanks @VGR

import java.awt.Button;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.*;
import java.util.Random;

class apple1 extends Frame{
    private Button b;
    private Button b2;
    Graphics2D g2;
    TextField tf;
    TextArea lbl;
    int count = 1;
    private static final Color[] clrs = {Color.red,Color.blue};
    private Random rand = new Random();
    private Color bg = clrs[rand.nextInt(clrs.length)];
    public void paint(Graphics g) {
        g2 = (Graphics2D) g;
        g2.setColor(bg);
        g2.fillRect (60, 50, 200, 200);  
      }
    public apple1(){      
        tf = new TextField("Points: ");
        tf.setBounds(10, 30, 280, 20);

        //create components   
        b=new Button("RED");
        b.setBackground(Color.red);
        b.setBounds(80,260,80,30); 

        //register listener
        b.addActionListener(new ActionListener(){

            @Override
            public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub

                bg = clrs[rand.nextInt(clrs.length)];
                repaint();
                if(b.getBackground().equals(bg)){
                    tf.setText(String.valueOf(count++));

         }
                else{
                    tf.setText("Sorry your guess was wrong");       
                }
            }

        });//passing current instance 

        b2=new Button("BLUE");
        b2.setBackground(Color.blue);
        b2.setBounds(180,260,80,30); 

        b2.addActionListener(new ActionListener(){

            @Override
            public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub

                bg = clrs[rand.nextInt(clrs.length)];
                repaint();
                if(b2.getBackground().equals(bg)){
                    tf.setText(String.valueOf(count++));

         }
                else{
                    tf.setText("Sorry your guess was wrong");       
                }
            }

        });//passing current instance         
        //add components and set size, layout and visibility  
        add(b);add(b2);add(tf);  
        setSize(600,600);  
        setLayout(null);
        setVisible(true);
        }


public static void main(String args[]){  
new apple1();  
}  
}  

Solution

    1. A Graphics (or Graphics2D) object passed to a paint method is only valid for the duration of that paint method. You cannot use it once the paint method has exited.
    2. Paint methods are called by the system. You don’t have control over how often they’re called. Paint methods can be called for many reasons in addition to repaint() calls, including the window being moved/raised/lowered/resized, and even simply moving the mouse pointer over the window. For this reason, any logic which alters state must not take place in a paint method.

    Move your changing of the background to your ActionListener, and do not attempt to store a Graphics object in an instance field. Store the Color value itself in a field instead:

    private static final Color[] clrs = {Color.red,Color.blue};
    
    private final Random rand = new Random();
    
    private Color background = clrs[rand.nextInt(clrs.length)];
    
    // ...
    
    public void paint(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        g2.setColor(background);
        g2.fillRect(60, 50, 200, 200);  
    }
    
    // ...
    
        b.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
    
                if (b.getBackground().equals(background)) {
                    tf.setText(String.valueOf(count++));
                } else {
                    tf.setText("Sorry your guess was wrong");       
                }
    
                background = clrs[rand.nextInt(clrs.length)];
                repaint();
            }
        });
    
        // Do the same for the other ActionListener...
    

    Notice how the paint method does not change anything; it merely makes use of state variables changed by other methods. Notice also that no code refers to the Graphics object outside of the paint method.