简体   繁体   English

如何通过命令 JPanel、其组件及其颜色淡出或淡入

[英]How can I fade out or fade in by command JPanel, its components and its color

I wanted to make a Glass Panel that contain a JPanel with white background, border and the msg "please wait".我想制作一个玻璃面板,其中包含一个带有白色背景、边框和味精“请稍候”的 JPanel。

Here is the code example:下面是代码示例:

JLabel glassLabel = new JLabel("Please wait");
FadingPanel msg = new FadingPanel();
glassLabel.setFont(new Font("Dialog", Font.BOLD, 26));
msg.setLayout(new BorderLayout());
msg.add(glassLabel,BorderLayout.NORTH);
msg.setBackground(Color.white);
msg.setFont(UIManager.getFont("Table.font").deriveFont(24f));   
msg.setBorder(new CompoundBorder(new TitledBorder(""),
  new EmptyBorder(20,20,20,20)));

It will fade in and out while waiting for the query.它会在等待查询时淡入淡出。 the problem is that I am getting a bad result.问题是我得到了一个糟糕的结果。

need help需要帮忙

the other is that none of them show it with glass panel另一个是他们都没有用玻璃面板显示它

Animating the opacity state of a glassPane is no different from animating the state of any Swing component, after all, the glassPane is just another component.glassPane的不透明状态设置动画与为任何 Swing 组件的状态设置动画没有什么不同,毕竟glassPane只是另一个组件。

one is that the Timer system doesn't know if the start function started and it keeps the panel hanging on because it closing it before fading the panel and then before it shows it and then it dont try to close it again一个是定时器系统不知道启动功能是否启动,它使面板保持挂起,因为它在面板消失之前关闭它,然后在它显示之前关闭它,然后它不会再次尝试关闭它

This is more about your own internal state management.这更多是关于您自己的内部状态管理。 The panel shouldn't care, it should just be responding to the request to change opacity level, forward or backwards面板不应该关心,它应该只是响应更改不透明度级别的请求,向前或向后

What you should have, is some kind of "engine" which can provide events when certain states are achieved, at which time, you make decisions about what should be done, removing the functionality from the "panel" itself.您应该拥有的是某种“引擎”,它可以在达到某些状态时提供事件,此时,您可以决定应该做什么,从“面板”本身中删除功能。

Theory TL;DR理论 TL; DR

Okay, first, some theory.好的,首先,一些理论。

Animation...动画片...

Animation is the illusion of change over time.动画是随时间变化的幻觉。 In your case, you're moving from 0 to 1 and back again over a specified period of time.在您的情况下,您在指定的时间段内从 0 移动到 1 并再次返回。 This is commonly known as "linear progression/animation".这通常称为“线性进程/动画”。 Most naive animation implementations will simple add a constant delta to a value and keep doing so until a desired state is reached.大多数简单的动画实现将简单地向一个值添加一个恒定的增量,并继续这样做直到达到所需的状态。 This is naive because not all systems are equal.这是天真的,因为并非所有系统都是平等的。 Some will be able to achieve the desired state faster than others, making the animation uneven and providing a poor user experience.有些将能够比其他更快地达到所需的状态,从而使动画不均匀并提供糟糕的用户体验。

Instead, you should be focused on perform a operation over a fixed period of time, calculating the required value as fast as the system will allow.相反,您应该专注于在固定时间段内执行操作,以系统允许的速度计算所需的值。 This allows the animation to "drop" frames as required based on the system's capabilities.这允许动画根据系统功能根据需要“丢弃”帧。 This is commonly known as "duration based animation".这通常称为“基于持续时间的动画”。

This approach is much more powerful, as it allows you to play around with the speed of the animation in a very simply way.这种方法更强大,因为它允许您以非常简单的方式玩弄动画的速度。 It also allows you do some very advanced operations, like easement, which wouldn't be easily achievable through a linear progression.它还允许您执行一些非常高级的操作,例如地役权,这是通过线性进程不容易实现的。

