我有一個非常具體的問題: 我希望能夠通過方法調用,彈出工具提示文本(可以說什麼)在在方法調用上一段時間(例如邏輯處於通話方法)屏幕上的給定位置並消失。我怎麼能這樣做呢?有沒有辦法通過JTooltip來做到這一點?或者我需要深入JNA才能得到我想要的東西?如何通過Java中的腳本彈出文本框(或工具提示)
我應該提到我希望工具提示可以在給定位置彈出文本而不需要鼠標懸停,就像彈出一樣。另外,萬一一個工具提示並不是我想要的東西(我希望我已經明確了)的正確方法,是否有更有效的選擇?
我有一個非常具體的問題: 我希望能夠通過方法調用,彈出工具提示文本(可以說什麼)在在方法調用上一段時間(例如邏輯處於通話方法)屏幕上的給定位置並消失。我怎麼能這樣做呢?有沒有辦法通過JTooltip來做到這一點?或者我需要深入JNA才能得到我想要的東西?如何通過Java中的腳本彈出文本框(或工具提示)
我應該提到我希望工具提示可以在給定位置彈出文本而不需要鼠標懸停,就像彈出一樣。另外,萬一一個工具提示並不是我想要的東西(我希望我已經明確了)的正確方法,是否有更有效的選擇?
有幾種方法可以實現。一種可能的方式是通過使用一個透明JWindow
和擺動Timer
基本上,這樣做是創建一個JWindow
,設置的它的背景顏色爲完全透明,使得透明窗口。然後它使用簡單的BackgroundPane
(渲染一個不錯的背景)和MessagePane
來保存實際的消息。你可以在一個面板上做到這一點,但我喜歡這種靈活性。
現在,就個人而言,我會創造出能夠建立彈出窗口,並創建具有可變延遲一個Timer
一個簡單的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%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);
}
}
}
}
現在,你可能還通過改變幀的最大透明度水平做到這一點,但是,如果你改變的BackgroundPane
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
AlphaComposite alpha = AlphaComposite.SrcOver.derive(0.75f);
g2d.setComposite(alpha);
的paintComponent
你也可以在彈出消息的不透明性影響的。這種方法將隻影響背景,而不是消息文本...
我下載了代碼,並嘗試了它,併爲我的目的,我認爲它的工作原理,但有一個問題。如果我嘗試抽象部分代碼,以便可以指定文本泡泡的引用和位置,則會出現編譯器錯誤,指出由於它使用內部類,因此我傳入的參數必須聲明爲final。現在錯誤本身是顯而易見的,但我想知道如何在給定此設置的情況下添加指定報價和位置的功能。我可以嘗試完全重新編寫這段代碼,但是我想知道是否有一種方法可以保留這個架構 – user3670987
正如我所提到的,實際上它會做的是創建一個具有一個或多個靜態方法的工廠類。這些將創建窗口並應用消息,就像現在的構造函數一樣。您可以通過在窗口上重新設置setLocationRelativeTo方法和setLocation來指定窗口的位置,其餘的應該已經設置好了......) – MadProgrammer
感謝您的建議,它非常完美!我試圖讓alpha組合起作用,但我覺得我迷失了一步。我假設你嘗試在繪製組件方法的背景窗格中應用alpha複合,影響g2d,但是我所做的任何事情都沒有對透明度產生任何影響。我也試着做同樣的事情glp,但我不認爲alpha組合適用於那裏。如果你對此有任何建議,我很樂意知道(看到你已經在工作了,當然可以隨意給我一個提示,這樣更有趣) – user3670987