为了账号安全,请及时绑定邮箱和手机立即绑定

动画定时paintComponent顶部的JButton

动画定时paintComponent顶部的JButton

牛魔王的故事 2021-08-25 10:23:41
我有一个 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);                }            }            }        }    };  
查看完整描述

3 回答

?
Cats萌萌

TA贡献1805条经验 获得超9个赞

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

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

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

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

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


查看完整回答
反对 回复 2021-08-25
?
Helenr

TA贡献1780条经验 获得超3个赞

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


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 所依赖的状态可能会产生意外且难以诊断的结果。


在这种情况下,您有两种选择,根据您的需要使用 SwingTimer或 a SwingWorker。


查看Swing中的并发以获取更多详细信息


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


该文档的状态


 公共无效旋转(双θ,

                   双锚x,

                   双锚) 

将此变换与围绕锚点旋转坐标的变换连接起来。这个操作相当于平移坐标,使锚点在原点(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的旋转角度

anchory-旋转锚点的 X 坐标 - 旋转锚点的 Y 坐标


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


使用 Graphics#create

//img1.sycdn.imooc.com//6125a9ec0001576702360235.jpg

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();

        }


    }


}

不使用 Graphics#create

//img1.sycdn.imooc.com//6125aa06000110ce04620473.jpg

哦,哦,我的按钮在哪里 - 根据您对Graphics上下文所做的更改,可能围绕容器的中心点旋转了 90 度,所以现在它们可能不在屏幕上



查看完整回答
反对 回复 2021-08-25
?
临摹微笑

TA贡献1982条经验 获得超2个赞

我已经转移到 JLayeredPane 以获得我正在寻找的效果。我可以点击顶层并拖动底层。

//img1.sycdn.imooc.com//6125aa370001ab8119171083.jpg

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


查看完整回答
反对 回复 2021-08-25
  • 3 回答
  • 0 关注
  • 183 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信