gogo
gogo

Reputation: 429

I try to use the method repaint after paintComponent but its not work

First it will be a little longer because I want to show all the code I have done until now, so excuse me..

This is my first time in java. I'm trying to build an aquarium with fish and jellyfish drawing and use threads. When I try to add animal I want to paint it but without success, I built PaintComponent method but when I try to use repaint I can not draw.. What am I missing?

It looks that way, when I click on Add Animal window opens , I choose the values and after I click OK, need to draw the animal

enter image description here

I hope that the rest of what I did was okay .. thank you so much for helping!

paintComponent and repaint is at AquaPanel Class.

public class AquaFrame extends JFrame {

    private AquaPanel mPanel;
    private JLabel label1;
    private ImageIcon icon;
    private BufferedImage imag;

    public AquaFrame() {
        super("my Aquarium");
        setLayout(new BorderLayout());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(700, 600);
        setResizable(false);
        setVisible(true);
        setLocationRelativeTo(null);

        mPanel = new AquaPanel(getGraphics());
        add(mPanel);
    }

    public void buildFrame(){   
        JMenuBar menuBar = new JMenuBar();
        setJMenuBar(menuBar);

        JMenu file = new JMenu("File");
        menuBar.add(file);
        JMenuItem exItem = new JMenuItem("Exit");
        file.add(exItem);
        exItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });

        JMenu background = new JMenu("Background");
        menuBar.add(background);
        JMenuItem blue = new JMenuItem("Blue");
        blue.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                mPanel.setBackground(Color.BLUE);
            }
        });

        JMenuItem none = new JMenuItem("None");
        none.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                mPanel.setBackground(null);
            }
        });

        JMenuItem image = new JMenuItem("Image");
        image.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {

                try {
                    imag = ImageIO.read(new File("aquarium_background.jpg"));
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }
        });

        background.add(image);
        background.add(blue);
        background.add(none);

        JMenu help = new JMenu("Help");
        JMenuItem helpItem = new JMenuItem("help");
        helpItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(null,"GUI @ Threads");
            }
        });

        menuBar.add(help);
        help.add(helpItem);

        setVisible(true);
    }

    public void paint(Graphics g){
        g.drawImage(imag, 0, 0, null);
    }

    public static void main(String[] args) {        
        AquaFrame mFrame = new AquaFrame();
        mFrame.buildFrame();
    }

}


/******************************************/
public class AquaPanel extends JPanel {

    private JFrame infoTableFrame;
    private JTable infoTable;
    private Set<Swimmable > swimmables = new HashSet<Swimmable>();
    private AddAnimalDialog animalDialog;
    private int totalEatCounter;
    private Graphics g;

