简体   繁体   English

Swing / JFrame与AWT / Frame在EDT之外渲染

[英]Swing/JFrame vs AWT/Frame for rendering outside the EDT

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? 在实现自己的渲染而不使用标准Java GUI组件时,使用AWT Frame和Swing JFrame有什么主要区别?

This is a follow on from a previous question: 这是上一个问题的后续内容:

AWT custom rendering - capture smooth resizes and eliminate resize flicker AWT自定义渲染 - 捕获平滑调整大小并消除调整大小闪烁

The typical talking points on Swing vs AWT don't seem to apply because we're only using frames. 关于Swing vs AWT的典型谈话要点似乎并不适用,因为我们只使用框架。 Heavyweight vs Lightweight goes out the window (and JFrame extends Frame), for example. 例如,重量级和轻量级超出窗口(并且JFrame扩展了Frame)。

So which is best, JFrame or Frame for this situation ? 那么哪种情况最好,JFrame或Frame适用于这种情况 Does it make any meaningful difference? 它有什么有意义的区别吗?

Note: this scenario is one where rendering in the EDT is not desirable . 注意:这种情况是不希望在EDT中进行渲染的情况。 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. 有一个应用程序工作流程没有链接到EDT,渲染是在EDT之外的需要基础上完成的。 To synchronize rendering with the EDT would add latency to the rendering. 要使渲染与EDT同步会增加渲染的延迟。 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). 除了Frame或JFrame之外,我们不渲染任何Swing或AWT组件(如果最好的话,我们不会渲染封闭的JPanel / Component / etc)。

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());
}

}

Swing is double buffered by default so generally you only need to concentrate on your painting. 默认情况下,Swing是双缓冲的,所以通常你只需要专注于你的绘画。

Here is the Swing version: 这是Swing版本:

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);
    }

}

Expanding on @camickr's answer , the "missing detail" is JRootPane , which manages the contentPane . 扩展@ camickr的答案“缺少细节”JRootPane ,它管理contentPane Note that for JFrame " add and its variants, remove and setLayout have been overridden to forward to the contentPane as necessary." 请注意,对于JFrameadd及其变体,已removesetLayout以根据需要转发到contentPane 。” JRootPane#createContentPane() "creates a new JComponent a[n]d sets a BorderLayout as its LayoutManager ." JRootPane#createContentPane() “创建一个新的JComponent a [n] d将BorderLayout设置为其LayoutManager 。” As an implementation detail, that JComponent happens to be a new JPanel() . 作为一个实现细节, JComponent恰好是一个new JPanel() This has several consequences for the contentPane of JFrame : 这对JFramecontentPane有几个影响:

  • The contentPane is double buffered by default. 默认情况下, contentPane是双缓冲的。
  • The contentPane has a BorderLayout , although JPanel ordinarily defaults to FlowLayout . contentPane有一个BorderLayout ,虽然JPanel通常默认为FlowLayout
  • The contentPane has a L&F specific UI delegate, typically derived from PanelUI , that may affect appearance and geometry. contentPane具有L&F特定的UI委托,通常从PanelUI派生,可能会影响外观和几何。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM