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

时间:2014-07-16 21:12:47

标签: java swing jmenu jmenuitem jmenubar

我需要为一些选定的菜单项和它们的菜单设置动画。到目前为止,我得到的解决方案与menuitems配合得很好,但与父菜单不兼容。 (解决方案来源:Is it possible to make some items in the menu to fade in with 500 ms onset delay in Java?)。为了对JMenus做同样的效果,我尝试做同样的事情,在解决方案中为JMenuItems设置动画(重写addNotify()和removeNotify()check 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);
        }
    });
}

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

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

重写方法:

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

最初我看起来很好。菜单文本出现在动画中,但是当该动画菜单下的子项目再次选择菜单文本动画时。这是问题所在,我不想在选择菜单文本的子菜单时为其设置动画。在这方面我真的需要帮助。提前致谢。

1 个答案:

答案 0 :(得分:2)

  

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

仅在未选择菜单时调用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();
            }
        }
    });
}