第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何從擴展線程的類在 JPanel 中啟動動畫(將圓從一個點移動到另一個點)?

如何從擴展線程的類在 JPanel 中啟動動畫(將圓從一個點移動到另一個點)?

神不在的星期二 2022-12-15 16:01:10
我有一個名為 Player 的類,它擴展了線程,它的參數(shù)是一個JPanel(稱為DrawPanel)和坐標 x,y;在Player構造函數(shù)中,我在面板上的 x、y 位置畫了一個圓圈(我不知道它有多正確)。在Player運行函數(shù)中,我想啟動一個動畫,將一個小的紅色圓圈從玩家坐標移動到另一個點。就像在這個動畫中一樣。我怎樣才能做到這一點?public class Player extends Thread { private  Graphics graphic; private Graphics2D g2; private int x; private int y; private DrawPanel panel;    public Player(int x, int y,DrawPanel panel)     {        this.x = x;        this.y = y;        this.panel = panel;        graphic = panel.getGraphics();        g2 = (Graphics2D) graphic;        g2.fillOval( column,row, 10, 10);    }    public void run()    {     //startAnimation(this.x,this.y,destination.x,destination.y)    }}
查看完整描述

2 回答

?
ITMISS

TA貢獻1871條經(jīng)驗 獲得超8個贊

我只想開始,動畫并不容易,好的動畫也很難。有很多理論可以讓動畫“看起來”很好,我不打算在這里介紹,有更好的人和資源。

我要討論的是如何在基本級別上用 Swing 制作“好的”動畫。

第一個問題似乎是您對 Swing 中的繪畫工作原理沒有很好的理解。您應該首先閱讀在 Swing 中執(zhí)行自定義繪畫和在 Swing繪畫

接下來,您似乎沒有意識到 Swing 實際上不是線程安全的(并且是單線程的)。這意味著您不應該從事件調(diào)度線程的上下文之外更新 UI 或 UI 所依賴的任何狀態(tài)。有關詳細信息,請參閱Swing 中的并發(fā)。

解決此問題的最簡單方法是使用 Swing ,有關詳細信息Timer,請參閱如何使用 Swing 計時器。

現(xiàn)在,您可以簡單地運行 aTimer并進行直線、線性進展,直到您的所有點都達到目標,但這并不總是最好的解決方案,因為它不能很好地擴展,并且會根據(jù)個人的不同在不同的 PC 上顯示不同能力。

在大多數(shù)情況下,基于持續(xù)時間的動畫效果更好。這允許算法在 PC 無法跟上時“丟棄”幀。它可以更好地擴展(時間和距離)并且可以高度配置。

我喜歡生成可重復使用的代碼塊,所以我將從一個簡單的“基于持續(xù)時間的動畫引擎”開始......

// Self contained, duration based, animation engine...

public class AnimationEngine {


    private Instant startTime;

    private Duration duration;


    private Timer timer;


    private AnimationEngineListener listener;


    public AnimationEngine(Duration duration) {

        this.duration = duration;

    }


    public void start() {

        if (timer != null) {

            return;

        }

        startTime = null;

        timer = new Timer(5, new ActionListener() {

            @Override

            public void actionPerformed(ActionEvent e) {

                tick();

            }

        });

        timer.start();

    }


    public void stop() {

        timer.stop();

        timer = null;

        startTime = null;

    }


    public void setListener(AnimationEngineListener listener) {

        this.listener = listener;

    }


    public AnimationEngineListener getListener() {

        return listener;

    }


    public Duration getDuration() {

        return duration;

    }


    public double getRawProgress() {

        if (startTime == null) {

            return 0.0;

        }

        Duration duration = getDuration();

        Duration runningTime = Duration.between(startTime, Instant.now());

        double progress = (runningTime.toMillis() / (double) duration.toMillis());


        return Math.min(1.0, Math.max(0.0, progress));

    }


    protected void tick() {

        if (startTime == null) {

            startTime = Instant.now();

        }

        double rawProgress = getRawProgress();

        if (rawProgress >= 1.0) {

            rawProgress = 1.0;

        }


        AnimationEngineListener listener = getListener();

        if (listener != null) {

            listener.animationEngineTicked(this, rawProgress);

        }


        // This is done so if you wish to expand the 

        // animation listener to include start/stop events

        // this won't interfer with the tick event

        if (rawProgress >= 1.0) {

            rawProgress = 1.0;

            stop();

        }

    }


    public static interface AnimationEngineListener {


        public void animationEngineTicked(AnimationEngine source, double progress);

    }

}

它并不過分復雜,它有一段duration時間,它會運行。它將tick以固定間隔(不少于 5 毫秒)生成tick事件,報告動畫的當前進度(作為 0 到 1 之間的標準化值)。


這里的想法是我們將“引擎”與使用它的那些元素分離。這使我們能夠?qū)⑺糜诟鼜V泛的可能性。


接下來,我需要一些方法來跟蹤移動物體的位置......


public class Ping {


    private Point point;

    private Point from;

    private Point to;

    private Color fillColor;


    private Shape dot;


    public Ping(Point from, Point to, Color fillColor) {

        this.from = from;

        this.to = to;

        this.fillColor = fillColor;

        point = new Point(from);


        dot = new Ellipse2D.Double(0, 0, 6, 6);

    }


    public void paint(Container parent, Graphics2D g2d) {

        Graphics2D copy = (Graphics2D) g2d.create();

        int width = dot.getBounds().width / 2;

        int height = dot.getBounds().height / 2;

        copy.translate(point.x - width, point.y - height);

        copy.setColor(fillColor);

        copy.fill(dot);

        copy.dispose();

    }


    public Rectangle getBounds() {

        int width = dot.getBounds().width;

        int height = dot.getBounds().height;


        return new Rectangle(point, new Dimension(width, height));

    }


    public void update(double progress) {

        int x = update(progress, from.x, to.x);

        int y = update(progress, from.y, to.y);


        point.x = x;

        point.y = y;

    }


    protected int update(double progress, int from, int to) {

        int distance = to - from;

        int value = (int) Math.round((double) distance * progress);

        value += from;

        if (from < to) {

            value = Math.max(from, Math.min(to, value));

        } else {

            value = Math.max(to, Math.min(from, value));

        }


        return value;

    }

}

這是一個簡單的對象,它獲取起點和終點,然后根據(jù)進度計算對象在這些點之間的位置。它可以在需要時自行繪制。


現(xiàn)在,我們只需要一些方法把它放在一起......


public class TestPane extends JPanel {


    private Point source;

    private Shape sourceShape;

    private List<Ping> pings;

    private List<Shape> destinations;


    private Color[] colors = new Color[]{Color.BLACK, Color.BLUE, Color.CYAN, Color.DARK_GRAY, Color.GREEN, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED, Color.YELLOW};


    private AnimationEngine engine;


    public TestPane() {

        source = new Point(10, 10);

        sourceShape = new Ellipse2D.Double(source.x - 5, source.y - 5, 10, 10);


        Dimension size = getPreferredSize();


        Random rnd = new Random();

        int quantity = 1 + rnd.nextInt(10);

        pings = new ArrayList<>(quantity);

        destinations = new ArrayList<>(quantity);

        for (int index = 0; index < quantity; index++) {

            int x = 20 + rnd.nextInt(size.width - 25);

            int y = 20 + rnd.nextInt(size.height - 25);


            Point toPoint = new Point(x, y);


            // Create the "ping"

            Color color = colors[rnd.nextInt(colors.length)];

            Ping ping = new Ping(source, toPoint, color);

            pings.add(ping);


            // Create the destination shape...

            Rectangle bounds = ping.getBounds();

            Shape destination = new Ellipse2D.Double(toPoint.x - (bounds.width / 2d), toPoint.y - (bounds.height / 2d), 10, 10);

            destinations.add(destination);

        }


        engine = new AnimationEngine(Duration.ofSeconds(10));

        engine.setListener(new AnimationEngine.AnimationEngineListener() {

            @Override

            public void animationEngineTicked(AnimationEngine source, double progress) {

                for (Ping ping : pings) {

                    ping.update(progress);

                }

                repaint();

            }

        });

        engine.start();

    }


    @Override

    public Dimension getPreferredSize() {

        return new Dimension(200, 200);

    }


    protected void paintComponent(Graphics g) {

        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g.create();


        // This is probably overkill, but it will make the output look nicer ;)

        g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);

        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);

        g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);

        g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);

        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

        g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);


        // Lines first, these could be cached

        g2d.setColor(Color.LIGHT_GRAY);

        double fromX = sourceShape.getBounds2D().getCenterX();

        double fromY = sourceShape.getBounds2D().getCenterY();

        for (Shape destination : destinations) {

            double toX = destination.getBounds2D().getCenterX();

            double toY = destination.getBounds2D().getCenterY();

            g2d.draw(new Line2D.Double(fromX, fromY, toX, toY));

        }


        // Pings, so they appear above the line, but under the points

        for (Ping ping : pings) {

            ping.paint(this, g2d);

        }


        // Destination and source

        g2d.setColor(Color.BLACK);

        for (Shape destination : destinations) {

            g2d.fill(destination);

        }


        g2d.fill(sourceShape);


        g2d.dispose();

    }


}

