有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

多线程Java线程和图形2D

我需要一个如何使我的程序正常工作的提示。我创建了一个从JComponent扩展而来的类。我还把整个面板做成了白色。现在我想让我的线程Wolf被画在JC组件上,并移动一次。不幸的是,我的代码不起作用,我认为这是因为wolf没有被画在白板上。如何更改程序以使其工作。我将非常感激你的帮助

public class Plansza extends JComponent implements ActionListener {

    static int   width = 500;
    static int   height = 500;
    Ellipse2D wolf;
    Ellipse2D hare;

    // size of frame n x m (width,height)
    public Dimension getPreferredSize(){
        return new Dimension(width,height);
    }

    protected void paintComponent(Graphics g){
        Graphics2D g2 = (Graphics2D) g;
        //draw a background
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, width, height);


    }   


    class Wilk implements Runnable{
        private int x;
        private int y;


        //when creating a thread we get a first position of wolf 
        Wilk(int posx, int posy){
            x=posx;
            y=posy;
        }

        protected void paintComponent(Graphics g){
            Graphics2D g2 = (Graphics2D) g;

            //draw a wolf
            g.setColor(Color.BLUE);
            wolf = new Ellipse2D.Double(x,y, 10, 10);
            g2.fill(wolf);
            }

        public void run() {
            x=x+5;
            y=y+5;
            repaint();

        }

    }



    public static void main( final String args[]) {
            SwingUtilities.invokeLater(new Runnable() {
        public void run() {
        JFrame window = new JFrame("Wilki vs Zajace");
        Plansza p = new Plansza();
        window.add(p);
        window.pack();
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setLocationRelativeTo(null);
        window.setVisible(true);
    //  Timer t = new Timer(10,p);  //action listener referred to Plansza(1 cycle every 100miliseconds)
    //  t.start();
            Wilk wolf = new Wilk(10,10);
        Thread myWolf = new Thread(wolf);
        myWolf.start();
            }
    });
    }

    @Override
    public void actionPerformed(ActionEvent e) {        
        }


}   

共 (2) 个答案

  1. # 1 楼答案

    从看Performing Custom PaintingPainting in AWT and Swing开始,了解Swing中如何进行绘画的细节

    查看Concurrency in Swing了解有关处理Swing a线程的详细信息

    基本上,只会在展示的容器上绘制一个组件。这意味着只有你的Plansza会被绘制,但只有当它被添加到一个类似JFrame的东西中,并且JFrame才是可见的

    这意味着Wilk永远无法绘制,因此它的paintComponent方法变得有些毫无意义(在本文中)

    您可以使用某种方式将您想要绘制的内容从Wilk(控制器)传达到Plansza(视图)。这通常是通过使用某种模型来实现的,该模型允许控制器更改其状态,并允许视图渲染该状态

    例如

    Bounce

    这是Model-Control-View实现的基本演示

    模型驱动视图,控制器驱动模型。这样,只要满足模型的契约,各个元素就相互独立

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Rectangle;
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ChangeListener;
    
    public class PaintModel {
    
        public static void main(String[] args) {
            new PaintModel();
        }
    
        public PaintModel() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    MutableModel model = new DefaultModel();
                    Controller controller = new Controller(model);
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new View(model));
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
    
                    controller.start();
                }
            });
        }
    
        public interface Model {
    
            public Rectangle getBounds();
            public Dimension getSize();
            public void addChangeListener(ChangeListener listener);
            public void removeChangeListener(ChangeListener listener);
    
        }
    
        public interface MutableModel extends Model {
    
            public void update();
    
        }
    
        public class DefaultModel implements MutableModel {
    
            private final Dimension size = new Dimension(200, 200);
            private final Rectangle bounds = new Rectangle(95, 95, 10, 10);
    
            private int xDelta = ((int) (Math.random() * 5)) + 1;
            private int yDelta = ((int) (Math.random() * 5)) + 1;
    
            private List<ChangeListener> changeListeners;
    
            public DefaultModel() {
                changeListeners = new ArrayList<>(25);
            }
    
            @Override
            public void addChangeListener(ChangeListener listener) {
                changeListeners.add(listener);
            }
    
            @Override
            public void removeChangeListener(ChangeListener listener) {
                changeListeners.remove(listener);
            }
    
            protected void fireStateChanged() {
                if (changeListeners.size() > 0) {
                    ChangeEvent evt = new ChangeEvent(this);
                    Iterator<ChangeListener> it = changeListeners.iterator();
                    while (it.hasNext()) {
                        ChangeListener listener = it.next();
                        listener.stateChanged(evt);
                    }
                }
            }
    
            @Override
            public Dimension getSize() {
                return size;
            }
    
            @Override
            public Rectangle getBounds() {
                return bounds;
            }
    
            @Override
            public void update() {
                bounds.x += xDelta;
                bounds.y += yDelta;
                if (bounds.x < 0) {
                    bounds.x = 0;
                    xDelta *= -1;
                } else if (bounds.x + bounds.width > size.width) {
                    bounds.x = size.width - bounds.width;
                    xDelta *= -1;
                }
                if (bounds.y < 0) {
                    bounds.y = 0;
                    yDelta *= -1;
                } else if (bounds.y + bounds.height > size.height) {
                    bounds.y = size.height - bounds.height;
                    yDelta *= -1;
                }
                fireStateChanged();
            }
    
        }
    
        public class Controller extends Thread {
    
            private MutableModel model;
    
            public Controller(MutableModel model) {
                this.model = model;
                setDaemon(true);
            }
    
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(40);
                    } catch (InterruptedException ex) {
                    }
                    model.update();
                }
            }
    
        }
    
        public class View extends JComponent implements ChangeListener {
    
            private Model model;
    
            public View(Model model) {
                this.model = model;
                this.model.addChangeListener(this);
                setBackground(Color.WHITE);
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(model.getSize());
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setColor(getBackground());
                g2d.fillRect(0, 0, getWidth(), getHeight());
                Rectangle bounds = model.getBounds();
                g2d.setColor(Color.BLUE);
                g2d.drawOval(bounds.x, bounds.y, bounds.width, bounds.height);
                g2d.dispose();
            }
    
            @Override
            public void stateChanged(ChangeEvent e) {
                repaint();
            }
    
        }
    
    }
    
  2. # 2 楼答案

    在许多现代语言中,UI在主线程上运行,您不能从另一个线程修改它(或者至少不应该)。(http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html

    尽管repaint()和revalidate()是线程安全的,并且它们有自己的invokeAndWait,但您必须使用类似的方式创建UI

    SwingUtilities.invokeAndWait(new Runnable() {
        public void run() {
            createGUI();
         }
    });
    

    因此,每次绘制主面板时,都会创建一条绘制狼线

    甲骨文还建议在http://docs.oracle.com/javase/tutorial/uiswing/painting/closer.html中调用super.paintComponent(g);

    我建议您完全阅读《Oracle Swing指南》,然后尝试修改Flipper coin示例,使其能够按照您的需要工作(http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/examples/concurrency/FlipperProject/src/concurrency/Flipper.java