旋转后图像不在正确的位置(图形)

2023-12-02

我试图以不同的速率显示两个直径为 512untis 的旋转轮,但我无法删除以前绘制的图像图形并将旋转的图形设置在正确的位置。 现在我正在以任意角度进行旋转。 我尝试了 affineTransform 并获得了旋转,但很奇怪,就像所有像素都散开一样。 我将 while 循环与 thread.sleep() 一起使用。以下是代码: //drawSmallCircle和drawBigCircle返回两个图像。

class MyFramePart2 extends JFrame

{ 

    String name;
    JPanel big_obj_panel,small_obj_panel;    
    JLabel bigLabel,smallLabel;BufferedImage imgRet,imgRetSmall;
    static double radians,angle,rev,fps,smallAngle,smallRadians;               
    int numLines,i=0;    

    MyFramePart2(String frameName,int numStrokes,double revolutions,double frameps)
    {       
        numLines=numStrokes;
        smallAngle=smallRadians=angle=radians=Math.toRadians(360/numLines);        
        rev=revolutions;
        fps=frameps; 

        setSize(1240,720);       
        setLocation(0,0);
        setLayout(null); 
        getContentPane().setBackground(Color.WHITE);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

        big_obj_panel=new JPanel();
        big_obj_panel.setLayout(null);
        big_obj_panel.setSize(512,512);
        big_obj_panel.setLocation(100,100); 
        big_obj_panel.setBackground(Color.white);
        add(big_obj_panel);   


        imgRet=drawBigCircle();
        bigLabel = new JLabel(new ImageIcon(imgRet));
        bigLabel.setLayout(null);        
        bigLabel.setLocation(0,0);
        bigLabel.setSize(512,512);
        bigLabel.setOpaque(true);
        bigLabel.setBackground(Color.white);  
        big_obj_panel.add(bigLabel);

        small_obj_panel=new JPanel();
        small_obj_panel.setLayout(null);
        small_obj_panel.setSize(512,512);
        small_obj_panel.setLocation(700,100); 
        small_obj_panel.setBackground(Color.white);
        add(small_obj_panel);   

        imgRetSmall=drawSmallCircle();

        smallLabel = new JLabel(new ImageIcon(imgRetSmall));
        smallLabel.setLayout(null);        
        smallLabel.setLocation(0,0);
        smallLabel.setSize(512,512);
        smallLabel.setOpaque(true);
        smallLabel.setBackground(Color.white);  
        small_obj_panel.add(smallLabel);

        setVisible(true);               

        while(i!=5) // suppose to be while true, just checking 
      {                 
        setVisible(true);          
        bigLabel.setIcon(new ImageIcon(imgRet));         
        smallLabel.setIcon(new ImageIcon(imgRetSmall));
        try{
        Thread.sleep(10);        
        }
        catch(Exception e)
        {}
        i++;               
     }                         
 }

    @Override
    public void paint(Graphics g)
    {        
        super.paint(g);
        Graphics2D g2d=(Graphics2D)g;           
        g2d.translate(256,256);
        g2d.rotate(Math.toRadians(20));                       
        g2d.translate(-256,-256); 
        g2d.drawImage(imgRet,0,0,null);
        g2d.dispose();        

        super.paint(g);
        g2d=(Graphics2D)g;
        g2d.translate(256,256);
        g2d.rotate(Math.toRadians(30));
        g2d.translate(-256,-256);        
        g2d.drawImage(imgRetSmall,0,0,null);        
        g2d.dispose();
    }

