如何慢慢地将对象颜色从一个变为另一个?

时间:2015-04-22 11:59:18

标签: java swing colors

我正在尝试实现一种对象颜色从一种颜色缓慢变为另一种颜色的场景。

我的初始颜色为targetColor,最终颜色为updateColor。 changingSpeed变量设置为5.

我必须使用的机制是

  1. 使用getRed()getGreen()getBlue()获取红色,绿色和蓝色
  2. 计算目标颜色的差异bytargetColor-color = [dr dg db]
  3. 通过除以向量[dr dg db] T(小心div为零)的范数来标准化[dr dg db]
  4. 通过changeSpeed将其乘以控制更改颜色的速度
  5. 将颜色更新为颜色+ [dr'dg'db']
  6. 到目前为止,我已经能够制作以下代码:

    dr=targetColor.getRed()-updateColor.getRed();
            dg=targetColor.getGreen()-updateColor.getGreen();
            db=targetColor.getBlue()-updateColor.getBlue();
    
            double nrml= Math.sqrt((dr*dr)+(dg*dg)+(db*db));
    
            dr=dr/nrml;
            dg=dg/nrml;
            db=db/nrml;
    

    如何执行第4步和第5步? 可以请任何人通过代码示例指定如何做到这一点? 另外,请检查上面的代码是否正确。

6 个答案:

答案 0 :(得分:3)

以下示例在您从组件移动到组件时淡化背景:

import java.awt.*;
import java.awt.event.*;
import java.util.Hashtable;
import java.util.ArrayList;
import javax.swing.*;

public class Fader
{
    //  background color when component has focus
    private Color fadeColor;

    //  steps to fade from original background to fade background
    private int steps;

    //  apply transition colors at this time interval
    private int interval;

    //  store transition colors from orginal background to fade background
    private Hashtable backgroundColors = new Hashtable();

    /*
     *  Fade from a background color to the specified color using
     *  the default of 10 steps at a 50 millisecond interval.
     *
     *  @param fadeColor the temporary background color
     */
    public Fader(Color fadeColor)
    {
        this(fadeColor, 10, 50);
    }

    /*
     *  Fade from a background color to the specified color in the
     *  specified number of steps at the default 5 millisecond interval.
     *
     *  @param fadeColor the temporary background color
     *  @param steps     the number of steps to fade in the color
     */
    public Fader(Color fadeColor, int steps)
    {
        this(fadeColor, steps, 50);
    }

    /*
     *  Fade from a background color to the specified color in the
     *  specified number of steps at the specified time interval.
     *
     *  @param fadeColor the temporary background color
     *  @param steps     the number of steps to fade in the color
     *  @param intevral  the interval to apply color fading
     */
    public Fader(Color fadeColor, int steps, int interval)
    {
        this.fadeColor = fadeColor;
        this.steps = steps;
        this.interval = interval;
    }

    /*
     *  Add a component to this fader.
     *
     *  The fade color will be applied when the component gains focus.
     *  The background color will be restored when the component loses focus.
     *
     *  @param component apply fading to this component
    */
    public Fader add(JComponent component)
    {
        //  Get colors to be used for fading

        ArrayList colors = getColors( component.getBackground() );

        //  FaderTimer will apply colors to the component

        new FaderTimer( colors, component, interval );

        return this;
    }

    /*
    **  Get the colors used to fade this background
    */
    private ArrayList getColors(Color background)
    {
        //  Check if the color ArrayList already exists

        Object o = backgroundColors.get( background );

        if (o != null)
        {
            return (ArrayList)o;
        }

        //  Doesn't exist, create fader colors for this background

        ArrayList colors = new ArrayList( steps + 1 );
        colors.add( background );

        int rDelta = ( background.getRed() - fadeColor.getRed() ) / steps;
        int gDelta = ( background.getGreen() - fadeColor.getGreen() ) / steps;
        int bDelta = ( background.getBlue() - fadeColor.getBlue() ) / steps;

        for (int i = 1; i < steps; i++)
        {
            int rValue = background.getRed() - (i * rDelta);
            int gValue = background.getGreen() - (i * gDelta);
            int bValue = background.getBlue() - (i * bDelta);

            colors.add( new Color(rValue, gValue, bValue) );
        }

        colors.add( fadeColor );
        backgroundColors.put(background, colors);

        return colors;
    }

    class FaderTimer implements FocusListener, ActionListener
    {
        private ArrayList colors;
        private JComponent component;
        private Timer timer;
        private int alpha;
        private int increment;

        FaderTimer(ArrayList colors, JComponent component, int interval)
        {
            this.colors = colors;
            this.component = component;
            component.addFocusListener( this );
            timer = new Timer(interval, this);
        }

        public void focusGained(FocusEvent e)
        {
            alpha = 0;
            increment = 1;
            timer.start();
        }

        public void focusLost(FocusEvent e)
        {
            alpha = steps;
            increment = -1;
            timer.start();
        }

        public void actionPerformed(ActionEvent e)
        {
            alpha += increment;

            component.setBackground( (Color)colors.get(alpha) );

            if (alpha == steps || alpha == 0)
                timer.stop();
        }
    }

    public static void main(String[] args)
    {
        // Create test components

        JComponent textField1 = new JTextField(10);
        textField1.setBackground( Color.YELLOW );
        JComponent textField3 = new JTextField(10);
        JComponent textField4 = new JTextField(10);
        JComponent button = new JButton("Start");
        JComponent checkBox = new JCheckBox("Check Box");

        JFrame frame = new JFrame("Fading Background");
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.getContentPane().add(textField1, BorderLayout.NORTH );
        frame.getContentPane().add(button, BorderLayout.SOUTH );
        frame.getContentPane().add(textField3, BorderLayout.WEST );
        frame.getContentPane().add(textField4, BorderLayout.EAST );
        frame.getContentPane().add(checkBox);

        //  Gradual Fading (using defaults)

//      Fader fader = new Fader( new Color(155, 255, 155) );
        Fader fader = new Fader( new Color(155, 255, 155), 10, 50 );
        fader.add( textField1 );
        fader.add( textField3 );
        fader.add( checkBox );

        //  Instant Fading

        fader = new Fader( new Color(255, 155, 155), 1, 1 );
        fader.add( textField4 );
        fader.add( button );

        frame.pack();
        frame.setVisible( true );
    }
}

它使用Timer以指定的间隔更新背景。然后根据所需的步数在两种颜色之间进行插值。

答案 1 :(得分:0)

为了实现缓慢的行为,使用Robot类的实例可能是个好主意。

//Method to obtain the offset of the color

static int [] getColorOffset(Color initial, Color final){
    int [] colorOffset = new int[3];
    colorOffset[0]= final.getRed()-initial.getRed();
    colorOffset[1] = final.getGreen()-initial.getGreen();
    colorOffset[2]= final.getBlue()-initial.getBlue();
    return colorOffset;
}

updateColor(int [] colorOffset) throws AWTException{
    int  dr = colorOffset[0];
    int  dg = colorOffset[1];
    int  db = colorOffset[2];
    Robot slow = new Robot();
    int i=0;
    while(i<=10){
        slow.delay(1000)
        //sleep will sleep for 1000ms

        setColor(targetColor.getRed() + dr/10, targetColor.getGreen(),targetColor.getBlue());
        setColor(targetColor.getRed(), targetColor.getGreen() + (dg/10),targetColor.getBlue());
        setColor(targetColor.getRed(), targetColor.getGreen(),targetColor.getBlue() + db/10);

        i++;
    }

}

public static void main(String args[]) throws AWTException{
    Color initial = Color.black;
    Color final = Color,white;
    int [] colorOffset = getColorOffset(initial, final);
    updateColor(colorOffset);
}

答案 2 :(得分:0)

看看这个例子:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Test {

    public static void main(String args[]) {
        final JFrame frame = new JFrame();
        frame.setBounds(100, 100, 300, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // set some random initial color
        final Component comp = frame.getContentPane();
        comp.setBackground(new Color(
            (float) Math.random(),
            (float) Math.random(),
            (float) Math.random()));

        frame.setVisible(true);

        final Timer timer = new Timer(50, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {
                final Color targetColor = new Color(30,40,50);
                final int changingSpeed = 5;

                final Color currentColor = comp.getBackground();

                // step 1
                int r = currentColor.getRed();
                int g = currentColor.getGreen();
                int b = currentColor.getBlue();

                // step 2
                double dr = targetColor.getRed() - r;
                double dg = targetColor.getGreen() - g;
                double db = targetColor.getBlue() - b;

                // step 3
                double norm = Math.sqrt(dr*dr+dg*dg+db*db);
                if (norm < .001) {
                    ((Timer)(evt.getSource())).stop();
                    return;
                }
                dr /= norm;
                dg /= norm;
                db /= norm;

                // step 4
                dr *= Math.min(changingSpeed, norm);
                dg *= Math.min(changingSpeed, norm);
                db *= Math.min(changingSpeed, norm);

                // step 5
                r += dr;
                g += dg;
                b += db;
                comp.setBackground(new Color(r,g,b));

                frame.repaint();
            }
        });
        timer.start();
    }
}

有几点需要注意:

  1. 使用计时器触发更新。这确保了它们在EventThread中完成,这是操作Swing GUI所必需的。

  2. 测试非常小的标准。这意味着,您的delta接近于零,您应该停止更新颜色。

  3. 使用最小标准和您的变化速度。如果您的变化速度足够高,您的颜色将在目标颜色周围交替,您的增量将永远交换标志,并且过程不会终止。因此,如果您的delta小于您的更改速度,请使用delta!

  4. 操作完颜色后,别忘了给重画打电话。

答案 3 :(得分:0)

是的,而不是在行中使用for循环

而(I&LT; = 10);

你实际上可以使用你的变化速度。同时你的changingSpeed应该

是长度为3的数组,因为颜色间隔的偏差不同,即

dr,dg,db这样他们可以独立照顾。

像这样......

int [] changingSpeed(int []Offset){

int loop = 5;

// 5 means the color should be change 5 times

int [] changeSpeed = new int[3];

changeSpeed[0]= offset[0]/loop;

changeSpeed[1]= offset[1]/loop;

changeSpeed[2]= offset[2]/loop;

return changeSpeed;
}

// your update method will now look like this

updateColor(int [] changeSpeed) throws AWTException{

int dr = changeSpeed[0];

int dg = changeSpeed[1];

int db = changeSpeed[2];

Robot slow = new Robot();

int i=0;


int f= loop; // the number of time you want the color to change

while(i<=f){

slow.delay(1000)

//sleep will sleep for 1000ms

setColor(targetColor.getRed() + dr/10, targetColor.getGreen(),targetColor.getBlue());

setColor(targetColor.getRed(), targetColor.getGreen() + (dg/10),targetColor.getBlue());

setColor(targetColor.getRed(), targetColor.getGreen(),targetColor.getBlue() + db/10);

i++;

}

}

答案 4 :(得分:0)

我不会依赖特定的延迟时间来计算动画中的下一步,因为这肯定会在不同的机器中提供不同的执行时间,尽管它可能不是相关的差异。

您可以使用表示动画总时间的长度而不是更改速度因子,并使用Thread(或其他多线程机制)来控制动画生命周期(例如计算自上次以来经过的时间)重新绘制并描述下一次迭代完成的百分比。)

