Java applet displays itself multiple times

前提是你 提交于 2019-12-11 05:46:31

问题


I am making a Java applet for school whose function is to randomly select six numbers for coordinates of three points and connect them to make a triangle. It is only supposed to draw one triangle and find the "length of the sides". However when I put it on my website it will redraw itself multiple times.

I made another applet, simpler, that only selects 4 random numbers for coordinates to draw a line. Same problem.

The redrawing problem seems to happen when the user moves the screen, e.g. when I scroll or when I resize the applet viewer in Eclipse. My source code is posted here.

I appreciate any help! Thanks!

import javax.swing.JApplet;
import java.awt.*;

@SuppressWarnings("serial")
public class LineApplet extends JApplet {

    /**
     * Create the applet.
     */

    static int width;
    int height;


    public void init() {

          width = getSize().width;
          height = getSize().height;

       }

    public static int[] randomLine() {
        int[] pointArray = new int[4];
        int x;
        for (int i = 0; i < 4; i++) {
            x = ((int)(Math.random()*(width/10-2)))*20+10;
            pointArray[i] = x;
        }
        return pointArray;
    }

    public void paint(Graphics g) {
        g.setColor(Color.blue);
        int[] coords = new int[4];
        coords = randomLine();
        g.drawLine(coords[0], coords[1], coords[2], coords[3]);
        g.drawString(coords[0]/10 + ", " + coords[1]/10, coords[0], coords[1]);
        g.drawString(coords[2]/10 + ", " + coords[3]/10, coords[2], coords[3]);
        int midpointx = (coords[0] + coords[2])/2;
        int midpointy = (coords[1] + coords[3])/2;
        g.drawString(midpointx/10 + ", " + midpointy/10, midpointx, midpointy);
    }
}

回答1:


As pointed out by Reimues, you are re-generating your coords each time the applet is repaint.

The other problem with your paint method is actually you're not clear the previous state of the graphics context (this would have being done by paint, but you failed to respect it's functionality when you overrode it).

You have two choices.

  1. call super.paint(g)
  2. call super.paint(g) and call Graphics#clearRect(int, int, int, int) or Graphics#fillRect(int, int, int, int)

You should also, very rarely, need to override the paint method of top level containers. One of the reasons is that they're not double buffered, the other is the paint chain is complex and easily broken...

You're better off using a JPanel (or such) and overriding the paintComponent method instead...

UPDATED

I updated your code to demonstrate the issues.

public class TestBadApplet extends JApplet {

    public void init() {
    }

    @Override
    public void start() {

        final LinePane linePane = new LinePane();

        setLayout(new BorderLayout());
        JButton update = new JButton("Update");
        add(linePane);
        add(update, BorderLayout.SOUTH);

        update.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                linePane.regenerate();
            }
        });

    }

    protected class LinePane extends JPanel {

        private int[] coords = new int[4];

        public void regenerate() {
            coords = randomLine();
            repaint();
        }

        public int[] randomLine() {
            int[] pointArray = new int[4];
            int x;
            for (int i = 0; i < 4; i++) {
                x = ((int) (Math.random() * (Math.min(getWidth(), getHeight()) / 10 - 2))) * 20 + 10;
                pointArray[i] = x;
            }
            return pointArray;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.blue);
            g.drawLine(coords[0], coords[1], coords[2], coords[3]);
            g.drawString(coords[0] / 10 + ", " + coords[1] / 10, coords[0], coords[1]);
            g.drawString(coords[2] / 10 + ", " + coords[3] / 10, coords[2], coords[3]);
            int midpointx = (coords[0] + coords[2]) / 2;
            int midpointy = (coords[1] + coords[3]) / 2;
            g.drawString(midpointx / 10 + ", " + midpointy / 10, midpointx, midpointy);
        }
    }
}

With super.paintComponent

Without super.paintComponent




回答2:


You are calculating new co-ordinates every time paint() is called.

paint() is called every time the applet window is resized or regains focus.

To fix, you could make

int[] coords = new int[4];

a class member variable and move

coords = randomLine();

to your init() method, which will only be called once upon initialization.

Addendum:

  • Always call super.paint(g); when overriding paint().

  • For custom painting using Swing, the preferred approach is to extends a JComponent component leveraging the enhanced paint functionality offered by using paintComponent.

For more see: Performing Custom Painting.




回答3:


The trouble seems to be that paint() is called every time the component needs repainting.

paint() methods should be written in a way that doesn't produce side effects and they shouldn't change the internal state of the applet. paint() must be restricted to doing just that: painting.



来源:https://stackoverflow.com/questions/13168078/java-applet-displays-itself-multiple-times

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