好吧,這個“看起來”很復雜,其實很簡單。

  • 我們創(chuàng)建一個“源”點

  • 然后我們創(chuàng)建隨機數(shù)量的“目標”

  • 然后我們創(chuàng)建一個動畫引擎并啟動它。

然后動畫引擎將循環(huán)遍歷所有Pings 并根據(jù)當前進度值更新它們并觸發(fā)新的繪制通道,然后繪制源點和目標點之間的線,繪制Pings,最后繪制源和所有目標點。簡單的。

如果我想讓動畫以不同的速度運行怎么辦?

啊,好吧,這要復雜得多,需要更復雜的動畫引擎。

一般來說,您可以建立一個“可動畫化”的概念。然后,這將由一個中央“引擎”更新,該引擎不斷“滴答作響”(本身不受持續(xù)時間的限制)。

然后,每個“可動畫化的”都需要決定如何更新或報告其狀態(tài),并允許更新其他對象。

在這種情況下,我會尋找更現(xiàn)成的解決方案,例如......

可運行的例子....

https://i.stack.imgur.com/MFQt4.gif

import java.awt.Color;

import java.awt.Container;

import java.awt.Dimension;

import java.awt.EventQueue;

import java.awt.Graphics;

import java.awt.Graphics2D;

import java.awt.Point;

