Java Swing JMenu文本动画无法按预期工作

Java Swing JMenu文本动画无法按预期工作,java,swing,jmenu,jmenuitem,jmenubar,Java,Swing,Jmenu,Jmenuitem,Jmenubar,我需要动画一些选定的菜单项和他们的菜单。到目前为止,我得到的解决方案可以很好地用于菜单项,但不能很好地用于其父菜单。(解决方案来源:)。为了在JMenus上实现相同的效果,我尝试了与设置JMenuItems动画解决方案中相同的操作(覆盖addNotify()和removeNotify()检查FadeMenuClass) 我的代码如下(您可以运行此代码): AnimationEngine.java package aphemeralmenudemo; import java.awt.AlphaC

我需要动画一些选定的菜单项和他们的菜单。到目前为止,我得到的解决方案可以很好地用于菜单项,但不能很好地用于其父菜单。(解决方案来源:)。为了在JMenus上实现相同的效果,我尝试了与设置JMenuItems动画解决方案中相同的操作(覆盖addNotify()和removeNotify()检查
FadeMenu
Class)

我的代码如下(您可以运行此代码):

AnimationEngine.java

package aphemeralmenudemo;

import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

public class FadeMenuDemo {

private AnimationEngine engine;

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

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

            engine = new AnimationEngine();

            JMenuBar mb = new JMenuBar();
            JMenu Level1 = new JMenu("Level 1");
            Level1.add("111");
            Level1.add("222");
            JMenu Level2 = new FadeMenu("Flip");
            Level1.add(Level2);

            Level2.add(new FadeMenuItem("Fade 1"));
            Level2.add(new FadeMenuItem("Fade 2"));

            Level2.add("Static 1");
            Level2.add("Static 2");





            mb.add(Level1);

            JFrame frame = new JFrame("Testing");
            frame.setJMenuBar(mb);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout(new BorderLayout());
            frame.add(new TestPane());
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    });
}
public class AnimationEngine {

    private Timer fade;
    private float alpha;
    private long startTime;
    private long duration = 1000;
    private List<TimingListener> listeners;

    public AnimationEngine() {
        listeners = new ArrayList<>(5);
        fade = new Timer(40, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                long elapsed = System.currentTimeMillis() - startTime;
                if (elapsed >= duration) {
                    ((Timer) e.getSource()).stop();
                    alpha = 1f;
                } else {
                    alpha = (float) elapsed / (float) duration;
                }
                fireTimingEvent();
            }
        });
        fade.setRepeats(true);
        fade.setCoalesce(true);
        fade.setInitialDelay(500);
    }

    public void addTimingListener(TimingListener listener) {
        listeners.add(listener);
    }

    public void removeTimingListener(TimingListener listener) {
        listeners.add(listener);
    }

    protected void fireTimingEvent() {
        for (TimingListener listener : listeners) {
            listener.timingEvent();
        }
    }

    public void restart() {
        fade.stop();
        alpha = 0;
        fireTimingEvent();
        startTime = System.currentTimeMillis();
        fade.start();
    }

    public float getAlpha() {
        return alpha;
    }

    public void stop() {
        fade.stop();
    }
}
TestPane.java

public class TestPane extends JPanel {

    public TestPane() {
    }

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

public class FadeMenuItem extends JMenuItem {

    public FadeMenuItem(String text) {
        super(text);
        engine.addTimingListener(new TimingListener() {
            @Override
            public void timingEvent() {
                repaint();
            }
        });
    }

    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setComposite(AlphaComposite.SrcOver.derive(engine.getAlpha()));
        super.paintComponent(g2d);
        g2d.dispose();
    }

    @Override
    public void removeNotify() {
        Container parent = getParent();
        if (parent instanceof JPopupMenu) {
            JPopupMenu menu = (JPopupMenu) parent;
            engine.stop();
        }
        super.removeNotify(); 
    }

    @Override
    public void addNotify() {
        super.addNotify();
        Container parent = getParent();
        if (parent instanceof JPopupMenu) {
            JPopupMenu menu = (JPopupMenu) parent;
            engine.restart();
        }
    }
}
FadeMenu.java

