繁体   English   中英

没有图形的Java GUI淡入淡出动画

[英]Java GUI fading animation without graphics

我正在使用Java GUI进行游戏,并且尝试制作一些淡入淡出的动画。 我知道使用Java图形要容易得多,但是为此,我正在使用JLabels和Swing,所以我实际上不能做到这一点。 我想做的褪色动画是我将JLabel的背景颜色逐渐从一种颜色变为另一种颜色,所以我尝试这样做的方法是创建一系列颜色并具有一个TimerTask将JLabel的背景一一设置为每种颜色。

TimerTask task = new TimerTask() {
    @Override
    public void run() {
        setBackground(c);
    }
};
tasks[i] = task;

这是我的TimerTask。 颜色c是我在此处作为示例使用的颜色,该颜色部分介于原始颜色和最终颜色之间。 例如,如果我尝试从黑色渐变为白色,则程序最好先将颜色设置为深灰色,然后将颜色设置为中灰,再将其设置为浅灰色,最后设置为最终的白色。 我测试了这些TimerTasks,它们似乎没有任何问题,因此我尝试使用Timer逐个执行它们,但似乎并非每次都执行。

Timer timer = new Timer();
for (int i = 0; i < f; i++) {
    timer.schedule(tasks[i], delay);
}

通常最终会发生的是,颜色会部分褪色,而JLabel最终会停留在介于原始颜色和最终颜色之间的某种颜色上,好像并不是所有预定的任务都已完成。 我在做什么错,尝试用JLabels制作动画甚至明智吗? 提前致谢!


编辑:对不起,我之前的描述不太清楚。 如果我提供了原始代码的某些部分,可能会更容易些,并且我将尝试解释我尝试使其逐步执行的操作。

/** Create array of colors **/
Color[] animationColors = new Color[f];      // f is the number of frames
// find difference between old and new values of r, g, b
int diffR = newColor.getRed() - oldColor.getRed();
int diffG = newColor.getGreen() - oldColor.getGreen();
int diffB = newColor.getBlue() - oldColor.getBlue();
// fill array with colors
for (int i = 0; i < f; i++) {
    int newR = (int)(diffR * (i + 1) / f) + oldColor.getRed();
    int newG = (int)(diffG * (i + 1) / f) + oldColor.getGreen();
    int newB = (int)(diffB * (i + 1) / f) + oldColor.getBlue();
    Color c = new Color(newR, newG, newB);
    animationColors[i] = c;
}

/** Set new background after each delay **/
int delay = (int)(t / f);         // t is the time that the animation will last in total
Timer timer = new Timer();
TimerTask task = new TimerTask() {
    @Override
    public void run() {
        animationCount++;
        if (animationCount == animationColors.length) {
            animationCount = 0;
            timer.cancel();
        } else {
            setBackground(animationColors[animationCount]);
        }
    }
};
timer.schedule(task, delay, delay);

首先,我尝试通过创建在每个短时间间隔后将JLabel设置为的颜色数组来进行淡入淡出动画。 我指定了要进行动画处理的多个帧,在第1帧,JLabel的颜色将在位置1处设置为animationColors,在第2帧的颜色将在位置2处设置为animationColors,以此类推。每帧是从第一种颜色到最终颜色的渐变,从黑色到白色的渐变将先从深灰色开始,然后是中灰,浅灰色,最后是白色。

这里的问题是,瓷砖的颜色通常不会完全褪色。 有时,它淡出的颜色最终将变为原始颜色,而不是我设置为最终颜色的颜色。 问题可能出在我编写计时器的方式上,还是在GUI应用程序中使用计时器通常是个坏主意? 到目前为止,我已经阅读了对该问题的回答,但我对其中的一些内容还不太了解,因此,如果您能进一步解释它们,也将不胜感激。

许多Swing组件不能很好地处理半透明性,尤其是当它发生变化时。

这是一个将标签绘制为BufferedImage的示例,然后可以将其用作另一个标签的图标。 使用这种方法会失去标准标签的许多功能,但可能就足够了。

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.net.*;

public class FadingLabel {

