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

2024-03-22

我有一个非常具体的问题: 我希望能够通过方法调用,在方法调用的一定时间内在屏幕上的给定位置弹出带有文本的工具提示(可以说任何内容)(假设逻辑在 talk 方法中)并且淡去。我该怎么办呢?有没有办法通过 JTooltip 来做到这一点?或者我必须深入 JNA 才能得到我想要的东西?

我应该提到,我希望在给定位置弹出带有文本的工具提示,而无需鼠标悬停的提示,就像弹出窗口一样。

另外,如果工具提示不是实现我想要的内容的正确方法(我希望我说清楚),是否有更有效的替代方案?


有几种方法可以实现这一目标。一种可能的方法是使用透明的JWindow和一个秋千Timer

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

现在,就我个人而言,我会创建一个更简单的 API,它可以构建弹出窗口并创建一个Timer有可变的延迟,但你明白了

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%AlphaComposite

Updated

您可以使用工厂或构建器模式来提供简单的 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 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);

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