i need a hint how to make my program to work properly. I created a class that extends from JComponent. I also managed to make the whole panel of white colors. Now i am trying to make that my thread Wolf will be painted on the JCOmponent and will move one time. Unfortunately my code dont works and i think its because wolf is not being painted on the white board. How to change the program to make it work. I will be grateful for help.

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


}   
有帮助吗?

解决方案

Start by talking a look at Performing Custom Painting and Painting in AWT and Swing for details about how painting is performed in Swing.

Take a look at Concurrency in Swing for details about dealing with Swing a threads.

Basically, only a component on a displayed container will be painted. This means that only your Plansza will be painted, but only when it's added to a (directly or otherwise) something like JFrame and the JFrame is made visible.

This means that Wilk can never be painted and therefore it's paintComponent method becomes somewhat pointless (in this context)

What you could use is some way to communicate what you want to paint from your Wilk (controller) to Plansza (view). This is typically achieved via the use of some kind of model, which allows your controller to change it's state and your view to render that state.

For example...

Bounce

This is a basic demonstration of a Model-Control-View implementation.

The model drives the view and the controller drives the model. In this way, so long as the contract of the model is meet, the various elements are independent of each other

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

    }

}

其他提示

In many modern languages the UI runs on the main thread, and you cannot modify it (or you shouldn't at least) from another thread. (http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html)

Although repaint(), and revalidate() are threadsafe and they have their own invokeAndWait, you MUST create the UI using something like this.

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

Therefore you are creating a paint wolf thread each time you paint the main panel.

Also Oracle suggest to call super.paintComponent(g); in http://docs.oracle.com/javase/tutorial/uiswing/painting/closer.html

I recommend you to read completely the Oracle Swing guide, and then try to modify the Flipper coin example to work as you want (http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/examples/concurrency/FlipperProject/src/concurrency/Flipper.java)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top