admin管理员组文章数量:1123885
Im trying to make this fade animation that will work for any component
Im overriding the paint component alphacomposite but it seems it does absolutely nothing.
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package JAnimator;
import java.awt.AlphaComposite;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.Timer;
public class JAnimator {
public static class fade_animation extends JComponent{
private float opacity;
private Timer timer;
private Component target;
private int speed=100;
private boolean isIn = true;
public fade_animation(Component targetComponent, int SpeedMilisec) {
this.target = targetComponent;
this.speed = SpeedMilisec;
timer = new Timer(speed, new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
if(isIn){
opacity += 0.1f;
if(opacity>=1.0f){
opacity = 1.0f;
timer.stop();
}
target.repaint();
}else{
opacity -=0.1f;
if(opacity<=0.0f){
opacity = 0.0f;
timer.stop();
}
target.repaint();
}
}
});
}
public void playIn(){
opacity = 0.0f;
target.repaint();
isIn = true;
try{
timer.stop();
}catch(Exception e){
}
timer.start();
}
public void playOut(){
isIn = false;
opacity = 1.0f;
target.repaint();
try{
timer.stop();
}catch(Exception e){
}
timer.start();
}
@Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, this.opacity));
super.paint(g2d);
super.update(g);
}
}
}
And in my main program im trying to call it like this
JAnimator.fade_animation ani1 = new JAnimator.fade_animation(JPanel1, 100);
ani1.playOut();
This panel was made from designer, netbeans 16
I tried the revalidating and updating ui methods for target component but this had no effect at all
Im trying to make this fade animation that will work for any component
Im overriding the paint component alphacomposite but it seems it does absolutely nothing.
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package JAnimator;
import java.awt.AlphaComposite;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.Timer;
public class JAnimator {
public static class fade_animation extends JComponent{
private float opacity;
private Timer timer;
private Component target;
private int speed=100;
private boolean isIn = true;
public fade_animation(Component targetComponent, int SpeedMilisec) {
this.target = targetComponent;
this.speed = SpeedMilisec;
timer = new Timer(speed, new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
if(isIn){
opacity += 0.1f;
if(opacity>=1.0f){
opacity = 1.0f;
timer.stop();
}
target.repaint();
}else{
opacity -=0.1f;
if(opacity<=0.0f){
opacity = 0.0f;
timer.stop();
}
target.repaint();
}
}
});
}
public void playIn(){
opacity = 0.0f;
target.repaint();
isIn = true;
try{
timer.stop();
}catch(Exception e){
}
timer.start();
}
public void playOut(){
isIn = false;
opacity = 1.0f;
target.repaint();
try{
timer.stop();
}catch(Exception e){
}
timer.start();
}
@Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, this.opacity));
super.paint(g2d);
super.update(g);
}
}
}
And in my main program im trying to call it like this
JAnimator.fade_animation ani1 = new JAnimator.fade_animation(JPanel1, 100);
ani1.playOut();
This panel was made from designer, netbeans 16
I tried the revalidating and updating ui methods for target component but this had no effect at all
Share Improve this question edited yesterday Just a Developer asked yesterday Just a DeveloperJust a Developer 213 bronze badges 4 |1 Answer
Reset to default 0You are trying to create a component which paints the contents of another component. To do this, your paintComponent method must actually make use of that other component. It will not somehow know to paint that component just because there is a reference to that component somewhere in your class.
One way to do that is with SwingUtilities.paintComponent, which is specifically designed to paint a component in an arbitrary Graphics.
SwingUtilities.paintComponent requires these arguments: a Graphics, the component to paint, a temporary parent container, and the rectangular area where painting will take place.
The temporary parent container is just that: an invisible parent (typically a JPanel) to which the component that will be painted can be added, long enough to make sure it is in a drawable state.
So, in the fade animation class, we will need these fields:
public final class Fader
extends JPanel {
@Serial
private static final long serialVersionUID = 1;
private final JComponent view;
private final JComponent parent;
private final Timer timer;
private float opacity;
private boolean fadingIn;
(Usually, it is better to extend JPanel for custom painting, rather than extending JComponent directly, as doing so will take care of some subtle behaviors of Swing painting.)
Then we can initialize them:
public Fader(JComponent target,
Duration frameDelay) {
Objects.requireNonNull(target, "Target component cannot be null.");
Objects.requireNonNull(frameDelay, "Delay cannot be null.");
this.target = target;
this.parent = new JPanel(new BorderLayout());
this.timer = new Timer((int) frameDelay.toMillis(), e -> fade());
}
That fade()
method is similar to what you have already written:
private void fade() {
if (fadingIn) {
opacity += 0.1f;
if (opacity >= 1) {
opacity = 1;
timer.stop();
}
} else {
opacity -= 0.1f;
if (opacity <= 0) {
opacity = 0;
timer.stop();
}
}
repaint();
getToolkit().sync();
}
(Calling Toolkit.sync() after frequent repaints will make your animation smoother.)
The methods to start the fade timer can be pretty short:
public void fadeIntoView() {
opacity = 0;
fadingIn = true;
timer.restart();
}
public void fadeOutOfView() {
opacity = 1;
fadingIn = false;
timer.restart();
}
Before we write a paintComponent method, we first have to make sure this custom component is large enough to display the target component. We do that by overriding its getPreferredSize() method:
@Override
public Dimension getPreferredSize() {
Dimension size = target.getPreferredSize();
// Account for border, if any.
Insets insets = getInsets();
size.width += insets.left + insets.right;
size.height += insets.top + insets.bottom;
return size;
}
Finally, we can write the paintComponent method:
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2 = (Graphics2D) g2.create();
g2.setComposite(AlphaComposite.SrcOver.derive(opacity));
SwingUtilities.calculateInnerArea(this, innerArea);
SwingUtilities.paintComponent(g2, target, parent, innerArea);
g2.dispose();
}
(AlphaComposite.SrcOver.derive(opacity) is a shorter equivalent to AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity).)
innerArea
is a Rectangle which holds the region of the custom component which is inside any Border which may have been added. We can declare innerArea
as another private field in the class:
private final Rectangle innerArea = new Rectangle();
Putting it all together looks something like this:
import java.io.Serial;
import java.io.IOException;
import java.net.URI;
import java.time.Duration;
import java.util.Objects;
import javax.imageio.ImageIO;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.AlphaComposite;
import java.awt.Rectangle;
import java.awt.EventQueue;
import java.awt.Image;
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JFrame;
import javax.swing.ImageIcon;
import javax.swing.Timer;
import javax.swing.SwingUtilities;
import javax.swing.BorderFactory;
public final class Fader
extends JPanel {
@Serial
private static final long serialVersionUID = 1;
private final JComponent target;
private final JComponent parent;
private final Timer timer;
private final Rectangle innerArea = new Rectangle();
private float opacity;
private boolean fadingIn;
public Fader(JComponent target,
Duration frameDelay) {
Objects.requireNonNull(target, "Target component cannot be null.");
Objects.requireNonNull(frameDelay, "Delay cannot be null.");
this.target = target;
this.parent = new JPanel(new BorderLayout());
this.timer = new Timer((int) frameDelay.toMillis(), e -> fade());
}
@Override
public Dimension getPreferredSize() {
Dimension size = target.getPreferredSize();
// Account for border, if any.
Insets insets = getInsets();
size.width += insets.left + insets.right;
size.height += insets.top + insets.bottom;
return size;
}
private void fade() {
if (fadingIn) {
opacity += 0.1f;
if (opacity >= 1) {
opacity = 1;
timer.stop();
}
} else {
opacity -= 0.1f;
if (opacity <= 0) {
opacity = 0;
timer.stop();
}
}
repaint();
getToolkit().sync();
}
public void fadeIntoView() {
opacity = 0;
fadingIn = true;
timer.restart();
}
public void fadeOutOfView() {
opacity = 1;
fadingIn = false;
timer.restart();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2 = (Graphics2D) g2.create();
g2.setComposite(AlphaComposite.SrcOver.derive(opacity));
SwingUtilities.calculateInnerArea(this, innerArea);
SwingUtilities.paintComponent(g2, target, parent, innerArea);
g2.dispose();
}
public static void main(String[] args)
throws IOException {
URI imageLocation = URI.create(args.length > 0 ? args[0] :
"https://cdn.sstatic.net/Sites/stackoverflow" +
"/Img/apple-touch-icon.png");
Image image = ImageIO.read(imageLocation.toURL());
if (image == null) {
throw new RuntimeException("No image found at " + imageLocation);
}
EventQueue.invokeLater(() -> {
JLabel target = new JLabel(new ImageIcon(image));
Fader fader = new Fader(target, Duration.ofMillis(100));
fader.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
JButton fadeInButton = new JButton("Fade In");
fadeInButton.addActionListener(e -> fader.fadeIntoView());
JButton fadeOutButton = new JButton("Fade Out");
fadeOutButton.addActionListener(e -> fader.fadeOutOfView());
JPanel buttonPanel = new JPanel();
buttonPanel.add(fadeInButton);
buttonPanel.add(fadeOutButton);
JFrame frame = new JFrame("Fader");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(fader, BorderLayout.CENTER);
frame.getContentPane().add(buttonPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
});
}
}
本文标签: JPanel Fade animation java swing doesnt workStack Overflow
版权声明:本文标题:JPanel Fade animation java swing doesnt work - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736606856a1945349.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
paintComponent
method must not call paint or update, becase Swing already overrides paint to call paintComponent. Secondly, why does fade_animation extend JComponent while referring to another component that it does not contain? – VGR Commented yesterday