    public AquaPanel(Graphics g) {
        this.g = g;
        totalEatCounter = 0;
        infoTableFrame = new JFrame();
        infoTableFrame.setVisible(false);

        setLayout(new GridBagLayout());

        GridBagConstraints constraints = new GridBagConstraints();
        constraints.anchor = GridBagConstraints.PAGE_END;
        constraints.weighty = 1;

        JButton btAdd = new JButton("Add Animal");
        btAdd.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (swimmables.size() >= 5)
                {
                    JOptionPane.showMessageDialog(null, "You can't have more than 5 animals at the same time.");
                }
                else
                {
                    animalDialog = new AddAnimalDialog(AquaPanel.this);
                    animalDialog.setVisible(true);
                }
            }
        });

        JButton btSleep = new JButton("Sleep");
        btSleep.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                for (Swimmable swimmable : swimmables)
                {
                    swimmable.setSuspend();
                }
            }
        });

        JButton btWakeup = new JButton("Wake Up");
        btWakeup.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                for (Swimmable swimmable : swimmables)
                {
                    swimmable.setResume();
                }
            }
        });

        JButton btRst = new JButton("Reset");
        btRst.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                for (Swimmable swimmable : swimmables)
                {
                    swimmable.kill();
                }
                swimmables.clear();
            }
        });

        JButton btFood = new JButton("Food");
        btFood.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (swimmables.size() > 0)
                {
                    CyclicBarrier barrier = new CyclicBarrier(swimmables.size());
                    for (Swimmable swimmable : swimmables)
                    {
                        swimmable.setBarrier(barrier);
                        swimmable.setFood(true);
                    }
                    Graphics2D g2 = (Graphics2D) g;
                    g2.setStroke(new BasicStroke(3));
                    g2.setColor(Color.red);
                    g2.drawArc(getWidth() / 2, getHeight() / 2 - 5, 10, 10, 30, 210);
                    g2.drawArc(getWidth()/2, getHeight()/2+5, 10, 10, 180, 270);
                    g2.setStroke(new BasicStroke(1));
                }
            }
        });

        JButton btInfo = new JButton("Info");
        btInfo.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                    showInfoTable();
            }
        });

        JButton btExit = new JButton("Exit");
        btExit.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });

        add(btAdd,constraints);
        add(btSleep,constraints);
        add(btWakeup,constraints);
        add(btRst,constraints);
        add(btFood,constraints);
        add(btInfo,constraints);
        add(btExit,constraints);
    }

    public void showInfoTable(){
        if (infoTableFrame.isVisible())
        {
            infoTableFrame.remove(infoTable);
            infoTableFrame.setVisible(false);
        }
        else
        {
            String[] col = {"Animal","Color","Size","Hor.speed","Ver.speed","Eat counter"};
            String[][] data = new String[swimmables.size()][col.length];
            int i=0;
            for (Swimmable swimmable : swimmables)
            {
                data[i][0] = swimmable.getAnimalName();
                data[i][1] = swimmable.getColor();
                data[i][2] = "" + swimmable.getSize();
                data[i][3] = "" + swimmable.getHorSpeed();
                data[i][4] = "" + swimmable.getVerSpeed();
                data[i][5] = "" + swimmable.getEatCount();
                ++i;
            }
            infoTable = new JTable(data, col);

            //TODO - not overriding values

            JScrollPane jPane = new JScrollPane(infoTable);
            infoTableFrame.add(jPane, BorderLayout.CENTER);
            infoTableFrame.setSize(300, 150);
            infoTableFrame.setVisible(true);
        }
    }

    public void addAnimal(Swimmable animal)
    {
        animal.setAquaPanel(this);
        swimmables.add(animal);
        animal.run();
        //myrepaint();
    /**********************************/    
        repaint();
    /**********************************/
    }


    public void onEatFood(Swimmable eater)
    {
        eater.eatInc();
        ++totalEatCounter;
        for (Swimmable swimmable : swimmables)
        {
            swimmable.setFood(false);
        }
    }

    /*public void myrepaint()
    {
        for (Swimmable swimmable : swimmables)
        {
            swimmable.drawAnimal(g);
        }
    }*/

    /************************************************/
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (Swimmable swimmable : swimmables)
        {
            swimmable.drawAnimal(g);
        }
    }
    /*********************************************/
}



public abstract class Swimmable extends Thread {

    protected AquaPanel aquaPanel;
    protected boolean isFood;
    protected boolean isSuspended;
    protected int horSpeed;
    protected int verSpeed;
    protected int x_dir, y_dir;
    protected int eatCount;
    protected CyclicBarrier barrier;
    protected int x0, y0;

    protected boolean isAlive;

    public Swimmable() {
        horSpeed = 0;
        verSpeed = 0;
        x_dir = 1;
        y_dir = 1;
        eatCount = 0;
    }

    public Swimmable(int hor, int ver) {
        horSpeed = hor;
        verSpeed = ver;
        x_dir = 1;
        y_dir = 1;
        eatCount = 0;
    }