import java.awt.Rectangle;

import java.awt.RenderingHints;

import java.awt.Shape;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.awt.geom.Ellipse2D;

import java.awt.geom.Line2D;

import java.time.Duration;

import java.time.Instant;

import java.util.ArrayList;

import java.util.List;

import java.util.Random;

import javax.swing.JFrame;

import javax.swing.JPanel;

import javax.swing.Timer;

import javax.swing.UIManager;

import javax.swing.UnsupportedLookAndFeelException;


public class JavaApplication124 {


    public static void main(String[] args) {

        new JavaApplication124();

    }


    public JavaApplication124() {

        EventQueue.invokeLater(new Runnable() {

            @Override

            public void run() {

                try {

                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {

                    ex.printStackTrace();

                }


                JFrame frame = new JFrame("Testing");

                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                frame.add(new TestPane());

                frame.pack();

                frame.setLocationRelativeTo(null);

                frame.setVisible(true);

            }

        });

    }


    public class TestPane extends JPanel {


        private Point source;

        private Shape sourceShape;

        private List<Ping> pings;

        private List<Shape> destinations;


        private Color[] colors = new Color[]{Color.BLACK, Color.BLUE, Color.CYAN, Color.DARK_GRAY, Color.GREEN, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED, Color.YELLOW};


        private AnimationEngine engine;


        public TestPane() {

            source = new Point(10, 10);

            sourceShape = new Ellipse2D.Double(source.x - 5, source.y - 5, 10, 10);


            Dimension size = getPreferredSize();


            Random rnd = new Random();

            int quantity = 1 + rnd.nextInt(10);

            pings = new ArrayList<>(quantity);

            destinations = new ArrayList<>(quantity);

            for (int index = 0; index < quantity; index++) {

                int x = 20 + rnd.nextInt(size.width - 25);

                int y = 20 + rnd.nextInt(size.height - 25);


                Point toPoint = new Point(x, y);


                // Create the "ping"

                Color color = colors[rnd.nextInt(colors.length)];

                Ping ping = new Ping(source, toPoint, color);

                pings.add(ping);


                // Create the destination shape...

                Rectangle bounds = ping.getBounds();

                Shape destination = new Ellipse2D.Double(toPoint.x - (bounds.width / 2d), toPoint.y - (bounds.height / 2d), 10, 10);

                destinations.add(destination);

            }


            engine = new AnimationEngine(Duration.ofSeconds(10));

            engine.setListener(new AnimationEngine.AnimationEngineListener() {

                @Override

                public void animationEngineTicked(AnimationEngine source, double progress) {

                    for (Ping ping : pings) {

                        ping.update(progress);

                    }

                    repaint();

                }

            });

            engine.start();

        }


        @Override

        public Dimension getPreferredSize() {

            return new Dimension(200, 200);

        }


        protected void paintComponent(Graphics g) {

            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D) g.create();


            // This is probably overkill, but it will make the output look nicer ;)

            g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);

            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);

