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

标签 java swing jmenu jmenuitem jmenubar

我需要为一些选定的菜单项及其相关菜单设置动画。到目前为止,我得到的解决方案适用于菜单项,但不适用于其父菜单。 (解决方案来源:Is it possible to make some items in the menu to fade in with 500 ms onset delay in Java?)。为了对 JMenus 实现相同的效果,我尝试执行与动画 JMenuItems 解决方案中相同的操作(覆盖 addNotify() 和 removeNotify() 检查 FadeMenu 类)。

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

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

一开始我看起来很好。菜单文本以动画形式出现,但是当该动画菜单下的子项选择菜单文本时,菜单文本再次以动画形式显示。这就是问题,我不想在选择子菜单时为菜单文本设置动画。在这方面我确实需要帮助。提前致谢。

最佳答案

This is the problem, I don't want to animate the menu text upon selecting it's submenu.

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

关于Java Swing JMenu 文本动画无法按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24790864/

相关文章:

java - 连接至小米手环 2

java - 如何在其他 Activity 中发送从二维码扫描仪读取的字符串

java - 如何在 Tomcat 中定义特定于应用程序的类路径?

java - 如何在 java 中打印 jpanel?

java - 使用 hibernate 和 java Swing 从 MySQL DB 恢复表

java - 添加 Play Services 依赖项会导致与 Firebase 发生冲突

java - JEdi​​torPane HTML 渲染

java - JMenuItems 隐藏在我的 JApplet 后面

java - MenuListener 实现,如何检测点击了哪个 JMenu?

Java 在鼠标悬停时重新绘制组件。