    @Override
    public void run() {
        isAlive = true;
        while (isAlive) {
            try {
                sleep(10);
                if (isSuspended)
                {
                    wait();
                }
                else
                {
                    if (isFood)
                    {
                        barrier.await();
                        updateFrontsTowardsFood();
                        if (isNearFood())
                        {
                            aquaPanel.onEatFood(this);
                        }
                    }
                    else
                    {
                        updateFronts();
                    }
                    //aquaPanel.myrepaint();
                    aquaPanel.repaint();
                }
            }
            catch (Exception e)
            {
                //TODO - handle exception
            }

        }
    }

    public void kill()
    {
        isAlive = false;
    }

    public int getHorSpeed() {
        return horSpeed;
    }

    public int getVerSpeed() {
        return verSpeed;
    }

    public void setHorSpeed(int hor) {
        horSpeed = hor;
    }

    public void setVerSpeed(int ver) {
        verSpeed = ver;
    }

    abstract public int getSize();

    abstract public String getColor();

    public void setSuspend()
    {
        isSuspended = true;
    }

    public void setResume()
    {
        isSuspended = false;
    }

    public void eatInc()
    {
        ++eatCount;
    }

    public int getEatCount()
    {
        return eatCount;
    }

    public void setBarrier(CyclicBarrier b)
    {
        barrier = b;
    }

    public void setFood(boolean isFood)
    {
        this.isFood = isFood;
    }

    public void setAquaPanel(AquaPanel panel)
    {
        aquaPanel = panel;
        x0 = aquaPanel.getWidth() / 2;
        y0 = aquaPanel.getHeight() / 2;
    }

    abstract public String getAnimalName();

    abstract public void drawAnimal(Graphics g);

    abstract protected void updateFronts();
    abstract protected void updateFrontsTowardsFood();

    abstract protected boolean isNearFood();
}



public class Fish extends Swimmable {

    protected int x_front , y_front;
    private int size;
    private Color color;

    public Fish(Color col, int sz, int hor, int ver) {
        super(hor, ver);
        size = sz;
        color = col;
        x_front = 0;
        y_front = 0;
    }

    public void drawAnimal(Graphics g) {

        g.setColor(color);
        if (x_dir == 1) // fish swims to right side
        {
            // Body of fish
            g.fillOval(x_front - size, y_front - size / 4, size, size / 2);

            // Tail of fish
            int[] x_t = { x_front - size - size / 4, x_front - size - size / 4, x_front - size };
            int[] y_t = { y_front - size / 4, y_front + size / 4, y_front };
            Polygon t = new Polygon(x_t, y_t, 3);
            g.fillPolygon(t);

            // Eye of fish
            Graphics2D g2 = (Graphics2D) g;
            g2.setColor(new Color(255 - color.getRed(),255 - color.getGreen(),255- color .getBlue()));
            g2.fillOval(x_front-size/5, y_front-size/10, size/10, size/10);

            //Mouth of fish
            if(size>70)
                g2.setStroke(new BasicStroke(3));
            else if(size>30)
                g2.setStroke(new BasicStroke(2));
            else
                g2.setStroke(new BasicStroke(1));

            g2.drawLine(x_front, y_front, x_front-size/10, y_front+size/10);
            g2.setStroke(new BasicStroke(1));
        }

        else // fish swims to left side
        {
            // Body of fish
            g.fillOval(x_front, y_front - size / 4, size, size / 2);

            // Tail of fish
            int[] x_t = { x_front + size + size / 4, x_front + size + size / 4, x_front + size };
            int[] y_t = { y_front - size / 4, y_front + size / 4, y_front };
            Polygon t = new Polygon(x_t, y_t, 3);
            g.fillPolygon(t);

            // Eye of fish
            Graphics2D g2 = (Graphics2D) g;
            g2.setColor(new Color(255 - color.getRed(), 255 - color.getGreen(), 255 - color.getBlue()));
            g2.fillOval(x_front+size/10, y_front-size/10, size/10, size/10);

            // Mouth of fish
            if (size > 70)
                g2.setStroke(new BasicStroke(3));
            else if (size > 30)
                g2.setStroke(new BasicStroke(2));
            else
                g2.setStroke(new BasicStroke(1));
            g2.drawLine(x_front, y_front, x_front + size / 10, y_front + size / 10);
            g2.setStroke(new BasicStroke(1));
        }

    }