答案 5 :(得分:0)

我不知道我是否按照你的数学指示。

我创建了一个Swing GUI,因此我可以观察从一种颜色到另一种颜色的转换。

Color Change Tester

“重置颜色”按钮生成随机起始颜色和随机整理颜色。 “开始”按钮将底部面板从起始颜色转换为精加工颜色。每次转换在红色,绿色或蓝色维度上移动约5个值,延迟为300毫秒。

我倾向于观察数字的变化,而不是颜色。我想确保转型相当均匀。

无论如何,这里是代码。您可以使用它来建模其他Swing GUI。我将所有类放在一个文件中,这样我就可以在这里粘贴代码了。您应该将类​​分成单独的文件。

package com.ggl.testing;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class ColorChangeTest implements Runnable {

    private static final Insets normalInsets = new Insets(10, 10, 0, 10);

    private Color currentColor;
    private Color targetColor;

    private ColorPanel changingColorPanel;
    private ColorPanel currentColorPanel;
    private ColorPanel targetColorPanel;

    private JLabel changingLabel;
    private JLabel currentLabel;
    private JLabel targetLabel;

    public static void main(String args[]) {
        SwingUtilities.invokeLater(new ColorChangeTest());
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("Color Change Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BorderLayout());

        mainPanel.add(createColorPanel(), BorderLayout.NORTH);
        mainPanel.add(createChangingPanel(), BorderLayout.CENTER);

        frame.add(mainPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    private JPanel createColorPanel() {
        JPanel colorPanel = new JPanel();

        setNewColors();

        JPanel currentPanel = new JPanel();
        currentPanel.setLayout(new BorderLayout());

        JPanel currentLabelPanel = new JPanel();
        currentLabelPanel.setLayout(new BorderLayout());

        JLabel startLabel = new JLabel("Starting Color");
        startLabel.setHorizontalAlignment(JLabel.CENTER);
        currentLabelPanel.add(startLabel, BorderLayout.NORTH);

        currentLabel = new JLabel(getColorString(currentColor));
        currentLabel.setHorizontalAlignment(JLabel.CENTER);
        currentLabelPanel.add(currentLabel, BorderLayout.SOUTH);

        currentPanel.add(currentLabelPanel, BorderLayout.NORTH);

        currentColorPanel = new ColorPanel(100, 100, currentColor);
        currentPanel.add(currentColorPanel, BorderLayout.CENTER);

        colorPanel.add(currentPanel);

        JPanel targetPanel = new JPanel();
        targetPanel.setLayout(new BorderLayout());

        JPanel targetLabelPanel = new JPanel();
        targetLabelPanel.setLayout(new BorderLayout());

        JLabel finishLabel = new JLabel("Finishing Color");
        finishLabel.setHorizontalAlignment(JLabel.CENTER);
        targetLabelPanel.add(finishLabel, BorderLayout.NORTH);

        targetLabel = new JLabel(getColorString(targetColor));
        targetLabel.setHorizontalAlignment(JLabel.CENTER);
        targetLabelPanel.add(targetLabel, BorderLayout.SOUTH);

        targetPanel.add(targetLabelPanel, BorderLayout.NORTH);

        targetColorPanel = new ColorPanel(100, 100, targetColor);
        targetPanel.add(targetColorPanel, BorderLayout.CENTER);

        colorPanel.add(targetPanel);
        colorPanel.add(createButtonPanel());

        return colorPanel;
    }

    private JPanel createButtonPanel() {
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new GridBagLayout());

        int gridy = 0;

        JButton resetButton = new JButton("Reset Colors");
        resetButton.addActionListener(new ResetColorsListener(this));
        addComponent(buttonPanel, resetButton, 0, gridy++, 1, 1, normalInsets,
                GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL);

        JButton startButton = new JButton("Start");
        startButton.addActionListener(new ColorChangeListener(this));
        addComponent(buttonPanel, startButton, 0, gridy++, 1, 1, normalInsets,
                GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL);

        return buttonPanel;
    }

    private JPanel createChangingPanel() {
        JPanel changingPanel = new JPanel();
        changingPanel.setLayout(new BorderLayout());

        changingLabel = new JLabel(getColorString(currentColor));
        changingLabel.setHorizontalAlignment(JLabel.CENTER);
        changingPanel.add(changingLabel, BorderLayout.NORTH);

        changingColorPanel = new ColorPanel(300, 200, currentColor);
        changingPanel.add(changingColorPanel, BorderLayout.CENTER);

        return changingPanel;
    }

    public void setChangingColorLabelText(Color color) {
        changingLabel.setText(getColorString(color));
    }

    public void setNewColors() {
        currentColor = getRandomColor();
        targetColor = getRandomColor();
    }

    public void displayNewColors() {
        currentLabel.setText(getColorString(currentColor));
        targetLabel.setText(getColorString(targetColor));
        changingLabel.setText(getColorString(currentColor));
        currentColorPanel.setColor(currentColor);
        targetColorPanel.setColor(targetColor);
        changingColorPanel.setColor(currentColor);
    }

    public Color getCurrentColor() {
        return currentColor;
    }

    public Color getTargetColor() {
        return targetColor;
    }

    public ColorPanel getChangingColorPanel() {
        return changingColorPanel;
    }

    private Color getRandomColor() {
        return new Color((float) Math.random(), (float) Math.random(),
                (float) Math.random());
    }

    private String getColorString(Color color) {
        int r = color.getRed();
        int g = color.getGreen();
        int b = color.getBlue();
        return "(" + r + ", " + g + ", " + b + ")";
    }

    private void addComponent(Container container, Component component,
            int gridx, int gridy, int gridwidth, int gridheight, Insets insets,
            int anchor, int fill) {
        GridBagConstraints gbc = new GridBagConstraints(gridx, gridy,
                gridwidth, gridheight, 1.0D, 1.0D, anchor, fill, insets, 0, 0);
        container.add(component, gbc);
    }

    public class ColorPanel extends JPanel {

        private static final long serialVersionUID = -2894328511698328096L;

        private Color color;

        public ColorPanel(int width, int height, Color color) {
            this.color = color;
            this.setPreferredSize(new Dimension(width, height));
        }

        public void setColor(Color color) {
            this.color = color;
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            g.setColor(color);
            g.fillRect(0, 0, getWidth(), getHeight());
        }
    }

    public class ResetColorsListener implements ActionListener {

        private ColorChangeTest colorChangeTest;

        public ResetColorsListener(ColorChangeTest colorChangeTest) {
            this.colorChangeTest = colorChangeTest;
        }

        @Override
        public void actionPerformed(ActionEvent event) {
            colorChangeTest.setNewColors();
            colorChangeTest.displayNewColors();
        }

    }

    public class ColorChangeListener implements ActionListener {

        private ColorChangeTest colorChangeTest;

        public ColorChangeListener(ColorChangeTest colorChangeTest) {
            this.colorChangeTest = colorChangeTest;
        }

        @Override
        public void actionPerformed(ActionEvent event) {
            ColorChange colorChange = new ColorChange(colorChangeTest);
            new Thread(colorChange).start();
        }
    }

    public class ColorChange implements Runnable {

        private static final long sleepTime = 300L;

        private double r, g, b, dr, dg, db;

        private int tr, tg, tb, cr, cg, cb;

        private ColorChangeTest colorChangeTest;

        public ColorChange(ColorChangeTest colorChangeTest) {
            this.colorChangeTest = colorChangeTest;
        }

        @Override
        public void run() {
            calculateColorChange();
            sleep(sleepTime);
            while (calculateNextColor()) {
                sleep(sleepTime);
            }
            setColor(colorChangeTest.getTargetColor());
        }

        private void calculateColorChange() {
            double increment = 5D;

            // step 1
            r = cr = colorChangeTest.getCurrentColor().getRed();
            g = cg = colorChangeTest.getCurrentColor().getGreen();
            b = cb = colorChangeTest.getCurrentColor().getBlue();

            // step 2
            tr = colorChangeTest.getTargetColor().getRed();
            tg = colorChangeTest.getTargetColor().getGreen();
            tb = colorChangeTest.getTargetColor().getBlue();

            dr = tr - cr;
            dg = tg - cg;
            db = tb - cb;

            // step 3
            double d = Math.sqrt(dr * dr + dg * dg + db * db);
            int steps = (int) (d / increment);

            dr /= (double) steps;
            dg /= (double) steps;
            db /= (double) steps;

            setColor(new Color(cr, cg, cb));
        }

        private boolean calculateNextColor() {
            // step 5
            r += dr;
            g += dg;
            b += db;

            if (isFinished()) {
                return false;
            } else {
                setColor(new Color(round(r), round(g), round(b)));
                return true;
            }
        }

        private boolean isFinished() {
            return isColorFinished(cr, tr, round(r))
                    || isColorFinished(cg, tg, round(g))
                    || isColorFinished(cb, tb, round(b));
        }

        private int round(double value) {
            return (int) Math.round(value);
        }

        private boolean isColorFinished(int original, int target, int current) {
            boolean isFinished = false;
            if (current < 0 || current > 255) {
                isFinished = true;
            } else if ((target >= original) && (current >= target)) {
                isFinished = true;
            } else if ((target <= original) && (current <= target)) {
                isFinished = true;
            }

            return isFinished;
        }

        private void setColor(final Color color) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    colorChangeTest.getChangingColorPanel().setColor(color);
                    colorChangeTest.setChangingColorLabelText(color);
                }
            });
        }

        private void sleep(long sleepTime) {
            try {
                Thread.sleep(sleepTime);
            } catch (InterruptedException e) {
            }
        }

    }
}