问题
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
回答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();
}
回答2:
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.
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);
}
}
}
来源:https://stackoverflow.com/questions/29268783/jprogressbar-duplicating