    public String getAnimalName() {
        return "Fish";
    }

    public int getSize() {
        return size;
    }

    public String getColor() {
        if (color == Color.RED)
            return "RED";
        else if (color == Color.GREEN)
            return "GREEN";
        else if (color == Color.ORANGE)
            return "ORANGE";
        else
            return "UNKNOWN";
    }

    protected void updateFronts()
    {
        x_front += x_dir * horSpeed;
        y_front += y_dir * verSpeed;
        if (x_front > x0*2 || x_front < 0)
            x_dir *= -1;
        if (y_front > y0*2 || y_front < 0)
            y_dir *= -1;
    }

    protected void updateFrontsTowardsFood()
    {
        //TODO - copy from word
    }

    protected boolean isNearFood()
    {
        return ((Math.abs(x_front-x0) <= 5) && (Math.abs(y_front-y0) <= 5));
    }

}



public class Jellyfish extends Swimmable {

    private int x_front , y_front;
    private int size;
    private Color color;

    public Jellyfish(Color col, int sz, int hor, int ver) {
        super(hor, ver);
        size = sz;
        color = col;
        x_front = 0;
        y_front = 0;
    }

    public void drawAnimal(Graphics g) {
        int numLegs;
        if (size < 40)
            numLegs = 5;
        else if (size < 80)
            numLegs = 9;
        else
            numLegs = 12;
        g.setColor(color);
        g.fillArc(x_front - size / 2, y_front - size / 4, size, size / 2, 0, 180);
        for (int i = 0; i < numLegs; i++)
            g.drawLine(x_front - size / 2 + size / numLegs + size * i / (numLegs + 1), y_front,
                    x_front - size / 2 + size / numLegs + size * i / (numLegs + 1), y_front + size / 3);
    }


    public String getAnimalName() {
        return "Jellyfish";
    }

    public int getSize() {
        return size;
    }

    public String getColor() {
        if (color == Color.RED)
            return "RED";
        else if (color == Color.GREEN)
            return "GREEN";
        else if (color == Color.ORANGE)
            return "ORANGE";
        else
            return "UNKNOWN";
    }

    public void updateFronts()
    {
        x_front += x_dir * horSpeed;
        y_front += y_dir * verSpeed;
        if (x_front > x0*2 || x_front < 0)
            x_dir *= -1;
        if (y_front > y0*2 || y_front < 0)
            y_dir *= -1;
    }

    protected void updateFrontsTowardsFood()
    {
        //TODO - copy from word
    }

    protected boolean isNearFood()
    {
        return ((Math.abs(x_front-x0) <= 5) && (Math.abs(y_front-y0) <= 5));
    }
}



public class AddAnimalDialog extends JDialog {

    private JButton btOk, btCancel;
    private JTextField tfSize, tfHspeed, tfVspeed;
    private ButtonGroup groupType, groupColor;
    private JRadioButton rbFish, rbJellyfish, rbRed, rbGreen, rbOrange;
    JPanel panel;

