为什么JFrame的输出与.paint方法不同,以及如何解决这个问题?
问题描述:
我试图设置一个系统,使用Swing呈现项目的快速列表,因为它的布局管理器完全适合我的情况。然而,在尝试使用文本包装时,我发现演示JFrame中显示的结果与调用.print/.paint(All)时得到的结果不同。为什么JFrame的输出与.paint方法不同,以及如何解决这个问题?
这是一个最小的,完整的,并且可验证例如:
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class TextWrapTest {
public static void main(String[] args) throws IOException {
final JPanel panel = new JPanel(new GridBagLayout());
final GridBagConstraints gbc = new GridBagConstraints();
gbc.gridy = 0;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
panel.add(new JLabel("<html>This is a piece of text."), gbc);
gbc.gridy++;
panel.add(new JLabel("<html>This is a very long piece of text that needs to be wrapped in order to fit in the frame."), gbc);
gbc.gridy++;
panel.add(new JLabel("<html>Another piece of text."), gbc);
// Output the frame
final JFrame frame = new JFrame();
frame.setUndecorated(true);
frame.setSize(200, 200);
frame.add(panel);
frame.setVisible(true);
// Output the image
final BufferedImage image = new BufferedImage(frame.getWidth(), frame.getHeight(), BufferedImage.TYPE_INT_RGB);
frame.paintAll(image.getGraphics());
ImageIO.write(image, "png", new File("output.png"));
}
}
JFrame中:https://i.stack.imgur.com/zbTPz.png
output.png:https://i.stack.imgur.com/OcM4x.png
正如你所看到的,其结果显然是不同的,文本拒绝使用.getGraphics()
绘制使用GridBagConstraints,甚至尝试使用JTextArea的文本包装,而不是打包无济于事。
在这个问题上的任何帮助将不胜感激,因为我不知道如何让paint方法服从文字环绕。
此致,
伦斯Rikkerink
答
可能有许多原因,但是,我会建议避免paint
和paintAll
,因为他们调用API的双缓冲方面,可能会导致之前的延迟图像实际上被绘制到Graphics
上下文中。相反,我建议使用printAll
,因为它在绘画时会禁用双缓冲。
另一个问题可能是框架可能无法在屏幕上实现(或甚至没有完全绘制)。调用setVisible
会调用很多后台工作,并会调用EDT回调以启动绘画过程。在这种情况下,我建议在UI显示后使用SwingUtilities.invokeLater
块。
这会做一些事情,首先,我可以将任务放置在事件队列中,在事件队列创建完成后,但更重要的是,它会同步绘画,所以你不打架EDT试图在同一时间
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
final BufferedImage image = new BufferedImage(frame.getWidth(), frame.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = image.createGraphics();
frame.paintAll(g2d);
g2d.dispose();
ImageIO.write(image, "png", new File("output.png"));
}
});
首先要画到屏幕上,你应该避免调用'paintAll',坚持'printAll',因为这会删除所有的双缓冲和其他一些相关问题 – MadProgrammer
你可以也是在与UI的竞争状态中变得实现并着色 – MadProgrammer
@MadProgrammer这似乎是问题所在。添加'Thread.sleep(1000);'解决了他的问题 – XtremeBaumer