我想用Java制作一个程序。我想要做的是,当用户点击屏幕时,绘制一个小方块。一个接一个地显示十个正方形,前一个正方形位于中心。当绘制第六个方格时,第一个方格消失,当绘制第七个方格时,第二个方格消失等,直到所有方格都消失。
这是MainActivity:
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainActivity {
public static int width = 900;
public static int height = width / 16 * 9;
static HandlerClass handler = new HandlerClass();
static JFrame window;
static JPanel windowInner;
public static void main(String[] args) {
window = new JFrame("Squarmony 1.0");
window.setSize(width, height);
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
windowInner = new JPanel();
windowInner.setSize(width, height);
windowInner.setBackground(Color.BLACK);
window.add(windowInner);
windowInner.addMouseListener(handler);
}
private static class HandlerClass implements MouseListener {
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
GraphicsActivity g = new GraphicsActivity();
g.drawRectRipple(window.getGraphics(), e);
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}
}
这是GraphicsActivity:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
public class GraphicsActivity {
public void drawRectRipple(Graphics g, MouseEvent e) {
g.setColor(Color.WHITE);
for (int i = 0; i <= 10; i++) {
for (int j = 0; j <= 250; j += 10) {
g.drawRect(e.getX() + j / 2, e.getY() - j / 2, j - j / 2, j + j / 2);
try {
Thread.sleep(250);
} catch (InterruptedException e1) {
}
}
}
}
}
如何将矩形逐个绘制(如涟漪)到屏幕上?
谢谢,
约翰
答案 0 :(得分:1)
所以可能有很多方法可以实现这一目标,有些更容易,有些更难。
Backgound:
动画是随时间变化的幻觉。这意味着在一段时间内,预计会发生某种变化。在你的情况下,一些正方形被绘制,有些则没有。
现在,这表明我们需要一些方法来定期更新我们的UI。现在你可以使用Thread
,但坦率地说,有更简单的方法。
Swing提供了一个Timer
类,它以固定的时间间隔提供事件,这使我们可以在事件调度线程的上下文中安全地更改UI。
这很重要,因为预计对UI的所有更新和修改都发生在EDT的上下文中。此外,阻止EDT的任何操作都将阻止UI更新。查看Concurrency in Swing了解详情。
现在,您可以将计时器设置为以符合您需要的预定义时间间隔打勾。也就是说,你需要在 n 秒的时间内进行10次更新,但这开始让你处于轻微的劣势,因为你所有的计算都是基于一些已知的,音乐会价值...虽然你可以当然这样做,我更喜欢更灵活的解决方案。
所以,相反,我选择使用基于“百分比”的方法。也就是说,我的所有动画都是基于知道在循环中给定百分比的情况下需要发生的事情。这使得可以具有可变的时间范围而不会对绘制算法产生不利影响。
为实现这一目标,我们需要知道循环何时开始以及循环时间。这样我们就可以计算一个周期运行的持续时间和完成周期的百分位数,例如
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Check to see if the cycle has being completed...
if (cycleStartedAt == -1) {
// The time that this cycle started
cycleStartedAt = System.currentTimeMillis();
}
// The amount of time this cycle has being running
long duration = System.currentTimeMillis() - cycleStartedAt;
// The progress through this cycle...
progress = (double)duration / (double)runningTime;
// Check for the completion of this cycle...
if (progress > 1.0d) {
// Reset..
cycleStartedAt = -1;
progress = 0;
}
repaint();
}
});
timer.setRepeats(true);
timer.start();
这实际上为我们提供了什么?这使我们能够根据时间百分比对动画进行建模。例如......
private double[][] squares = {
{0, 0.30},
{0.075, 0.375},
{0.15, 0.45},
{0.225, 0.525},
{0.30, 0.60},
{0.30, 0.675},
{0.375, 0.75},
{0.45, 0.825},
{0.525, 0.90},
{0.6, 0.975},
};
这是10个方格的列表,每个方格都有一个开始和结束百分比,表示每个方格应该可见的时间。
最后,一个可运行的例子......
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Squares {
public static void main(String[] args) {
new Squares();
}
public Squares() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private int runningTime = 5000;
private long cycleStartedAt = -1;
private double progress = 0;
private double[][] squares = {
{0, 0.30},
{0.075, 0.375},
{0.15, 0.45},
{0.225, 0.525},
{0.30, 0.60},
{0.30, 0.675},
{0.375, 0.75},
{0.45, 0.825},
{0.525, 0.90},
{0.6, 0.975},
};
public TestPane() {
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (cycleStartedAt == -1) {
cycleStartedAt = System.currentTimeMillis();
}
long duration = System.currentTimeMillis() - cycleStartedAt;
progress = (double)duration / (double)runningTime;
if (progress > 1.0d) {
cycleStartedAt = -1;
progress = 0;
}
repaint();
}
});
timer.setRepeats(true);
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics g2d = (Graphics2D) g.create();
int width = getWidth() - 1;
int height = getHeight() - 1;
int hGap = width / squares.length;
int vGap = height / squares.length;
int index = 0;
for (double[] square : squares) {
if (progress >= square[0] && progress <= square[1]) {
int sWidth = hGap * (index + 1);
int sHeight = vGap * (index + 1);
int x = (width - sWidth) / 2;
int y = (height - sHeight) / 2;
g2d.drawRect(x, y, sWidth, sHeight);
}
index++;
}
g2d.dispose();
}
}
}