簡體   English   中英

為什么星星自轉一段時間后會自動減慢

[英]Why does the star rotation slows down automatically after some time

我有一個程序,我必須使用內部 Timer 事件以圓周運動旋轉一顆星。 框架中有一個按鈕可以改變星星的方向,還有一個 slider 可以改變星星旋轉的速度。

這是我的主 Class

import javax.swing.JFrame;

public class Main {
    public static void main(String args[]) {
//      Making an instance of the class that makes the frame
        MainFrame frame = new MainFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500, 500);
        frame.setVisible(true);
    }
}

制作框架的 MainFrame Class。

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;


@SuppressWarnings("serial")
public class MainFrame extends JFrame{
    private StarGraphics frameStar;
    private JButton starToggle;
    public JSlider starSpeed;
    
    
    public MainFrame() {
//      Setting some properties of the frame
        setTitle("Star Moving with Internal Events");
        setLayout(new BorderLayout());
        
//      Initializing the panel which has rotating star
        frameStar = new StarPainter(this);
        
//      Adding the bottom toggle button and slider
        addToggler();   
    }
    
//  Getter for the slider value
    public int sliderSpeed() {
        return starSpeed.getValue();
    }
    
    
//  Adds Button to change the direction of the star
    private void addToggler() {
//      Adding another jpanel which has layout set to null so i can add button of my size
        JPanel panel = new JPanel();
        panel.setLayout(null);
        panel.setPreferredSize(new Dimension(20,80));
        panel.setBackground(Color.WHITE);
        
//      Initializing button and its action listener to change star direction
        starToggle = new JButton("Toggle");
        starToggle.setBounds(190, 0, 80, 20);
        starToggle.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if(e.getSource() == starToggle) {
                    frameStar.ChangeDirections();
                }
            }
        });
        
//      Adding button to panel
        panel.add(starToggle);
        
//      Adding slider to the panel
        addSlider(panel);
        
//      Adding panel to the main Panel at the bottom
        add(panel, BorderLayout.SOUTH);
    }
    
    private void addSlider(JPanel panel) {
//      Adding Slider and it's properties
        starSpeed = new JSlider(JSlider.HORIZONTAL, 0, 20, 5);
        starSpeed.setMajorTickSpacing(10);
        starSpeed.setMinorTickSpacing(1);
        starSpeed.setPaintTicks(true);
        starSpeed.setPaintLabels(true);
        starSpeed.setBounds(70,30,400, 45);
        
//      Adding Slider-ChangeListener to change the rotation speed of the star
        starSpeed.addChangeListener(new ChangeListener() { // anonymous inner class  
            // handle change in slider value
            @Override
            public void stateChanged(ChangeEvent e) {
                frameStar.ChangeSpeed(starSpeed.getValue());
            }
         } 
      );
        
//      Adding label besides the slider
        JLabel label = new JLabel("Speed : ");
        label.setBounds(10 , 10, 80, 80);
        panel.add(label);
        panel.add(starSpeed);
    }
}

Class 創建有星形旋轉的面板

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

@SuppressWarnings("serial")
public class StarGraphics extends JPanel{
    private boolean toggleDir = false;
    private int speed = 10;
    private Timer timer;
    protected double angleOfStarRotation = 0;
    
    public StarGraphics(JFrame frame) {
        
        setPreferredSize(new Dimension(500, 470));
        setBackground(Color.BLACK);
        setLayout(new BorderLayout());
        frame.add(this, BorderLayout.CENTER);
        
        startTimer();
    }
    
    public void startTimer() {
        timer = new Timer(speed, new ActionListener() {
            public void actionPerformed(ActionEvent e){
//              System.out.println(angleOfStarRotation);
                if(!toggleDir)  //rotates clockwise
                    angleOfStarRotation = angleOfStarRotation + 1;
                else        //rotates counterclockwise
                    angleOfStarRotation = angleOfStarRotation - 1;
                  
//                if (angleOfStarRotation == 360 || angleOfStarRotation == -360)  // If there is a full circle, it will reset the angle to zero
//                    angleOfStarRotation = 0;
                  
                repaint();
            }});
        timer.start();
    }
    
    public void ChangeSpeed(int newSpeed) { 
        this.speed = newSpeed;
        timer.setDelay(speed);
    }   
    public void ChangeDirections() {toggleDir = !toggleDir; }

}

還有一個 class 把星星畫到面板上

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.GeneralPath;
import java.security.SecureRandom;

