Skip to main content

Canvas level BufferStrategy

6 replies [Last post]
ser207
Offline
Joined: 2008-08-11

Hello

I’m new to graphics and am in the process of bringing myself up to speed on java 2d. I am now looking at how to use the BufferStratergy to manage the offscreen buffer.

I’ve written a test program but nothing appears in my canvas/frame. Any idea what I’m doing wrong? I’m sure it must be something trivial.

I’m using Java 1.6.0_6 on windows XP

<br />
package waterfall;</p>
<p>import java.awt.Color;<br />
import java.awt.Dimension;<br />
import java.awt.Graphics;<br />
import java.awt.Graphics2D;<br />
import java.awt.event.ActionEvent;<br />
import java.awt.event.ActionListener;<br />
import java.awt.image.BufferStrategy;<br />
import java.util.Random;</p>
<p>public class Waterfall05 extends java.awt.Canvas implements Runnable {</p>
<p>    final int WATERFALL_WIDTH = 701;<br />
    final int WATERFALL_HEIGHT = 300;</p>
<p>    Random rnd = new Random();<br />
    final int width;<br />
    final int height;        </p>
<p>    BufferStrategy bufferStratergy=null;</p>
<p>    Color[] newLine = null;<br />
    int numLines=0;</p>
<p>    public Waterfall05() {<br />
        setPreferredSize(new java.awt.Dimension(701, 300));<br />
        setIgnoreRepaint(true);</p>
<p>        Dimension size = getPreferredSize();</p>
<p>        width  =  size.width;//- insets.left - insets.right;<br />
        height =  size.height;// - insets.top - insets.bottom;</p>
<p>        newLine = new Color[0];</p>
<p>        ActionListener taskPerformer = new ActionListener()<br />
        {<br />
            public void actionPerformed(ActionEvent evt)<br />
            {<br />
                generateNewData();<br />
            }<br />
        };<br />
        javax.swing.Timer t = new javax.swing.Timer(500, taskPerformer);<br />
        t.start();<br />
    }</p>
<p>    private void generateNewData()<br />
    {<br />
        newLine = new Color[WATERFALL_WIDTH];</p>
<p>        for(int i=0; i<br />
    private void initComponents() {</p>
<p>        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);</p>
<p>        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());<br />
        getContentPane().setLayout(layout);<br />
        layout.setHorizontalGroup(<br />
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)<br />
            .addGap(0, 400, Short.MAX_VALUE)<br />
        );<br />
        layout.setVerticalGroup(<br />
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)<br />
            .addGap(0, 300, Short.MAX_VALUE)<br />
        );</p>
<p>        pack();<br />
    }//                         </p>
<p>    /**<br />
    * @param args the command line arguments<br />
    */<br />
    public static void main(String args[]) {<br />
        java.awt.EventQueue.invokeLater(new Runnable() {<br />
            public void run() {<br />
                new TestWaterfall05().setVisible(true);<br />
            }<br />
        });<br />
    }<br />
}</p>
<p>

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Dmitri Trembovetski

You don't want to use Swing components and Canvas together.
Use Frame instead of JFrame.

Thanks,
Dmitri