Swing and animation...摇摆和动画...

Swing is SINGLE threaded. Swing 是单线程的。 This means you can't perform blocking or long running operations within the context of the Event Dispatching Thread.这意味着您不能在事件调度线程的上下文中执行阻塞或长时间运行的操作。

Swing is also NOT thread safe. Swing 也不是线程安全的。 This means you shouldn't update the UI (or any state the UI depends on) from outside the context of the EDT.这意味着您不应从 EDT 的上下文之外更新 UI(或 UI 所依赖的任何状态)。

For animation, what you need is some way to post, fast, repetitive, events onto the EDT, which will allow you to make changes to the UI safely.对于动画,您需要某种方式将快速、重复的事件发布到 EDT 上,这将允许您安全地更改 UI。 For this, the most common tool is a Swing Timer ...为此,最常用的工具是 Swing Timer ...

The Framework框架

So based on that, what we need is some kind of "engine", which given a "range" and a "duration" can notify us of "ticks" on a regular bases from which we can calculate the progression that the animation has played, and calculate the value we should use based on our inputs ... simple ...所以基于此,我们需要的是某种“引擎”,它给定“范围”和“持续时间”可以定期通知我们“滴答”,我们可以从中计算动画播放的进度,并根据我们的输入计算我们应该使用的值......简单......

I, personally, prefer to use an animation library, but the simple framework presented in the examples basically abstracts all these concepts into a re-usable framework.我个人更喜欢使用动画库,但是示例中提供的简单框架基本上将所有这些概念抽象为一个可重用的框架。

Make it so...弄成这样...

nb: I ran out of room, so the underlying framework is included in the main example注意:我用完了空间,所以底层框架包含在主要示例中

Okay, that's all nice and fluffy, but how does this actually help us.好的,这一切都很好而且很蓬松,但这对我们有什么帮助。 Essentially, the idea of the above is to abstract common functionality out and make it re-usable (and yes, I actually do use it, a lot)本质上,上面的想法是将通用功能抽象出来并使其可重用(是的,我确实经常使用它)

What we now need, is a component which can actually use it, something like...我们现在需要的是一个可以实际使用它的组件,例如......

public interface FaderListener {
    public void fadeDidComplete(FadePane pane);
}

public class FadePane extends JPanel {

    private double alpha = 1;
    private boolean fadingIn = true;
    private DoubleAnimatable animatable;
    private Duration duration = Duration.ofSeconds(5);
    private List<FaderListener> listeners = new ArrayList<>(5);

    public FadePane() {
        setOpaque(false);
    }
    
    public void addFadeListener(FaderListener listener) {
        listeners.add(listener);
    }

    public void removeFadeListener(FaderListener listener) {
        listeners.remove(listener);
    }
    
    public boolean isFadingIn() {
        return fadingIn;
    }
    
    public double getAlpha() {
        return alpha;
    }

    @Override
    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setComposite(AlphaComposite.SrcOver.derive((float)getAlpha()));
        g2d.setColor(getBackground());
        g2d.fillRect(0, 0, getWidth(), getHeight());
        super.paint(g2d);
        g2d.dispose();
    }
    
    protected void fadeTo(double to) {
        double currentAlpha = getAlpha();
        if (animatable != null) {
            animatable.stop();
            animatable = null;
        }
        
        if (currentAlpha == to) {
            fadeDidComplete();
            return;
        }
        
        DoubleRange animationRange = new DoubleRange(currentAlpha, to);
        double maxFrom = to == 1 ? 1 : 0;
        double maxTo = to == 1 ? 0 : 1;
        DoubleRange maxRange = new DoubleRange(maxFrom, maxTo);
        
        animatable = new DoubleAnimatable(animationRange, maxRange, duration, new AnimatableListener<Double>() {
            @Override
            public void animationChanged(Animatable<Double> animatable) {
                alpha = animatable.getValue();
                repaint();
            }
        }, new AnimatableLifeCycleListenerAdapter<Double>() {
            @Override
            public void animationCompleted(Animatable<Double> animatable) {
                fadeDidComplete();
            }
        });
        
        Animator.INSTANCE.add(animatable);
    }
    
    public void fadeIn() {
        fadingIn = true;
        fadeTo(1);
    }
    
    public void fadeOut() {
        fadingIn = false;
        fadeTo(0);
    }
    
    protected void fadeDidComplete() {            
        for (FaderListener listener : listeners) {
            listener.fadeDidComplete(this);
        }
    }

}

