如何在Java中通过脚本弹出文本框(或工具提示)

如何在Java中通过脚本弹出文本框(或工具提示),java,popup,tooltip,jna,jtooltip,Java,Popup,Tooltip,Jna,Jtooltip,我有一个非常具体的问题: 我希望能够通过方法调用,在方法调用(比如逻辑在对话方法中)的一定时间内,在屏幕上的给定位置弹出带有文本(它可以说任何东西)的工具提示,并逐渐消失。我怎么能这样做呢?有没有办法通过JTooltip实现这一点?还是我必须潜入JNA才能得到我想要的 我应该提到的是,我希望工具提示在给定位置弹出文本,而不需要鼠标的提示,就像弹出窗口一样 此外,如果工具提示不是我想要的正确方式(我希望我已经明确指出),是否有更有效的替代方法?实现这一点的方法很少。一种可能的方法是使用透明的JWi

我有一个非常具体的问题: 我希望能够通过方法调用,在方法调用(比如逻辑在对话方法中)的一定时间内,在屏幕上的给定位置弹出带有文本(它可以说任何东西)的工具提示,并逐渐消失。我怎么能这样做呢?有没有办法通过JTooltip实现这一点?还是我必须潜入JNA才能得到我想要的

我应该提到的是,我希望工具提示在给定位置弹出文本,而不需要鼠标的提示,就像弹出窗口一样


此外,如果工具提示不是我想要的正确方式(我希望我已经明确指出),是否有更有效的替代方法?

实现这一点的方法很少。一种可能的方法是使用透明的
JWindow
和Swing
定时器

基本上,这会创建一个
JWindow
,将其背景色设置为完全透明,从而创建一个透明窗口。然后,它使用简单的
BackgroundPane
(渲染一个漂亮的背景)和
MessagePane
来保存实际的消息。您可以在一个面板中完成此操作,但我喜欢它为我提供的灵活性

现在,就我个人而言,我将创建一个更简单的API,它可以构建弹出窗口,并创建一个具有可变延迟的
计时器,但您明白了

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

    }

}
您可以在背景面板上使用
AlphaComposite
创建半透明背景

使用50%的字母组合弹出窗口

已更新

您可以使用factory或builder模式来提供简单的API,例如

new PopupBuilder().at(new Point(100, 100)).withMessage("Hello").withDelay(5000).show();
构建器将收集您想要指定的属性,在您没有设置它们的地方提供默认值,然后显示最终的弹出窗口

基本思想是,当您调用
show
时,它将收集属性并构建类似于构造函数现在工作方式的窗口

使用淡入淡出的弹出窗口更新

这是一个如何产生淡入淡出效果的(有点过分)示例。该示例保证消息将在指定的延迟时间内显示在屏幕上(完整)

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

        }

    }

}

现在,您也可以通过更改帧的最大不透明度级别来执行此操作,但是,如果您更改
背景窗格的
paintComponent

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

您还可以影响弹出消息的不透明度。此方法只会影响背景,而不会影响消息文本…

我下载了代码并试用了它,出于我的目的,我认为它可以工作,但有一个问题。如果我试图抽象代码的某些部分,以便为文本冒泡指定引号和位置,我会得到一个编译器错误,因为它使用内部类,所以传入的参数必须声明为final。现在,错误本身是显而易见的,但我想知道在这种设置下,您将如何添加指定报价和位置的功能。我可以尝试完全重新编译这段代码,但是我想知道是否有一种方法可以保存这个架构,正如我提到的,它实际上要做的是用一个或多个静态方法创建一个工厂类。这将创建窗口并应用消息,就像构造函数现在所做的那样。您可以通过将setLocationRelativeTo方法与窗口上的setLocation重新定距来指定窗口的位置,其余的应该已经设置为转到…或多或少;)谢谢你的建议,它工作得很好!我正试图让阿尔法合成图工作,但我想我一步就迷路了。我假设您尝试在paint component方法的背景窗格中应用alpha合成,影响g2d,但无论我做了什么,都不会对透明度产生任何影响。我也试着对glp做同样的事情,但我不认为alpha composite在那里适用。如果你对此有任何建议,我很想知道(因为你已经让它工作了。当然,请随意给我一个提示,那样更有趣)嗯,有两种方法。一种是在你画任何东西之前,先在背景上应用它。另一个是设置windows不透明度级别;)@用户3670987添加了其他示例