我有一个非常具体的问题: 我希望能够通过方法调用,在方法调用的一定时间内在屏幕上的给定位置弹出一个带有文本(可能会说什么)的工具提示(比如逻辑是在谈话方法中)淡去。我怎么能这样做?有没有办法通过JTooltip做到这一点?或者我是否需要深入JNA才能得到我想要的东西?
我应该提一下,我希望工具提示在给定位置弹出文本而不用鼠标的提示,就像弹出窗口一样。
此外,如果工具提示不是正确的方式来实现我想要的东西(我希望我明确表示),是否有更有效的替代方案?
答案 0 :(得分:2)
实现这一目标的方法很少。一种可能的方法是使用透明的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);
}
}
}
}
现在,您可能还会通过更改框架的最大不透明度级别来执行此操作,但是,如果您更改paintComponent
的{{1}}
BackgroundPane
您还可以影响弹出消息的过度不透明度。此方法仅影响背景,而不影响消息文本...