    public static BufferedImage drawBigCircle()
    {
        BufferedImage img=new BufferedImage(512,512,BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d=img.createGraphics();                
        g2d.setColor(Color.black);
        g2d.drawOval(0,0,511,511);

        Line2D l2d;
        while(angle <= 2*Math.PI)
        {
            l2d=new Line2D.Double(256,256,256+256*Math.cos(angle),256+256*Math.sin(angle));
            g2d.draw(l2d);
            angle=angle+radians;
        }               
        return img;
    }        
}

Swing 的第一条规则。不要阻塞事件调度线程。这样做会使您的应用程序看起来像是挂起的,并阻止 EDT 处理任何重绘请求。

这意味着,您需要某种方法来安排更新而不阻止 EDT

Swing 的第二条规则。不要从 EDT 之外的任何线程创建或修改任何 UI 组件。

一般来说,您应该避免覆盖paint顶级容器的方法,例如JFrame,除了其他一切之外,它们不是双缓冲的,这意味着您的绘画在更新时会闪烁。相反,您应该使用其中之一Swing容器,例如JPanel

有很多不同的方法可以实现这一目标。基本上,这里我使用了三个列表,但如果我认真的话,我会创建一个可以维护所有所需信息(图像、角度和增量)的对象

为了实现实际的动画,我使用了javax.swing.Timer。这将至少每隔一段时间触发一个事件n周期,但更重要的是,它是在事件调度线程的上下文中执行的。这确保了对角度所做的所有更改都以防止在我们更新值时发生任何绘画的可能性......

此示例以不同(随机)速度旋转三个图像......

enter image description here

public class TestRotation {

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

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

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new AnimationPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class AnimationPane extends JPanel {

        private List<BufferedImage> images;
        private List<Double> angles;
        private List<Double> speed;

        public AnimationPane() {
            images = new ArrayList<>(5);
            images.add(createWheel(50, 4));
            images.add(createWheel(50, 3));
            images.add(createWheel(50, 6));
            angles = new ArrayList<>();
            speed = new ArrayList<>();
            for (int index = 0; index < images.size(); index++) {
                angles.add(0d);
                speed.add(Math.random() * 5d);
            }

            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    for (int index = 0; index < angles.size(); index++) {
                        double angle = angles.get(index);
                        double delta = speed.get(index);
                        angle += delta;
                        angles.set(index, angle);
                    }
                    repaint();
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(true);
            timer.start();

        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            int x = 0;
            int y = 0;
            for (int index = 0; index < images.size(); index++) {
                BufferedImage image = images.get(index);
                double angle = angles.get(index);

                // This is important.  Basically we going to grab a isolated snap shot
                // of the current graphics context.  This means any changes we make
                // will not affect the original graphics context (other then painting)
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                AffineTransform at = new AffineTransform();
                at.translate(x, y);
                at.rotate(Math.toRadians(angle), image.getWidth() / 2, image.getHeight() / 2);
                g2d.setTransform(at);
                g2d.drawImage(image, 0, 0, this);
                g2d.dispose();

                x += image.getWidth();

            }
        }

    }

    protected Point2D calculateOutterPoint(int radius, double angel) {

        int x = Math.round(radius / 2);
        int y = Math.round(radius / 2);

        double rads = Math.toRadians((angel + 90));

        // This determins the length of tick as calculate from the center of
        // the circle.  The original code from which this derived allowed
        // for a varible length line from the center of the cirlce, we
        // actually want the opposite, so we calculate the outter limit first
        double fullLength = (radius / 2d);

        // Calculate the outter point of the line
        double xPosy = (x + Math.cos(rads) * fullLength);
        double yPosy = (y - Math.sin(rads) * fullLength);

        return new Point2D.Double(xPosy, yPosy);

    }

    public BufferedImage createWheel(int radius, int spokes) {
        BufferedImage img = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = img.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setColor(Color.black);
        g2d.drawOval(0, 0, radius - 1, radius - 1);

        Point2D center = new Point2D.Double(radius / 2d, radius / 2d);
        double angle = 360d / spokes;
        for (int index = 0; index < spokes; index++) {
            Point2D p = calculateOutterPoint(radius, index * angle);
            g2d.draw(new Line2D.Double(center, p));
        }

        g2d.dispose();
        return img;

    }

}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

旋转后图像不在正确的位置(图形) 的相关文章

随机推荐

  • 二叉搜索树中的有序后继者

    给定 BST 中的一个节点 如何找到下一个更高的密钥 一般方法取决于节点中是否有父链接 如果您存储父链接 然后你选择 如果当前节点有右子节点 则为右子节点的最左子节点 如果右孩子没有左孩子 那么右孩子就是你的顺序继承人 向上导航父祖先节点
  • 如何将数据聚合到范围(分桶)?

    我有一张像这样的桌子 id value 1 118 0 2 109 0 3 113 0 4 82 0 5 60 0 6 111 0 7 107 0 8 84 0 9 91 0 10 118 0
  • 寻求以更干净/更有效的方式将字符串与整数相关联

    我该如何改进这个 这种关系是一对一的并且在 1 5 上连续 所以我正在考虑使用枚举 但我不确定如何将字符串值与枚举值进行比较 如果有更好的方法可以做到这一点 请建议 Thanks private int evaluateWord Strin
  • Firebase 功能部署失败

    每当我部署 firebase 函数时 我都会收到以下错误 错误 解析函数触发器时发生错误 Error ERR PACKAGE PATH NOT EXPORTED No exports main defined in D Proyectos
  • 为什么 for(;;) 而不是 while(1) ? [复制]

