PaintComponent Java Slow

1.6k Views Asked by At

I have been developing on my Mac a JAVA Applications . The logic is as follows:

  1. A Server sends to a client application some orders to Draw basic shapes
  2. The client applications draws the the basic shapes into a Jpanel

Every Time a Shape arrives the program calls repaint()

 public void paintShape(Shape p) 
{
    //this.paintComponent(this.getGraphics());
   arrayofShapes.add(p);
   this.repaint();
    //this.updateUI();
    //this.update(this.getGraphics());

}
public void paintComponent(Graphics g) 
{ 
    super.paintComponent(g);
    g2d = (Graphics2D) g.create();
    g2d.setStroke(new BasicStroke(2));
    g2d.setColor(pickedColor);
    for(final Shape p : arrayofShapes)
    {
        g2d.draw(p);
    }
    //g2d.dispose();

}

Everything works smoothly(on real time) , so I decided to test the same application on a Windows computer. The result is a laggy application. These are the conclusion that I have reached.

  • RepaintManager is accumulating repaint() calls. I see how the shapes arrive at destination but in some cases more than 5 repaint calls are accumulated into one, which make the application very lagged/not real Time.

I have tried instead of calling repaint every time a shape arrives to do it with a Timer every few milliseconds, the result is the same. Code :

ActionListener listener = new ActionListener(){
          public void actionPerformed(ActionEvent event){
            repaint();
          }
        };

Timer displayTimer = new Timer(5, listener);
displayTimer.start();

In addition i have tested some random code that allows you to paint with the mouse, same logic as mine with paintComponent. In this case it work smoothly without sense of lag.... Example: http://javagraphics.blogspot.com.es/2010/06/shapes-implementing-freehand-pencil.html

I do not understand why paintComponent is so slow on my Windows Computer(same Jar). What could be affecting the performance of my program?

I have read all the answers regarding paint Components but any of them has solved this issue.

Any advice on how could I solve the problem and actually archive Real-Time?

Thank you in advance

Update Videos:

Mac Video:https://youtu.be/OhNXdGXoQpk real Time no problem handling heavy load

Windows Video https://youtu.be/yol2miHudZc clearly laggy

I apologize for the low quality

Update BufferedImage:

After introducing the BufferedImage the result is still a slow painting Application. It creates another problem, since one of the orders is to delete all shapes, it adds some complexity since I have to do a :

 g2d.clearRect(0, 0, screenSize.width, screenSize.height);

HW/OS/JavaVersion

Windows

  • Processor i5-4300u 2.5ghz
  • Ram 12gb
  • Java version 1.7.0_71

MAC

  • Processor i7 2.9ghz
  • Ram 8gb
  • Java version 1.7.0_67

Java VisualVM

Video of live VisualVM:https://youtu.be/cRNX4b3rlZk

I do not see anything strange that could explain why the lag occurs but I'm far from being an expert(Again sorry for low quality)

Thank you for all your responses

3

There are 3 best solutions below

3
On

There's no need to create() a new graphics context each time; just cast g to Graphics2D. This is safe on all concrete implementations. This also obviates the need to dispose() of the created context. As noted here, preserve any context variables that may be critical for later painting.

public void paintComponent(Graphics g) { 
    super.paintComponent(g);
    g2d = (Graphics2D) g;
    Stroke oldStroke = g2d.getStroke();
    g2d.setStroke(new BasicStroke(2));
    g2d.setColor(pickedColor);
    for(final Shape p : arrayofShapes) {
        g2d.draw(p);
    }
    g2d.setStroke(oldStroke);
}

Also, compare the profiles on both platforms to look for disparities. For reference, the example cited here comfortably handles selections containing hundreds of shapes on either platform.

4
On

I would recommend that you do static drawing to a BufferedImage, and then draw the BufferedImage in your paintComponent method.

e.g.,

private BufferedImage bufferedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, BufferedImage.TYPE_INT_ARGB);

public void paintShape(Shape p) {
    Graphics2D g2 = bufferedImage.createGraphics();
    g2d.setStroke(MY_STROKE); // make this a constant
    g2d.setColor(pickedColor);
    g2d.draw(p);
    g2d.dispose();
    this.repaint();
}

public void paintComponent(Graphics g) { 
    super.paintComponent(g);
    if (bufferedImage != null) {
       g2.drawImage(bufferedImage, 0, 0, null);
    }
    // do dynamic drawing such as drawing of moving sprites here
}
1
On

After more than two days of debugging I have found out that the problem has nothing to do with paintComponent()

With the same server generating random shapes

At the Windows app, some shapes are received at the same time which is impossible since I am sending shapes every 15 ms. That's why it accumulates shapes(result =lag).

On the other Hand at the Mac app, every shape has different time reception (result = real Time)

Thank you for the kind responses, and sorry for inconvenience I may have cause