understanding difficulties java swing

2020-05-05 16:55发布

im trying to paint random (not yet) circles on a JPanel through click on a JMenu. Im using a JTextField (and have to keep this) for some output. Here is my Class:

class RandomDrawer extends JPanel implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        //double x = Math.random();
        //double y = Math.random();
        Random generator = new Random();
        int x = generator.nextInt(100)+1;
        int y = generator.nextInt(100)+1;
        //System.out.printf("x = %d y = %d\n", x, y);
        status.setText(String.format("rnd draw x: %d y: %d", x, y));
        Graphics2D gg = (Graphics2D) canvas.getGraphics();
        gg.setColor(Color.BLACK);
        gg.drawOval(50, 50, 50, 50);
    }
}

As long i let the line

status.setText(String.format("rnd draw x: %d y: %d", x, y));

stay in there i get nothing drawn. Without it i get my circle, im not sure what the problem is. I cant figure out why nothing is drawn.

Thanks a lot

EDIT:

Hello, i tried to understand the given informations. Sadly I have to draw using the Graphics2D class, so i guess i can not draw using shapes. So i tried this, sadly it wont draw yet, can u give me some tips? I tried to create a new class DrawShape, my thought was that i could keep track with those objects. In my understanding there should be a drawn oval right now
gg.drawOval(100,100,100,100);

Thank you.

class DrawShape {
    public DrawShape(String string) {
        // TODO Auto-generated constructor stub
    }
}

class RandomDrawer extends JPanel implements ActionListener {
    /* (non-Javadoc)
     * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
     */ 
    private List<DrawShape> shapes = new ArrayList<DrawShape>();


    public void addShape(DrawShape s) {
        shapes.add(s);
        repaint();
    }


    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        final Graphics2D gg = (Graphics2D) g;
        gg.setColor(Color.BLACK);
        gg.drawOval(100, 100, 100, 100);
    }


    @Override
    public void actionPerformed(ActionEvent e) {
        Random generator = new Random();
        int x = generator.nextInt(100)+100;
        int y = generator.nextInt(100)+100;

        if (e.getActionCommand()==("Draw RandomCircle")) {
            System.out.printf("x = %d y = %d\n", x, y);
            status.setText(String.format("rnd draw x:%d  y:%d ", x, y));
            DrawShape circle = new DrawShape("Circle");
            addShape(circle);
            int count = shapes.size(); 
            System.out.printf("objects in array: %d\n", count); 
        }

        else if (e.getActionCommand()==("Draw RandomRectangle")) {
            System.out.printf("x = %d y = %d\n", x, y);
            //status.setText(String.format("rnd draw x:  y: "));
            //Graphics2D gg = (Graphics2D) canvas.getGraphics();
            //gg.setColor(Color.BLACK);
            //gg.drawRect(x, y, generator.nextInt(x), generator.nextInt(y));
        }
    }
}

3条回答
闹够了就滚
2楼-- · 2020-05-05 17:45

Painting and such happens event-driven. If a a piece of a component needs to be redrawn its paintComponent method is called.

This means you need a component that nows how to draw by for instance:

public class DrawShape {

    public final String text;
    public final Color color;
    public final Shape shape;

    public DrawShape(String text, Color color, Shape shape) {
        this.text = text;
        this.color = color;
        this.shape = shape;
    }
}

public class CanvasWithShapes extends JPanel {

    private List<DrawShape> shapes = new ArrayList<>();

    public void addShape(DrawShape shape) {
        shapes.add(shape);
    }

    @Override
    public void paintComponent(Graphics g) {
        final Graphics2D gg = (Graphics2D) g;
        // Java 8: shapes.stream().forEach((shape) -> gg.draw(shape));
        for (DrawShape drawShape : shapes) {
            gg.setColor(drawShape.color);
            gg.draw(drawShape.shape);
            Rectangle bounds = shape.getBounds();
            gg.drawString(shape.text, bounds.x+ 10, bounds.y + 20);
        }
    }
}

And then just add shapes to be redrawn a bit later.

Shape oval = ...;
c.add(oval);
c.repaint(50L); // A bit later 

More detailed

A Shape has many implementations of interest like rectangle and oval. Graphics2D can draw and fill a Shape. So in your case it would be ideal to add such a Shape. Maybe together with color and text. So I took your DrawShape class to hold these properties.

    Random generator = new Random();
    int x = generator.nextInt(100)+100;
    int y = generator.nextInt(100)+100;

    if (e.getActionCommand().equals("Draw RandomCircle")) {
        System.out.printf("x = %d y = %d\n", x, y);
        status.setText(String.format("rnd draw x:%d  y:%d ", x, y));
        int w = generator.nextInt(100) + 10;
        int h = w;
        Shape circle = new Ellipse2D.Double(x, y, w, h);
        addShape(new DrawShape(text, Color.BLACK, circle));
        int count = shapes.size(); 
        System.out.printf("objects in array: %d\n", count); 
    } else if (e.getActionCommand().equals("Draw RandomRectangle")) {
        System.out.printf("x = %d y = %d\n", x, y);

generator.nextInt(y)); int w = generator.nextInt(100) + 10; int h = generator.nextInt(100) + 10; Shape rect = Rectangle2D.Double(x, y, w, h) addShape(new DrawShape(text, Color.BLACK, rect)); }

查看更多
祖国的老花朵
3楼-- · 2020-05-05 17:51

Graphics2D gg = (Graphics2D) canvas.getGraphics();

Don't use the getGraphics() method to do painting. The painting is temporary. It will be lost if you resize the frame for example.

Instead you need to override the paintComponent() method of your panel.

If you want to paint multiple objects then you need to keep track of each object. Check out Custom Painting Approaches for the two common ways to do this:

  1. keep of List of Objects to paint and then iterate through the List each time the component is repainted.
  2. paint the Object directly to a BufferedImage and then just paint the BufferedImage.

The example paints Rectangles. Basically you need a method like the addRectangle(...) method to add a new object to paint. So every time you click your button you add the new random shape.

查看更多
够拽才男人
4楼-- · 2020-05-05 17:56

Presumably, your problem arises from the setText() invocation modifying the Graphics object in some unexpected way. It is rarely appropriate to use getGraphics() in your own code. Instead, paint with the Graphics that is given to you.

Your approach is anyway flawed. If you manage to draw on a GUI component only once, as you are trying to do, then whatever you have drawn will disappear when the component is next repainted. Repainting can happen for a wide variety of reasons, many of them unrelated to the program's own behavior.

What you need to do is store some kind of data that the component's paintComponent() method will rely upon to do your custom painting every time. It follows that you will need to override the paintComponent() method of the component on which you want the circles to be drawn. For example, you might create a class that records all the needed drawing details for one circle, and give RandomDrawer a List of those objects as a member variable. The action listener manipulates that list appropriately and schedules a repainting, and paintComponent() is overridden to perform the actual painting.

查看更多
登录 后发表回答