Okay, this is a pretty simple concept.好的,这是一个非常简单的概念。 It's a JPanel which has a alpha property which changes the opacity level of the component - basically, this is all faked, as Swing only support opaque and transparent components, not translucent components.这是一个JPanel ,它有一个alpha属性,可以改变组件的不透明度级别——基本上,这都是伪造的,因为 Swing 只支持不透明和透明组件,不支持半透明组件。 So we set the component to be transparent and manually paint the background ourselves.所以我们将组件设置为透明并自己手动绘制背景。

The component exposes two methods, fadeIn and fadeOut and supports a FaderListener which can be used to notify interested parties that the fade operation has been completed该组件公开了两个方法, fadeInfadeOut并支持一个FaderListener ,可用于通知相关方淡入淡出操作已完成

Runnable example...可运行示例...

褪色

import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
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 java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setBackground(Color.RED);
            setLayout(new BorderLayout());

            FadePane pane = new FadePane();
            pane.setLayout(new GridBagLayout());
            pane.add(new JLabel("Look ma, no hands"));

            add(pane);

            JButton btn = new JButton("Switch");
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    btn.setEnabled(false);
                    if (pane.isFadingIn()) {
                        pane.fadeOut();
                    } else {
                        pane.fadeIn();
                    }
                }
            });
            add(btn, BorderLayout.SOUTH);

            pane.addFadeListener(new FaderListener() {
                @Override
                public void fadeDidComplete(FadePane pane) {
                    btn.setEnabled(true);
                }
            });
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

    public interface FaderListener {
        public void fadeDidComplete(FadePane pane);
    }

    public class FadePane extends JPanel {

        private double alpha = 1;
        private boolean fadingIn = true;
        private DoubleAnimatable animatable;
        private Duration duration = Duration.ofSeconds(5);
        private List<FaderListener> listeners = new ArrayList<>(5);

        public FadePane() {
            setOpaque(false);
        }

        public void addFadeListener(FaderListener listener) {
            listeners.add(listener);
        }

        public void removeFadeListener(FaderListener listener) {
            listeners.remove(listener);
        }

        public boolean isFadingIn() {
            return fadingIn;
        }

        public double getAlpha() {
            return alpha;
        }

        public void setFaddedOut() {
            alpha = 0;
            fadingIn = false;
        }

        public void setFaddedIn() {
            alpha = 1;
            fadingIn = true;
        }

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

        protected void fadeTo(double to) {
            double currentAlpha = getAlpha();
            if (animatable != null) {
                animatable.stop();
                animatable = null;
            }

            if (currentAlpha == to) {
                fadeDidComplete();
                return;
            }

            DoubleRange animationRange = new DoubleRange(currentAlpha, to);
            double maxFrom = to == 1 ? 1 : 0;
            double maxTo = to == 1 ? 0 : 1;
            DoubleRange maxRange = new DoubleRange(maxFrom, maxTo);

            animatable = new DoubleAnimatable(animationRange, maxRange, duration, new AnimatableListener<Double>() {
                @Override
                public void animationChanged(Animatable<Double> animatable) {
                    alpha = animatable.getValue();
                    repaint();
                }
            }, new AnimatableLifeCycleListenerAdapter<Double>() {
                @Override
                public void animationCompleted(Animatable<Double> animatable) {
                    fadeDidComplete();
                }
            });

            Animator.INSTANCE.add(animatable);
        }

        public void fadeIn() {
            fadingIn = true;
            fadeTo(1);
        }

        public void fadeOut() {
            fadingIn = false;
            fadeTo(0);
        }

        protected void fadeDidComplete() {            
            for (FaderListener listener : listeners) {
                listener.fadeDidComplete(this);
            }
        }

    }

    public class DoubleAnimatable extends AbstractAnimatable<Double> {

        public DoubleAnimatable(DoubleRange animationRange, DoubleRange maxRange, Duration duration, AnimatableListener<Double> listener, AnimatableLifeCycleListener<Double> lifeCycleListener) {
            super(animationRange, duration, listener, lifeCycleListener);

            double maxDistance = maxRange.getDistance();
            double aniDistance = animationRange.getDistance();

            double progress = Math.min(100, Math.max(0, Math.abs(aniDistance / maxDistance)));
            Duration remainingDuration = Duration.ofMillis((long) (duration.toMillis() * progress));
            setDuration(remainingDuration);
        }

    }

    public interface AnimatableListener<T> {
        public void animationChanged(Animatable<T> animatable);
    }

    public interface AnimatableLifeCycleListener<T> {
        public void animationStopped(Animatable<T> animatable);
        public void animationCompleted(Animatable<T> animatable);
        public void animationStarted(Animatable<T> animatable);
        public void animationPaused(Animatable<T> animatable);        
    }

    public class AnimatableLifeCycleListenerAdapter<T> implements AnimatableLifeCycleListener<T> {

        @Override
        public void animationStopped(Animatable<T> animatable) {
        }

        @Override
        public void animationCompleted(Animatable<T> animatable) {
        }

        @Override
        public void animationStarted(Animatable<T> animatable) {
        }

        @Override
        public void animationPaused(Animatable<T> animatable) {
        }

    }

    public abstract class AbstractAnimatable<T> implements Animatable<T> {

        private Range<T> range;
        private LocalDateTime startTime;
        private Duration duration = Duration.ofSeconds(5);
        private T value;
        private AnimatableListener<T> animatableListener;
        private AnimatableLifeCycleListener<T> lifeCycleListener;
//        private Easement easement;
        private double rawOffset;

        public AbstractAnimatable(Range<T> range, Duration duration, AnimatableListener<T> listener) {
            this.range = range;
            this.value = range.getFrom();
            this.animatableListener = listener;
        }

        public AbstractAnimatable(Range<T> range, Duration duration, AnimatableListener<T> listener, AnimatableLifeCycleListener<T> lifeCycleListener) {
            this(range, duration, listener);
            this.lifeCycleListener = lifeCycleListener;
        }

//        public AbstractAnimatable(Range<T> range, Duration duration, Easement easement, AnimatableListener<T> listener) {
//            this(range, duration, listener);
//            this.easement = easement;
//        }
//
//        public AbstractAnimatable(Range<T> range, Duration duration, Easement easement, AnimatableListener<T> listener, AnimatableLifeCycleListener<T> lifeCycleListener) {
//            this(range, duration, easement, listener);
//            this.lifeCycleListener = lifeCycleListener;
//        }
//
//        public void setEasement(Easement easement) {
//            this.easement = easement;
//        }
//
//        @Override
//        public Easement getEasement() {
//            return easement;
//        }

        public Duration getDuration() {
            return duration;
        }

        public Range<T> getRange() {
            return range;
        }

        public void setRange(Range<T> range) {
            this.range = range;
        }

        @Override
        public T getValue() {
            return value;
        }

        protected void setDuration(Duration duration) {
            this.duration = duration;
        }

        public double getCurrentProgress(double rawProgress) {
            double progress = Math.min(1.0, Math.max(0.0, getRawProgress()));
//            Easement easement = getEasement();
//            if (easement != null) {
//                progress = easement.interpolate(progress);
//            }
            return Math.min(1.0, Math.max(0.0, progress));
        }

        public double getRawProgress() {
            if (startTime == null) {
                return 0.0;
            }
            Duration duration = getDuration();
            Duration runningTime = Duration.between(startTime, LocalDateTime.now());
            double progress = rawOffset + (runningTime.toMillis() / (double) duration.toMillis());

            return Math.min(1.0, Math.max(0.0, progress));
        }

        @Override
        public void tick() {
            if (startTime == null) {
                startTime = LocalDateTime.now();
                fireAnimationStarted();
            }
            double rawProgress = getRawProgress();
            double progress = getCurrentProgress(rawProgress);
            if (rawProgress >= 1.0) {
                progress = 1.0;
            }
            value = getRange().valueAt(progress);
            fireAnimationChanged();
            if (rawProgress >= 1.0) {
                fireAnimationCompleted();
            }
        }

        @Override
        public void start() {
            if (startTime != null) {
                // Restart?
                return;
            }
            Animator.INSTANCE.add(this);
        }

        @Override
        public void stop() {
            stopWithNotification(true);
        }

        @Override
        public void pause() {
            rawOffset += getRawProgress();
            stopWithNotification(false);

            double remainingProgress = 1.0 - rawOffset;
            Duration remainingTime = getDuration().minusMillis((long) remainingProgress);
            setDuration(remainingTime);

            lifeCycleListener.animationStopped(this);
        }

        protected void fireAnimationChanged() {
            if (animatableListener == null) {
                return;
            }
            animatableListener.animationChanged(this);
        }

        protected void fireAnimationCompleted() {
            stopWithNotification(false);
            if (lifeCycleListener == null) {
                return;
            }
            lifeCycleListener.animationCompleted(this);
        }

        protected void fireAnimationStarted() {
            if (lifeCycleListener == null) {
                return;
            }
            lifeCycleListener.animationStarted(this);
        }

        protected void fireAnimationPaused() {
            if (lifeCycleListener == null) {
                return;
            }
            lifeCycleListener.animationPaused(this);
        }

        protected void stopWithNotification(boolean notify) {
            Animator.INSTANCE.remove(this);
            startTime = null;
            if (notify) {
                if (lifeCycleListener == null) {
                    return;
                }
                lifeCycleListener.animationStopped(this);
            }
        }

    }

    public interface Animatable<T> {

        public Range<T> getRange();

        public T getValue();

        public void tick();

        public Duration getDuration();

        //public Easement getEasement();

        // Wondering if these should be part of a secondary interface
        // Provide a "self managed" unit of work
        public void start();

        public void stop();

        public void pause();
    }

    public abstract class Range<T> {

        private T from;
        private T to;

        public Range(T from, T to) {
            this.from = from;
            this.to = to;
        }

        public T getFrom() {
            return from;
        }

        public T getTo() {
            return to;
        }

        @Override
        public String toString() {
            return "From " + getFrom() + " to " + getTo();
        }

        public abstract T valueAt(double progress);

    }

    public class DoubleRange extends Range<Double> {

        public DoubleRange(Double from, Double to) {
            super(from, to);
        }

        public Double getDistance() {
            return getTo() - getFrom();
        }

        @Override
        public Double valueAt(double progress) {
            double distance = getDistance();
            double value = distance * progress;
            value += getFrom();
            return value;
        }
    }

    public enum Animator {
        INSTANCE;
        private Timer timer;
        private List<Animatable> properies;

        private Animator() {
            properies = new ArrayList<>(5);
            timer = new Timer(5, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    List<Animatable> copy = new ArrayList<>(properies);
                    Iterator<Animatable> it = copy.iterator();
                    while (it.hasNext()) {
                        Animatable ap = it.next();
                        ap.tick();
                    }
                    if (properies.isEmpty()) {
                        timer.stop();
                    }
                }
            });
        }

        public void add(Animatable ap) {
            properies.add(ap);
            timer.start();
        }

        protected void removeAll(List<Animatable> completed) {
            properies.removeAll(completed);
        }

        public void remove(Animatable ap) {
            properies.remove(ap);
            if (properies.isEmpty()) {
                timer.stop();
            }
        }

    }

}

