-1

My JProgressBar is worked perfectly up until i set my JFrame GlassPane visible. It then randomly decides to shoot across the screen and duplicate.

Here is an animated GIF displaying the bug. This happens no matter what my code is - even with an extremely basic GUI

http://i.gyazo.com/bd70df610a3cad6bfff258b80f21c78a.gif

This ONLY happens when i do this.getGlassPane().setVisible(true);

Here is the code:

    public void setProgress(final int percent) {
            pb.setValue(percent);

            if (percent == 100) {

                    SwingUtilities.invokeLater(new Runnable() {
                            public void run() {
                                    FadingMirror glassPane = new FadingMirror();
                                    instance.setGlassPane(glassPane);

                                    ((FadingMirror)instance.getGlassPane()).startAnimation();
                                    ((FadingMirror)instance.getGlassPane()).setVisible(true);
                            }
                    });
            }
    }

    @Override
    public void addText(String text) {
            System.out.println(text);
    }

    public static class FadingMirror extends JPanel implements ActionListener {

            /**
             *
             */
            private static final long serialVersionUID = 7341931028635559650L;
            private float opacity = 0f;
            private Timer fadeTimer;

            public void startAnimation() {
                    fadeTimer = new javax.swing.Timer(75, this);
                    fadeTimer.setInitialDelay(0);
                    fadeTimer.start();

            }

            public void actionPerformed(ActionEvent e) {
                    opacity += .03;
                    if(opacity > 1) {
                            opacity = 1;
                            fadeTimer.stop();
                            fadeTimer = null;
                    }
                    repaint();
            }

            public void paintComponent(Graphics g) {
                    //super.paintComponent(g); //Cannot do this before setting composite without destroying the animation
                    ((Graphics2D) g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
                    g.setColor(getBackground());
                    g.fillRect(0,0,getWidth(),getHeight());
            }
    }

}

Thanks for reading

TacoB
  • 71
  • 9
  • 2
    For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve) (Minimal Complete Verifiable Example) or [SSCCE](http://www.sscce.org/) (Short, Self Contained, Correct Example). – Andrew Thompson Mar 26 '15 at 00:00
  • 1
    You're using a cusomt component for the `glassPane`, which is overriding the `paint` or `paintComponent` methods, but not call it's super method first – MadProgrammer Mar 26 '15 at 00:05
  • MadProgrammer - Looks like you're absolutely right. Only problem is i'm overriding it because if i call super it screws up my fade animation – TacoB Mar 26 '15 at 00:08
  • Then it looks like you need to fix your fade animation. – Hovercraft Full Of Eels Mar 26 '15 at 00:10
  • `Graphics` is a shared resource, you MUST call `super.paintComponent` in order to prepare the `Graphics` for painting, otherwise it will contain what ever was painted to it previously... – MadProgrammer Mar 26 '15 at 00:11
  • 2
    Consider providing a [runnable example](https://stackoverflow.com/help/mcve) which demonstrates your problem. This is not a code dump, but an example of what you are doing which highlights the problem you are having. This will result in less confusion and better responses – MadProgrammer Mar 26 '15 at 00:11
  • Here you go MadProgrammer - my bad for being vague. http://pastebin.com/2ML3T1kZ – TacoB Mar 26 '15 at 00:14
  • Make a copy of the Graphics object, set the composite on **that** and draw with that. Then dispose of it. – Hovercraft Full Of Eels Mar 26 '15 at 00:19
  • Make the component transparent – MadProgrammer Mar 26 '15 at 00:20
  • 1
    *"Here is the code:"* An uncompilable code snippet is not an MCVE or a runnable example, as has now been linked twice for you in the comments. Try following the link and reading the document.. – Andrew Thompson Mar 26 '15 at 00:21
  • Hovercraft Full Of Eels - I tried that. Same result. http://pastebin.com/eA9PNHZa – TacoB Mar 26 '15 at 00:24
  • MadProgrammer - Worked! I simply set setOpaque(false); – TacoB Mar 26 '15 at 00:26

2 Answers2

1

Make a copy of the Graphics object, set the composite on that and draw with that. Then dispose of it.

public void paintComponent(Graphics g) {
    super.paintComponent(g); 
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
    g2.setColor(getBackground());
    g2.fillRect(0,0,getWidth(),getHeight());
    g2.dispose();
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • Don't suppose you could add a vote to [request to fix the hanging close bracket](http://meta.stackexchange.com/q/251795/155831)? – Andrew Thompson Mar 27 '15 at 06:16
1

Graphics is a shared resource. Generally, any Swing component painted by the frame uses the same Graphics context. One of the jobs of paintComponent is to prepare the Graphics context for painting, typically by filling it the current background color.

Because Graphics is a shared resource, any changes you make to it will affect any other components that are painted after it. You should be restoring the Graphics context to it's previous state before paintComponent exists. This is most easily achieved by using Graphics#create which will create a snap-shot the properties of the Graphics context, but won't affect the original. You should then ensure that you call Graphics#dispose on your copy when you're done.

Your glass pane should also be transparent, allowing what ever is below it to be painted.

Fade

import java.awt.AlphaComposite;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setGlassPane(new FadePane());
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class FadePane extends JPanel {

        private float alpha = 0;
        private Timer timer;

        public FadePane() {
            timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    alpha += 0.1f;
                    if (alpha > 1.0) {
                        alpha = 1f;
                        timer.stop();
                    }
                    repaint();
                }
            });
            setOpaque(false);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setComposite(AlphaComposite.SrcOver.derive(alpha));
            g2d.setColor(getBackground());
            g2d.fillRect(0, 0, getWidth(), getHeight());
            g2d.dispose();
        }

        public void fadeAway() {
            setVisible(true);
            timer.stop();
            alpha = 0f;
            timer.start();
        }

    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new GridBagLayout());
            setBorder(new EmptyBorder(50, 50, 50, 50));

            JButton btn = new JButton("It's better to burn out then fade away");
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    JRootPane rootPane = (JRootPane) SwingUtilities.getAncestorOfClass(JRootPane.class, TestPane.this);
                    FadePane fadePane = (FadePane) rootPane.getGlassPane();
                    fadePane.fadeAway();
                }
            });
            add(btn);
        }

    }

}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366