Java Drawing Multiple Squares in Same JFrame

*爱你&永不变心* 提交于 2021-02-05 11:04:02

问题


I am trying to make an animation with multiple thread. I want to paint n squares where this n comes from commend-line argument. Every square has their x-y coordinates, colors and speed. They are moving to the right of the frame with different speed, color and coordinates. Since I am using multi thread I assume I have to control each squares. So I have to store each square object in the ArrayList. However, I am having trouble with painting those squares. I can paint one square but when I try to paint multiple squares, it does not show. Here what I have done so far:

DrawSquare.java

import java.awt.Graphics;
import javax.swing.JPanel;

public class DrawSquare extends JPanel {
    public Square square;
    public DrawSquare() {
        square = new Square();
    }

    @Override
    public void paintComponents(Graphics g) {
        // TODO Auto-generated method stub
        super.paintComponents(g);

    }

    @Override
    public void paint(Graphics g) {
        // TODO Auto-generated method stub
        super.paint(g);

        g.setColor(square.getC());
        g.fillRect(square.getX(), square.getY(), square.getR(), square.getR());
    }
}

Square.java

import java.awt.Color;
import java.util.Random;

public class Square {
    private int x,y,r,s;
    private Color c;
    private Random random;

    public Square() {
        random = new Random();
        x = random.nextInt(100) + 30;
        y = random.nextInt(100) + 30;
        r = random.nextInt(50) + 20;
        s = random.nextInt(20) + 5;
        c = new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255));
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public int getR() {
        return r;
    }

    public int getS() {
        return s;
    }

    public Color getC() {
        return c;
    }
}

Animation.java

import java.awt.BorderLayout;

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

public class Animation extends JFrame implements Runnable {
    private JPanel panel;
    private DrawSquare square;

    public Animation() {

    }

    public static void main(String[] args) {
        Animation w = new Animation();
        DrawSquare square = new DrawSquare();
        JFrame f = new JFrame("Week 9");
        int n = Integer.parseInt(args[0]);
        f.setVisible(true);
        f.setSize(700,700);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setResizable(false);
        for(int i=0; i<n; i++) {
            f.getContentPane().add(square);
        }
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub

    }
}

回答1:


So, starting with...

public class DrawSquare extends JPanel {
    public Square square;
    public DrawSquare() {
        square = new Square();
    }

    @Override
    public void paintComponents(Graphics g) {
        // TODO Auto-generated method stub
        super.paintComponents(g);

    }

    @Override
    public void paint(Graphics g) {
        // TODO Auto-generated method stub
        super.paint(g);

        g.setColor(square.getC());
        g.fillRect(square.getX(), square.getY(), square.getR(), square.getR());
    }
}

As general recommendation, it's preferred to put custom painting in the paintComponent method (note, there's no s at the end)

When paint is called, the Graphics context has already been translated to the component coordinate position. This means that 0x0 is the top/left corner of the component, this also means that...

g.fillRect(square.getX(), square.getY(), square.getR(), square.getR());

is painting the rect at x + x x y + y, which will, at the very least, paint the rect in the wrong position, at worst paint it beyond the visible scope of the component.

You're also not providing any sizing hints for the component, so it's default size will be 0x0, which prevent it from been painted.

Since I am using multi thread I assume I have to control each squares.

Well, since I can't really see what's driving the animation, I imagine that when you say "multi thread" you're suggesting that each square has it's own `Thread. In this case, that's a bad idea. Let's put aside the thread synchronisation issues for a moment, more threads doesn't equate to more work you can do, at some point, it will begin to degrade the system performance.

In most cases, a single, well managed thread, is all you really need. You also have to understand that Swing is NOT thread safe. This means that you shouldn't update the UI (or states that the UI relies on) from outside the context of the Event Dispatching Thread.

So, why you're thread can update the position of the rects, you need to take care to ensure that they are not been painted why they are been update. Once you've updated the state, you then need to trigger a paint pass (which is trivial in of itself)

So I have to store each square object in the ArrayList.

Yep, good start

However, I am having trouble with painting those squares. I can paint one square but when I try to paint multiple squares, it does not show.

Okay, so instead of using multiple components, use one. Run through your ArrayList within the paintComponent method of this component and paint all the rects to it. This provides a much simpler way to manage things like bounds detection, as you have only one container to worry about.

I'd highly recommend you have a look at:

  • Java Bouncing Ball which demonstrates many of the concepts discussed here
  • Concurrency in Swing
  • How to use Swing Timers
  • Performing Custom Painting
  • Painting in AWT and Swing


来源:https://stackoverflow.com/questions/47461863/java-drawing-multiple-squares-in-same-jframe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!