请问swing中的双缓冲怎么用啊?能给个简单的例子吗?

解决方案 »

  1.   

    双缓冲是为了解决重绘的闪烁问题
    JComponet默认实现了双缓冲的,其他组件继承这个类
    如果没有必要,不用自己实现双缓冲
      

  2.   

    晕,三楼的大哥能帮我说下,swing中的双缓冲怎么用吗?我必须用它保存图形啊。
      

  3.   

    private Image doubleBuffer;
    ...
    public void update(Graphics g) {
        Dimension size = getSize();
        if (doubleBuffer == null ||
            doubleBuffer.getWidth(this) != size.width ||
            doubleBuffer.getHeight(this) != size.height)
        {
            doubleBuffer = createImage(size.width, size.height);
        }
        if (doubleBuffer != null) {
            //向双缓冲中绘图
            Graphics g2 = doubleBuffer.getGraphics();
            paint(g2);
            g2.dispose();        //显示双缓冲中的内容
            g.drawImage(doubleBuffer, 0, 0, null);
        }
        else {
            paint(g);
        }
    }public void paint(Graphics g) {
        // do drawing here
        ...
    }
      

  4.   

    楼上的这不是自己实现双缓冲吗???
    AWT中的双缓冲我会。
    请帮帮忙,给我说下swing中所谓的自带双缓冲怎么用?
      

  5.   

    JComponent默认实现了double buffering,如果你觉得不满意,你可以参考一下JComponent的paintDoubleBuffered方法。
      

  6.   

    JComponent的paintDoubleBuffered方法怎么都是private的啊?
    有没有提供什么可以操作后台图象的方法呢?
    大家帮帮忙啊,我找了好久了。
      

  7.   

    怎么这么死心眼呢,呵呵,你参考哪个方法重写paintComponent阿,你的paint方法默认实现会调用你的paintComponent, paintBorder和paintChildren,其中paintChildren会递归调用子组件的paint方法。所以,不要重写paint,那样可能导致你的子组件无法正确显示,如果你对paintComponent方法重写,就不会影响Swing的机制。不过我是在不太清楚你为什么要重新实现Swing的double buffering,看看下面的内容,估计你就不会打算自己在swing里做double buffering了One of the most notable features of Swing is that it builds support for double-buffering right into the toolkit. It does the by providing a "doubleBuffered" property on javax.swing.JComponent:      public boolean isDoubleBuffered()
        public void setDoubleBuffered(boolean o)
    Swing's double buffer mechanism uses a single offscreen buffer per containment hierarchy (usually per top-level window) where double-buffering has been enabled. And although this property can be set on a per-component basis, the result of setting it on a particular container will have the effect of causing all lightweight components underneath that container to be rendered into the offscreen buffer, regardless of their individual "doubleBuffered" property values. By default, this property is set to true for all Swing components. But the setting that really matters is on JRootPane, because that setting effectively turns on double-buffering for everything underneath the top-level Swing component. For the most part, Swing programs don't need to do anything special to deal with double-buffering, except to decide whether it should be on or off (and for smooth GUI rendering, you'll want it on!). Swing ensures that the appropriate type of Graphics object (offscreen image Graphics for double-buffering, regular Graphics otherwise) is passed to the component's paint callback, so all the component needs to do is draw with it. This mechanism is explained in greater detail later in this article, in the section on Paint Processing. 
      

  8.   

    可是我想在swing中保存已经画好的图象,并能够在窗口重新获得焦点时,还能显示
    所以我想调用swing的off screen
    如果我不想把已经做好的程序保存在一个图象中,我该如何做?
      

  9.   

    你要保存的是图形还是包含其他Swing组件的Panel之类的?
    如果是前者,你可以用背景的off screen,对于包含Swing子组件的,你最好别这样做(其实差不多是没法做)我猜你是在做什么画图的东西才这么问的吧???
      

  10.   

    恩,是的
    就是想做个小的画图板
    现在不知道在swing中怎么将画出的东西保存下来
    请大哥介绍个方法给我。
    不胜感激
      

  11.   

    我猜你是不是在paint里面有几何计算之类的,导致每次你的窗体哪怕是很小一部分被其它窗体挡住了,然后都需要对整个客户区计算并重绘,所以很慢?那样的话可以放Image里,你创建一个Image:
    doubleBuffer = createImage(size.width, size.height);当你的程序的内部数据变化的时候,比如用户新画了一条线,在事件响应函数里你向Image绘图:
     Graphics g2 = doubleBuffer.getGraphics();
     //更改绘图......;
     g2.dispose();然后你通知Swing准备重绘:
    repaint();在paint方法里,你就不用再去绘图了,直接把画好的image拿出来
     g.drawImage(doubleBuffer, 0, 0, null);如果你的绘图可以把计算限定在某一个区域,那么用update方法更好,因为update并不擦除背景(如果它本身是轻量级组件),你可以增量重绘,这是最好的方法,但是不幸的是,大多数情况很难对某一个特定的区域重新计算,所以JComponent的update方法默认实现直接就调用paint()。
      

  12.   

    楼上的大哥还是说的双缓冲嘛
    可是在swing里不是默认实现了双缓冲了吗?
    上面的方法我试过,但是
    doubleBuffer = createImage(size.width, size.height);
     g.drawImage(doubleBuffer, 0, 0, null);
    第二句总是提醒我找不到源image。而且抛出空指针异常。
    是不是createImage的调用者不对啊?我这里是一个JInternerFrame
      

  13.   

    >>楼上的大哥还是说的双缓冲嘛可是在swing里不是默认实现了双缓冲了吗?Swing是实现了双缓冲,但是如果你想自己做,你可以参靠下面的例子import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Image;
    import java.awt.event.ActionListener;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;import javax.swing.JFrame;
    import javax.swing.JMenu;
    import javax.swing.JMenuBar;
    import javax.swing.JMenuItem;
    import javax.swing.JPanel;
    public class MyPanel extends JPanel {

    Image doubleBuffer;
    int clickCount;
    private static final Dimension pSize = new Dimension(300, 300);

    public void paint(Graphics g) {
    long t1 = System.currentTimeMillis();
    if (doubleBuffer == null) {
    doubleBuffer = createImage(this.getWidth(),  this.getHeight());
    }
    g.drawImage(doubleBuffer, 0, 0, null);
    long t2 = System.currentTimeMillis();
    System.out.println("Render consumed " + (t2 - t1) + " milliseconds");

    }
     
    public Dimension getPreferredSize()
    {
    return pSize;
    }

    public void changeInternalStatus()
    {
     Graphics g2 = doubleBuffer.getGraphics();
     //更改绘图......;
     g2.drawLine(0, clickCount, doubleBuffer.getWidth(null), clickCount);
     clickCount += 5;
     g2.dispose();
     repaint();
    } public static void main(String[] args) {
    final MyPanel p = new MyPanel();
    JFrame f = new JFrame();
    JMenuBar mb = new JMenuBar();
    JMenu m = new JMenu("Test");
    mb.add(m);
    JMenuItem mi = new JMenuItem("Draw in off screen");
    m.add(mi);
    mi.addActionListener(new ActionListener(){
    public void actionPerformed(java.awt.event.ActionEvent e) {
    p.changeInternalStatus();
    }

    });

    f.setJMenuBar(mb);
    f.setContentPane(p);
    f.pack();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.show();
    }

    }建议你看看http://java.sun.com/products/jfc/tsc/articles/painting/index.html
      

  14.   

    这个使用了double buffer,你看控制台输出一般都是
    Render consumed 0 milliseconds
    Render consumed 0 milliseconds
    Render consumed 0 milliseconds
    Render consumed 0 milliseconds
    Render consumed 0 millisecondsimport java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Image;
    import java.awt.event.ActionListener;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;import javax.swing.JFrame;
    import javax.swing.JMenu;
    import javax.swing.JMenuBar;
    import javax.swing.JMenuItem;
    import javax.swing.JPanel;
    public class MyPanel extends JPanel {

    Image doubleBuffer;
    int clickCount;
    private static final Dimension pSize = new Dimension(512, 512);

    public void paint(Graphics g) {
    long t1 = System.currentTimeMillis();
    if (doubleBuffer == null) {
    doubleBuffer = createImage(this.getWidth(),  this.getHeight());
    }
    g.drawImage(doubleBuffer, 0, 0, null);
    long t2 = System.currentTimeMillis();
    System.out.println("Render consumed " + (t2 - t1) + " milliseconds");

    }
     
    public Dimension getPreferredSize()
    {
    return pSize;
    }

    public void changeInternalStatus()
    {
     Graphics g = doubleBuffer.getGraphics();
     //更改绘图......;
     g.drawLine(0, clickCount, doubleBuffer.getWidth(null), clickCount);
     clickCount += 5;
     
     for (int i = 0; i < 256; i ++) {
      g.setColor(new Color(i, i / 2, i / 3));
      g.drawRoundRect(i, i, this.getWidth() - i * 2, this.getHeight() - i * 2, i / 5, i / 10);
     }
     g.dispose();
     repaint();
    } public static void main(String[] args) {
    final MyPanel p = new MyPanel();
    JFrame f = new JFrame();
    JMenuBar mb = new JMenuBar();
    JMenu m = new JMenu("Test");
    mb.add(m);
    JMenuItem mi = new JMenuItem("Draw in off screen");
    m.add(mi);
    mi.addActionListener(new ActionListener(){
    public void actionPerformed(java.awt.event.ActionEvent e) {
    p.changeInternalStatus();
    }

    });

    f.setJMenuBar(mb);
    f.setContentPane(p);
    f.pack();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.show();
    }

    }这个是不用double buffer的,控制台输出为
    Render consumed 16 milliseconds
    Render consumed 47 milliseconds
    Render consumed 15 milliseconds
    Render consumed 31 milliseconds
    Render consumed 16 milliseconds
    Render consumed 47 milliseconds
    Render consumed 16 milliseconds程序:
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Image;
    import java.awt.event.ActionListener;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;import javax.swing.JFrame;
    import javax.swing.JMenu;
    import javax.swing.JMenuBar;
    import javax.swing.JMenuItem;
    import javax.swing.JPanel;
    public class MyPanel extends JPanel {


    int clickCount;
    private static final Dimension pSize = new Dimension(512, 512);

    public void paint(Graphics g) {
    long t1 = System.currentTimeMillis();  //更改绘图......;
     g.drawLine(0, clickCount, this.getWidth(), clickCount);
     
     for (int i = 0; i < 256; i ++) {
      g.setColor(new Color(i, i / 2, i / 3));
      g.drawRoundRect(i, i, this.getWidth() - i * 2, this.getHeight() - i * 2, i / 5, i / 10);
     } long t2 = System.currentTimeMillis();
    System.out.println("Render consumed " + (t2 - t1) + " milliseconds");

    }
     
    public Dimension getPreferredSize()
    {
    return pSize;
    }

    public void changeInternalStatus()
    {
     clickCount += 5;
     repaint();
    } public static void main(String[] args) {
    final MyPanel p = new MyPanel();
    JFrame f = new JFrame();
    JMenuBar mb = new JMenuBar();
    JMenu m = new JMenu("Test");
    mb.add(m);
    JMenuItem mi = new JMenuItem("Draw in off screen");
    m.add(mi);
    mi.addActionListener(new ActionListener(){
    public void actionPerformed(java.awt.event.ActionEvent e) {
    p.changeInternalStatus();
    }

    });

    f.setJMenuBar(mb);
    f.setContentPane(p);
    f.pack();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.show();
    }

    }
      

  15.   

    你可以看出来,明显我自己实现的double buffer更快。
    但是这是有代价的,这个自己实现版本的不能够再添加新的子组件
    这就是我为什么一开始不想让你自己实现off screen的原因
    (因为你问我问的是swing的双缓冲怎么用,问法)
    你看看http://java.sun.com/products/jfc/tsc/articles/painting/index.html
    我觉得会对你很有帮助
      

  16.   

    试试Swing Component中的:setDoubleBuffer(boolean) ?
      

  17.   

    DanielYWoo(绿色毒汁) ( ) 是不是最近刚升星了,也不散分?佩服上面的解说,虽然还没有太明白,学习。