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

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

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

此外,如果工具提示不是正确的方式来实现我想要的(我希望我明确表示),是否有更有效的替代方案?

实现这一目标的方法很少。 一种可能的方法是使用透明的JWindow和Swing 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弹出窗口

弹出

更新

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

现在,您可能还通过更改框架的最大不透明度级别来执行此操作,但是,如果更改BackgroundPanepaintComponent

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

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