gpt4 book ai didi

resize - AWT 自定义呈现 - 捕获平滑的调整大小并消除调整大小闪烁

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:18:59 25 4
gpt4 key购买 nike

几个月来我一直在研究这个,这是迄今为止我想到的最好的。

结构(在 EDT 之外呈现)无可争议,因为我们的应用程序以这种方式运行并且不会被重写。该应用程序具有集成的布局模型和脚本模型并驱动渲染,因此渲染必须在 AWT 绘制模型之外执行。

我试图达到的是执行自定义渲染的最佳且可靠的方式。

以下 SSCCE 对我们来说效果很好。但是,在调整帧大小时,它有两个缺点:

  • 偶尔会出现闪烁,尤其是在快速调整大小时
  • 从 paint() 调用调用调整大小(通过此处的 checkSize)的“平滑调整大小”技巧仅适用于扩展。缩小帧时,它通常在释放鼠标按钮之前不会呈现
  • 此外,但在这里不是很明显,它确实会偶尔抛出 IllegalStateExceptions - 是否可以简单地捕获/忽略这些异常?

关于这是否是在 EDT 之外发生的自定义渲染路径的最佳方法的输入也很有用。我尝试了最多,并进行了相当广泛的研究。这种组合(后台缓冲图像、双缓冲策略)似乎效果最好。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferStrategy;

public class SmoothResize extends Frame implements ComponentListener, MouseMotionListener {

public SmoothResize() {
addComponentListener(this);
addMouseMotionListener(this);
}

private boolean sizeChanged = false;
private Dimension old = new Dimension(0, 0);
private synchronized void checkSize(String source) {
int width = getWidth();
int height = getHeight();
if (old.width == width && old.height == height)
return;
sizeChanged = true;
String type =
(old.width > width && old.height > height) ? "shrink" :
(old.width < width && old.height < height) ? "expand" : "resize";
System.out.println(source + " reports " + type + ": "+getWidth()+", "+getHeight());
old.setSize(width, height);
}

public void componentResized(ComponentEvent arg0) { checkSize("componentResized"); }
public void mouseMoved(MouseEvent e) { checkSize("mouseMoved"); }
public void paint(Graphics g) { checkSize("paint"); }
public void update(Graphics g) { paint(g); }

public void addNotify() {
super.addNotify();
createBufferStrategy(2);
}

private synchronized void render() {
BufferStrategy strategy = getBufferStrategy();
if (strategy==null || !sizeChanged) return;
sizeChanged = false;
// Render single frame
do {
// The following loop ensures that the contents of the drawing buffer
// are consistent in case the underlying surface was recreated
do {
System.out.println("render");
Graphics draw = strategy.getDrawGraphics();
Insets i = getInsets();
int w = getWidth()-i.left-i.right;
int h = getHeight()-i.top-i.bottom;
draw.setColor(Color.YELLOW);
draw.fillRect(i.left, i.top+(h/2), w/2, h/2);
draw.fillRect(i.left+(w/2), i.top, w/2, h/2);
draw.setColor(Color.BLACK);
draw.fillRect(i.left, i.top, w/2, h/2);
draw.fillRect(i.left+(w/2), i.top+(h/2), w/2, h/2);
draw.dispose();

// Repeat the rendering if the drawing buffer contents
// were restored
} while (strategy.contentsRestored());

// Display the buffer
strategy.show();

// Repeat the rendering if the drawing buffer was lost
} while (strategy.contentsLost());
}

public static void main(String[] args) {
Toolkit.getDefaultToolkit().setDynamicLayout(true);
System.setProperty("sun.awt.noerasebackground", "true");
SmoothResize srtest = new SmoothResize();
//srtest.setIgnoreRepaint(true);
srtest.setSize(100, 100);
srtest.setVisible(true);
while (true) {
srtest.render();
}
}

public void componentHidden(ComponentEvent arg0) { }
public void componentMoved(ComponentEvent arg0) { }
public void componentShown(ComponentEvent arg0) { }

public void mouseDragged(MouseEvent e) { }
}

最佳答案

这是使用外部线程完成所有工作的代码。它通过能够呈现任何实现 Renderable 接口(interface)的东西来做到这一点。我已经用 Swing 和 AWT(JFrameFrame)对此进行了测试,它没有闪烁。请注意,如果您在 JRootPane 上实现并将该 Pane 设置为 JFrame 的根 Pane ,它确实会闪烁。这与组件的缓冲方式有关,如果您希望这样使用它,则可以修复。

如果这仍然不是您想要的,请直接说,我会再试一次。这实际上很有趣,因为自从我完成任何 Java GUI 工作以来已经有一段时间了。

不管怎样,给你:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Toolkit;
import javax.swing.JFrame;

public class SmoothResize extends Frame implements Renderable {

public static void main(String[] args) {
Toolkit.getDefaultToolkit().setDynamicLayout(true);
System.setProperty("sun.awt.noerasebackground", "true");
SmoothResize srtest = new SmoothResize();
RenderThread renderThread = new RenderThread(srtest);
renderThread.start();
srtest.setSize(100, 100);
srtest.setVisible(true);
}

public SmoothResize() {
}

public void addNotify() {
super.addNotify();
createBufferStrategy(2);
}

@Override
public Dimension getSize() {
return new Dimension(getWidth(), getHeight());
}

@Override
public Graphics acquireGraphics() {
return this.getGraphics();
}
}

class RenderThread extends Thread {

Renderable target;
Dimension last_size = new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);

public RenderThread(Renderable d) {
if (d == null) {
throw new NullPointerException("Drawable target cannot be null.");
}
target = d;

}

@Override
public void run() {
while (true) {
render(false);
}
}

private synchronized void render(boolean force) {
Dimension size;
do {
size = target.getSize();
if (size == null) {
return;
}

Graphics draw = target.acquireGraphics();
if (draw == null) {
return;
}
draw.setPaintMode();
int w = (int) (((double) (size.width)) / 2 + 0.5);
int h = (int) (((double) (size.height)) / 2 + 0.5);
draw.setColor(Color.YELLOW);
draw.fillRect(0, h, w, h);
draw.fillRect(w, 0, w, h);
draw.setColor(Color.BLACK);
draw.fillRect(0, 0, w, h);
draw.fillRect(w, h, w, h);
draw.dispose();
// Repeat the rendering if the target changed size
} while (!size.equals(target.getSize()));
}
}

interface Renderable {

public Graphics acquireGraphics();

public Dimension getSize();
}

关于resize - AWT 自定义呈现 - 捕获平滑的调整大小并消除调整大小闪烁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6824756/

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