    public AddAnimalDialog(AquaPanel aquaPanel) {
        this.setLayout(new FlowLayout());
        panel = new JPanel();
        panel.setLayout(new GridLayout(10, 20));
        panel.add(new JLabel("Size(20-320): "));
        panel.add(tfSize = new JTextField());
        panel.add(new JLabel("Horizontal speed(1-10): "));
        panel.add(tfHspeed = new JTextField());
        panel.add(new JLabel("Vertical speed(1-10): "));
        panel.add(tfVspeed = new JTextField());
        panel.add(new JLabel("Type: "));
        panel.add(new JLabel("                     "));
        panel.add(rbFish = new JRadioButton("fish"));
        panel.add(rbJellyfish = new JRadioButton("jellyfish"));
        panel.add(new JLabel("Color: "));
        panel.add(new JLabel("                     "));
        panel.add(rbRed = new JRadioButton("Red"));
        panel.add(rbGreen = new JRadioButton("Green"));
        panel.add(rbOrange = new JRadioButton("Orange"));

        // Group the radio buttons.
        groupType = new ButtonGroup();
        groupType.add(rbFish);
        groupType.add(rbJellyfish);
        rbFish.setSelected(true);
        groupColor = new ButtonGroup();
        groupColor.add(rbRed);
        groupColor.add(rbGreen);
        groupColor.add(rbOrange);
        rbRed.setSelected(true);
        panel.add(new JLabel(""));
        panel.add(btOk = new JButton("OK"));
        panel.add(btCancel = new JButton("Cancel"));
        this.add(panel);
        this.setLocationRelativeTo(null);
        this.setResizable(false);
        this.pack();

        this.btOk.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                try {
                    int size = Integer.parseInt(tfSize.getText());
                    int hSpeed = Integer.parseInt(tfHspeed.getText());
                    int vSpeed = Integer.parseInt(tfVspeed.getText());

                    if (checkValues(size, hSpeed, vSpeed)) {
                        Color clr = Color.RED;
                        if (rbRed.isSelected()) {
                            clr = Color.RED;
                        } else if (rbGreen.isSelected()) {
                            clr = Color.GREEN;
                        } else if (rbOrange.isSelected()) {
                            clr = Color.ORANGE;
                        } else {
                            JOptionPane.showMessageDialog(null, "You must choose a color!");
                        }

                        if (rbFish.isSelected()) {
                            setVisible(false);
                            aquaPanel.addAnimal(new Fish(clr, size, hSpeed, vSpeed));
                        } else if (rbJellyfish.isSelected()) {
                            setVisible(false);
                            aquaPanel.addAnimal(new Jellyfish(clr, size, hSpeed, vSpeed));
                        } else {
                            JOptionPane.showMessageDialog(null, "You must choose animal type!");
                        }
                    }
                } catch (NumberFormatException e) {
                    JOptionPane.showMessageDialog(null, "One of the number values has wrong format, please check it");
                }
            }
        });
        this.btCancel.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                setVisible(false);
                System.out.println("Click the Close button if you want to stop adding windows");
            }
        });
    }

    private boolean checkValues(int size, int hspeed, int vspeed) {
        if ((size > 320 || size < 20) || (hspeed < 1 || hspeed > 10) || (vspeed < 1 || vspeed > 10)) {
            JOptionPane.showMessageDialog(null, "One of the values is out of bounds, please follow the restrictions.");
            return false;
        }
        return true;
    }

}

Upvotes: 0

Views: 277

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347244

There are a number of basic problems...

The main problem is with your Swimmable run method, it is blocking the Event Dispatching Thread, preventing it from been able to respond to UI events, including repaint events. See Concurrency in Java for more details.

You should NEVER use getGraphics, apart from been able to return null, anything you paint to it is painted outside of the normal paint cycle and will painted over the next time component is repainted. See Painting in AWT and Swing and Performing Custom Painting for more details.

Your current approach won't scale well, the more fish you add, the more resources they will consume and will affect the ability for the program to keep up with all the different changes and repaint requests.

A better solution would be to have a single "update" loop which takes care of telling each of the Swimmables that it needs to update and then schedules a single repaint each cycle. Personally, I'd start with a Swing Timer as it "ticks" within the EDT, making it much safer to modify the state of the objects which the paintComponent method needs.

See How to use Swing Timers for more details

I would suggest having a look at this, which basically describes what you're trying to do and what I'm suggesting you should do instead

Upvotes: 1

Givenchdy
Givenchdy

Reputation: 95

Try calling repaint in your JFrame class after calling the addAnimal method. There is also revalidate() method in there as well and their difference is in this article: Java Swing revalidate() vs repaint()

Upvotes: 0

Related Questions