Java AWT画布在手动调整大小时闪烁
只是出于智力上的兴趣,你可以使画布在手动调整大小时不闪烁Java AWT画布在手动调整大小时闪烁,java,user-interface,swing,awt,Java,User Interface,Swing,Awt,只是出于智力上的兴趣,你可以使画布在手动调整大小时不闪烁 public class FlickerAWT extends Canvas { public static void main(String[] args) { Frame f = new Frame(str); //this line change nothing //JFrame f = new JFrame(str); f.add(new FlickerAWT()); f.pack(); int frameWidt
public class FlickerAWT extends Canvas {
public static void main(String[] args) {
Frame f = new Frame(str);
//this line change nothing
//JFrame f = new JFrame(str);
f.add(new FlickerAWT());
f.pack();
int frameWidth = f.getWidth();
int frameHeight = f.getHeight();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
f.setLocation(screenSize.width / 2 - frameWidth / 2, screenSize.height / 2 - frameHeight / 2);
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowDeiconified(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
});
}
private Color bgColor; private Color contentColor;
Font f = new Font("Georgia", Font.BOLD, 16);
static String str = "AWT Canvas Resize Flickering";
public FlickerAWT() {
Random r = new Random();
bgColor = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256));
contentColor = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256));
}
public Dimension getPreferredSize() {
FontMetrics fm = getFontMetrics(f);
return new Dimension(fm.stringWidth(str) + 20, fm.getHeight() + 10);
}
public void paint(java.awt.Graphics g) {
g.setColor(bgColor);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(contentColor);
g.setFont(f);
FontMetrics fm = g.getFontMetrics(f);
int dx = getWidth() / 2 - (fm.stringWidth(str) / 2);
int dy = getHeight() / 2 + (fm.getHeight() / 2);
g.drawString(str, dx, dy);
}
}
您可以在Java编辑器中复制粘贴并运行该示例。我认为关键是使用双缓冲区,一种可能的解决方法是使用Swing,默认情况下使用双缓冲区:
import java.awt.*;
import java.util.Random;
import javax.swing.*;
public class FlickerSwing extends JPanel {
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
private static void createAndShowGui() {
JFrame f = new JFrame(str);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new FlickerSwing());
f.setLocationRelativeTo(null);
f.pack();
f.setVisible(true);
}
private Color bgColor;
private Color contentColor;
Font f = new Font("Georgia", Font.BOLD, 16);
static String str = "Swing Resize Flickering";
public FlickerSwing() {
Random r = new Random();
bgColor = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256));
contentColor = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256));
setBackground(bgColor);
}
public Dimension getPreferredSize() {
FontMetrics fm = getFontMetrics(f);
return new Dimension(fm.stringWidth(str) + 20, fm.getHeight() + 10);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(contentColor);
g.setFont(f);
FontMetrics fm = g.getFontMetrics(f);
int dx = getWidth() / 2 - (fm.stringWidth(str) / 2);
int dy = getHeight() / 2 + (fm.getHeight() / 2);
g.drawString(str, dx, dy);
}
}
您可以将其添加到主方法的开头,以避免背景闪烁:
System.setProperty("sun.awt.noerasebackground", "true");
我知道这个问题由来已久,但在我寻找的过程中,我发现了一个解决方案: 有两个问题: 一方面,java.awt.Container的
update(…)
方法如下所示:
public void update(Graphics g) {
if (isShowing()) {
if (! (peer instanceof LightweightPeer)) {
g.clearRect(0, 0, width, height);
}
paint(g);
}
}
也就是说,它调用g.clearRect(…)
在绘制其子对象之前擦除当前内容
因此,您需要在视图堆栈中java.awt.Container的每个子代中覆盖update(…)
,这些子代还没有覆盖,如下所示:
public void update(Graphics g) {
if (isShowing()) paint(g);
}
此外,AWT或JVM或其他任何人(还没有弄清楚这一点)似乎也会清除主窗口的背景,而与任何容器的更新方法无关。为了防止出现这种情况,请按照@WhiteFang34的建议,在代码的某个地方添加以下行:
System.setProperty("sun.awt.noerasebackground", "true");
只有同时完成这两项工作,才能最终解决我的闪烁问题……“您可以在Java编辑器中复制粘贴并运行示例。”而不是在编译产生25个错误时。为了更快地获得更好的帮助,请发布一条消息。@Andrew:我相信他忘记了导入。@HFOE:+1我有时会明确说明
super(true)
constructor.OP要求纯java.awt
解决方案。“不摇摆”。他问,他绝对不会考虑使用挥杆吗?事实上,必须把它放在虚拟机的论点中。我刚刚做了另一个我想用它的项目,它使用了-D
标志。为我完全解决了闪烁问题,但我仍然不明白,为什么我不必重写paint(…)方法,因为它在渲染子对象之前默认也会清除组件。我以为操作系统会直接调用绘画方法,因为系统触发了绘画?