How to pop up a text box(or tooltip) via script in Java

前端 未结 1 599
执念已碎
执念已碎 2021-01-26 05:57

I have a very specific question: I want to be able to, via a method call, popup a tooltip with text(it could say anything) in a given location on the screen for a certain amount

1条回答
  •  孤城傲影
    2021-01-26 06:35

    There are few ways this might be achieved. One possible way is through the use of a transparent JWindow and a Swing Timer

    Basically, what this does is creates a JWindow, set's it's background color to fully transparent, making a transparent window. It then uses simple BackgroundPane (to render a nice background) and MessagePane to hold the actual message. You can do this in one panel, but I like the flexibility this affords me.

    Popup

    Now, personally, I would create a simpler API which could build the popup window and create a Timer with a variable delay, but you get the idea

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.GridBagLayout;
    import java.awt.LinearGradientPaint;
    import java.awt.Point;
    import java.awt.RenderingHints;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.geom.RoundRectangle2D;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JWindow;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.border.EmptyBorder;
    
    public class PopupMessageWindow {
    
        public static void main(String[] args) {
            new PopupMessageWindow();
        }
    
        public PopupMessageWindow() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    final JWindow frame = new JWindow();
                    frame.setBackground(new Color(0, 0, 0, 0));
                    BackgroundPane pane = new BackgroundPane();
                    pane.setMessage("Boo, This is a popup...");
                    frame.add(pane);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                    frame.setAlwaysOnTop(true);
    
                    Timer timer = new Timer(10000, new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            frame.dispose();
                            System.exit(0);
                        }
                    });
                    timer.setRepeats(false);
                    timer.start();
                }
            });
        }
    
        public class BackgroundPane extends JPanel {
    
            private MessagePane messagePane;
    
            public BackgroundPane() {
                setBorder(new EmptyBorder(40, 40, 40, 40));
                messagePane = new MessagePane();
                setLayout(new BorderLayout());
                add(messagePane);
                setOpaque(false);
            }
    
            public void setMessage(String msg) {
                messagePane.setMessage(msg);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
                g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
                g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
                g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
                LinearGradientPaint glp = new LinearGradientPaint(
                                new Point(0, 0),
                                new Point(0, getHeight()),
                                new float[]{0f, 1f},
                                new Color[]{Color.GRAY, Color.BLACK});
                RoundRectangle2D frame = new RoundRectangle2D.Float(0, 0, getWidth() - 1, getHeight() - 1, 20, 20);
                g2d.setPaint(glp);
                g2d.fill(frame);
                g2d.setColor(Color.WHITE);
                g2d.draw(frame);
            }
    
        }
    
        public class MessagePane extends JPanel {
    
            private JLabel label;
    
            public MessagePane() {
                setOpaque(false);
                label = new JLabel();
                label.setForeground(Color.WHITE);
                setLayout(new GridBagLayout());
                add(label);
            }
    
            public void setMessage(String msg) {
                label.setText(msg);
            }
    
        }
    
    }
    

    You could play with a AlphaComposite on the background panel to create a semi transparent background

    Popup window using a 50% AlphaComposite

    Popup

    Updated

    You could use a factory or builder pattern to provide a simple API, for example...

    new PopupBuilder().at(new Point(100, 100)).withMessage("Hello").withDelay(5000).show();
    

    The builder would collect the properties you want to specify, provide defaults where you didn't set them and then would show the final popup.

    The basic idea is when you call show, it would collect the properties and build the window similar to how the constructor works right now...

    Updated with a fading popup window

    This is (a somewhat over the top) example of how you might be able to produce a fading in/out effect. The example guarantees that the message will be on the screen (full) for at specified delay period

    Popup

    import java.awt.AlphaComposite;
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.GridBagLayout;
    import java.awt.LinearGradientPaint;
    import java.awt.Point;
    import java.awt.RenderingHints;
    import java.awt.Window;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.geom.RoundRectangle2D;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JWindow;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.border.EmptyBorder;
    
    public class PopupMessageExample {
    
        public static void main(String[] args) {
            new PopupMessageExample();
        }
    
        public PopupMessageExample() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
                    new PopupMessageBuilder().withDelay(10000).withMessage("Hello, this is a fading message").show();
                }
            });
        }
    
        public class PopupMessageBuilder {
    
            private int delay;
            private Point location;
            private String message;
    
            private long startTime;
            private Timer fadeTimer;
    
            public PopupMessageBuilder at(Point p) {
                this.location = p;
                return this;
            }
    
            public PopupMessageBuilder withDelay(int delay) {
                this.delay = delay;
                return this;
            }
    
            public PopupMessageBuilder withMessage(String msg) {
                this.message = msg;
                return this;
            }
    
            public PopupMessageBuilder show() {
    
                final JWindow frame = new JWindow();
                frame.setOpacity(0f);
                frame.setBackground(new Color(0, 0, 0, 0));
                BackgroundPane pane = new BackgroundPane();
                pane.setMessage(message);
                frame.add(pane);
                frame.pack();
                if (location == null) {
                    frame.setLocationRelativeTo(null);
                } else {
                    frame.setLocation(location);
                }
                frame.setVisible(true);
                frame.setAlwaysOnTop(true);
    
                new FadeTimer(frame, 1000, 0f, 1f, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        Timer timer = new Timer(delay, new ActionListener() {
                            @Override
                            public void actionPerformed(ActionEvent e) {
                                new FadeTimer(frame, 1000, 1f, 0f, new ActionListener() {
                                    @Override
                                    public void actionPerformed(ActionEvent e) {
                                        frame.dispose();
                                    }
                                }).start();
                            }
                        });
                        timer.setRepeats(false);
                        timer.start();
                    }
                }).start();
    
                return this;
            }
    
            public class FadeTimer extends Timer implements ActionListener {
    
                private final float startAt;
                private final float endAt;
                private final int duration;
                private long startTimer;
    
                private ActionListener endListener;
    
                private Window window;
    
                public FadeTimer(Window window, int duration, float startAt, float endAt, ActionListener endListener) {
                    super(5, null);
                    addActionListener(this);
                    this.duration = duration;
                    this.startAt = startAt;
                    this.endAt = endAt;
                    this.window = window;
    
                    this.endListener = endListener;
                }
    
                @Override
                public void start() {
                    startTime = System.currentTimeMillis();
                    super.start();
                }
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    long now = System.currentTimeMillis();
                    long lapsed = now - startTime;
                    float opacity = startAt;
                    if (lapsed >= duration) {
                        opacity = endAt;
                        ((Timer) e.getSource()).stop();
                        if (endListener != null) {
                            endListener.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "stopped"));
                        }
                    } else {
                        float progress = (float) lapsed / (float) duration;
                        float distance = endAt - startAt;
                        opacity = (float) (distance * progress);
                        opacity += startAt;
                    }
                    window.setOpacity(opacity);
                }
    
            }
    
            public class BackgroundPane extends JPanel {
    
                private MessagePane messagePane;
    
                public BackgroundPane() {
                    setBorder(new EmptyBorder(40, 40, 40, 40));
                    messagePane = new MessagePane();
                    setLayout(new BorderLayout());
                    add(messagePane);
                    setOpaque(false);
                }
    
                public void setMessage(String msg) {
                    messagePane.setMessage(msg);
                }
    
                @Override
                protected void paintComponent(Graphics g) {
                    super.paintComponent(g);
                    Graphics2D g2d = (Graphics2D) g.create();
                    g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
                    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                    g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
                    g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
                    g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
                    g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
                    g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                    g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
                    LinearGradientPaint glp = new LinearGradientPaint(
                                    new Point(0, 0),
                                    new Point(0, getHeight()),
                                    new float[]{0f, 1f},
                                    new Color[]{Color.GRAY, Color.BLACK});
                    RoundRectangle2D frame = new RoundRectangle2D.Float(0, 0, getWidth() - 1, getHeight() - 1, 20, 20);
                    g2d.setPaint(glp);
                    g2d.fill(frame);
                    g2d.setColor(Color.WHITE);
                    g2d.draw(frame);
                }
    
            }
    
            public class MessagePane extends JPanel {
    
                private JLabel label;
    
                public MessagePane() {
                    setOpaque(false);
                    label = new JLabel();
                    label.setForeground(Color.WHITE);
                    setLayout(new GridBagLayout());
                    add(label);
                }
    
                public void setMessage(String msg) {
                    label.setText(msg);
                }
    
            }
    
        }
    
    }
    

    Now, you probably also do this by changing the maximum opacity level of the frame, but, if you change the paintComponent of the BackgroundPane

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        AlphaComposite alpha = AlphaComposite.SrcOver.derive(0.75f);
        g2d.setComposite(alpha);
    

    you can also effect the over opacity of the popup message. This method will only effect the background, not the message text...

    0 讨论(0)
提交回复
热议问题