Question

So I want to go through a loop to paint several rectangles to represent values in a graphical bar chart on a JPanel.

I have extended JPanel to include my painting commands and I have a loop which calls values from an array and paints them at points along the axis. However when I run my program it only paints the last one?

Does .repaint() resets my canvas? Is it simply repainting my buffered image and then only updating my panel when the loop is finished?

My extension of JPanel:

class myJPanel extends JPanel 
{

     private Rectangle2D.Double rectangle;

     /**
      * Override paintComnponent method with our draw commands
      * 
      */
     public void paintComponent(Graphics g) 
     {

         super.paintComponent(g);

         // Change the dimension and location of the rectangle 
         // obtained from the user interface.
         rectangle = new Rectangle2D.Double(iX, iY, iWidth, iHeight);

         // Set the drawing colour, then draw a filled rectangle
         // on the graphics context of the BufferedImage object
         g2dImg.setPaint(Color.black);
         g2dImg.fill(rectangle);


         // Transfer the image from the BufferedImage to the JPanel to make it visible.
         g.drawImage(img, 0, 0, null);
     }

     // super.paintComponent clears off screen pixmap,
     // since we're using double buffering by default.
     protected void clear(Graphics g) {
         super.paintComponent(g);

         // Also clear the BufferedImage object by drawing a white coloured filled rectangle all over.
         g2dImg.setPaint(Color.WHITE);
         g2dImg.fill(new Rectangle2D.Double(0, 0, img.getWidth(), img.getHeight()));
     }
}

Here is my panel code:

        final myJPanel jPanelDraw = new myJPanel();
        jPanelDraw.setLayout(new GridBagLayout());
        jPanelDraw.setBounds(248, 152, 604, 257);
        jPanelDraw.setBackground(Color.white);
        jPanelDraw.setEnabled(false);
        jPanelDraw.setPreferredSize(new Dimension(281, 155));
        jPanelDraw.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
        frmUSnowboarding.getContentPane().add(jPanelDraw);

        //Instantiate the BufferedImage object and give it the same width 
        // and height as that of the drawing area JPanel
        img = new BufferedImage(jPanelDraw.getWidth(), 
                                jPanelDraw.getHeight(), 
                                BufferedImage.TYPE_INT_RGB);

        //Get its graphics context. 
        g2dImg = (Graphics2D)img.getGraphics();

        //Draw a filled white coloured rectangle on the entire area to clear it.
        g2dImg.setPaint(Color.WHITE);
        g2dImg.fill(new Rectangle2D.Double(0, 0, img.getWidth(), img.getHeight()));

And here's my loop which is within the action listener for my draw button:

            for (int iI = 0; iI < 6; iI++) {
                iHeight = (double) iaRun1[iI];
                iX = 0 + (iI * 40);
                iY = (double) (jPanelDraw.getHeight() - iHeight);
                jPanelDraw.repaint();
            }
Was it helpful?

Solution

It's not that it only repaints once, it's that it only repaints after the loop ends.

The repaint method doesn't repaint immediately, instead it marks the panel to be repainted as soon as possible (but not right now).

Swing does not use threads, so only thing can run at a time. There are a lot of tasks Swing does behind the scenes, in-between calling your listeners, and one of those tasks is repainting windows that need to be repainted. Swing will not repaint a window while your listener is running.

Also, even if repaint did repaint immediately, the animation would happen too fast for anyone to notice.

OTHER TIPS

You're probably running that code in the event dispatch thread in which case the UI won't repaint until after the loop. If you'd debug your code you'd find that jPanelDraw.repaint(); is called multiple times but the actual update of the UI is put into the same event queue that is being blocked by your loop.

Try executing that loop in a SwingWorker or Timer instead.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top