问题
What are the principle differences between using an AWT Frame and a Swing JFrame when implementing your own rendering and not using standard Java GUI components?
This is a follow on from a previous question:
AWT custom rendering - capture smooth resizes and eliminate resize flicker
The typical talking points on Swing vs AWT don't seem to apply because we're only using frames. Heavyweight vs Lightweight goes out the window (and JFrame extends Frame), for example.
So which is best, JFrame or Frame for this situation? Does it make any meaningful difference?
Note: this scenario is one where rendering in the EDT is not desirable. There is an application workflow which is not linked to the EDT and rendering is done on an as-needs basis outside of the EDT. To synchronize rendering with the EDT would add latency to the rendering. We are not rendering any Swing or AWT components other than the Frame or JFrame (or an enclosed JPanel/Component/etc if it is best).
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.image.BufferStrategy;
import java.awt.Frame;
public class SmoothResize extends Frame {
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);
}
public SmoothResize() {
render();
}
private Dimension old_size = new Dimension(0, 0);
private Dimension new_size = new Dimension(0, 0);
public void validate() {
super.validate();
new_size.width = getWidth();
new_size.height = getHeight();
if (old_size.equals(new_size)) {
return;
} else {
render();
}
}
public void paint(Graphics g) {
validate();
}
public void update(Graphics g) {
paint(g);
}
public void addNotify() {
super.addNotify();
createBufferStrategy(2);
}
protected synchronized void render() {
BufferStrategy strategy = getBufferStrategy();
if (strategy == null) {
return;
}
// 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 {
Graphics draw = strategy.getDrawGraphics();
Insets i = getInsets();
int w = (int)(((double)(getWidth() - i.left - i.right))/2+0.5);
int h = (int)(((double)(getHeight() - i.top - i.bottom))/2+0.5);
draw.setColor(Color.YELLOW);
draw.fillRect(i.left, i.top + h, w,h);
draw.fillRect(i.left + w, i.top, w,h);
draw.setColor(Color.BLACK);
draw.fillRect(i.left, i.top, w, h);
draw.fillRect(i.left + w, i.top + h, w,h);
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());
}
}
回答1:
Expanding on @camickr's answer, the "missing detail" is JRootPane, which manages the contentPane
. Note that for JFrame "add
and its variants, remove
and setLayout
have been overridden to forward to the contentPane
as necessary." JRootPane#createContentPane() "creates a new JComponent
a[n]d sets a BorderLayout
as its LayoutManager
." As an implementation detail, that JComponent
happens to be a new JPanel()
. This has several consequences for the contentPane
of JFrame
:
- The
contentPane
is double buffered by default. - The
contentPane
has aBorderLayout
, althoughJPanel
ordinarily defaults toFlowLayout
. - The
contentPane
has a L&F specific UI delegate, typically derived fromPanelUI
, that may affect appearance and geometry.
回答2:
Swing is double buffered by default so generally you only need to concentrate on your painting.
Here is the Swing version:
import java.awt.*;
import javax.swing.*;
public class SwingResize extends JPanel
{
protected void paintComponent(Graphics g)
{
int w = (int)(((double)(getWidth()))/2+0.5);
int h = (int)(((double)(getHeight()))/2+0.5);
g.setColor(Color.YELLOW);
g.fillRect(0, h, w,h);
g.fillRect(w, 0, w,h);
g.setColor(Color.BLACK);
g.fillRect(0, 0, w, h);
g.fillRect(w, h, w,h);
}
public static void main(String[] args)
{
// Toolkit.getDefaultToolkit().setDynamicLayout(true);
// System.setProperty("sun.awt.noerasebackground", "true");
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.add( new SwingResize() );
frame.setSize(100, 100);
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
来源:https://stackoverflow.com/questions/6899004/swing-jframe-vs-awt-frame-for-rendering-outside-the-edt