JButton在Animated Timed paintComponent之上

问题描述 投票:-1回答:3

我有一个BVH播放器有9个视图,可以在计时器上设置动画,我试图在每个面板上放置控件来单独控制变换操作。 按钮正在我的paintComponent后面呈现,但有时可以单击。我还有一个MouseListener来调整骨架的变换,有时它可以工作。我可以发布听众,但我认为这不重要。

我尝试过各种graphics.dispose和graphics2d.dispose的组合,我尝试用奇怪的结果改变super.paintComponent(g)的位置,但没什么好处的。 以下是显示问题的视频。如果仔细观察,当你将鼠标悬停在它们应该的位置时,你会看到按钮弹出。你还会看到,当我g.dispose()时,它在两个地方的按钮变得陌生,但只在一个地方点击(这不是它们最明显的地方)。 https://youtu.be/CyFpUlbFI1U 这是我的源代码:

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"));
}

这是计时器:

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;
    }
}
java jpanel paintcomponent jcomponent bounding-volume
3个回答
0
投票

如果仔细观察,当你将鼠标悬停在它们应该的位置时,你会看到按钮弹出。

这意味着您有一个ZOorder问题。 ZOrder是组件在z轴上彼此堆叠时被绘制的顺序。

Swing以与组件添加到面板相反的顺序绘制组件,因此添加的最后一个组件首先被绘制。所以听起来你有多个面板堆叠在一起,你添加的最后一个面板包含按钮,但它首先被绘制,所以其他面板都涂在它上面。

当鼠标移动到按钮上时,按钮需要重新绘制以显示按钮的滚动效果,因此当重新建立正确的ZOrder时,按钮会暂时被绘制在顶部直到下一次重新绘制父面板。

我不太了解你的程序的结构,但我会质疑为什么你有一堆面板堆叠在一起。您只需要一个带有自定义绘画的面板,然后将按钮放在此面板上。


0
投票

你的主要问题就在这里......

Graphics2D g2d = (Graphics2D) g;
g2d.translate(getWidth() / 2, getHeight() / 2);

AffineTransform at = AffineTransform.getTranslateInstance(0, 0);

传递给组件的Graphics上下文是一个共享资源,它被传递给在绘制周期中绘制的所有组件,这意味着当您更改原点和旋转之类的内容时,它会影响在其后绘制的所有组件。

相反,您应该在应用更改之前创建Graphics状态的副本,这会使原始状态保持不变

Graphics2D g2d = (Graphics2D) g.create();
g2d.translate(getWidth() / 2, getHeight() / 2);

AffineTransform at = AffineTransform.getTranslateInstance(0, 0);
//...
g2d.dispose();   

你的第二个错误是......

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

Swing不是线程安全的,并且更新UI或UI所依赖的状态可能会产生意外且难以诊断的结果。

在这种情况下,您有两种选择,根据您的需要使用Swing TimerSwingWorker

请查看Concurrency in Swing了解更多详情

另一个问题是at.rotate(Math.toRadians(90), Math.toRadians(90), Math.toRadians(90));。这根本没有意义。

documentation

 public void rotate​(double theta,
                   double anchorx,
                   double anchory) 

将此变换与围绕锚点旋转坐标的变换连接。此操作等效于平移坐标以使锚点位于原点(S1),然后围绕新原点(S2)旋转它们,最后进行平移以使中间原点恢复到原始锚点的坐标(S3)。此操作等效于以下调用序列:

 translate(anchorx, anchory);      // S3: final translation
 rotate(theta);                    // S2: rotate around anchor
 translate(-anchorx, -anchory);    // S1: translate anchor to origin   Rotating by a positive angle theta rotates points on the

正X轴朝向正Y轴。另请注意上面处理90度旋转的讨论。 参数: theta - 以弧度为单位测量的旋转角度 anchorx - 旋转锚点的X坐标 anchory - 旋转锚点的Y坐标

这就是说,第二个和第三个参数实际上是旋转发生的点。在你的情况下,at.rotate(Math.toRadians(90), 0, 0);可能是你真正想要的。

Using Graphics#create

Happy, happy, joy, joy

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private double angle;

        public TestPane() {
            setLayout(new GridBagLayout());
            for (int index = 0; index < 5; index++) {
                add(new JButton("Here"));
            }

            Timer timer = new Timer(5, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    angle += 0.01;
                    repaint();
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            //Graphics2D g2d = (Graphics2D) g;
            g2d.translate(getWidth() / 2, getHeight() / 2);

            AffineTransform at = AffineTransform.getTranslateInstance(0, 0);
            at.rotate(Math.toRadians(90), 0, 0);
            g2d.drawRect(-50, -50, 100, 100);
            g2d.setColor(Color.RED);
            g2d.rotate(angle, 0, 0);
            g2d.drawRect(-100, -100, 200, 200);
            g2d.dispose();
        }

    }

}

Not using Graphics#create

Boowho

哦哦,哪里有我的按钮 - 可能围绕容器的中心点旋转90度,根据你对Graphics上下文的变化,所以现在他们可能在屏幕外


0
投票

我已经转移到JLayeredPane以获得我正在寻找的效果。我可以点击顶层并拖动底层。 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));
© www.soinside.com 2019 - 2024. All rights reserved.