更改变量时重绘不起作用

Repaint doesn't work when changing variable

我对使用 java 进行开发还很陌生,但我有一些一般的编码经验。我知道想用我创建的函数绘制 "picture/fractal"。我完成了所有代码,我想通过添加到函数 XOFF 来自动移动 "fractal",(我有一个计时器)现在我希望变量自动增加,以便它在图片中滚动。我尝试使用重绘和重新验证但它不起作用:(

而且我知道我写了 MandelBrotSet,尽管它与它没有任何关系 ^^

package Pack1;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

import javax.swing.Timer;
import javax.swing.JComponent;
import javax.swing.JFrame;

public class Main extends JComponent implements ActionListener {
    public static void main(String[] args) {
        new Main();
    }

    public static final int WIDTH = 1000;
    public static final int HEIGHT = 800;
    public int XOFF = 0;
    public int YOFF = 0;

    private BufferedImage buffer;
    private Timer timer;

    public Main(){

        buffer = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        timer = new Timer(10, this);
        renderMandelBrotSet();

        JFrame frame = new JFrame("Mandelbrot Set");

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(true);
        frame.getContentPane().add(this);
        frame.pack();
        frame.setVisible(true);
    }

    @Override 
    public void addNotify() {       
        setPreferredSize(new Dimension(WIDTH, HEIGHT));
        timer.start();
    }

    public void renderMandelBrotSet() {
        System.out.println(XOFF);
        int vx = 0;
        int vy = 0;
        int zoom = 1;

        for(int x = 0; x < WIDTH; x++)
            for(int y = 0; y < HEIGHT; y++) {
                vx = ((x - WIDTH/2));
                vy = ((y - HEIGHT/2));
                vx = vx + XOFF;
                vy = vy + 0;
                int color = (int) (Math.abs(vx)/Math.sqrt(Math.abs(vy))*(vx/zoom));    //calculatePoint((x - WIDTH/2), (y - HEIGHT/2) );

                buffer.setRGB(x, y, color);
            }
    }


    @Override
    public void paint(Graphics g) {
        g.drawImage(buffer, 0, 0, null);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        XOFF++;
        renderMandelBrotSet();
        revalidate();
        repaint();
    }
}

我希望代码有意义...,如果我忘记提及任何内容,我很抱歉。如果您需要什么,请随时问我。

我认为addNotify是你的问题。该方法已经做了一些事情,并且您覆盖它的方式似乎没有执行其文档所说的任何操作。干脆去掉它,把它的代码移到别处。

这似乎对我有用。我还将您的计时器减慢到 100 毫秒,因为我从经验中知道 Java Swing 的更新速度并不能那么快。 100 毫秒到 250 毫秒是更新 Swing 的一个很好的范围。

我也摆脱了 revalidate 因为那只适用于添加或删除组件或更改大小时。您只需要重新绘制,因为您的图像不会改变大小。

(Hovercraft 指出代码确实应该覆盖 paintComponent,而不是 paint。他说得很对;这在教程中有解释:https://docs.oracle.com/javase/tutorial/uiswing/painting/closer.html

(虽然我正在修复问题,但我不妨指出 Swing is not thread safe, 和 GUI 创建(包括图像和计时器)确实需要在 GUI 线程上完成。)

package quicktest;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;

/**
 *
 * @author Brenden
 */
public class MandelbrotSet {

}


class Main extends JComponent implements ActionListener {

    public static void main(String[] args) {
        new Main();
    }

    public static final int WIDTH = 800;
    public static final int HEIGHT = 600;
    public int XOFF = 0;
    public int YOFF = 0;

    private BufferedImage buffer;
    private Timer timer;


    public Main(){
       SwingUtilities.invokeLater( this::createGui );
    }

    private void createGui() {
        buffer = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        timer = new Timer(100, this);
        setPreferredSize( new Dimension( WIDTH, HEIGHT ) );
        renderMandelBrotSet();

        JFrame frame = new JFrame("Mandelbrot Set");

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(true);
        frame.getContentPane().add(this);
        frame.pack();
        frame.setVisible(true);
        timer.start();
    }       

//    @Override 
//    public void addNotify() {
//        setPreferredSize(new Dimension(WIDTH, HEIGHT));
//        timer.start();
//    }

    public void renderMandelBrotSet() {
        System.out.println(XOFF);
        int vx = 0;
        int vy = 0;
        int zoom = 1;

        for(int x = 0; x < WIDTH; x++)
            for(int y = 0; y < HEIGHT; y++) {
                vx = ((x - WIDTH/2));
                vy = ((y - HEIGHT/2));
                vx = vx + XOFF;
                vy = vy + 0;
                int color = (int) (Math.abs(vx)/Math.sqrt(Math.abs(vy))*(vx/zoom));    //calculatePoint((x - WIDTH/2), (y - HEIGHT/2) );

                buffer.setRGB(x, y, color);
            }
    }

    @Override
    public void paintComponent(Graphics g) {
       super.paintComponent( g );
       System.err.println( "Repainting..." );
       g.drawImage(buffer, 0, 0, null);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
       System.err.println( "Timer: XOFF=" + XOFF );
        XOFF++;
        renderMandelBrotSet();
//        revalidate();
        repaint();
    }

}