계속 previous question에서 계속해서 활성 표현과 Java의 텍스트 필드를 결합하는 최적의 방법을 찾고 있습니다. BufferStrategy, VolatileImage를 사용하거나 표준 AWT에서 update() 및 paint()를 재정 의하여 여러 옵션을 시도했지만 Swing을 사용하여 종료되었습니다.활성 렌더링 효율을 높이거나 활성 렌더링을 GUI 위젯과 결합하는 방법
누군가가 내 코드 예제를 기반으로 새로운 통찰력을 얻은 경우에 대비하여 여기에 현재 상태를 게시하고 비슷한 응용 프로그램에서 작업하는 다른 사람들이 내 결과에서 이익을 얻을 수도 있습니다.
대상이 세 업적 달성하는 것이다
- 만 업데이트되는 배경 버퍼의 상단에 생기 객체 렌더링을 할 때, 렌더링 결과
- 리사이즈 위에 필요한
- 사용 텍스트 필드 문제가없는 윈도우
다음은 stackoverflower trashgod의 큰 도움으로 개발 된 데모 애플리케이션의 코드입니다.
두 노트 :
1) 애니메이션의 이전 단계에서 무효화 된 영역을 엄격하게 새로 고치면 시각적 오류가 발생하기 쉬워집니다. 이것은 이제 모든 프레임마다 전체 배경 버퍼를 다시 그려야 함을 의미합니다.
2) BufferedImage를 화면에 그리는 효율은 플랫폼에 따라 크게 달라집니다. Mac 구현은 하드웨어 가속을 적절히 지원하지 않는 것 같습니다. 따라서 창 크기에 따라 배경 이미지를 출력 창에 다시 칠하는 작업이 지루한 작업이됩니다. 5 MS, 35~40% : -
맥 OS 10.5 : : :
640 × 480 9 %
1920 X 1100 0.9 MS, 8
윈도우 XP :
640 × 480 : 0.05 MS,
1920 X 1100 0 % : 0.05 MS, 0 %
설명 :
화면 크기 : 프레임을 그리는 평균 시간, 응용 프로그램의 CPU 사용량.
내가 알 수있는 한, 아래 코드는 내 목표를 달성하는 가장 효율적인 방법입니다. 새로운 통찰력, 최적화 또는 테스트 결과는 대단히 환영합니다!
감사합니다, Mattijs
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;
public class SwingTest extends JPanel implements
ActionListener,
Runnable
{
private static final long serialVersionUID = 1L;
private BufferedImage backgroundBuffer;
private boolean repaintbackground = true;
private static final int initWidth = 640;
private static final int initHeight = 480;
private static final int radius = 25;
private final Timer t = new Timer(20, this);
private final Rectangle rect = new Rectangle();
private long totalTime = 0;
private int frames = 0;
private long avgTime = 0;
public static void main(String[] args) {
EventQueue.invokeLater(new SwingTest());
}
public SwingTest() {
super(true);
this.setPreferredSize(new Dimension(initWidth, initHeight));
this.setLayout(null);
this.setOpaque(false);
this.addMouseListener(new MouseHandler());
}
@Override
public void run() {
JFrame f = new JFrame("SwingTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.addComponentListener(new ResizeHandler());
/* This extra Panel with GridLayout is necessary to make sure
our content panel is properly resized with the window.*/
JPanel p = new JPanel(new GridLayout());
p.add(this);
f.add(p);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
createBuffer();
t.start();
}
@Override
public void actionPerformed(ActionEvent e) {
this.repaint();
}
@Override
protected void paintComponent(Graphics g) {
long start = System.nanoTime();
super.paintComponent(g);
if (backgroundBuffer == null) createBuffer();
if (repaintbackground) {
/* Repainting the background may require complex rendering operations,
so we don't want to do this every frame.*/
repaintBackground(backgroundBuffer);
repaintbackground = false;
}
/* Repainting the pre-rendered background buffer every frame
seems unavoidable. Previous attempts to keep track of the
invalidated area and repaint only that part of the background buffer
image have failed. */
g.drawImage(backgroundBuffer, 0, 0, null);
repaintBall(g, backgroundBuffer, this.getWidth(), this.getHeight());
repaintDrawTime(g, System.nanoTime() - start);
}
void repaintBackground(BufferedImage buffer) {
Graphics2D g = buffer.createGraphics();
int width = buffer.getWidth();
int height = buffer.getHeight();
g.clearRect(0, 0, width, height);
for (int i = 0; i < 100; i++) {
g.setColor(new Color(0, 128, 0, 100));
g.drawLine(width, height, (int)(Math.random() * (width - 1)), (int)(Math.random() * (height - 1)));
}
}
void repaintBall(Graphics g, BufferedImage backBuffer, int width, int height) {
double time = 2* Math.PI * (System.currentTimeMillis() % 3300)/3300.;
rect.setRect((int)(Math.sin(time) * width/3 + width/2 - radius), (int)(Math.cos(time) * height/3 + height/2) - radius, radius * 2, radius * 2);
g.setColor(Color.BLUE);
g.fillOval(rect.x, rect.y, rect.width, rect.height);
}
void repaintDrawTime(Graphics g, long frameTime) {
if (frames == 32) {avgTime = totalTime/32; totalTime = 0; frames = 0;}
else {totalTime += frameTime; ++frames; }
g.setColor(Color.white);
String s = String.valueOf(avgTime/1000000d + " ms");
g.drawString(s, 5, 16);
}
void createBuffer() {
int width = this.getWidth();
int height = this.getHeight();
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
backgroundBuffer = gc.createCompatibleImage(width, height, Transparency.OPAQUE);
repaintbackground = true;
}
private class MouseHandler extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
super.mousePressed(e);
JTextField field = new JTextField("test");
Dimension d = field.getPreferredSize();
field.setBounds(e.getX(), e.getY(), d.width, d.height);
add(field);
}
}
private class ResizeHandler extends ComponentAdapter {
@Override
public void componentResized(ComponentEvent e) {
super.componentResized(e);
System.out.println("Resized to " + getWidth() + " x " + getHeight());
createBuffer();
}
}
}
1) 포인터에 감사드립니다. 가장 신뢰할 수있는 벤치 마크로 시스템의 기본 Activity Monitor/Task Manager에서보고 한대로 CPU 사용량을 사용합니다. 이 데이터를 원래 게시물에 포함 시켰지만 여전히 Windows에서 Mac OS가 아닌 이미지를 다시 칠하기 위해 하드웨어 가속을 사용함을 나타냅니다. 2) 아, 실제로 JPanel을 추가하지 않으면 크기가 잘 조정됩니다. 3) 그리고 다시 말해서. 다행히도이 응용 프로그램은 데모 용이지만 실제 응용 프로그램에서는이를 염두에 두겠습니다. – Mattijs