-2

为什么 SWT 的绘制速度比 AWT 慢?

全部,

一个经典的问题,但数字上的差异确实让我感到惊讶。

附上 Swing 和 SWT 中的简单测试,用随机字体绘制文本 1000 次。

SWT(gc.advance off)

每绘制 1000 个文本约 80 毫秒

SWT(gc.advance on)

每绘制 1000 个文本约 200 毫秒

Swing(启用抗锯齿提示)

每绘制 1000 个文本约 30 毫秒

配置:

  • Win7
  • Java 1.6_25
  • SWT org.eclipse.swt.win32.win32.x86_3.7.1.v3738a.jar

谢谢大家。

SWTTest.java

import java.io.IOException;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class SWTTest {
    private static Font font;

public static void main(String[] args) throws IOException {

    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setBounds(0, 0, 500, 500);
    shell.open();
            font = new Font(display, new FontData("Tahoma", (int) (Math.random() * 30), SWT.NORMAL));

    shell.addPaintListener(new PaintListener() {

        @Override
        public void paintControl(PaintEvent e) {
            drawshit(e.gc);
        }
    });

    while (!shell.isDisposed()) {
        if (!display.readAndDispatch())
            display.sleep();
    }

    font.dispose();
    display.dispose();

    System.in.read();
}

private static void drawshit(Shell shell) {

    if (!shell.isDisposed()) {
        GC gc = new GC(shell);
        Rectangle bounds = shell.getBounds();

        long start = System.nanoTime();
        for (int i = 0; i < 1000; i++) {
            // try various different things here, e.g. drawing lines, rectangles, cacheing fonts etc.
            // Font font = new Font(gc.getDevice(), new FontData("Tahoma", (int) (Math.random() * 30), SWT.NORMAL));
            gc.setFont(font);
            gc.drawText("Hello World", (int) (Math.random() * 400), (int) (Math.random() * 400));
            font.dispose();
        }
        long stop = System.nanoTime();

        gc.dispose();

        System.out.println("SWT time: " + (stop - start) / 1000000 + " ms");
    }
}
}

AWTTest.java

import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

public class AWTTest extends Frame implements MouseListener, WindowListener {

public static void main(String[] args) {
    new AWTTest();
}

public AWTTest() {
    /*
     * Label hello = new Label("Hello World"); add(hello, "Center");
     */
    setSize(500, 500);
    setVisible(true);

    addMouseListener(this);
    addWindowListener(this);
}

@Override
public void paint(Graphics g) {
    super.paint(g);
    Graphics2D g2d = (Graphics2D) g;

    // SWT Default font:
    // [1|Tahoma|8.25|0|WINDOWS|1|-11|0|0|0|400|0|0|0|1|0|0|0|0|Tahoma]

    g2d.setBackground(Color.GRAY);
    g2d.clearRect(0, 0, 500, 500);
    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

    long start = System.nanoTime();
    for (int i = 0; i < 1000; i++) {
        // try various different things here, e.g. drawing lines, rectangles, cacheing fonts etc.
        g2d.setFont(new Font("Tahoma", Font.PLAIN, (int) (Math.random() * 30)));
        g2d.drawString("Hello World", (int) (Math.random() * 400), (int) (Math.random() * 400));
    }
    long stop = System.nanoTime();

    System.out.println("AWT time: " + (stop - start) / 1000000 + " ms");

}

@Override
public void mouseEntered(MouseEvent e) {
}

@Override
public void mouseClicked(MouseEvent e) {
    this.paintAll(getGraphics());
}

@Override
public void mouseExited(MouseEvent e) {
}

@Override
public void mousePressed(MouseEvent e) {
}

@Override
public void mouseReleased(MouseEvent e) {
}

@Override
public void windowActivated(WindowEvent e) {
}

@Override
public void windowClosed(WindowEvent e) {
}

@Override
public void windowClosing(WindowEvent e) {
    System.exit(0);
}

@Override
public void windowDeactivated(WindowEvent e) {
    // TODO Auto-generated method stub

}

@Override
public void windowDeiconified(WindowEvent e) {
    // TODO Auto-generated method stub

}

@Override
public void windowIconified(WindowEvent e) {
    // TODO Auto-generated method stub

}

@Override
public void windowOpened(WindowEvent e) {
    // TODO Auto-generated method stub

}
}
4

1 回答 1

1

正如 phineas 已经评论的那样,您的 SWT 代码并不好。

但是您也在比较两个非常不同的输出。SWT 通过设计在本机绘图。操作系统负责绘图,这可能会产生与使用 AWT 绘图非常不同的结果。您是否希望您的应用程序与用户操作系统的其他应用程序保持一致取决于您。

无论如何,在您的示例中,AWT 文本只是简单地消除了锯齿。SWT 文本由 Windows 使用ClearType绘制。如果您禁用 ClearType(在 Windows 设置中),“SWT”的性能会大大加快(实际上它是 Windows 的性能),即使您的基准测试存在提到的问题。

在另一个操作系统上运行您的基准测试将再次产生不同的数字。

更新

我刚刚使用了你的代码,修复了当前版本明显的 dispose 错误,添加

   shell.getDisplay().asyncExec(new Runnable() {

      @Override
      public void run() {
         drawshit(shell);
      }
   });

在 , 的末尾drawshit,并使字体大小为静态,因为它与性能非常相关。我使用 15 作为两个类的大小。

启用 ClearTypeSWTTest大约需要 50 毫秒,没有 ClearType 每次迭代大约需要 17 毫秒。我使用 WinXP SP3。

AWTTest在 3 ms 和 11 ms 之间的值仍然更快。

所有这一切都表明,ClearType 使文本的绘制速度大大减慢。这不是 SWT 的错,而是由于底层操作系统而发生的。在 Mac 上尝试该基准测试,您将获得完全不同的结果。

于 2012-04-17T21:20:25.613 回答