Rysowanie prostokąta w pętli?

Nov 20 2020

Próbuję animować prostokąt na podstawie współrzędnych określonych przez pętlę for, wewnątrz przycisku. Oto moja JComponentklasa:

public class Rect extends JComponent {
    public int x;
    public int y;
    public int w;
    public int h;
    
    public Rect (int x, int y, int w, int h) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        repaint();
    }

    @Override
    public void paintComponent(Graphics g)  {
        Graphics2D g2 = (Graphics2D) g;
        super.paintComponent(g);
        g2.setColor(Color.green);
        g2.drawRect(x+15, y+15, w, h);
    }
}

a oto mój przycisk i klasa buttonwewnętrzna JFrame:

public class MainFrame extends JFrame {
    Rect R = new Rect(15, 15, 50, 50);
    JPanel lm = new JPanel();
    LayoutManager lay = new OverlayLayout(lm);
    JButton animate = new JButton("animate");

    public MainFrame () {
        setSize(1200, 700);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        lm.setLayout(lay);
        lm.add(R);
}
    animate.addActionListener(new ActionListener() {
           public void actionPerformed(ActionEvent e) { 
               for (int k = 0; k < 500; k+=50) {
                R = new Rect(k, k, 50, 50);
               validate();
               repaint();
               }
           }   
  });
}

Ale kiedy uruchamiam kod i klikam przycisk, nic się nie dzieje. Co jest nie tak?

EDYCJA: Uruchamiam ramkę w mojej głównej klasie w ten sposób:

public class OrImage {
    public static void main(String[] args) throws Exception
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                MainFrame mf = new MainFrame();
                mf.setVisible(true);
            }
        });   
    }
}

Odpowiedzi

1 Abra Nov 20 2020 at 07:46

Zmieniłem kod klasy MainFrametak, że po naciśnięciu animateprzycisku coś się dzieje, ale nie wiem, czy tak właśnie chcesz.

Nie zmieniłem klasy Recti dodałem main()metodę, aby MainFramepo prostu zachować wszystko w jednej klasie.

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;

public class MainFrame extends JFrame {
    Rect R = new Rect(15, 15, 50, 50);
    JPanel lm = new JPanel();
    LayoutManager lay = new OverlayLayout(lm);
    JButton animate = new JButton("animate");

    public MainFrame () {
        setSize(1200, 700);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        lm.setLayout(lay);
        lm.add(R);
        animate.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) { 
                for (int k = 0; k < 500; k+=50) {
                    R = new Rect(k, k, 50, 50);
                    lm.add(R);
                }
                lm.revalidate();
                lm.repaint();
            }   
        });
        add(lm, BorderLayout.CENTER);
        add(animate, BorderLayout.PAGE_END);
        setLocationByPlatform(true);
        setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> new MainFrame());
    }
}

Główna zmiana dotyczy metody actionPerformed(). Musisz dodać Rdo JPanel. Musisz zadzwonić revalidate()do programu, JPanelponieważ zmieniłeś liczbę zawartych w nim komponentów. A po wywołaniu revalidate()powinieneś zadzwonić repaint()(ponownie na JPanel), aby sam się przerysował.

Tak to wygląda przed wciśnięciem animate.

A tak to wygląda po tłoczeniu animate

EDYTOWAĆ

Na życzenie - z animacją.

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;
import javax.swing.Timer;

public class MainFrame extends JFrame {
    Rect R = new Rect(15, 15, 50, 50);
    JPanel lm = new JPanel();
    LayoutManager lay = new OverlayLayout(lm);
    JButton animate = new JButton("animate");
    private int  x;
    private int  y;
    private Timer  timer;

    public MainFrame () {
        setSize(1200, 700);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        lm.setLayout(lay);
        lm.add(R);
        timer = new Timer(500, event -> {
            if (x < 500) {
                lm.remove(R);
                x += 50;
                y += 50;
                R = new Rect(x, y, 50, 50);
                lm.add(R);
                lm.revalidate();
                lm.repaint();
            }
            else {
                timer.stop();
            }
        });
        timer.setInitialDelay(0);
        animate.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                timer.start();
            }   
        });
        add(lm, BorderLayout.CENTER);
        add(animate, BorderLayout.PAGE_END);
        setLocationByPlatform(true);
        setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> new MainFrame());
    }
}