Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 968245
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 16, 20262026-05-16T02:26:52+00:00 2026-05-16T02:26:52+00:00

Continuing from a previous question , I keep searching for the optimal way to

  • 0

Continuing from a previous question, I keep searching for the optimal way to combine active rendering with textfields in Java. I tried several options, using BufferStrategy, VolatileImage or overriding update() and paint() in standard AWT, but I ended up using Swing.

I’m posting the current state of affairs here just in case someone happens to have new insights based on my code example, and perhaps others who are working on a similar app might benefit from my findings.

The target is to accomplish these three feats:

  • render an animating object on top of a background buffer that is updated only when necessary
  • use textfields on top of the rendered result
  • resize the window without problems

Below is the code of the demo application developed with the great help of stackoverflower trashgod.
Two notes:

1) Refreshing strictly the area that is invalidated by the previous step in the animation appears to be so much prone to visual errors that I gave up on it. This means I now redraw the entire background buffer every frame.

2) The efficiency of drawing a BufferedImage to screen is hugely dependent on the platform. The Mac implementation doesn’t seem to support hardware acceleration properly, which makes repainting the background image to the output window a tedious task, depending of course on the size of the window.

I found the following results on my 2.93 GHz dualcore iMac:

Mac OS 10.5:
640 x 480: 0.9 ms, 8 – 9%
1920 x 1100: 5 ms, 35 – 40%

Windows XP:
640 x 480: 0.05 ms, 0%
1920 x 1100: 0.05 ms, 0%

Legend:
screen size: average time to draw a frame, CPU usage of the application.

As far as I can see, the code below is the most efficient way of accomplishing my goals. Any new insights, optimizations or test results are very welcome!

Regards,
Mattijs

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;

public class SwingTest extends JPanel implements 
 ActionListener, 
 Runnable 
{
 private static final long serialVersionUID = 1L;

 private BufferedImage backgroundBuffer;
    private boolean repaintbackground = true;

    private static final int initWidth = 640;
    private static final int initHeight = 480;
    private static final int radius = 25;
    private final Timer t = new Timer(20, this);
    private final Rectangle rect = new Rectangle(); 

    private long totalTime = 0;
    private int frames = 0;
    private long avgTime = 0;

    public static void main(String[] args) {
        EventQueue.invokeLater(new SwingTest());
    }

    public SwingTest() {
        super(true);
        this.setPreferredSize(new Dimension(initWidth, initHeight));
        this.setLayout(null);
        this.setOpaque(false);
        this.addMouseListener(new MouseHandler());
    }

    @Override
    public void run() {
        JFrame f = new JFrame("SwingTest");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.addComponentListener(new ResizeHandler());

/*      This extra Panel with GridLayout is necessary to make sure 
   our content panel is properly resized with the window.*/
        JPanel p = new JPanel(new GridLayout()); 
        p.add(this);
        f.add(p);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);

        createBuffer();     
        t.start();
    }    

    @Override
    public void actionPerformed(ActionEvent e) {
        this.repaint();
    }    

    @Override
    protected void paintComponent(Graphics g) {
     long start = System.nanoTime();
     super.paintComponent(g);

     if (backgroundBuffer == null) createBuffer();
     if (repaintbackground) {

/*   Repainting the background may require complex rendering operations, 
   so we don't want to do this every frame.*/       
      repaintBackground(backgroundBuffer);
            repaintbackground = false;
     }

/*  Repainting the pre-rendered background buffer every frame
       seems unavoidable. Previous attempts to keep track of the 
       invalidated area and repaint only that part of the background buffer 
       image have failed. */
     g.drawImage(backgroundBuffer, 0, 0, null);
     repaintBall(g, backgroundBuffer, this.getWidth(), this.getHeight());
     repaintDrawTime(g, System.nanoTime() - start);
    }

    void repaintBackground(BufferedImage buffer) {    
     Graphics2D g = buffer.createGraphics();
  int width = buffer.getWidth();
  int height = buffer.getHeight();

  g.clearRect(0, 0, width, height);
  for (int i = 0; i < 100; i++) {
   g.setColor(new Color(0, 128, 0, 100));
   g.drawLine(width, height, (int)(Math.random() * (width - 1)), (int)(Math.random() * (height - 1)));
  }
    }

    void repaintBall(Graphics g, BufferedImage backBuffer, int width, int height) {
     double time = 2* Math.PI * (System.currentTimeMillis() % 3300) / 3300.;
        rect.setRect((int)(Math.sin(time) * width/3 + width/2 - radius), (int)(Math.cos(time) * height/3 + height/2) - radius, radius * 2, radius * 2);

        g.setColor(Color.BLUE);
        g.fillOval(rect.x, rect.y, rect.width, rect.height);
    }

    void repaintDrawTime(Graphics g, long frameTime) {
     if (frames == 32) {avgTime = totalTime/32; totalTime = 0; frames = 0;}
     else {totalTime += frameTime; ++frames; }
     g.setColor(Color.white);
     String s = String.valueOf(avgTime / 1000000d + " ms");
        g.drawString(s, 5, 16);
    }

    void createBuffer() {
        int width = this.getWidth();
        int height = this.getHeight();

        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice gs = ge.getDefaultScreenDevice();
        GraphicsConfiguration gc = gs.getDefaultConfiguration();
        backgroundBuffer = gc.createCompatibleImage(width, height, Transparency.OPAQUE);        

        repaintbackground = true;
    }    

    private class MouseHandler extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent e) {
            super.mousePressed(e);
            JTextField field = new JTextField("test");
            Dimension d = field.getPreferredSize();
            field.setBounds(e.getX(), e.getY(), d.width, d.height);
            add(field);
        }
    }

    private class ResizeHandler extends ComponentAdapter {

     @Override
     public void componentResized(ComponentEvent e) {
      super.componentResized(e);
      System.out.println("Resized to " + getWidth() + " x " + getHeight());
      createBuffer();
     }    
    }
}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-16T02:26:52+00:00Added an answer on May 16, 2026 at 2:26 am

    I have a few observations:

    1. Your improved repaintDrawTime() is very readable, but it is a micro-benchmark and subject to the vagaries of the host OS. I can’t help wondering if the XP results are an artifact of that system’s limited clock resolution. I see very different results on Windows 7 and Ubuntu 10.

    2. If you don’t use a null layout, you won’t need the extra panel; the default layout for JPanel is FlowLayout, and f.add(this) simply adds it to the center of the frame’s default BorderLayout.

    3. Repeated constructor invocations can be time consuming.

      Consider replacing

      g.setColor(new Color(0, 128, 0, 100));
      

      with

      private static final Color color = new Color(0, 128, 0, 100);
      ...
      g.setColor(color);
      

      Alternatively, a simple color lookup table, may be useful, e.g.

      private final Queue<Color> clut = new LinkedList<Color>();
      
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.