java2d@JAVADESKTOP.ORG wrote:
> Hello
>
> I’m new to graphics and am in the process of bringing myself up to speed on java 2d. I am now looking at how to use the BufferStratergy to manage the offscreen buffer.
>
> I’ve written a test program but nothing appears in my canvas/frame. Any idea what I’m doing wrong? I’m sure it must be something trivial.
>
> I’m using Java 1.6.0_6 on windows XP
>
> [code]
> package waterfall;
>
> import java.awt.Color;
> import java.awt.Dimension;
> import java.awt.Graphics;
> import java.awt.Graphics2D;
> import java.awt.event.ActionEvent;
> import java.awt.event.ActionListener;
> import java.awt.image.BufferStrategy;
> import java.util.Random;
>
> public class Waterfall05 extends java.awt.Canvas implements Runnable {
>
> final int WATERFALL_WIDTH = 701;
> final int WATERFALL_HEIGHT = 300;
>
>
> Random rnd = new Random();
> final int width;
> final int height;
>
> BufferStrategy bufferStratergy=null;
>
> Color[] newLine = null;
> int numLines=0;
>
>
> public Waterfall05() {
> setPreferredSize(new java.awt.Dimension(701, 300));
> setIgnoreRepaint(true);
>
>
> Dimension size = getPreferredSize();
>
> width = size.width;//- insets.left - insets.right;
> height = size.height;// - insets.top - insets.bottom;
>
>
> newLine = new Color[0];
>
> ActionListener taskPerformer = new ActionListener()
> {
> public void actionPerformed(ActionEvent evt)
> {
> generateNewData();
> }
> };
> javax.swing.Timer t = new javax.swing.Timer(500, taskPerformer);
> t.start();
> }
>
>
> private void generateNewData()
> {
> newLine = new Color[WATERFALL_WIDTH];
>
> for(int i=0; i > {
> newLine[i] = getColor();
> }
> if (numLines<300)
> numLines++;
> }
>
>
> private Color getColor() {
> return new Color(rnd.nextInt(0x1000000));
> }
>
>
>
> private void render()
> {
> System.out.println("render!");
> if (bufferStratergy==null)
> {
> bufferStratergy = getBufferStrategy();
> System.out.println("....created buffer stratergy...");
> }
>
>
> // 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
> {
> // Get a new graphics context every time through the loop
> // to make sure the strategy is validated
> Graphics graphics = bufferStratergy.getDrawGraphics();
>
> // Render to graphics
> render(graphics);
>
> // Dispose the graphics
> graphics.dispose();
>
> // Repeat the rendering if the drawing buffer contents
> // were restored
> } while (bufferStratergy.contentsRestored());
>
> // Display the buffer
> bufferStratergy.show();
>
> // Repeat the rendering if the drawing buffer was lost
> } while (bufferStratergy.contentsLost());
>
> }
>
>
>
> private void render(Graphics g)
> {
> Graphics2D g2d = (Graphics2D)g;
> System.out.println("painting frame");
>
> g2d.setColor(Color.ORANGE);
> g2d.fillRect(0, 0, width, height);
>
> }
>
>
> private void renderX(Graphics g)
> {
> Graphics2D g2d = (Graphics2D)g;
> System.out.println("painting frame: "+g2d);
>
> g2d.copyArea(0, 0, width, height-1, 0, 1);
>
> for(int i=0; i > {
> g2d.setColor(newLine[i]);
> g2d.drawRect(i, 0, 1, 1);
> }
> }
>
> public void startRendering()
> {
> System.out.println("startRendering....");
> Thread thread = new Thread(this);
> thread.start();
> }
>
> public void run()
> {
> while (true) {
> render();
>
> try
> {
> Thread.sleep(300);
> }
> catch (InterruptedException e)
> {
> System.out.println("interrupt");
> }
> }
> }
> }
>
> package waterfall;
>
> import java.awt.Canvas;
>
> public class TestWaterfall05 extends javax.swing.JFrame {
>
> /** Creates new form TestWaterfall05 */
> public TestWaterfall05() {
> initComponents();
> Waterfall05 waterfall = new Waterfall05();
> this.getContentPane().add(waterfall);
> this.setSize(waterfall.getPreferredSize().width, waterfall.getPreferredSize().height);
> //this.setIgnoreRepaint(true);
> waterfall.createBufferStrategy(2);
> waterfall.setVisible(true);
> waterfall.startRendering();
> }
>
> /** This method is called from within the constructor to
> * initialize the form.
> * WARNING: Do NOT modify this code. The content of this method is
> * always regenerated by the Form Editor.
> */
> @SuppressWarnings("unchecked")
> //
> private void initComponents() {
>
> setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
>
> javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
> getContentPane().setLayout(layout);
> layout.setHorizontalGroup(
> layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
> .addGap(0, 400, Short.MAX_VALUE)
> );
> layout.setVerticalGroup(
> layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
> .addGap(0, 300, Short.MAX_VALUE)
> );
>
> pack();
> }//

>
> /**
> * @param args the command line arguments
> */
> public static void main(String args[]) {
> java.awt.EventQueue.invokeLater(new Runnable() {
> public void run() {
> new TestWaterfall05().setVisible(true);
> }
> });
> }
> }
>
> [/code]
> [Message sent by forum member 'ser207' (ser207)]
>
> http://forums.java.net/jive/thread.jspa?messageID=292552
>
> ===========================================================================
> To unsubscribe, send email to listserv@java.sun.com and include in the body
> of the message "signoff JAVA2D-INTEREST". For general help, send email to
> listserv@java.sun.com and include in the body of the message "help".

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

ser207
Offline
Joined: 2008-08-11

Thanks for your reply Dmitri.

Changing the JFrame to the AWT Frame got my program to work. Should'nt it have worked with JFrame as well?

Does this means that I can't make use of a BufferStratergy backed animation area in a Swing application. There is no Canvas equivalent in Swing.

fred34
Offline
Joined: 2004-06-19

Swing already uses an accelerated back buffer for its drawing. Internally this is either a VolatileImage (from JDK1.4+) or a BufferStrategy (from JDK1.6+). The equivalent of Canvas in Swing is just a sub-classed JComponent or JPanel, since all Swing components are lightweight. There's very little use for an actual Canvas object now. A Window object (e.g. window/frame/dialog) can also be used to create a BufferStrategy which would save you the trouble of ever using Canvas. Putting a Canvas into a JFrame is a bad idea due to the rather erratic behaviour that can result from using heavyweight components inside lightweight ones.

ser207
Offline
Joined: 2008-08-11

Thanks for the explanation, now it all makes sense.

So I guess for the high graphics intensive content that I will have in my Swing application I will have to make do with using a JComponent/JPanel and an offscreen buffer, perhaps a VolatileImage. Although I was trying to keep away from it as its usage is not intuitive.

Thanks again.

Dmitri Trembovetski

If your application doesn't have a requirement of precise rendering
timing(as a first person shooter would, for example), you may just be
fine with Swing's repainting mechanism. That is, you'd control the
painting rate with calling repaint() at some intervals (or when you
have something to repaint).

In this case the rendering will still be accelerated since you'll
be rendering into Swing's backbuffer which is (as mentioned) either
a VolatileImage or BufferStrategy.

Thanks,
Dmitri

java2d@JAVADESKTOP.ORG wrote:
> Thanks for the explanation, now it all makes sense.
>
> So I guess for the high graphics intensive content that I will have in my Swing application I will have to make do with using a JComponent/JPanel and an offscreen buffer, perhaps a VolatileImage. Although I was trying to keep away from it as its usage is not intuitive.
>
> Thanks again.
> [Message sent by forum member 'ser207' (ser207)]
>
> http://forums.java.net/jive/thread.jspa?messageID=293038
>
> ===========================================================================
> To unsubscribe, send email to listserv@java.sun.com and include in the body
> of the message "signoff JAVA2D-INTEREST". For general help, send email to
> listserv@java.sun.com and include in the body of the message "help".

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

ser207
Offline
Joined: 2008-08-11

No I haven’t got precise rendering time requirements just that the display be flicker-free. The only thing is that my application will receive inputs from multiple external sources at rates of up to 16Hz. These inputs obviously change the graphics that are displayed and have to be re-rendered. My screen has a resolution of 1600x1200 and I have two of these.

I’ve been doing some rough timings based on my waterfall test program posted earlier. I have 3 versions:
(a) renders directly to the screen in the paintComponent method (if I understood correctly, then this should be accelerated behind the scenes by the Swing framework).
(b) Renders to offsceen buffer (compatible buffered image) and paintComponent copies this to the screen
(c) Renders to offsceen buffer (volatile image) and paintComponent copies this to the screen (using the template code found in VolatileImage Java 6 Javadoc)
The results to render the graphics (slowest to fastest): a (0.013ms), c (0.009) and finally b(0.002). The figures are just to show the order of magnitude. Is this as expected?
And the results to get the image to the screen (paintComponent): b (0.002ms) and c (0.00007). As you would expect.

Message was edited by: ser207