But it's not a glassPane但它不是glassPane

... ok, as I said, a glassPane is just another component ...好吧,正如我所说, glassPane只是另一个组件

This is a simple example which makes use of the frame's glassPane and will, when the panel is faded out, reset the glassPane to a default component这是一个简单的例子,它使用框架的glassPane ,当面板淡出时,将glassPane重置为默认组件

import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new GridBagLayout());

            JButton btn = new JButton("Switch");
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Window window = SwingUtilities.getWindowAncestor(TestPane.this);
                    if (!(window instanceof JFrame)) {
                        System.out.println("Not out frame");
                        return;
                    }
                    JFrame frame = (JFrame) window;
                    FadePane pane = new FadePane();
                    pane.setLayout(new BorderLayout());
                    pane.add(new JLabel("All your base are belong to us"));
                    pane.setFaddedOut();
                    pane.addFadeListener(new FaderListener() {
                        @Override
                        public void fadeDidComplete(FadePane pane) {
                            System.out.println("Completed");
                            if (pane.getAlpha() == 1) {
                                System.out.println("Fade out");
                                pane.fadeOut();
                            } else {
                                System.out.println("Remove glasspane");
                                frame.setGlassPane(new JPanel());
                            }
                        }
                    });
                    frame.setGlassPane(pane);
                    System.out.println("Fade in");
                    pane.setVisible(true);
                    pane.fadeIn();
                }
            });
            add(btn);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

}

