javaswingjpanelpaintcomponentjcomponent

JButton on top of Animated Timed paintComponent


I have a BVH player that has 9 views that work on a timer to animate them and I'm trying to place controls on top of each panel to control transform operations individually.

The buttons are being rendered behind my paintComponent but can be clicked sometimes. I also have a MouseListener to adjust the transform of the skeleton and sometimes it works. I can post the listener, but I don't think it is important.

I've tried various combinations of graphics.dispose and graphics2d.dispose and I've tried changing the position of super.paintComponent(g) with weird results but nothing good.

Below is a video showing the problem. If you watch closely you'll see the buttons popping up when you hover over where they are supposed to be. You'll also see that when I g.dispose() it gets stranger with the buttons in two places but only clicking in one place (which is not where they are most visible). https://youtu.be/CyFpUlbFI1U

Here is my source code:

public SkeletonPlayer(int camera, double scale, int rotLeftRight, int rotUpDown, double translateLeftRight, double translateUpDown) {
    this.camera = camera;
    this.scale = scale;
    this.rotLeftRight = rotLeftRight;
    this.rotUpDown = rotUpDown;
    this.translateLeftRight = translateLeftRight;
    this.translateUpDown = translateUpDown;
    panel = new JPanel() {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.translate(getWidth() / 2, getHeight() / 2);

            AffineTransform at = AffineTransform.getTranslateInstance(0, 0);
            at.rotate(Math.toRadians(90), Math.toRadians(90), Math.toRadians(90));

            for (int n = 0; n < MainFrame.skeleton[camera].getNodes().size(); n++) {
                Node node = MainFrame.skeleton[camera].getNodes().get(n);
                int x1 = (int) (scale * node.getPosition().getX());
                int y1 = (int) (-scale * node.getPosition().getY());
                g2d.setColor(Color.RED);
                g2d.fillOval((int) (x1 - 2), (int) (y1 - 2), 4, 4);

                g2d.setColor(Color.BLACK);
                //g2d.drawString(node.getName(), x1 + 10, y1);

                for (Node child : node.getChildrens()) {
                    int x2 = (int) (scale * child.getPosition().getX());
                    int y2 = (int) (-scale * child.getPosition().getY());
                    g2d.drawLine(x1, y1, x2, y2);
                }
            }

            int x1 = (int) (scale * groundPlane.rootNode.getPosition().getX());
            int y1 = (int) (-scale * groundPlane.rootNode.getPosition().getY());
            g2d.setColor(Color.BLACK);
            g2d.fillOval((int) (x1 - 2), (int) (y1 - 2), 4, 4);

            for (int n = 1; n < groundPlane.nodes.size(); n++) {
                Node node = groundPlane.nodes.get(n);

                int x2 = (int) (scale * node.getPosition().getX());
                int y2 = (int) (-scale * node.getPosition().getY());
                g2d.setColor(Color.BLACK);
                g2d.fillOval((int) (x2 - 2), (int) (y2 - 2), 4, 4);

                g2d.setColor(Color.GREEN);

                g2d.drawLine(x1, y1, x2, y2);
                //System.out.println("line:" + x1 + "," + y1 + " " + x2 + "," + y2);
            }
        }
    };
    panel.addMouseListener(this);
    panel.addMouseMotionListener(this);
    panel.addMouseWheelListener(this);
    MigLayout layout = new MigLayout(
            "insets 10, gap 10, wrap", // Layout Constraints
            "[fill,grow][fill,grow][fill,grow]", // Column constraints with default align
            "[fill,grow][fill,grow][fill,grow]");
    panel.setLayout(layout);
    panel.add(new JButton("here"));
    panel.add(new JButton("here"));
    panel.add(new JButton("here"));
    panel.add(new JButton("here"));
    panel.add(new JButton("here"));
    panel.add(new JButton("here"));
    panel.add(new JButton("here"));
    panel.add(new JButton("here"));
    panel.add(new JButton("here"));
}

And here is the timer:

new Timer().scheduleAtFixedRate(new TimerTask() {

        @Override
        public void run() {
            update();
        }
    }, 0, (long) Math.round(motion.getFrameTime() * 1000));

private static void update() {
    for (int i = 0; i < NUM_SKELETON_PLAYERS; i++) {
        MainFrame.skeleton[i].setPose((int) frameIndex, i);
        skeletonPlayers[i].groundPlane.setPose(i);
        skeletonPlayers[i].panel.repaint();
    }
    //skeleton.setPose(null);
    frameIndex += 1;
    if (frameIndex > motion.getFrameSize() - 1) {
        frameIndex = 0;
    }
}

Solution

  • I've moved over to a JLayeredPane to get the effect I was looking for. I'm able to click through the top layer and drag the bottom layer. enter image description here

        LayerUI backgroundUI = new WallpaperLayerUI();
        jlayer = new JLayer<JPanel>(panel, backgroundUI);
    
        LayerUI controlsUI = new LayerUI();
        JPanel controlPanel = new JPanel();
        MigLayout layout = new MigLayout(
                "debug, insets 10, gap 10, wrap", // Layout Constraints
                "[fill,grow][fill,grow][fill,grow]", // Column constraints with default align
                "[fill,grow][fill,grow][fill,grow]");
        controlPanel.setLayout(layout);
        controlPanel.add(new JButton("here"));
        controlPanel.add(new JButton("here"));
        controlPanel.add(new JButton("here"));
        controlPanel.add(new JButton("here"));
        controlPanel.add(new JButton("here"));
        controlPanel.add(new JButton("here"));
        controlPanel.add(new JButton("here"));
        controlPanel.add(new JButton("here"));
        controlPanel.add(new JButton("here"));
    
        jlayer2 = new JLayer<JPanel>(controlPanel, controlsUI);
    
        panel.addMouseListener(this);
        panel.addMouseMotionListener(this);
        panel.addMouseWheelListener(this);
    
        finalPanel = new JLayeredPane();
        finalPanel.setPreferredSize(new Dimension(300, 310));
        //finalPanel.setLayout(null);
        jlayer.setBounds(0, 0, (808-40)/3, (608-40)/3);
        jlayer2.setBounds(0, 0, (808-80)/3, (608-80)/3);
        controlPanel.setBackground(new Color(0,0,0,0));
        finalPanel.add(jlayer, new Integer(0));
        finalPanel.add(jlayer2 ,new Integer(1));