            g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);

            g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);

            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

            g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);


            // Lines first, these could be cached

            g2d.setColor(Color.LIGHT_GRAY);

            double fromX = sourceShape.getBounds2D().getCenterX();

            double fromY = sourceShape.getBounds2D().getCenterY();

            for (Shape destination : destinations) {

                double toX = destination.getBounds2D().getCenterX();

                double toY = destination.getBounds2D().getCenterY();

                g2d.draw(new Line2D.Double(fromX, fromY, toX, toY));

            }


            // Pings, so they appear above the line, but under the points

            for (Ping ping : pings) {

                ping.paint(this, g2d);

            }


            // Destination and source

            g2d.setColor(Color.BLACK);

            for (Shape destination : destinations) {

                g2d.fill(destination);

            }


            g2d.fill(sourceShape);


            g2d.dispose();

        }


    }


    // Self contained, duration based, animation engine...

    public static class AnimationEngine {


        private Instant startTime;

        private Duration duration;


        private Timer timer;


        private AnimationEngineListener listener;


        public AnimationEngine(Duration duration) {

            this.duration = duration;

        }


        public void start() {

            if (timer != null) {

                return;

            }

            startTime = null;

            timer = new Timer(5, new ActionListener() {

                @Override

                public void actionPerformed(ActionEvent e) {

                    tick();

                }

            });

            timer.start();

        }


        public void stop() {

            timer.stop();

            timer = null;

            startTime = null;

        }


        public void setListener(AnimationEngineListener listener) {

            this.listener = listener;

        }


        public AnimationEngineListener getListener() {

            return listener;

        }


        public Duration getDuration() {

            return duration;

        }


        public double getRawProgress() {

            if (startTime == null) {

                return 0.0;

            }

            Duration duration = getDuration();

            Duration runningTime = Duration.between(startTime, Instant.now());

            double progress = (runningTime.toMillis() / (double) duration.toMillis());


            return Math.min(1.0, Math.max(0.0, progress));

        }


        protected void tick() {

            if (startTime == null) {

                startTime = Instant.now();

            }

            double rawProgress = getRawProgress();

            if (rawProgress >= 1.0) {

                rawProgress = 1.0;

            }


            AnimationEngineListener listener = getListener();

            if (listener != null) {

                listener.animationEngineTicked(this, rawProgress);

            }


            // This is done so if you wish to expand the 

            // animation listener to include start/stop events

            // this won't interfer with the tick event

            if (rawProgress >= 1.0) {

                rawProgress = 1.0;

                stop();

            }

        }


        public static interface AnimationEngineListener {


            public void animationEngineTicked(AnimationEngine source, double progress);

        }

    }


    public class Ping {


        private Point point;

        private Point from;

        private Point to;

        private Color fillColor;


        private Shape dot;


        public Ping(Point from, Point to, Color fillColor) {

            this.from = from;

            this.to = to;

            this.fillColor = fillColor;

            point = new Point(from);


            dot = new Ellipse2D.Double(0, 0, 6, 6);

        }


        public void paint(Container parent, Graphics2D g2d) {

            Graphics2D copy = (Graphics2D) g2d.create();

            int width = dot.getBounds().width / 2;

            int height = dot.getBounds().height / 2;

            copy.translate(point.x - width, point.y - height);

            copy.setColor(fillColor);

            copy.fill(dot);

            copy.dispose();

        }


        public Rectangle getBounds() {

            int width = dot.getBounds().width;

            int height = dot.getBounds().height;


            return new Rectangle(point, new Dimension(width, height));

        }


        public void update(double progress) {

            int x = update(progress, from.x, to.x);

            int y = update(progress, from.y, to.y);


            point.x = x;

            point.y = y;

        }


        protected int update(double progress, int from, int to) {

            int distance = to - from;

            int value = (int) Math.round((double) distance * progress);

            value += from;

            if (from < to) {

                value = Math.max(from, Math.min(to, value));

            } else {

                value = Math.max(to, Math.min(from, value));

            }


            return value;

        }

    }


}

有沒有更簡單的??

正如我所說,好的動畫很難。需要付出很多努力和計劃才能做好。我什至沒有談到地役權、鏈式或混合算法,所以請相信我,這實際上是一個簡單、可重用的解決方案

不信,看看Java Swing 中的 JButton 懸停動畫


查看完整回答
反對 回復 2022-12-15
?
智慧大石

TA貢獻1946條經(jīng)驗 獲得超3個贊

試試這個:


public class Player extends Thread {

 private  Graphics graphic;

 private Graphics2D g2;

 private int x;

 private int y;

 private DrawPanel panel;

 private numberOfIteration=5;

 private currentNumberOfIteration=0;

    public Player(int x, int y,DrawPanel panel) 

    {

        this.x = x;

        this.y = y;

        this.panel = panel;

        graphic = panel.getGraphics();

        g2 = (Graphics2D) graphic;

        g2.fillOval( column,row, 10, 10);

    }

    public Player(int x, int y,DrawPanel panel,int numberOfIteration) 

    {

        this.x = x;

        this.y = y;

        this.panel = panel;

        this.numberOfIteration=numberOfIterarion;

        graphic = panel.getGraphics();

        g2 = (Graphics2D) graphic;

        g2.fillOval( column,row, 10, 10);

    }

    public void run()

    {

     //startAnimation(this.x,this.y,destination.x,destination.y)

        currentNumberOfIteration=(++currentNumberOfIteration)%numberOfIteration;

        currentX=(int)((destinationX*currentNumberOfIteration+this.x)/(currentNumberOfIteration+1));

        currentY=(int)((destinationY*currentNumberOfIteration+this.y)/(currentNumberOfIteration+1));

        g2.fillOval( currentX,currentY, 10, 10);


    }

}

我沒有看到destinationXand的任何聲明部分destinationY。


查看完整回答
反對 回復 2022-12-15
  • 2 回答
  • 0 關注
  • 143 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網(wǎng)微信公眾號