nb: The required classes are in the previous example注意:所需的类在前面的例子中

Consider using JDialog container.考虑使用JDialog容器。 When it is undecorated , you can change its opacity :当它未装饰时,您可以更改其不透明度

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.WindowConstants;


public class FadeDialog extends JDialog  {

    private float alfa = 1;
    private JLabel label;
    private boolean isFadeIn = true;
    private JButton fadeIn, fadeOut;

    FadeDialog() {

        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        setLocation(new Point(300, 300));
        getContentPane().setLayout(new BorderLayout(5,0));
        setUndecorated(true); //opacity supported for undecorated JDialogs

        JButton close = new JButton("Close");
        close.addActionListener(e -> dispose());
        getContentPane().add(close, BorderLayout.PAGE_END);
        getContentPane().add(new ContentPane(), BorderLayout.CENTER);
        pack();
        setVisible(true);

        Timer timer = new Timer(2000,  e -> fade());//endless fade-in-out loop
        timer.setInitialDelay(100);
        timer.start();
    }

    void fade() {

        alfa = isFadeIn ? alfa + 0.1f : alfa -0.1f;
        if(alfa <=0 ) {
            alfa = 0; isFadeIn = true;
        }else if(alfa >= 1) {
            alfa = 1; isFadeIn = false;
        }

        fadeIn.setEnabled(! isFadeIn); fadeOut.setEnabled(isFadeIn);
        label.setText("Alfa is " + alfa);
        setOpacity(alfa); //set JDialog opacity
    }

    class ContentPane extends JPanel {

        ContentPane() {
            setPreferredSize(new Dimension(200, 100));
            setLayout(new BorderLayout());
            fadeIn = new JButton("Fade In");
            fadeIn.addActionListener(e -> isFadeIn = true);
            add(fadeIn, BorderLayout.PAGE_START);

            label = new JLabel("Alfa is " + alfa);
            add(label, BorderLayout.CENTER);

            fadeOut = new JButton("Fade Out");
            fadeOut.addActionListener(e -> isFadeIn = false);
            add(fadeOut, BorderLayout.PAGE_END);
        }
    }

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM