1

I have the following:

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JLayeredPane;
import javax.swing.JFrame;
import javax.swing.BorderFactory;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
import java.awt.GridLayout;
import java.awt.Dimension;
import java.awt.Color;
import java.util.Random;

class Cell extends JLayeredPane
{
    private JLabel image1;
    private JLabel image2;
    private JLabel image3;

    private Random rand;

    public static int CELLHEIGHT = 22;
    public static int CELLWIDTH = 22;

    public Cell ()
    {
        setPreferredSize (new Dimension (CELLWIDTH, CELLHEIGHT));
        setOpaque (true);
        setBackground (Color.LIGHT_GRAY);
        setBorder (BorderFactory.createLineBorder (Color.BLACK, 1));
        setBounds (0, 0, CELLWIDTH, CELLHEIGHT);

        image1 = new JLabel (new ImageIcon (getClass ().getResource ("image1.png")));   //size is 20 x 20 pixels
        image2 = new JLabel (new ImageIcon (getClass ().getResource ("image2.jpg")));   //size is 20 x 20 pixels
        image3 = new JLabel (new ImageIcon (getClass ().getResource ("image3.jpg")));   //size is 20 x 20 pixels

        image1.setBounds (0, 0, 20, 20);
        image2.setBounds (0, 0, 20, 20);
        image3.setBounds (0, 0, 20, 20);

        add (image1, new Integer (0));
        add (image2, new Integer (1));
        add (image3, new Integer (2));
    }

    public void updateLayers ()
    {
        removeAll ();   //method from JLayeredPane

        add (image1, new Integer (2));
        add (image2, new Integer (1));
        add (image3, new Integer (0));

        repaint ();
    }
}

class MyPanel extends JPanel
{
    private Cell[][] cells;

    public MyPanel (int cellcount_rows, int cellcount_columns)
    {
        super ();

        setLayout (new GridLayout (cellcount_rows, cellcount_columns, 0, 0));

        cells = new Cell[cellcount_rows][cellcount_columns];    //results in about 500 Cell objects

        for (int i = 0; i < cellcount_rows; i++)
        {
            for (int j = 0; j < cellcount_columns; j++)
            {
                cells[i][j] = new Cell ();

                add (cells[i][j]);
            }
        }
    }
}

class MouseHandler implements MouseListener
{
    private MyPanel panel;

    public MouseHandler (MyPanel panel)
    {
        this.panel = panel;
    }

    public void mouseClicked (MouseEvent e)
    {
        Cell cell = (Cell) panel.getComponentAt (e.getX (), e.getY ());

        if (e.getButton () == MouseEvent.BUTTON1)
        {//some very fast (and irrelevant) cell modification goes here
            cell.updateLayers ();
        }
        else if (e.getButton () == MouseEvent.BUTTON3)
        {//some very fast (and irrelevant) cell modification goes here
            cell.updateLayers ();
        }
    }

    public void mouseEntered (MouseEvent e) { }
    public void mouseExited (MouseEvent e) { }
    public void mousePressed (MouseEvent e) { }
    public void mouseReleased (MouseEvent e) { }
}

public class GUI
{
    private JFrame mainframe;
    private MyPanel panel;

    private static final int ROWS = 20;
    private static final int COLS = 25;

    public GUI ()
    {
        mainframe = new JFrame ();
        mainframe.setSize (Cell.CELLWIDTH * COLS + 100, Cell.CELLHEIGHT * ROWS + 100);
        mainframe.setResizable (false);
        mainframe.setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE);
        panel = new MyPanel (ROWS, COLS);

        panel.addMouseListener (new MouseHandler (panel));

        mainframe.setLayout (null);
        panel.setBounds (20, 20, Cell.CELLWIDTH * COLS, Cell.CELLHEIGHT * ROWS);

        mainframe.add (panel);

        mainframe.setVisible (true);    
    }

    public static void main (String[] args)
    {
        javax.swing.SwingUtilities.invokeLater (new Runnable ()
        {
            public void run ()
            {
                GUI t = new GUI ();
            }
        });
    }
}

So basically I have a subclass of JPanel which contains in it about 500 objects of type Cell (which is subclass of JLayeredPane).

Basically, every time a user clicks on one of those components, that component re-organizes its layers and repaints itself.

The problem is that it is kind of slow and I can't figure out why. In about 50 % of cases, the user has to click more than once for it to work.

Maybe the repaint has a problem or maybe the getComponentAt fails in 50 % of cases. I don't know... And I have no idea how to solve it... Please help.

Radu Murzea
  • 10,724
  • 10
  • 47
  • 69
  • 3
    *"I'm sorry it's not actual code, but the actual code would be too much to be confortable to read."* For better help sooner, post an [SSCCE](http://sscce.org/). (And give the classes sensible names.) – Andrew Thompson Jan 25 '12 at 12:44
  • 1
    At the beginning you might start with explaining why would you need to repaint 500 objects at every click? I think the problem lies here not in the code. – mohdajami Jan 25 '12 at 12:58
  • @medopal it doesn't repaint all 500 objects. It repaints only one of them (the one on which the user clicks). – Radu Murzea Jan 25 '12 at 13:27
  • What medopal says sounds correct to me. You seem to have ~500 ImageIcons which will all be removed from the layered pane, re-added to the layered pane, then repainted with each click. Are all the images really visible? Does the order really change completely? Without an SSCCE, or at least some more informative sample code, it's impossible to for us to do more than guess! – vaughandroid Jan 25 '12 at 13:36
  • @Baqueta Ok, I updated the code. Don't know if it's compilable, though. – Radu Murzea Jan 25 '12 at 14:05
  • 1
    @SoboLAN I think you missed the compilable part of SSCCE. – AHungerArtist Jan 25 '12 at 14:18
  • @AHungerArtist Compile it and run it, it works now. I know it's usually very recommended to provide compilable/runnable code... I am sorry for not doing that from the beginning. – Radu Murzea Jan 25 '12 at 14:42
  • running your code, I can reproduce the need to click twice - iff I'm moving the mouse very quickly. But that has nothing to do with the painting, instead it's due the click not being fired if the mouse is moved between a pressed and released. Check if that could be the real reason in your context as well: move the re-ordering code into mousePressed – kleopatra Jan 26 '12 at 11:23
  • @kleopatra putting the code in mousePressed does indeed make the program feel more fluid, but it is not the behaviour I want. The components must change on mouse click, not on mouse press. But maybe I could do a combination of mousePressed and mouseReleased to achieve the desired goal... thank you :) . – Radu Murzea Jan 26 '12 at 12:10

1 Answers1

1

If you read the javadoc the repaint() function schedules a repaint to occur as soon as possible which obviously is not immediate.

Immediately after modifying the cell contents write this function as shown:

cell.paintComponent(cell.getGraphics());

This should immediately paint the contents of the cell :)

kidhuvig
  • 134
  • 5
  • Thank you very much, it runs a little faster now :) . I think if I can write a perfectly functional custom method to replace `getComponentAt`, everything will be perfect. – Radu Murzea Jan 25 '12 at 15:22
  • @kleopatra if you have a better solution, please post it :) . – Radu Murzea Jan 26 '12 at 12:23