gpt4 book ai didi

java 什么更重 : Canvas or paintComponent()?

转载 作者:行者123 更新时间:2023-12-02 05:45:16 25 4
gpt4 key购买 nike

有人可以告诉我应该使用什么在 JPanel 上绘制图形:Canvas,还是简单地在 paintComponent() 中绘制所有内容?我每秒大约 30 次绘制数百个小图像,我想知道哪一个是最轻量级的,以及在什么条件下我应该同时使用这两个图像?谢谢。

最佳答案

这个问题相当广泛,而背景却相当薄弱。

考虑看看 Rotating multiple images causing flickering. Java Graphics2DSwing animation running extremely slow例如。

第一个使用 paintComponent 以 25fps(或尽可能接近)渲染多达 10, 000 个旋转图像。

第二个实际上可以对多达 4, 500 个基于组件的图像进行动画处理

以这种速度有效绘画的能力只是整体情况的一个考虑因素

已更新

使用 JPanelCanvas 之间的主要区别在于渲染算法的差异。

使用JPanel,您仍然受重绘管理器的支配。这种方法通常被称为“被动渲染”。也就是说,经理负责确定应该绘制什么内容以及何时绘制。当重绘管理器决定需要绘制某些内容时(例如因为某些操作系统事件已请求应更新部分或整个屏幕),绘制是临时完成的。

从技术上讲,您无法控制此过程,只能简单地发出重新绘制的请求。由于系统介入并强制更新,您偶尔也可能会遇到一些延迟

Canvas 为您提供了 BufferStrategy,它与底层渲染管道的联系更紧密,可能会使其速度更快。

有了这个,您就可以负责安排重画。这通常称为“主动渲染”。

您仍然可以使用这种方法来处理操作系统...

无论哪种方式,除非您的更新/渲染管道得到很好的优化,否则您仍然可能会遇到很多问题,并且实际上可以通过使用 JPanel 而不是 Canvas 获得更好的性能

就个人而言,如果您不确定或者以前没有做过类似的事情,我会从 JPanel 开始。一般来说,处理起来稍微简单一些。

我更改了链接的示例以维护 FPS 计数器...

MiniFig

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class ZombieLand {

protected static final Random RND = new Random();

private static BufferedImage zombie;
private static int fps = 25;

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

public ZombieLand() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}

try {
zombie = ImageIO.read(getClass().getResource("/MiniFig.png"));
} catch (IOException ex) {
ex.printStackTrace();
}

final ZombiePane zombiePane = new ZombiePane();

final JSlider slider = new JSlider(1, 10000);
slider.setMajorTickSpacing(1000);
slider.setMinorTickSpacing(100);
slider.setPaintTicks(true);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
JSlider slider = (JSlider) e.getSource();
zombiePane.setZombies(slider.getValue());
}
});

JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(zombiePane);
frame.add(slider, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);

SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
slider.setValue(10000);
}
});
}
});
}

public static class ZombiePane extends JPanel {

private List<ZombieSprite> sprites;
protected static final Object SPRITE_LOCK = new Object();

private int desiredCount = 1;

public ZombiePane() {
sprites = new ArrayList<>(25);
sprites.add(new ZombieSprite());
Thread t = new Thread(new GameLoop());
t.setDaemon(false);
t.start();
Font font = getFont();
setFont(font.deriveFont(Font.BOLD, 48f));
}

public void setZombies(int count) {
desiredCount = count;
}

@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
synchronized (SPRITE_LOCK) {
for (ZombieSprite sprite : sprites) {
sprite.paint(g2d);
}
}
String text = Integer.toString(sprites.size());
FontMetrics fm = g2d.getFontMetrics();
g2d.drawString(text, getWidth() - fm.stringWidth(text), getHeight() - fm.getHeight() + fm.getAscent());

text = Integer.toString(fps);
g2d.drawString(text, 0, getHeight() - fm.getHeight() + fm.getAscent());
g2d.dispose();
}

protected void cycle() {
synchronized (SPRITE_LOCK) {
if (desiredCount != sprites.size()) {
int count = 0;
int fill = 100;
while (sprites.size() > desiredCount && count < fill) {
sprites.remove(0);
count++;
}
count = 0;
while (sprites.size() < desiredCount && count < fill) {
sprites.add(new ZombieSprite());
count++;
}
}

for (ZombieSprite sprite : sprites) {
sprite.update(getWidth(), getHeight());
}
}
}

public static class ZombieSprite {

private Point motionDelta;
private double rotationDelta;

private Point location;
private double angle;

public ZombieSprite() {
motionDelta = new Point();
motionDelta.x = (int) ((Math.random() * 3) + 1);
motionDelta.y = (int) ((Math.random() * 3) + 1);
if (Math.random() > 0.5) {
motionDelta.x *= -1;
}
if (Math.random() > 0.5) {
motionDelta.y *= -1;
}
rotationDelta = (int) ((Math.random() * 9) + 1);
if (Math.random() > 0.5) {
rotationDelta *= -1;
}
}

public void paint(Graphics2D g2d) {
if (location != null) {
Graphics2D g = (Graphics2D) g2d.create();
AffineTransform at = new AffineTransform();
at.translate(location.x, location.y);
at.rotate(Math.toRadians(angle), zombie.getWidth() / 2, zombie.getHeight() / 2);
g.setTransform(at);
g.drawImage(zombie, 0, 0, null);
g.dispose();
}
}

public void update(int width, int height) {
if (location == null) {
angle = (Math.random() * 360d);
location = new Point();
location.x = (int) (Math.random() * (width - zombie.getWidth()));
location.y = (int) (Math.random() * (height - zombie.getHeight()));
} else {
angle += rotationDelta;
location.x += motionDelta.x;
location.y += motionDelta.y;

if (location.x < 0) {
location.x = 0;
motionDelta.x *= -1;
} else if (location.x + zombie.getWidth() > width) {
location.x = width - zombie.getWidth();
motionDelta.x *= -1;
}
if (location.y < 0) {
location.y = 0;
motionDelta.y *= -1;
} else if (location.y + zombie.getHeight() > height) {
location.y = height - zombie.getHeight();
motionDelta.y *= -1;
}
}
}

}

public class GameLoop implements Runnable {

private long last;
private long start;
private int wait;

private boolean keepRunning = true;

public void run() {

// Calculate the optimal/maximum delay time
// This is converted to nanos so it can be
// used to calculate the actual delay...
long millisPerSecond = TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS);
long optimalDelay = Math.round(millisPerSecond / 25);

optimalDelay = TimeUnit.MILLISECONDS.toNanos(optimalDelay);

// Last start of a "second" loop
long loop = System.nanoTime();
int frameCount = 0;
// While gaming...
while (keepRunning) {
// Start of this cycle...
long now = System.nanoTime();

// Update the state and render the
// current frame...
cycle();
repaint();

// How long did that update take??
long timeTaken = System.nanoTime();
long delta = timeTaken - now;

// Subtract the delay from the maximum delay
long delay = optimalDelay - delta;
if (delay > 0) {
try {
// Sleep expects milliseconds...
delay = TimeUnit.NANOSECONDS.toMillis(delay);
Thread.sleep(delay);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}

// Calculate if we've being running for a second yet...
long loopDelay = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - loop);
// If the loop has been cycling for a second...
if (loopDelay >= 1) {
// Reset the loop time
loop = System.nanoTime();
System.out.println("FPS = " + frameCount);
fps = frameCount;
frameCount = 0;
} else {
// Add another frame to the pile...
frameCount++;
}
}
}
}
}
}

关于java 什么更重 : Canvas or paintComponent()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24131513/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com