    这个问题在这里已经有答案了 可能的重复 for 比 while TRUE 快吗 如果没有 人们为什么要使用它 为什么要用丑的for 语法而不是看起来稍微好一点的while true loop 没有什么优势可以for over while 1
  • 正则表达式匹配长度超过 5 个字符且具有两个连续数字的密码

    这就是我所拥有的 有人可以告诉我哪里错了吗 let sampleWord bana12 let pwRegex w 5 d 2 Change this line let result pwRegex test sampleWord cons
  • DexArchiveMergerException:无法合并 dex

    昨天从 2 3 3 版本更新 Android studio 3 0 后 我遇到了与 DexMergerException 相关的问题 其他人也发布了相关问题this 但在这个问题中 我想分析堆栈跟踪以找到相关的解决方案 因为我是这里的新手
  • 使用 excel 插件注册带有参数描述的 UDF

    我有一个带有 UDF 的插件getRegExResult 我想向该函数添加函数描述和参数描述 因此当用户安装插件 关闭 打开 Excel 几次并进入 插入函数 对话框时 他将能够找到带有参数描述的函数 同样被问到here 我找到了一个ans
  • JSF:使用 Icefaces 组件上传文件的问题

    我想得到FileUpload与 Icefaces 配合使用的功能ace 文件条目 but my fileUploadListener服务器上未调用 代码如下 xhtml 片段
  • 在Python中循环压缩列表

    我正在研究 python 中的 zip 函数 并在使用 for 循环时发现了一个问题 这是我的代码 list1 monday tuesday wednesday thursday list2 1 2 3 4 zipped list zip
  • Excel VBA:批量重命名工作表

    有没有办法在VBA中批量重命名工作表 就像是 sheets array 1 2 3 name array hep hey heppa 将工作表 1 2 3 命名为 hep hey 和 heppa 显然它不能直接工作 和一些实验选定的表不要带
  • 发送 QUERY 数据包时出错

    我试图将一些数据插入数据库 但出现此错误 发送 QUERY 数据包时出错 insertDeta conPat gt prepare insert into table1 data VALUES data insertDeta gt bind
  • 如何使用 postgres 将时间间隔转换为小时数?

    假设我有一个像这样的间隔 4 days 10 00 00 在 postgres 中 我如何将其转换为小时数 在本例中为 106 是否有函数或者我应该硬着头皮做类似的事情 extract days my interval 24 extract
  • 使用 NHibernate ISqlExceptionConverter 自定义异常

    我需要为 NHibernate 方言注册自定义异常 我已经实施并 注册了 ISqlExceptionConverter 如 NHibernate 测试中所示 但 当代码中抛出异常时 它不会被转换 我的转换代码 甚至不打电话 我的代码非常简单
  • 如何演示 sigma(i/2^i)<=2(i=1 到 n)

    如何证明以下不等式 sigma i 2 i lt 2 i 1 to n 如果我们看一下series然后它看起来像 我们认为总和的最大值为 n 无穷大 S 1 2 2 4 3 8 4 16 5 32 0 1 清楚地 S 2 1 4 2 8 3
  • Bootstrap下拉菜单点击后消失

    div class container div class dropdown col xs 8 div div
  • Jquery 如何使用美元符号? [复制]

    这个问题在这里已经有答案了 可能的重复 javascript中 符号的含义是什么 如果 Jquery 只是外部 javascript 代码 那么它如何使用美元符号 这不是要添加新的语法吗 只是一个普通变量 你可以做var 42
  • Android 11 (R) 中捕获和裁剪图像

    根据 android R 隐私政策的变化 我想为 android R 设备执行捕获和裁剪图像功能 我尝试了下面的方法 但它保存了空文件 文件正在指定文件夹中创建 但大小为 0kb 我在用着Android 图像裁剪器库来裁剪图像 public
  • 如何在 Vuejs 渲染函数中复制插槽?

    我有一个通过插槽传递内容的组件 我正在使用渲染函数来输出内容 我使用渲染函数的原因是因为我想多次复制内容 当我使用这段代码时 一切正常 render createElement return createElement div this s
  • 旋转后图像不在正确的位置(图形)

    我试图以不同的速率显示两个直径为 512untis 的旋转轮 但我无法删除以前绘制的图像图形并将旋转的图形设置在正确的位置 现在我正在以任意角度进行旋转 我尝试了 affineTransform 并获得了旋转 但很奇怪 就像所有像素都散开一