【问题标题】:Swing/JFrame vs AWT/Frame for rendering outside the EDTSwing/JFrame 与 AWT/Frame 在 EDT 外渲染
【发布时间】:2011-10-17 11:02:08
【问题描述】:

在实现自己的渲染和不使用标准 Java GUI 组件时,使用 AWT 框架和 Swing JFrame 之间的主要区别是什么?

这是上一个问题的后续:

AWT custom rendering - capture smooth resizes and eliminate resize flicker

Swing 与 AWT 的典型谈话要点似乎并不适用,因为我们只使用框架。例如,重量级与轻量级的对比(JFrame 扩展了 Frame)。

那么对于这种情况来说,JFrame 还是 Frame 哪个最好?它有什么有意义的区别吗?

注意:这种情况是不希望在 EDT 中渲染。有一个未链接到 EDT 的应用程序工作流,并且渲染是在 EDT 之外根据需要完成的。将渲染与 EDT 同步会增加渲染的延迟。除了 Frame 或 JFrame(或封闭的 JPanel/Component/etc,如果最好的话),我们不会渲染任何 Swing 或 AWT 组件。

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

}

【问题讨论】:

  • 来自Frame的一些Nested and Inherit方法直接在JFrame APIdownload.oracle.com/javase/6/docs/api/javax/swing/JFrame.html中实现,
  • 我看不出FrameJFrameMsExcellMozillaFirefox之间有任何区别,如果完成,请删除notify(i3/530/3,43Gb RAM,WinXP,板载GPU/无sharedMemory/编译JDK1.6.22)
  • @mKorbel:MsExcel 和 MozillaFirefox 有什么关系?
  • 在显示器上调整容器的大小和移动,仅此而已

标签: java swing rendering awt doublebuffered


【解决方案1】:

扩展@camickr 的answer"missing detail"JRootPane,它管理contentPane。请注意,对于 JFrame "add 及其变体,removesetLayout 已被覆盖以根据需要转发到 contentPane。" JRootPane#createContentPane() "创建一个新的 JComponent a[n]d 将 BorderLayout 设置为其 LayoutManager。"作为实现细节,JComponent 恰好是new JPanel()。这对JFramecontentPane 有几个后果:

  • contentPane 默认情况下是双缓冲的。
  • contentPane 有一个BorderLayout,尽管JPanel 通常默认为FlowLayout
  • contentPane 具有特定于 L&F 的 UI 委托,通常派生自 PanelUI,它可能会影响外观和几何形状。

【讨论】:

  • 我想我是模棱两可的,但这是一个完全自定义的渲染周期。没有委托,没有 L&F,只有包装 Frame(或 JFrame 或任何其他需要的东西)和渲染在 EDT 外部完成,因为在 EDT 中进行会涉及延迟或黑客攻击或两者兼而有之。
  • Painting in AWT and Swing: Double Buffering Support 可能是恰当的:“真正重要的设置在JRootPane,因为该设置有效地为顶级 Swing 组件下的所有内容打开双缓冲。”我从来没有理由关掉它。 AFAIK,所有现存的主机渲染引擎都是单线程的。为什么使用 EDT?
  • 应用程序结构和延迟。有问题的应用程序有自己的脚本和布局引擎,它们是集成的并驱动渲染。就渲染要求而言,将其视为游戏而不是应用程序(尽管是后者)。它按需渲染到后备缓冲区,然后将其绘制到屏幕上。 EDT 和使用相同图像(后缓冲区)的应用程序线程往往会导致小问题。
  • 说你现有应用程序的模型和视图不能轻易解开对吗?
  • 我见过的最接近的模拟是Processing,提到了here
【解决方案2】:

Swing 默认是双缓冲的,所以通常你只需要专注于你的绘画。

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

}

【讨论】:

  • 我的错,但我把这个问题弄得太模糊了,随后的答案没有抓住重点,迫使你放弃 Swing 的 EDT 渲染范式。这是一个完全自定义的 UI,不需要任何 Swing 或 AWT。在 EDT 中绘画是不可取的,因为它在这种情况下需要兼顾应用程序周期和渲染周期,其中渲染是完全自定义的。
猜你喜欢
  • 2010-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-11
  • 1970-01-01
  • 2013-02-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多