import javax.swing.JFrame;

@SuppressWarnings("serial")
public class StarPainter extends StarGraphics{
    private int[] starXPoints = {55, 67, 109, 73, 83, 55, 27, 37, 1, 43};
    private int[] starYPoints = {0, 36, 36, 54, 96, 72, 96, 54, 36, 36};
    GeneralPath starDesign = new GeneralPath();
    
    public StarPainter(JFrame frame) {
        super(frame);
    }
    
    public void drawStar(GeneralPath path) {
        path.moveTo(starXPoints[0], starYPoints[0]);
        
        for(int i=0; i<10; i++)
           path.lineTo(starXPoints[i], starYPoints[i]);
        
        path.closePath();
    }
    
    public void starActions(Graphics2D g) {
        int startAngle = 360;
        // For Random Color
        SecureRandom random = new SecureRandom(); 
           
        // rotate around origin and draw stars in random colors
        for (int count = 1; count <= 1; count++) 
        {
            double angle = startAngle - 90;
            // rotate coordinate system
            g.rotate(angleOfStarRotation * Math.PI / angle); //rotates as per the rotated angle    // 
           // set random drawing color
            g.setColor(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
          // draw filled star
            g.fill(starDesign);
          // dispose the star
            g.dispose();
        }
    }
    
    @Override
    public void paintComponent(Graphics g)
    {
       super.paintComponent(g);
       
       Graphics2D g2d = (Graphics2D) g;
      
       drawStar(starDesign);
       
       g2d.translate(250,150);
       
       starActions(g2d);
       
    }
}

運行代碼后,output 將顯示一個框架,其中着色星圍繞面板以圓周運動旋轉,但在旋轉 2 圈后,星旋轉自動減慢。 有誰知道為什么會這樣?

你的“核心”問題就在這里......

public void drawStar(GeneralPath path) {
    path.moveTo(starXPoints[0], starYPoints[0]);
    
    for(int i=0; i<10; i++)
       path.lineTo(starXPoints[i], starYPoints[i]);
    
    path.closePath();
}

每次重新繪制組件時都會調用此方法,這意味着您正在向形狀添加新點,從而使其在每次繪制過程中變得無限復雜。

相反,只需在構造函數中創建形狀...

public StarPainter() {
    starDesign.moveTo(starXPoints[0], starYPoints[0]);

    for (int i = 0; i < 10; i++) {
        starDesign.lineTo(starXPoints[i], starYPoints[i]);
    }

    starDesign.closePath();
}

正如已經指出的那樣,您正在處理一個不是您創建的Graphics上下文。

如果你要改變上下文的轉換,你應該總是創建一個你自己的副本,例如......

public void starActions(Graphics2D g) {
    int startAngle = 360;
    // For Random Color
    SecureRandom random = new SecureRandom();

    g = (Graphics2D) g.create();
    // rotate around origin and draw stars in random colors
    //for (int count = 1; count <= 1; count++) {
        double angle = startAngle - 90;
        // rotate coordinate system
        g.rotate(angleOfStarRotation * Math.PI / angle); //rotates as per the rotated angle    // 
        // set random drawing color
        g.setColor(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
        // draw filled star
        g.fill(starDesign);
        // dispose the star
        g.dispose();
    //}
}

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

    Graphics2D g2d = (Graphics2D) g.create();
    g2d.translate(250, 150);
    starActions(g2d);
    g2d.dispose();

}

此外,將JFrame的引用傳遞給組件......

public StarGraphics(JFrame frame) {
    
    setPreferredSize(new Dimension(500, 470));
    setBackground(Color.BLACK);
    setLayout(new BorderLayout());
    frame.add(this, BorderLayout.CENTER);
    
    startTimer();
}

是個壞主意。 組件不需要,也不是它的責任,與框架交互。 您只是不必要地公開了實現細節。

可運行的例子

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.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.GeneralPath;
import java.security.SecureRandom;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.Timer;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class Main {

    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                MainFrame frame = new MainFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setSize(500, 500);
                frame.setVisible(true);
            }
        });
    }

    public class MainFrame extends JFrame {

        private StarGraphics frameStar;
        private JButton starToggle;
        public JSlider starSpeed;

        public MainFrame() {
            //      Setting some properties of the frame
            setTitle("Star Moving with Internal Events");
            setLayout(new BorderLayout());

            //      Initializing the panel which has rotating star
            frameStar = new StarPainter();
            add(frameStar);

            //      Adding the bottom toggle button and slider
            addToggler();
        }

        //  Getter for the slider value
        public int sliderSpeed() {
            return starSpeed.getValue();
        }

        //  Adds Button to change the direction of the star
        private void addToggler() {
            //      Adding another jpanel which has layout set to null so i can add button of my size
            JPanel panel = new JPanel();
            panel.setLayout(null);
            panel.setPreferredSize(new Dimension(20, 80));
            panel.setBackground(Color.WHITE);

            //      Initializing button and its action listener to change star direction
            starToggle = new JButton("Toggle");
            starToggle.setBounds(190, 0, 80, 20);
            starToggle.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (e.getSource() == starToggle) {
                        frameStar.ChangeDirections();
                    }
                }
            });

            //      Adding button to panel
            panel.add(starToggle);

            //      Adding slider to the panel
            addSlider(panel);

            //      Adding panel to the main Panel at the bottom
            add(panel, BorderLayout.SOUTH);
        }

        private void addSlider(JPanel panel) {
            //      Adding Slider and it's properties
            starSpeed = new JSlider(JSlider.HORIZONTAL, 0, 20, 5);
            starSpeed.setMajorTickSpacing(10);
            starSpeed.setMinorTickSpacing(1);
            starSpeed.setPaintTicks(true);
            starSpeed.setPaintLabels(true);
            starSpeed.setBounds(70, 30, 400, 45);

            //      Adding Slider-ChangeListener to change the rotation speed of the star
            starSpeed.addChangeListener(new ChangeListener() { // anonymous inner class  
                // handle change in slider value
                @Override
                public void stateChanged(ChangeEvent e) {
                    frameStar.ChangeSpeed(starSpeed.getValue());
                }
            }
            );

            //      Adding label besides the slider
            JLabel label = new JLabel("Speed : ");
            label.setBounds(10, 10, 80, 80);
            panel.add(label);
            panel.add(starSpeed);
        }
    }

    public class StarGraphics extends JPanel {

        private boolean toggleDir = false;
        private int speed = 10;
        private Timer timer;
        protected double angleOfStarRotation = 0;

        public StarGraphics() {
            setPreferredSize(new Dimension(500, 470));
            setBackground(Color.BLACK);
            setLayout(new BorderLayout());
            startTimer();
        }

        public void startTimer() {
            timer = new Timer(speed, new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    //              System.out.println(angleOfStarRotation);
                    if (!toggleDir) //rotates clockwise
                    {
                        angleOfStarRotation = angleOfStarRotation + 1;
                    } else //rotates counterclockwise
                    {
                        angleOfStarRotation = angleOfStarRotation - 1;
                    }

                    System.out.println("tick");
                    //                if (angleOfStarRotation == 360 || angleOfStarRotation == -360)  // If there is a full circle, it will reset the angle to zero
                    //                    angleOfStarRotation = 0;
                    repaint();
                }
            });
            timer.start();
        }

        public void ChangeSpeed(int newSpeed) {
            this.speed = newSpeed;
            timer.setDelay(speed);
        }

        public void ChangeDirections() {
            toggleDir = !toggleDir;
        }

    }

    public class StarPainter extends StarGraphics {

        private int[] starXPoints = {55, 67, 109, 73, 83, 55, 27, 37, 1, 43};
        private int[] starYPoints = {0, 36, 36, 54, 96, 72, 96, 54, 36, 36};
        GeneralPath starDesign = new GeneralPath();

        public StarPainter() {
            starDesign.moveTo(starXPoints[0], starYPoints[0]);

            for (int i = 0; i < 10; i++) {
                starDesign.lineTo(starXPoints[i], starYPoints[i]);
            }

            starDesign.closePath();
        }

        public void starActions(Graphics2D g) {
            int startAngle = 360;
            // For Random Color
            SecureRandom random = new SecureRandom();

            g = (Graphics2D) g.create();
            // rotate around origin and draw stars in random colors
            //for (int count = 1; count <= 1; count++) {
            double angle = startAngle - 90;
            // rotate coordinate system
            g.rotate(angleOfStarRotation * Math.PI / angle); //rotates as per the rotated angle    // 
            // set random drawing color
            g.setColor(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
            // draw filled star
            g.fill(starDesign);
            // dispose the star
            g.dispose();
            //}
        }

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

            Graphics2D g2d = (Graphics2D) g.create();
            g2d.translate(250, 150);
            starActions(g2d);
            g2d.dispose();

        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM