简体   繁体   English

从其他类中的线程调用时不重新出现

[英]Repaint not occurring when called from thread in a different class

I am trying to make a simple artillery game and print a circle moving across the screen in an arc when a button is clicked. 我正在尝试制作一个简单的火炮游戏,并在点击按钮时打印一个在圆弧中移动的圆圈。

On click i create a thread and calculate the location of the "projectile" and print out a circle at the calculate x and y locations. 点击后,我创建一个线程并计算“射弹”的位置,并在计算x和y位置打印出一个圆圈。

When i execute the code from the one class it calls repaint and plots the trajectory of the "projectile" but when i set up a separate class to call it and print it out on the click of a button it does not call the repaint from the loop. 当我从一个类执行代码时,它调用重绘并绘制“射弹”的轨迹,但是当我设置一个单独的类来调用它并在点击按钮时将其打印出来时它不会从中调用重绘环。

When i execute the class below by itself displays what i want. 当我执行下面的类本身显示我想要的。

import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Pong4 extends JPanel implements Runnable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private ScreenLocation location;

    private boolean renderBulit = false;

    public static void main(String[] args)
    {
        Pong4 p = new Pong4();

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(p);
        frame.setSize(800, 600);
        frame.setVisible(true);

        Thread thread = new Thread(p);
        thread.start();
        try {
            thread.join();
        } catch (InterruptedException ex) {
            // TODO Auto-generated catch block
            ex.printStackTrace();
        }
    }

    public Pong4()
    {
    }

    public ScreenLocation updatePosition(ScreenLocation location, double xSpeed, double ySpeed, double time) 
    {   
        return new ScreenLocation((int)(location.getX() + xSpeed * time), (int)(location.getY() - ySpeed * time));
    }


    @Override
    public void run()
    {

        double time = 0;
        location = new ScreenLocation(100, 400);
        renderBulit = true;

        double xSpeed = 50;
        double ySpeed = 50;

        while (location.getX() >= 0 && 800 > location.getX() && 400 >= location.getY())
        {       
            repaint();

            System.out.println("test");

            try {
                Thread.sleep(15);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            time += 0.01;
            location = updatePosition(location, xSpeed, ySpeed, time);
            ySpeed = ySpeed - Constants.GRAVITY * time;
        }

        renderBulit = false;
        repaint();

    }

    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponents(g); 
        Graphics2D g2d = (Graphics2D)g;

        // Paint a gradient from top to bottom
        GradientPaint gp = new GradientPaint( 0, 0, Color.BLACK,
            0, getHeight( ), new Color(0, 0, 255).darker( ).darker() );

        g2d.setPaint( gp );
        g2d.fillRect( 0, 0, getWidth( ), getHeight( ) );

        if (renderBulit)
        {
            // draw circle (color already set to foreground)
            g.setColor(Color.red);
            g.fillOval(location.getX(), location.getY(), 4, 4);
            g.drawOval(location.getX(), location.getY(), 4, 4);


            //Image image = new ImageIcon("src/au/com/tankwarz/view/resources/images/BULIT0.GIF").getImage();
            //g.drawImage(image, location.getX(), location.getY(), this); 
        }
        g2d.dispose();       
    }

    public class ScreenLocation 
    {
        private int x;

        private int y;

        public ScreenLocation (int x, int y)
        {
            this.x = x;
            this.y = y;
        }

        public int getX() {
            return x;
        }

        public void setX(int x) {
            this.x = x;
        }

        public int getY() {
            return y;
        }

        public void setY(int y) {
            this.y = y;
        }


    }
}

But when i try the following it does not display. 但是,当我尝试以下时,它不会显示。

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.JPanel;

import org.jdesktop.application.Application;

public class Pong3 extends JPanel{

    public static void main(String[] args)
    {

        new Pong3();
    }

    private static final long serialVersionUID = 2944576178447230562L;

    private JButton fireButton;
    private JPanel controlsPanel;

    private Pong4 pong;

    public Pong3() {
        super();
        initGUI();

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(this);
        frame.setSize(800, 600);
        frame.setVisible(true);
    }

    private void initGUI() {
        try {
            this.setPreferredSize(new java.awt.Dimension(800, 600));
            this.setSize(800, 600);
            this.setLayout(null);
            {
                pong = new Pong4();
                this.add(pong);
                pong.setLayout(null);
                pong.setBounds(0, 0, 800, 450);
            }           
            {
                controlsPanel = new JPanel();
                this.add(controlsPanel);
                GridBagLayout controlsPanelLayout = new GridBagLayout();
                controlsPanelLayout.rowWeights = new double[] {0.1, 0.1, 0.1, 0.1};
                controlsPanelLayout.rowHeights = new int[] {7, 7, 7, 7};
                controlsPanelLayout.columnWeights = new double[] {0.1, 0.1, 0.1, 0.1};
                controlsPanelLayout.columnWidths = new int[] {7, 7, 7, 7};
                controlsPanel.setLayout(controlsPanelLayout);
                controlsPanel.setBounds(0, 450, 800, 110);
                controlsPanel.setName("controlsPanel");

                {
                    fireButton = new JButton();
                    controlsPanel.add(fireButton, new GridBagConstraints(3, 1, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
                    fireButton.setName("fireButton");
                    fireButton.setText("Fire");
                    fireButton.setPreferredSize(new java.awt.Dimension(104, 51));
                    fireButton.addActionListener(new ActionListener() {

                        @Override
                        public void actionPerformed(ActionEvent e) {            
                            Thread thread = new Thread(pong);
                            thread.start();
                            try {
                                thread.join();
                            } catch (InterruptedException ex) {
                                // TODO Auto-generated catch block
                                ex.printStackTrace();
                            }


                        }
                    });
                }
            }
            Application.getInstance().getContext().getResourceMap(getClass()).injectComponents(this);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

Would appreciate any help as to why this acts this way. 非常感谢任何帮助,为什么这样做。

Your thread.join() undoes all the benefits of trying to use a background thread by tying the "background" thread with the current thread, and thus you should not be doing this. 你的thread.join()通过将“后台”线程与当前线程绑在一起来解除尝试使用后台线程的所有好处,因此你不应该这样做。 The only reason things seem to work in the first code is due to your code initially running not in the event dispatch thread, and so your join() call joins the thread to the main thread, not the EDT, and so does not freeze the EDT. 事情似乎在第一个代码中工作的唯一原因是由于你的代码最初不在事件派发线程中运行,所以你的join()调用将线程连接到主线程,而不是EDT,因此不会冻结美东时间。 Either way, the join() is out and out wrong. 无论哪种方式, join()都出错了。

A much better solution I think is to use a Swing Timer. 我认为更好的解决方案是使用Swing Timer。 This will eliminate the need for explicit use of background threads. 这将消除显式使用后台线程的需要。

As an aside: avoid using null layouts if you want to create GUI's with powerful, flexible, and good looking layouts. 顺便说一句:如果要创建具有强大,灵活和美观的布局的GUI,请避免使用空布局。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM