【问题标题】:How to slowly change object color from one to another?如何缓慢地将对象颜色从一种更改为另一种?
【发布时间】:2015-06-30 01:40:50
【问题描述】:

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

我将初始颜色作为 targetColor,将最终颜色作为 updateColor。 changedSpeed 变量设置为 5。

我必须使用的机制是

  1. 使用getRed()getGreen()getBlue()获取红绿蓝颜色
  2. 通过targetColor–color = [ dr dg db]计算目标颜色的差异
  3. 通过将向量的范数除以 [ dr dg db] T 来归一化 [ dr dg db](注意 div 除以零)
  4. 乘以changeSpeed来控制改变颜色的速度
  5. 将颜色更新为 color + [ dr' dg' db' ]​​i>

到目前为止,我已经能够制作以下代码:

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 步? 任何人都可以通过代码示例指定如何执行此操作吗? 另外请检查上面的代码是否正确。

【问题讨论】:

  • 您使用的是什么 GUI 库?
  • 我已经创建了一个 JFrame 并使用 Graphics2D 来绘制它。
  • 我不知道你为什么要“乘”任何东西。随着时间的推移颜色的变化......将取决于您的代码在使用稍微改变的颜色绘制任何内容后应该具有的“睡眠”阶段?!
  • "I have created a JFrame and used Graphics2D to paint it" -- 添加了 Swing 标签。今后请务必使用相关标签,以免混淆。
  • 改变速度是控制改变颜色的速度。这是我必须满足的要求

标签: java swing colors


【解决方案1】:

这是一个示例,当您从一个组件移动到另一个组件时,背景会变淡:

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 );
    }
}

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

【讨论】:

  • Hashtable 和 rawtypes 表明这是从您的一些非常古老的代码中复制/粘贴的;)
【解决方案2】:

看这个例子:

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 小于您的变化速度,请使用 delta!

  4. 完成颜色操作后,不要忘记调用 repaint。

【讨论】:

  • 谢谢,到目前为止,您的回答已经包含了我想要的大部分内容。只是一个查询,如果我不想使用计时器,我怎么知道我的新颜色已经达到并且我现在可以停止这个循环?
【解决方案3】:

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

而(i

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

是一个长度为 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】:

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

您可以使用 long 表示动画总时间并使用 Thread(或其他多线程机制)来控制动画生命周期(例如计算自上次重绘以来经过了多少时间和下一次迭代的完成百分比是多少)。

【讨论】:

    【解决方案5】:

    我不知道我是否按照你的数学说明进行操作。

    我创建了一个 Swing GUI,以便我可以观察从一种颜色到另一种颜色的过渡。

    “重置颜色”按钮会生成随机起始颜色和随机结束颜色。开始按钮将底部面板从起始颜色转换为结束颜色。每个转换在红色、绿色或蓝色维度上移动大约 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) {
                }
            }
    
        }
    }
    

    【讨论】:

      【解决方案6】:

      为了实现缓慢的行为,使用 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);
      }
      

      【讨论】:

      • 感谢您提供此代码,但您可以使用我提供的步骤来实现它吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-26
      • 2013-08-15
      • 2012-02-18
      • 1970-01-01
      • 2019-05-11
      • 2018-11-17
      相关资源
      最近更新 更多