1

I'm following a Java 2D tutorial and have got stuck on a program written to display a rectangle and ellipse which should fade in colour when clicked ...only nothing happens and I cannot work out why. I modified the original code slightly by passing the Jpanel instance to the HitTest class constructor. By tracing through with the debugger I've established that the program does detect a mouse click in the displayed shape and creates a thread to adjust the colour - but for some reason the colour does not adjust and stays the same. I thought the problem might be to do with where the repaint method is being called but not sure? Thanks in advance for any help received.

Here's some of the code:

    public class Surface extends JPanel {
    private Ellipse2D ellipse;
    private float alpha_ellipse;    //This variable will be used to control the transparency of the ellipse
    
    public Surface() { 
        initSurface();
    }
    
    private void initSurface() {
        addMouseListener(new HitTestAdapter(this)); //pass instance of surface to mouse adapter class

        ellipse = new Ellipse2D.Float(120f, 30f, 60f, 60f);
        alpha_ellipse = 1f;        
    }

    private void doDrawing(Graphics g) {
        Graphics2D g2d = (Graphics2D) g.create();

        g2d.setPaint(new Color(50, 50, 50));

        RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        rh.put(RenderingHints.KEY_RENDERING,
                RenderingHints.VALUE_RENDER_QUALITY);

        g2d.setRenderingHints(rh);
        
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, // set the transparency using
                alpha_ellipse));                                             //alpha_ellipse value calculated in a thread
        g2d.fill(ellipse);
        
        g2d.dispose();
    }

    @Override
    public void paintComponent(Graphics g) {

        super.paintComponent(g);
        doDrawing(g);
    }
public Ellipse2D getEllipse() {
        return ellipse;
    }
    
    public float getAlphaEllipse() {
        return alpha_ellipse;
    }
}

public class HitTestAdapter extends MouseAdapter
                implements Runnable{
    private RectRunnable rectAnimator;
    private Thread ellipseAnimator;
    
    private Surface surf;
    float alpha_ellipse;
    
    public HitTestAdapter(Surface surface) {  // I passed surface as a parameter to get to Surface class methods from this class
        surf = surface;
    }    
    
    @Override
    public void mousePressed(MouseEvent e) {
        
      int x = e.getX();
      int  y = e.getY();

      if (surf.getEllipse().contains(x, y)) {    //if we press inside the ellipse
            ellipseAnimator = new Thread(this);     // a new thread is created
            ellipseAnimator.start();
        }
    }

    @Override
    public void run() {
        
        alpha_ellipse= surf.getAlphaEllipse();

        while (alpha_ellipse >= 0) {

            surf.repaint();
            alpha_ellipse += -0.01f;

            if (alpha_ellipse < 0) {

                alpha_ellipse = 0;
            }

            try {
                
                Thread.sleep(50);
            } catch (InterruptedException ex) {
                
                Logger.getLogger(Surface.class.getName()).log(Level.SEVERE, 
                    null, ex);
            }
        }
    }
}

camickr
  • 321,443
  • 19
  • 166
  • 288
Ingalator
  • 11
  • 1
  • 1
    *I thought the problem might be to do with where the repaint method is being called* - did you verify if the paintComponent() method is being invoked? Did you verify the alpha value is correct? If so, then maybe the problem is the AlphaComposite? I I've never used the AlphaComposite.SRC_OVER for transparency. Try creating a new Color object using the alpha value. – camickr Jul 23 '20 at 14:47
  • 1
    *"Here's some of the code:"* Glad you did not post *all* the code, but for better help sooner, post a [mre]. – Andrew Thompson Jul 23 '20 at 15:36
  • Thanks @camickr. I've now established that thee repaint method IS invoking the paintComponent() method and have done what you suggested - created a new shape object instance with recalculated RGB values and that's worked. I also commented out the AlphaComposite lines. Thanks – Ingalator Jul 23 '20 at 18:52
  • I wasn't suggesting to create a new shape object, only change the Color used in the setPaint() method to have an alpha value. – camickr Jul 23 '20 at 22:12
  • @camickr sorry I meant to say I created a new color object. That helped me figure out what was going wrong so thanks for your help. I've now got the setComposite working so I don't need to use setPaint to implement the fading effect. I discovered that I needed to set the alpha_ellipse value in the Surface class because the changes being made to alpha_ellipse in HitTest Adpater were contained in that class. – Ingalator Jul 24 '20 at 09:36

1 Answers1

0

See the commented changes needed in run:

@Override
public void run() {

    alpha_ellipse= surf.getAlphaEllipse();

    while (alpha_ellipse >= 0) {

        surf.repaint();
        
        //if alpha_ellipse becomes negative it will never become positive again 
        //so you can simply stop 
        alpha_ellipse += -0.01f;
        if (alpha_ellipse < 0) { 
            alpha_ellipse = 0;
        }       
        //need to set the new alpha in Surface. Add a setter to Surface 
        //a change to swing gui must be done on the EDT hence the use of invokeLater
        SwingUtilities.invokeLater(()->surf.setAlphaEllipse(alpha_ellipse));

        try {
            Thread.sleep(50);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }
}

Side note: consider using Swing Timer instead of a thread.

c0der
  • 18,467
  • 6
  • 33
  • 65