javaswingjbuttonactionlisteneractionevent

button triggers frame.repaint() even when I did not tell it to. What did I do wrong?


I just started learning java 4 days ago and am reading Head First Java, slow progress at Chapter 12. My JButton eastb triggers frame.repaint() even when I did not tell it to. I only told it to trigger setText() when pressed. Why is this happening? What did I miss?

Also what is an @Override? not the term 'override' as in in methods but the term '@Override' itself.

\\

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

    public class Exp {
     JFrame frame;
     JLabel label;
     JButton eastb;
     JButton southb;

     public static void main(String[] args) {
      Exp a = new Exp();
      a.start();
     }

     public void start() {
      frame = new JFrame();
      frame.setSize(700,700);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      label = new JLabel("I'm stored text only");
      frame.getContentPane().add(BorderLayout.WEST, label);

      eastb = new JButton("Don't click me");
      frame.getContentPane().add(BorderLayout.EAST, eastb);
      eastb.addActionListener(new EastButton());

      southb = new JButton("Change color");
      frame.getContentPane().add(BorderLayout.SOUTH, southb);
      southb.addActionListener(new SouthButton());

      frame.add(new DrawPanel());

      frame.setVisible(true);
     }

     class EastButton implements ActionListener {
      public void actionPerformed(ActionEvent event1) {  
       eastb.setText("Ouch!");
      }
     }

     class SouthButton implements ActionListener {
      public void actionPerformed(ActionEvent event2) {
       frame.repaint();
      }
     }

    }

    class DrawPanel extends JPanel {
     public void paintComponent(Graphics g) {

      int red = (int) (Math.random()*255);
      int green = (int) (Math.random()*255);
      int blue = (int) (Math.random()*255); 

      Color randomizer = new Color(red, green, blue);
      g.setColor(randomizer);

      int x = getWidth()/2;
      int y = getHeight()/2;
      int r = x/2;
      int d = 2*r;

      g.fillOval(x-r, y-r, d, d);
     }
    }

\\


Solution

  • I only told it to trigger setText() when pressed.

    When you change a property of a component it is possible that the size of the component changes. If the size changes, it is possible that it may effect the layout of all the comopnents, so the layout manager is invoked. Once the layout manager is invoked all the may have the size/location adjusted so all the components on the panel are repainted.

    This process is automatic, which leads to a problem with your code.

    A painting method should be for painting only. You should NOT be changing properties of you class in the painting method.

      int red = (int) (Math.random()*255);
      int green = (int) (Math.random()*255);
      int blue = (int) (Math.random()*255); 
    
      Color randomizer = new Color(red, green, blue);
    

    The above code should NOT be in your painting method. Again you can't control when the paintComponent() method is invoked. So you random color will be generated every time Swing determines the panel should be repainted.

    Instead you need to:

    1. add "randomizer" as in instance variable in your class.
    2. add a method like generateRandomColor()to set the value for this variable, which you could invoke in the constructor of you class, or invoke after you create the custom panel.
    3. change your painting logic to reference this "randomizer" variable.