Java:平滑的颜色过渡
Posted
技术标签:
【中文标题】Java:平滑的颜色过渡【英文标题】:Java: Smooth Color Transition 【发布时间】:2014-02-11 18:48:39 【问题描述】:我正在尝试制作一个health bar
,它可能是原始的,一开始是绿色的,在失去健康后你会发现它会变成黄色,然后是橙色,然后是红色.. 或者与此相关的东西.
我尝试使用此链接提供的方法:https://***.com/questions/19841477/java-smooth-color-transition
该链接的结果是这段代码,只是一个从值 100 到 0 的测试,但它以 IllegalArgumentException
结束,通常是 Red
和 Green
,我猜测原因是它超过了值255 个。
Color to = Color.red;
Color base = Color.green;
int red = (int)Math.abs((100 * to.getRed()) + ((1 - 100) * base.getRed()));
int green = (int)Math.abs((100 * to.getGreen()) + ((1 - 100) * base.getGreen()));
int blue = (int)Math.abs((100 * to.getBlue()) + ((1 - 100) * base.getBlue()));
setForeground(new Color(red, green, blue));
它并没有真正起作用,我完全不知道如何才能按照我希望的方式将它发送到 transition
。
所以在我的HealthBar
类中,我有一个update()
方法
public void update()
if (getValue() < 10) setForeground(Color.red);
else if (getValue() < 25) setForeground(Color.orange);
else if (getValue() < 60) setForeground(Color.yellow);
else setForeground(Color.green);
此代码在某些点进行基本转换。
我需要创建字段以在health bar
的某些values
上使用某些colors
,所以现在我有了这个..
if (getValue() < 10)
Color to = Color.black;
// Color current = getForeground() ?
Color from = Color.red;
// ?
我只是在最后一点用一个例子。
所以我知道我将拥有一个color
,我将拥有一个color
,这是一个基础。我不太确定是否需要color
用于当前。我现在看到的问题是过渡的步骤,因为每个过渡都有不同数量的步骤。
总结和问题
我不知道如何实现我正在尝试的目标,我只知道我需要一个 to 和 base color
,并且我提供了一个指向我看到的答案的链接,但我无法真正弄清楚.有了给定的信息,我怎么能把它送到transition colors
?
【问题讨论】:
这对我来说没有意义:(1 - 100) * base.getRed())
。乘以-99?真的吗?您不应该对这些数字进行硬编码,而应该使用转换的变量。您应该使用 println 测试您的代码以帮助调试它。
考虑创建并发布一个minimal, compilable, runnable example program,我们可以原封不动地运行,这向我们展示了您的问题。
【参考方案1】:
我花了很多时间试图找到/创建一个适合我的混合算法,这基本上是我能够蹒跚而行的。
我已经使用这种方法来生成混合多种颜色的渐变过渡,如 here 所示
基本上,这种方法允许您设置一系列颜色和百分比标记,以便您更好地控制颜色之间的过渡点。
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.text.NumberFormat;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class ColorFading
public static void main(String[] args)
new ColorFading();
public ColorFading()
EventQueue.invokeLater(new Runnable()
@Override
public void run()
try
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex)
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new FadePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
);
public class FadePane extends JPanel
private final float[] fractions = new float[]0f, 0.5f, 1f;
private final Color[] colors = new Color[]Color.RED, Color.YELLOW, Color.GREEN;
private float progress = 1f;
private JSlider slider;
public FadePane()
slider = new JSlider(0, 100);
setLayout(new BorderLayout());
add(slider, BorderLayout.SOUTH);
slider.addChangeListener(new ChangeListener()
@Override
public void stateChanged(ChangeEvent e)
progress = ((float)slider.getValue() / 100f);
repaint();
);
slider.setValue(100);
@Override
public Dimension getPreferredSize()
return new Dimension(200, 200);
@Override
protected void paintComponent(Graphics g)
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth();
int height = getHeight();
Color startColor = blendColors(fractions, colors, progress);
g2d.setColor(startColor);
g2d.fillRect(0, 0, width, height);
g2d.dispose();
public static Color blendColors(float[] fractions, Color[] colors, float progress)
Color color = null;
if (fractions != null)
if (colors != null)
if (fractions.length == colors.length)
int[] indicies = getFractionIndicies(fractions, progress);
float[] range = new float[]fractions[indicies[0]], fractions[indicies[1]];
Color[] colorRange = new Color[]colors[indicies[0]], colors[indicies[1]];
float max = range[1] - range[0];
float value = progress - range[0];
float weight = value / max;
color = blend(colorRange[0], colorRange[1], 1f - weight);
else
throw new IllegalArgumentException("Fractions and colours must have equal number of elements");
else
throw new IllegalArgumentException("Colours can't be null");
else
throw new IllegalArgumentException("Fractions can't be null");
return color;
public static int[] getFractionIndicies(float[] fractions, float progress)
int[] range = new int[2];
int startPoint = 0;
while (startPoint < fractions.length && fractions[startPoint] <= progress)
startPoint++;
if (startPoint >= fractions.length)
startPoint = fractions.length - 1;
range[0] = startPoint - 1;
range[1] = startPoint;
return range;
public static Color blend(Color color1, Color color2, double ratio)
float r = (float) ratio;
float ir = (float) 1.0 - r;
float rgb1[] = new float[3];
float rgb2[] = new float[3];
color1.getColorComponents(rgb1);
color2.getColorComponents(rgb2);
float red = rgb1[0] * r + rgb2[0] * ir;
float green = rgb1[1] * r + rgb2[1] * ir;
float blue = rgb1[2] * r + rgb2[2] * ir;
if (red < 0)
red = 0;
else if (red > 255)
red = 255;
if (green < 0)
green = 0;
else if (green > 255)
green = 255;
if (blue < 0)
blue = 0;
else if (blue > 255)
blue = 255;
Color color = null;
try
color = new Color(red, green, blue);
catch (IllegalArgumentException exp)
NumberFormat nf = NumberFormat.getNumberInstance();
System.out.println(nf.format(red) + "; " + nf.format(green) + "; " + nf.format(blue));
exp.printStackTrace();
return color;
【讨论】:
【参考方案2】:好的,在 Mad 发布他的答案(以及 1+)之前,我也在努力解决这个问题,所以我不妨发布我想出的内容....
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EnumMap;
import java.util.Map;
import javax.swing.*;
import javax.swing.event.*;
@SuppressWarnings("serial")
public class ColorTransition extends JPanel
private static final int TRANSITION_DELAY = 30;
private static final int PREF_W = 800;
private static final int PREF_H = 600;
private RgbSliderPanel rgbSliderPanel1 = new RgbSliderPanel("Color 1");
private RgbSliderPanel rgbSliderPanel2 = new RgbSliderPanel("Color 2");
private Color background1;
private Color background2;
private JButton button = new JButton(new ButtonAction("Push Me"));
public ColorTransition()
setBackground(Color.black);
add(rgbSliderPanel1.getMainPanel());
add(rgbSliderPanel2.getMainPanel());
add(button);
rgbSliderPanel1.addPropertyChangeListener(new PropertyChangeListener()
@Override
public void propertyChange(PropertyChangeEvent evt)
if (RgbSliderPanel.COLOR.equals(evt.getPropertyName()))
setBackground(rgbSliderPanel1.calculateColor());
);
@Override
public Dimension getPreferredSize()
return new Dimension(PREF_W, PREF_H);
@Override
public void setEnabled(boolean enabled)
super.setEnabled(enabled);
button.setEnabled(enabled);
rgbSliderPanel1.setEnabled(enabled);
rgbSliderPanel2.setEnabled(enabled);
private class ButtonAction extends AbstractAction
public ButtonAction(String name)
super(name);
@Override
public void actionPerformed(ActionEvent e)
ColorTransition.this.setEnabled(false);
background1 = rgbSliderPanel1.calculateColor();
background2 = rgbSliderPanel2.calculateColor();
setBackground(background1);
Timer timer = new Timer(TRANSITION_DELAY, new TransitionListener());
timer.start();
private class TransitionListener implements ActionListener
private int index = 0;
@Override
public void actionPerformed(ActionEvent e)
if (index > 100)
((Timer) e.getSource()).stop();
ColorTransition.this.setEnabled(true);
else
int r = (int) (background2.getRed() * index / 100.0 + background1
.getRed() * (100 - index) / 100.0);
int g = (int) (background2.getGreen() * index / 100.0 + background1
.getGreen() * (100 - index) / 100.0);
int b = (int) (background2.getBlue() * index / 100.0 + background1
.getBlue() * (100 - index) / 100.0);
setBackground(new Color(r, g, b));
index++;
private static void createAndShowGui()
JFrame frame = new JFrame("ColorTransition");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ColorTransition());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
public static void main(String[] args)
SwingUtilities.invokeLater(new Runnable()
public void run()
createAndShowGui();
);
enum Rgb
RED("Red"), GREEN("Green"), BLUE("Blue");
private String name;
private Rgb(String name)
this.name = name;
public String getName()
return name;
class RgbSliderPanel
public static final String COLOR = "color";
private JPanel mainPanel = new JPanel();
private SwingPropertyChangeSupport propertyChangeSupport = new SwingPropertyChangeSupport(
this);
private Map<Rgb, JSlider> colorSliderMap = new EnumMap<>(Rgb.class);
private String name;
protected Color color;
public RgbSliderPanel(String name)
this.name = name;
mainPanel.setBorder(BorderFactory.createTitledBorder(name));
//mainPanel.setOpaque(false);
mainPanel.setLayout(new GridLayout(0, 1));
for (Rgb rgb : Rgb.values())
JSlider colorSlider = new JSlider(0, 255, 0);
colorSliderMap.put(rgb, colorSlider);
mainPanel.add(colorSlider);
colorSlider.setBorder(BorderFactory.createTitledBorder(rgb.getName()));
colorSlider.setPaintTicks(true);
colorSlider.setPaintTrack(true);
colorSlider.setMajorTickSpacing(50);
colorSlider.setMinorTickSpacing(10);
colorSlider.addChangeListener(new ChangeListener()
@Override
public void stateChanged(ChangeEvent e)
Color oldValue = color;
Color newValue = calculateColor();
color = newValue;
propertyChangeSupport.firePropertyChange(COLOR, oldValue,
newValue);
);
public JComponent getMainPanel()
return mainPanel;
public void setEnabled(boolean enabled)
for (JSlider slider : colorSliderMap.values())
slider.setEnabled(enabled);
public Color calculateColor()
int r = colorSliderMap.get(Rgb.RED).getValue();
int g = colorSliderMap.get(Rgb.GREEN).getValue();
int b = colorSliderMap.get(Rgb.BLUE).getValue();
return new Color(r, g, b);
public String getName()
return name;
public void addPropertyChangeListener(PropertyChangeListener listener)
propertyChangeSupport.addPropertyChangeListener(listener);
public void removePropertyChangeListener(PropertyChangeListener listener)
propertyChangeSupport.removePropertyChangeListener(listener);
【讨论】:
以上是关于Java:平滑的颜色过渡的主要内容,如果未能解决你的问题,请参考以下文章