    private JComponent ui = null;
    private BufferedImage fadeImage;
    private BufferedImage clearImage;
    private JLabel opaqueLabel;
    private JLabel fadeLabel;

    FadingLabel() {
        try {
            initUI();
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        }
    }

    public final void initUI() throws MalformedURLException {
        if (ui!=null) return;

        ui = new JPanel(new BorderLayout(4,4));
        ui.setBorder(new EmptyBorder(4,4,4,4));
        URL url = new URL("https://i.stack.imgur.com/F0JHK.png");
        initialiseImages(url, "Fade me!");
        fadeLabel = new JLabel(new ImageIcon(fadeImage));
        ui.add(fadeLabel);

        ActionListener fadeListener = new ActionListener() {

            float transparency;
            float difference = .1f;

            @Override
            public void actionPerformed(ActionEvent e) {
                transparency += difference;
                if (transparency>=1f) {
                    difference = -.01f;
                    transparency = 1f;
                }
                if (transparency<=0f) {
                    difference = .01f;
                    transparency = 0f;
                }
                fadeImage(transparency);
                fadeLabel.repaint();
            }
        };
        Timer timer = new Timer(30, fadeListener);
        timer.start();
    }

    private void fadeImage(float transparency) {
        Dimension d = opaqueLabel.getSize();
        fadeImage.setData(clearImage.getData());
        Graphics2D g = fadeImage.createGraphics();
        Composite composite = AlphaComposite.getInstance(AlphaComposite.SRC, transparency);
        g.setComposite(composite);
        opaqueLabel.paint(g);
    }

    private void initialiseImages(URL iconURL, String text) {
        ImageIcon ii = new ImageIcon(iconURL);
        opaqueLabel = new JLabel(text, ii, SwingConstants.LEADING);
        opaqueLabel.setForeground(Color.BLUE);
        opaqueLabel.setSize(opaqueLabel.getPreferredSize());
        Dimension d = opaqueLabel.getSize();
        clearImage = new BufferedImage(d.width, d.height, BufferedImage.TYPE_INT_ARGB);
        fadeImage = new BufferedImage(d.width, d.height, BufferedImage.TYPE_INT_ARGB);
        Graphics g = fadeImage.getGraphics();
        opaqueLabel.paint(g);
    }

    public JComponent getUI() {
        return ui;
    }

    public static void main(String[] args) {
        Runnable r = () -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (Exception useDefault) {
            }
            FadingLabel o = new FadingLabel();

            JFrame f = new JFrame(o.getClass().getSimpleName());
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setLocationByPlatform(true);

            f.setContentPane(o.getUI());
            f.pack();
            f.setMinimumSize(f.getSize());

            f.setVisible(true);
        };
        SwingUtilities.invokeLater(r);
    }
}

@ AndrewThompson,@ TheUltimateMonkey表示没有图形,但这是一个很好的答案,但是对于没有图形的人,请使用以下命令:

try {

    JFrame frm = new JFrame("Fading Label");
    JLabel lbl = new JLabel("The background is changing!");

    lbl.setOpaque(true);
    lbl.setBackground(new Color(0, 0, 0));

    frm.add(lbl);
    frm.setDefaultCloseOperation(3);
    frm.pack();
    frm.setVisible(true);

    for(int a = 0; a < 256; a++) {

        lbl.setBackground(new Color(a, a, a));
        Thread.sleep(10);

    }

}
catch(Exception e) {}

但是您想尝试java.util.Timer ,然后使用:

try {

    JFrame frm = new JFrame("Fading Label");
    JLabel lbl = new JLabel("The background is changing!");

    lbl.setOpaque(true);
    lbl.setBackground(new Color(0, 0, 0));

    frm.add(lbl);
    frm.setDefaultCloseOperation(3);
    frm.pack();
    frm.setVisible(true);

    Timer tmr = new Timer();
    tmr.schedule(new TimerTask() {

        @Override
        public void run() {

            int a = lbl.getBackground().getRed();
            lbl.setBackground(new Color(a + 1, a + 1, a + 1));
            if(a == 254) System.exit(0); //This prevents the app from crashing, you can do something else to fix this.

        }

    }, 10, 10);

}
catch(Exception e) {}

暂无
暂无

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

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