【问题标题】:Drawing rectangle within the loop?在循环内绘制矩形?
【发布时间】:2020-11-20 07:17:53
【问题描述】:

我正在尝试根据由 for 循环确定的坐标在按钮内为矩形设置动画。这是我的JComponent 班级:

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);
    }
}

这是我的按钮和button 在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();
               }
           }   
  });
}

但是当我运行代码并单击按钮时,什么也没有发生。怎么了?

编辑:我像这样在我的主类中运行框架:

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);
            }
        });   
    }
}

【问题讨论】:

  • 类MainFrame 无法编译。 sg 是什么?
  • @Abra 我已经更新了代码。我在其他类中使用 main 方法运行MainFrame。我已经删除了sg
  • 我不确定,但看起来你的 MainFrame 类仍然无法编译,即使在你编辑之后。
  • Swing 中的动画类似于手动动画。您创建了一系列可以快速更改(重新绘制)的静止图像。您的绘图 JPanel 应根据逻辑模型的内容绘制图像。逻辑模型中的值使用 Swing Timer 更改。

标签: java swing awt draw


【解决方案1】:

我更改了MainFrame 类的代码,这样当你按下animate 按钮时,发生了一些事情,但我不知道这是否是你想要发生的。

我没有更改类Rect,而是将main() 方法添加到MainFrame,只是为了将所有内容都放在一个类中。

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());
    }
}

主要变化在于方法actionPerformed()。您需要将R 添加到JPanel。您需要在JPanel 上调用revalidate(),因为您更改了它包含的组件数量。在调用revalidate() 之后,您应该调用repaint()(同样,在JPanel 上)使其重绘。

这是按下animate之前的样子。

这是按下animate后的样子

编辑

根据要求 - 带有动画。

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());
    }
}

【讨论】:

  • 嗯,谢谢指正。实际上,我的代码很长,所以在我在这里发布之前我需要整理很多东西。您的演示正是我的想法,但我想知道有什么方法可以让我不必在每个循环中将R 添加到panel 中?因为我只想让矩形移动,而不是相乘。
  • @RainhardCalvin 对于 Swing 中的动画,您应该使用 Swing timer
  • 我认为 Swing Timer 只是为了在任务之前和之后添加延迟。也许我可以在每次循环后删除或处理矩形以使其看起来有动画效果?
  • 如果可以的话,还有一件事让我感到困惑;在我的完整代码中,for 循环在另一个 class 中。所以我想在按钮中调用class的方法,然后将add、revalidate和repaint放在循环中MainFrame mf = new Mainframe();然后mf.lm.add(R)、mf.lm.revalidate();、@987654355 @,但什么也没发生。我的代码错了吗?
  • @RainhardCalvin 如果您需要帮助调试您的代码,请在上面发布一个新问题或edit 您问题中的代码。无论哪种情况,请确保您发布minimal reproducible example。
猜你喜欢
  • 2014-01-13
  • 1970-01-01
  • 1970-01-01
  • 2016-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多