public class FadeMenu extends JMenu{

    public FadeMenu(String text) {
        super(text);
        engine.addTimingListener(new TimingListener() {
            @Override
            public void timingEvent() {
                repaint();
            }
        });
    }

    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setComposite(AlphaComposite.SrcOver.derive(engine.getAlpha()));
        super.paintComponent(g2d);
        g2d.dispose();
    }

    @Override
    public void removeNotify() {
        Container parent = getParent();
        if (parent instanceof JPopupMenu) {
            JPopupMenu menu = (JPopupMenu) parent;
            engine.stop();
        }
        super.removeNotify(); 
    }

    @Override
    public void addNotify() {
        super.addNotify();
        Container parent = getParent();
        if (parent instanceof JPopupMenu) {
            JPopupMenu menu = (JPopupMenu) parent;
            engine.restart();
        }
    }

}
TimingListener.java

public interface TimingListener {

    public void timingEvent();
}
AnimationEngine.java

package aphemeralmenudemo;

import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

public class FadeMenuDemo {

private AnimationEngine engine;

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

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

            engine = new AnimationEngine();

            JMenuBar mb = new JMenuBar();
            JMenu Level1 = new JMenu("Level 1");
            Level1.add("111");
            Level1.add("222");
            JMenu Level2 = new FadeMenu("Flip");
            Level1.add(Level2);

            Level2.add(new FadeMenuItem("Fade 1"));
            Level2.add(new FadeMenuItem("Fade 2"));

            Level2.add("Static 1");
            Level2.add("Static 2");





            mb.add(Level1);

            JFrame frame = new JFrame("Testing");
            frame.setJMenuBar(mb);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout(new BorderLayout());
            frame.add(new TestPane());
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    });
}
public class AnimationEngine {

    private Timer fade;
    private float alpha;
    private long startTime;
    private long duration = 1000;
    private List<TimingListener> listeners;

    public AnimationEngine() {
        listeners = new ArrayList<>(5);
        fade = new Timer(40, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                long elapsed = System.currentTimeMillis() - startTime;
                if (elapsed >= duration) {
                    ((Timer) e.getSource()).stop();
                    alpha = 1f;
                } else {
                    alpha = (float) elapsed / (float) duration;
                }
                fireTimingEvent();
            }
        });
        fade.setRepeats(true);
        fade.setCoalesce(true);
        fade.setInitialDelay(500);
    }

    public void addTimingListener(TimingListener listener) {
        listeners.add(listener);
    }

    public void removeTimingListener(TimingListener listener) {
        listeners.add(listener);
    }

    protected void fireTimingEvent() {
        for (TimingListener listener : listeners) {
            listener.timingEvent();
        }
    }

    public void restart() {
        fade.stop();
        alpha = 0;
        fireTimingEvent();
        startTime = System.currentTimeMillis();
        fade.start();
    }

    public float getAlpha() {
        return alpha;
    }

    public void stop() {
        fade.stop();
    }
}
一开始我看起来很好。菜单文本出现在动画中,但当该动画菜单下的子项选择该菜单文本时,该菜单文本再次显示为动画。这就是问题所在,我不想在选择菜单文本的子菜单时设置其动画。在这方面我真的需要帮助。提前谢谢

这就是问题所在,我不想在选择菜单文本的子菜单时设置其动画

只有在未选择菜单时才调用
repaint

示例代码:

public FadeMenu(String text) {
    super(text);
    engine.addTimingListener(new TimingListener() {
        @Override
        public void timingEvent() {
            // This condition is added here to stop animation when selected 
            if (!isSelected()) {
                repaint();
            }
        }
    });
}

非常感谢。我工作过。我被这件事困扰了大约一天。你救了我很多。再次感谢。实现相同效果的另一种方法是创建一个单独的AMIAtoreEngine实例,并将其与您的修改一起用于淡入淡出菜单。(只有您的修改也会产生一些奇怪的菜单外观)