Java:平滑的颜色转换
我正在试着做一个health bar
,就像原来的health bar
,它会开始变绿,在失去健康之后,你会发现它会变成黄色,然后变成橙色,然后变成红色……或者与之相关的东西。
我尝试使用此链接提供的方法: https : //stackoverflow.com/questions/19841477/java-smooth-color-transition
这个链接的结果是这个代码,只是一个从100到0的testing,但是它通常以Red
和Green
结束于IllegalArgumentException
,而我的理由是它的值超过了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); }
这段代码在某些地方做了一个基本的转换。
我需要创build字段来使用特定的colors
在health bar
某些values
,所以现在我有这个..
if (getValue() < 10) { Color to = Color.black; // Color current = getForeground() ? Color from = Color.red; // ? }
我只是要用最后一个例子。
所以我知道我将会有一种color
,而且是一种color
。 我不太确定,如果我需要一个当前的color
。 我现在看到的问题是转换的步骤,因为每个转换都有不同的步骤。
总结和问题
我不知道如何去实现我所尝试的,我所知道的是,我需要一个和基本的color
,我提供了一个链接到我看到的答案,但我无法真正弄清楚。 有了这些信息,我怎么才能把它transition colors
?
我花了很多时间试图find/创build一个适合我的混合algorithm,这基本上是我能够一起蹒跚的。
我已经使用这种方法来生成混合多种颜色的渐变过渡,如此处所示
基本上,这种方法允许您设置一系列的颜色和百分比标记,以便更好地控制颜色之间转换的点。
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; } }
好吧, 在疯子发表他的回答(还有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); } }