Creating a "movie" in Swing.

Discussion in 'Java' started by Aaron Fude, Oct 8, 2008.

  1. Aaron Fude

    Aaron Fude Guest

    Hi,

    I'm 100% sure that this is an FAQ, but I can't seem to find answer.

    Let's say I have 150 BufferedImages and I want to spit them out to a
    JPanel at a rate of 15fps so I can have 10 seconds of relatively
    smooth animation. I have a class VideoPanel that you can see below and
    a separate Thread that calls "repaint" on the VideoPanel 15 times a
    second. Now, the VideoPanel actually repaints when it wants to, so I
    get about 1 frame a second and I see about every 15th frame. What's
    the right way to fix this?

    public class VideoPanel extends JPanel {
    public void paint(Graphics g) {
    super.paint(g);
    Image img = myImages[myCurrentFrame];
    int w = img.getWidth(this);
    int h = img.getHeight(this);
    g.drawImage(img, 0, 0, w, h, 0, 0, w, h, this);
    }
    }


    My Thread class is this:

    public class Animate extends Thread {
    public void run() {
    while (true) {
    myVideoPanel.repaint();
    myCurrentFrame = (myCurrentFrame +1)%myImages.length;
    try {
    sleep(1000/15);
    }
    catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
    }
    Aaron Fude, Oct 8, 2008
    #1
    1. Advertising

  2. Aaron Fude wrote:
    > Hi,
    >
    > I'm 100% sure that this is an FAQ, but I can't seem to find answer.
    >
    > Let's say I have 150 BufferedImages and I want to spit them out to a
    > JPanel at a rate of 15fps so I can have 10 seconds of relatively
    > smooth animation. I have a class VideoPanel that you can see below and
    > a separate Thread that calls "repaint" on the VideoPanel 15 times a
    > second. Now, the VideoPanel actually repaints when it wants to, so I
    > get about 1 frame a second and I see about every 15th frame. What's
    > the right way to fix this?
    >
    > public class VideoPanel extends JPanel {
    > public void paint(Graphics g) {
    > super.paint(g);
    > Image img = myImages[myCurrentFrame];
    > int w = img.getWidth(this);
    > int h = img.getHeight(this);
    > g.drawImage(img, 0, 0, w, h, 0, 0, w, h, this);
    > }
    > }
    >
    >
    > My Thread class is this:
    >
    > public class Animate extends Thread {
    > public void run() {
    > while (true) {
    > myVideoPanel.repaint();
    > myCurrentFrame = (myCurrentFrame +1)%myImages.length;
    > try {
    > sleep(1000/15);
    > }
    > catch (Exception e) {
    > e.printStackTrace();
    > }
    > }
    > }
    > }


    Well you have to be sure that your computer can run that fast with
    images of that size. If you think it can then there are some things you
    can do to prevent the write coalescing with repaint(). First don't use
    repaint() because it will write coalesce. Call paintImmediately() from
    the EDT.

    public void run() {
    while (true) {
    try {
    Thread.sleep(66);
    } catch (InterruptedException ie) { }

    // increment counter or whatever you are using to point
    // to the next picture

    try {
    EventQueue.invokeAndWait(new Runnable() {
    public void run() {
    paintImmediately(0,0,getWidth(),getHeight());
    }
    });
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }

    Use paintComponent() instead of paint() to do your drawing on Swing
    components. If you are drawing the whole component or redrawing the
    complete background I would suggest that you NOT call
    super.paintComponent().

    There are numerous methods to get faster drawing, clipping, active
    rendering, using a BufferStrategy or a VolatileImage. The newer the JRE
    you use the better video performance you are going to get. Also, video
    cards play a big role. Windows is much faster than Linux as well.

    Another thing to keep in mind is that 150 images of any significant size
    will use a lot of memory.

    --

    Knute Johnson
    email s/nospam/knute2008/

    --
    Posted via NewsDemon.com - Premium Uncensored Newsgroup Service
    ------->>>>>>http://www.NewsDemon.com<<<<<<------
    Unlimited Access, Anonymous Accounts, Uncensored Broadband Access
    Knute Johnson, Oct 8, 2008
    #2
    1. Advertising

  3. In article <48ec18ba$0$13463$>,
    Knute Johnson <> wrote:

    > Aaron Fude wrote:
    > > Hi,
    > >
    > > I'm 100% sure that this is an FAQ, but I can't seem to find answer.
    > >
    > > Let's say I have 150 BufferedImages and I want to spit them out to a
    > > JPanel at a rate of 15fps so I can have 10 seconds of relatively
    > > smooth animation. I have a class VideoPanel that you can see below and
    > > a separate Thread that calls "repaint" on the VideoPanel 15 times a
    > > second. Now, the VideoPanel actually repaints when it wants to, so I
    > > get about 1 frame a second and I see about every 15th frame. What's
    > > the right way to fix this?
    > >
    > > public class VideoPanel extends JPanel {
    > > public void paint(Graphics g) {
    > > super.paint(g);
    > > Image img = myImages[myCurrentFrame];
    > > int w = img.getWidth(this);
    > > int h = img.getHeight(this);
    > > g.drawImage(img, 0, 0, w, h, 0, 0, w, h, this);
    > > }
    > > }
    > >
    > >
    > > My Thread class is this:
    > >
    > > public class Animate extends Thread {
    > > public void run() {
    > > while (true) {
    > > myVideoPanel.repaint();
    > > myCurrentFrame = (myCurrentFrame +1)%myImages.length;
    > > try {
    > > sleep(1000/15);
    > > }
    > > catch (Exception e) {
    > > e.printStackTrace();
    > > }
    > > }
    > > }
    > > }

    >
    > Well you have to be sure that your computer can run that fast with
    > images of that size. If you think it can then there are some things you
    > can do to prevent the write coalescing with repaint(). First don't use
    > repaint() because it will write coalesce. Call paintImmediately() from
    > the EDT.
    >
    > public void run() {
    > while (true) {
    > try {
    > Thread.sleep(66);
    > } catch (InterruptedException ie) { }
    >
    > // increment counter or whatever you are using to point
    > // to the next picture
    >
    > try {
    > EventQueue.invokeAndWait(new Runnable() {
    > public void run() {
    > paintImmediately(0,0,getWidth(),getHeight());
    > }
    > });
    > } catch (Exception e) {
    > e.printStackTrace();
    > }
    > }
    > }
    >
    > Use paintComponent() instead of paint() to do your drawing on Swing
    > components. If you are drawing the whole component or redrawing the
    > complete background I would suggest that you NOT call
    > super.paintComponent().
    >
    > There are numerous methods to get faster drawing, clipping, active
    > rendering, using a BufferStrategy or a VolatileImage. The newer the JRE
    > you use the better video performance you are going to get. Also, video
    > cards play a big role. Windows is much faster than Linux as well.
    >
    > Another thing to keep in mind is that 150 images of any significant size
    > will use a lot of memory.


    I'm Knute's student in this realm, but I'll venture two additions:

    First, consider pre-scaling your BufferedImages to the size of the
    destination; drawImage() won't have to scale and the observer parameter
    can be null.

    Second, consider javax.swing.Timer. It invokes the listener on the EDT
    and degrades gracefully by coalescing if you overrun the interval on a
    slower machine. Here's a simple example:

    <http://sites.google.com/site/drjohnbmatthews/subway>

    Of course, Knute's other optimizations (e.g. paintImmediately) would
    still apply.

    --
    John B. Matthews
    trashgod at gmail dot com
    home dot woh dot rr dot com slash jbmatthews
    John B. Matthews, Oct 8, 2008
    #3
  4. Aaron Fude

    Nigel Wade Guest

    Aaron Fude wrote:

    > Hi,
    >
    > I'm 100% sure that this is an FAQ, but I can't seem to find answer.
    >
    > Let's say I have 150 BufferedImages and I want to spit them out to a
    > JPanel at a rate of 15fps so I can have 10 seconds of relatively
    > smooth animation. I have a class VideoPanel that you can see below and
    > a separate Thread that calls "repaint" on the VideoPanel 15 times a
    > second. Now, the VideoPanel actually repaints when it wants to, so I
    > get about 1 frame a second and I see about every 15th frame. What's
    > the right way to fix this?
    >


    The method I use is to have SwingWorker handle the frame updates. Each frame is
    displayed using JLabel.setImage(). To update the frame I display the image in a
    method wrapped in EventQueue.InvokeAndWait() to ensure it's performed on the
    EDT, and completed before the SwingWorker thread attempts to display the next
    image. All the SwingWorker does is loop calling this method, and insert the
    appropriate delay between each frame.

    In my applet I manage to get about 20 frames per second using this method, but
    my objectives are neither speed nor smoothness. Each frame is a 707x500 raw
    ionogram, and all its intended to provide is an animated sequence of the data
    for quickly assessing the ionosphere during any particular day.

    If you want to see how it works there is an applet here:
    http://www.ion.le.ac.uk/cgi-bin/ionogram/day_gifs.php?Latest=1


    --
    Nigel Wade
    Nigel Wade, Oct 8, 2008
    #4
  5. John B. Matthews wrote:
    > In article <48ec18ba$0$13463$>,
    > Knute Johnson <> wrote:
    >
    >> Aaron Fude wrote:
    >>> Hi,
    >>>
    >>> I'm 100% sure that this is an FAQ, but I can't seem to find answer.
    >>>
    >>> Let's say I have 150 BufferedImages and I want to spit them out to a
    >>> JPanel at a rate of 15fps so I can have 10 seconds of relatively
    >>> smooth animation. I have a class VideoPanel that you can see below and
    >>> a separate Thread that calls "repaint" on the VideoPanel 15 times a
    >>> second. Now, the VideoPanel actually repaints when it wants to, so I
    >>> get about 1 frame a second and I see about every 15th frame. What's
    >>> the right way to fix this?
    >>>
    >>> public class VideoPanel extends JPanel {
    >>> public void paint(Graphics g) {
    >>> super.paint(g);
    >>> Image img = myImages[myCurrentFrame];
    >>> int w = img.getWidth(this);
    >>> int h = img.getHeight(this);
    >>> g.drawImage(img, 0, 0, w, h, 0, 0, w, h, this);
    >>> }
    >>> }
    >>>
    >>>
    >>> My Thread class is this:
    >>>
    >>> public class Animate extends Thread {
    >>> public void run() {
    >>> while (true) {
    >>> myVideoPanel.repaint();
    >>> myCurrentFrame = (myCurrentFrame +1)%myImages.length;
    >>> try {
    >>> sleep(1000/15);
    >>> }
    >>> catch (Exception e) {
    >>> e.printStackTrace();
    >>> }
    >>> }
    >>> }
    >>> }

    >> Well you have to be sure that your computer can run that fast with
    >> images of that size. If you think it can then there are some things you
    >> can do to prevent the write coalescing with repaint(). First don't use
    >> repaint() because it will write coalesce. Call paintImmediately() from
    >> the EDT.
    >>
    >> public void run() {
    >> while (true) {
    >> try {
    >> Thread.sleep(66);
    >> } catch (InterruptedException ie) { }
    >>
    >> // increment counter or whatever you are using to point
    >> // to the next picture
    >>
    >> try {
    >> EventQueue.invokeAndWait(new Runnable() {
    >> public void run() {
    >> paintImmediately(0,0,getWidth(),getHeight());
    >> }
    >> });
    >> } catch (Exception e) {
    >> e.printStackTrace();
    >> }
    >> }
    >> }
    >>
    >> Use paintComponent() instead of paint() to do your drawing on Swing
    >> components. If you are drawing the whole component or redrawing the
    >> complete background I would suggest that you NOT call
    >> super.paintComponent().
    >>
    >> There are numerous methods to get faster drawing, clipping, active
    >> rendering, using a BufferStrategy or a VolatileImage. The newer the JRE
    >> you use the better video performance you are going to get. Also, video
    >> cards play a big role. Windows is much faster than Linux as well.
    >>
    >> Another thing to keep in mind is that 150 images of any significant size
    >> will use a lot of memory.

    >
    > I'm Knute's student in this realm, but I'll venture two additions:
    >
    > First, consider pre-scaling your BufferedImages to the size of the
    > destination; drawImage() won't have to scale and the observer parameter
    > can be null.
    >
    > Second, consider javax.swing.Timer. It invokes the listener on the EDT
    > and degrades gracefully by coalescing if you overrun the interval on a
    > slower machine. Here's a simple example:
    >
    > <http://sites.google.com/site/drjohnbmatthews/subway>
    >
    > Of course, Knute's other optimizations (e.g. paintImmediately) would
    > still apply.
    >


    John's suggestion of the javax.swing.Timer is a good one. It is usually
    smoother than java.util.Timer and the code in the event listener is
    already running on the EDT.

    One of the things that can happen especially when you are redrawing the
    whole component is that once it gets started coalescing it will
    sometimes coalesce many more frames than you want. I think this is
    caused partly by the overhead of the coalesce, while faster than drawing
    it isn't free. Throw in some system overhead and you can get a
    situation where it draws a couple of frames, skips several, draws a
    couple more and skips again.

    If you draw the images synchronously, with paintImmediately() for
    example, on a slow computer the presentation will be slow but the whole
    story will appear.

    Remember that paintImediately() needs to be called from the EDT while
    repaint() may be called from any thread.

    --

    Knute Johnson
    email s/nospam/knute2008/

    --
    Posted via NewsDemon.com - Premium Uncensored Newsgroup Service
    ------->>>>>>http://www.NewsDemon.com<<<<<<------
    Unlimited Access, Anonymous Accounts, Uncensored Broadband Access
    Knute Johnson, Oct 8, 2008
    #5
  6. Nigel Wade wrote:
    > Aaron Fude wrote:
    >
    >> Hi,
    >>
    >> I'm 100% sure that this is an FAQ, but I can't seem to find answer.
    >>
    >> Let's say I have 150 BufferedImages and I want to spit them out to a
    >> JPanel at a rate of 15fps so I can have 10 seconds of relatively
    >> smooth animation. I have a class VideoPanel that you can see below and
    >> a separate Thread that calls "repaint" on the VideoPanel 15 times a
    >> second. Now, the VideoPanel actually repaints when it wants to, so I
    >> get about 1 frame a second and I see about every 15th frame. What's
    >> the right way to fix this?
    >>

    >
    > The method I use is to have SwingWorker handle the frame updates. Each frame is
    > displayed using JLabel.setImage(). To update the frame I display the image in a
    > method wrapped in EventQueue.InvokeAndWait() to ensure it's performed on the
    > EDT, and completed before the SwingWorker thread attempts to display the next
    > image. All the SwingWorker does is loop calling this method, and insert the
    > appropriate delay between each frame.
    >
    > In my applet I manage to get about 20 frames per second using this method, but
    > my objectives are neither speed nor smoothness. Each frame is a 707x500 raw
    > ionogram, and all its intended to provide is an animated sequence of the data
    > for quickly assessing the ionosphere during any particular day.
    >
    > If you want to see how it works there is an applet here:
    > http://www.ion.le.ac.uk/cgi-bin/ionogram/day_gifs.php?Latest=1
    >
    >


    Nice applet Nigel. I'm curious how you get your soundings?

    --

    Knute Johnson
    email s/nospam/knute2008/

    --
    Posted via NewsDemon.com - Premium Uncensored Newsgroup Service
    ------->>>>>>http://www.NewsDemon.com<<<<<<------
    Unlimited Access, Anonymous Accounts, Uncensored Broadband Access
    Knute Johnson, Oct 8, 2008
    #6
  7. In article <48ece777$0$28835$>,
    Knute Johnson <> wrote:

    > John B. Matthews wrote:
    > > In article <48ec18ba$0$13463$>,
    > > Knute Johnson <> wrote:
    > >
    > >> Aaron Fude wrote:
    > >>> Hi,
    > >>>
    > >>> I'm 100% sure that this is an FAQ, but I can't seem to find answer.
    > >>>
    > >>> Let's say I have 150 BufferedImages and I want to spit them out to a
    > >>> JPanel at a rate of 15fps so I can have 10 seconds of relatively
    > >>> smooth animation. I have a class VideoPanel that you can see below and
    > >>> a separate Thread that calls "repaint" on the VideoPanel 15 times a
    > >>> second. Now, the VideoPanel actually repaints when it wants to, so I
    > >>> get about 1 frame a second and I see about every 15th frame. What's
    > >>> the right way to fix this?
    > >>>
    > >>> public class VideoPanel extends JPanel {
    > >>> public void paint(Graphics g) {
    > >>> super.paint(g);
    > >>> Image img = myImages[myCurrentFrame];
    > >>> int w = img.getWidth(this);
    > >>> int h = img.getHeight(this);
    > >>> g.drawImage(img, 0, 0, w, h, 0, 0, w, h, this);
    > >>> }
    > >>> }
    > >>>
    > >>>
    > >>> My Thread class is this:
    > >>>
    > >>> public class Animate extends Thread {
    > >>> public void run() {
    > >>> while (true) {
    > >>> myVideoPanel.repaint();
    > >>> myCurrentFrame = (myCurrentFrame +1)%myImages.length;
    > >>> try {
    > >>> sleep(1000/15);
    > >>> }
    > >>> catch (Exception e) {
    > >>> e.printStackTrace();
    > >>> }
    > >>> }
    > >>> }
    > >>> }
    > >> Well you have to be sure that your computer can run that fast with
    > >> images of that size. If you think it can then there are some things you
    > >> can do to prevent the write coalescing with repaint(). First don't use
    > >> repaint() because it will write coalesce. Call paintImmediately() from
    > >> the EDT.
    > >>
    > >> public void run() {
    > >> while (true) {
    > >> try {
    > >> Thread.sleep(66);
    > >> } catch (InterruptedException ie) { }
    > >>
    > >> // increment counter or whatever you are using to point
    > >> // to the next picture
    > >>
    > >> try {
    > >> EventQueue.invokeAndWait(new Runnable() {
    > >> public void run() {
    > >> paintImmediately(0,0,getWidth(),getHeight());
    > >> }
    > >> });
    > >> } catch (Exception e) {
    > >> e.printStackTrace();
    > >> }
    > >> }
    > >> }
    > >>
    > >> Use paintComponent() instead of paint() to do your drawing on Swing
    > >> components. If you are drawing the whole component or redrawing the
    > >> complete background I would suggest that you NOT call
    > >> super.paintComponent().
    > >>
    > >> There are numerous methods to get faster drawing, clipping, active
    > >> rendering, using a BufferStrategy or a VolatileImage. The newer the JRE
    > >> you use the better video performance you are going to get. Also, video
    > >> cards play a big role. Windows is much faster than Linux as well.
    > >>
    > >> Another thing to keep in mind is that 150 images of any significant size
    > >> will use a lot of memory.

    > >
    > > I'm Knute's student in this realm, but I'll venture two additions:
    > >
    > > First, consider pre-scaling your BufferedImages to the size of the
    > > destination; drawImage() won't have to scale and the observer parameter
    > > can be null.
    > >
    > > Second, consider javax.swing.Timer. It invokes the listener on the EDT
    > > and degrades gracefully by coalescing if you overrun the interval on a
    > > slower machine. Here's a simple example:
    > >
    > > <http://sites.google.com/site/drjohnbmatthews/subway>
    > >
    > > Of course, Knute's other optimizations (e.g. paintImmediately) would
    > > still apply.

    >
    > John's suggestion of the javax.swing.Timer is a good one. It is usually
    > smoother than java.util.Timer and the code in the event listener is
    > already running on the EDT.
    >
    > One of the things that can happen especially when you are redrawing
    > the whole component is that once it gets started coalescing it will
    > sometimes coalesce many more frames than you want. I think this is
    > caused partly by the overhead of the coalesce, while faster than
    > drawing it isn't free. Throw in some system overhead and you can get
    > a situation where it draws a couple of frames, skips several, draws a
    > couple more and skips again.
    >
    > If you draw the images synchronously, with paintImmediately() for
    > example, on a slow computer the presentation will be slow but the
    > whole story will appear.


    Ah, thank you for clarifying this. Nothing is lost when I lose a frame
    or two in my simple motion simulation; in contrast, a dropped frame in
    Nigel's ionogram applet may be a significant extreme, lasting some
    portion of the sampling interval.

    No one-size-fits-all.

    > Remember that paintImediately() needs to be called from the EDT while
    > repaint() may be called from any thread.


    --
    John B. Matthews
    trashgod at gmail dot com
    home dot woh dot rr dot com slash jbmatthews
    John B. Matthews, Oct 8, 2008
    #7
  8. Aaron Fude

    Nigel Wade Guest

    Knute Johnson wrote:


    >>

    >
    > Nice applet Nigel. I'm curious how you get your soundings?
    >


    We have an ionosonde located on Svalbard, at our radar site near Longyearbyen
    between the EISCAT site and mine 7. Normally it takes a sounding every 4 mins.
    That data is transferred back to our web server, a jpg image is produced and
    put on the web. The applet makes a CGI request to the web server which responds
    with a ZIP file containing one days images. The "movie" just displays those
    images in sequence.

    The applet was developed to replace the QuickTime movie which we used to
    produce. QT had the advantage over most other (all other?) movie formats in
    that it allowed you to single step frames forward and backward and drag the
    frame pointer to any location in the movie. Something which is not really
    needed for movies, but is what we wanted for viewing data images. When we
    switched from IRIX to Linux we lost the ability to convert a sequence of JPGs
    to a QT movie. Hence the applet.

    Unfortunately we have lost funding for both the radar and the ionosonde and the
    service will cease next year (I think its next year). The UK govt. (or at least
    its funded research councils) don't consider Solar Terrestrial physics to be of
    any importance any more. After all why do we care about the Sun-Earth energy
    budget or understanding the onset of geomagnetic storms which can wipe out
    satellites like GPS? They think the tax payer who funds the research is much
    more interested in finding the Higgs Boson, because that's going to
    revolutionise their lives. But that's another story...

    --
    Nigel Wade
    Nigel Wade, Oct 9, 2008
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Big Daddy

    Java 1.2 Swing vs. Java 1.5 Swing

    Big Daddy, Apr 15, 2005, in forum: Java
    Replies:
    2
    Views:
    495
    Pete Barrett
    Apr 16, 2005
  2. mkrause
    Replies:
    0
    Views:
    669
    mkrause
    May 6, 2005
  3. lizard
    Replies:
    0
    Views:
    1,761
    lizard
    Jan 30, 2006
  4. S.T
    Replies:
    2
    Views:
    576
  5. Replies:
    3
    Views:
    150
    Jambalaya
    Oct 12, 2005
Loading...

Share This Page