javaswingrepaintawt-eventqueuecustom-painting

Draw Shapes on overlapping Panels, One panel Draw Stationary and another Draw Movable


I am creating Swing application. It is kind of road map with moving object application. I divide my shape components in two JPanels. One is static component JPanel, and second for dynamic component JPanel, and both added in mainPanel. Both panels are overlapped and for dynamic component panel the opaque is false to make it transparent. When I do repaint for dynamic component panel, it trigger repaint for static component panel also. I don't want to repaint the static component panel every time if there are changes in dynamic component panel's shape and static component panel shape should not be erased.

Currently my logic as below. It's pseudocode. Please help me how to draw movable component top of static component and draw static component once on startup.

public class layeredpanel extends JFrame
{

    private JPanel contentPane;


    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                try
                {
                    layeredpanel frame = new layeredpanel();
                    frame.setVisible(true);
                } catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public layeredpanel()
    {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 450, 300);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(new BorderLayout(0, 0));
        setContentPane(contentPane);

        JPanel panel = new JPanel();
        contentPane.add(panel, BorderLayout.CENTER);

        panel.setLayout( new OverlayLayout(panel) );


        final JPanel layer_1 = new layer1();

        layer_1.setOpaque(false);
        panel.add(layer_1);


        JPanel layer_2 = new layer2();      
        panel.add(layer_2);


        Thread thread = new Thread(new Runnable()
        {

            @Override
            public void run()
            {
                while(true)
                {try
                {
                    Thread.sleep(500);
                } catch (InterruptedException e)
                {

                    e.printStackTrace();
                }

                layer_1.repaint();
            }
            }
        });

        thread.start();



    }

    class layer1 extends JPanel
    {


        @Override
        public void paintComponent(Graphics g)
        {
            // TODO Auto-generated method stub
            super.paintComponent(g);
            System.out.println("Paint1");
            g.setColor(Color.blue);
            g.drawRect(30, 20, 40, 40);
        }

    }

    class layer2 extends JPanel
    {
        @Override
        public void paintComponent(Graphics g)
        {
            System.out.println("Paint2");
        // TODO Auto-generated method stub
        super.paintComponent(g);

        g.setColor(Color.green);
        g.fillRect(30, 20, 20, 20);}

    }
}

Output:Paint2

Paint1
Paint2
Paint1
Paint2
Paint1
Paint2
Paint1
Paint2
Paint1
Paint2
Paint1
Paint2
Paint1

Solution

  • This is the way Swing painting works. When you have a transparent panel the parent panel must also be painted to make sure there are no painting artifacts.

    To make the painting of the parent panel more efficient you could:

    1. Do the painting on a BufferedImage first (when you create your class) and then just repaint the BufferedImage.
    2. When you do a repaint of the top panel you can do repaint(....) to specify the Rectangular area to repaint. Then only that part of the parent panel is also repainted.

    Also, don't use a Thread with Thread.sleep() to do animation. If you want animation then use a Swing Timer to schedule the repainting.