Change/Display 带文本的光标
Change/Display Cursor with Text
我目前正在尝试将 JFrame
上显示的光标更改为某些文本,例如 "wait please your job is being done",而某个 button
的 actionPerformed()
方法正在执行。到目前为止,我找到的唯一解决方案是将 Cursor
更改为包含我想要的文本的 Image
。代码如下:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Hasikome extends JFrame{
static Cursor cursor;
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
final Hasikome hasi = new Hasikome();
hasi.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
hasi.setSize(new Dimension(1200, 1200));
hasi.setPreferredSize(new Dimension(500, 500));
Toolkit kit = Toolkit.getDefaultToolkit();
Dimension dim = kit.getBestCursorSize(16, 16);
BufferedImage buffered = null;
try {
buffered = ImageIO.read(new File(Paths.get("").toAbsolutePath().toString() + "\belge.png"));
} catch (IOException e) {
e.printStackTrace();
}
java.awt.Shape circle = new Ellipse2D.Float(0, 0, dim.width - 1, dim.height - 1);
Graphics2D g = buffered.createGraphics();
g.setColor(Color.BLUE);
g.draw(circle);
g.setColor(Color.RED);
hasi.add(new JButton(new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
hasi.setCursor(cursor);
try {
Thread.sleep(10000);
} catch (InterruptedException e1) {
e1.printStackTrace();
} finally {
hasi.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
}), BorderLayout.NORTH);
int centerX = (dim.width - 1) /2;
int centerY = (dim.height - 1) / 2;
g.drawLine(centerX, 0, centerX, dim.height - 1);
g.drawLine(0, centerY, dim.height - 1, centerY);
g.dispose();
cursor = kit.createCustomCursor(buffered, new Point(centerX, centerY), "myCursor");
hasi.pack();
hasi.setVisible(true);
}
}
此代码的问题是 Dimension dim = kit.getBestCursorSize(16, 16);
此行总是在 Windows
上生成大小为 32x32 的 Cursor
,并且它依赖于平台。我不能使用超过 32x32 的值,否则 cursor = kit.createCustomCursor(buffered, new Point(centerX, centerY), "myCursor");
行会出现异常。而且因为我使用了相当长的文本 (250x16),所以我无法将 text image
正确显示为 Cursor
。
这个解决方案不是必需的,我想要完成的是在执行某些 Button
的 actionPerformed()
方法时向用户显示文本 Cursor
。有什么办法可以做到这一点?提前致谢。
查看 Disabled Glass Pane 了解一种方法。
If 允许您在使用 "wait" 光标时显示带有在半透明背景上绘制的文本的 Glass Pane
。
除非您绝对必须使用文本 "Please wait,",否则使用计算机的内置加载图标可能会容易得多。如果您使用:
hasi.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
doProcessing();
hasi.setCursor(Cursor.getDefaultCursor());
应该是一样的效果
是否要阻塞 UI 线程?
无论如何,最好的方法可能是使用JLayeredPane,在JLayeredPane中的模态层上弹出一个JLabel(需要自己设置它的大小),然后在工作时将其删除完成。
这不是答案,但也许可以做你想做的事:
package com.Whosebug.questions;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
/**
* Just an idea for the Whosebug question
*/
public class SO27822671 extends JFrame {
/**
* The Glasspane on which we'll draw the "please wait..." thing.
*/
private MyGlassPane myGlassPane;
/**
* Blank cursor to hide the cursor.
*/
private final Cursor blankCursor;
/**
* Init.
*/
public SO27822671() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setBounds(300, 300, 400, 400);
myGlassPane = new MyGlassPane();
setGlassPane(myGlassPane);
getContentPane().setLayout(new FlowLayout());
getContentPane().add(new JButton(new AbstractAction("Click Me!") {
@Override
public void actionPerformed(ActionEvent e) {
doMyStuff();
}
}));
//
blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(
new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB), new Point(0, 0), "blank cursor");
}
/**
* Do the heavy stuff.
*/
private void doMyStuff() {
// show our glasspane
myGlassPane.setVisible(true);
// save the current cursor
final Cursor currentCursor = getCursor();
// hide the cursor
setCursor(blankCursor);
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
// hard work here
Thread.sleep(2000);
return null;
}
@Override
protected void done() {
try {
get();
}
catch (Exception e) {
// do your exception handling here
e.printStackTrace();
}
finally {
// hide our glasspane
myGlassPane.setVisible(false);
// restore the cursor
setCursor(currentCursor);
}
}
}.execute();
}
/**
* This is our glasspane.
*/
class MyGlassPane extends JComponent {
/**
* To save the mouse X position.
*/
private int mouseXPosition;
/**
* To save the mouse Y position.
*/
private int mouseYPosition;
/**
* The text to show.
*/
private String text = "Please wait...";
/**
* Init.
*/
public MyGlassPane() {
// to get the cursor position
MouseAdapter mouseAdapter = new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
computeMousePositionAndRepaint(e);
}
@Override
public void mouseEntered(MouseEvent e) {
computeMousePositionAndRepaint(e);
}
};
addMouseMotionListener(mouseAdapter);
addMouseListener(mouseAdapter);
}
/**
* Compute the mouse position and invoke repaint on our glasspane.
* @param e
*/
private void computeMousePositionAndRepaint(MouseEvent e) {
mouseXPosition = e.getX();
mouseYPosition = e.getY();
repaint();
}
@Override
protected void paintComponent(Graphics g) {
// draw here what you want instead
int textHeight = g.getFontMetrics().getHeight();
int textWidth = g.getFontMetrics().stringWidth(text);
int textDescent = g.getFontMetrics().getDescent();
int x = mouseXPosition - textWidth / 2;
int y = mouseYPosition - textHeight / 2;
g.setColor(Color.white);
g.fillRect(x - 4, y - 4, textWidth + 8, textHeight + 8);
((Graphics2D) g).setRenderingHint(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.black);
g.drawString(text, x, y + textHeight - textDescent);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new SO27822671().setVisible(true);
}
});
}
}
那是一个想法。
我目前正在尝试将 JFrame
上显示的光标更改为某些文本,例如 "wait please your job is being done",而某个 button
的 actionPerformed()
方法正在执行。到目前为止,我找到的唯一解决方案是将 Cursor
更改为包含我想要的文本的 Image
。代码如下:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Hasikome extends JFrame{
static Cursor cursor;
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
final Hasikome hasi = new Hasikome();
hasi.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
hasi.setSize(new Dimension(1200, 1200));
hasi.setPreferredSize(new Dimension(500, 500));
Toolkit kit = Toolkit.getDefaultToolkit();
Dimension dim = kit.getBestCursorSize(16, 16);
BufferedImage buffered = null;
try {
buffered = ImageIO.read(new File(Paths.get("").toAbsolutePath().toString() + "\belge.png"));
} catch (IOException e) {
e.printStackTrace();
}
java.awt.Shape circle = new Ellipse2D.Float(0, 0, dim.width - 1, dim.height - 1);
Graphics2D g = buffered.createGraphics();
g.setColor(Color.BLUE);
g.draw(circle);
g.setColor(Color.RED);
hasi.add(new JButton(new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
hasi.setCursor(cursor);
try {
Thread.sleep(10000);
} catch (InterruptedException e1) {
e1.printStackTrace();
} finally {
hasi.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
}), BorderLayout.NORTH);
int centerX = (dim.width - 1) /2;
int centerY = (dim.height - 1) / 2;
g.drawLine(centerX, 0, centerX, dim.height - 1);
g.drawLine(0, centerY, dim.height - 1, centerY);
g.dispose();
cursor = kit.createCustomCursor(buffered, new Point(centerX, centerY), "myCursor");
hasi.pack();
hasi.setVisible(true);
}
}
此代码的问题是 Dimension dim = kit.getBestCursorSize(16, 16);
此行总是在 Windows
上生成大小为 32x32 的 Cursor
,并且它依赖于平台。我不能使用超过 32x32 的值,否则 cursor = kit.createCustomCursor(buffered, new Point(centerX, centerY), "myCursor");
行会出现异常。而且因为我使用了相当长的文本 (250x16),所以我无法将 text image
正确显示为 Cursor
。
这个解决方案不是必需的,我想要完成的是在执行某些 Button
的 actionPerformed()
方法时向用户显示文本 Cursor
。有什么办法可以做到这一点?提前致谢。
查看 Disabled Glass Pane 了解一种方法。
If 允许您在使用 "wait" 光标时显示带有在半透明背景上绘制的文本的 Glass Pane
。
除非您绝对必须使用文本 "Please wait,",否则使用计算机的内置加载图标可能会容易得多。如果您使用:
hasi.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
doProcessing();
hasi.setCursor(Cursor.getDefaultCursor());
应该是一样的效果
是否要阻塞 UI 线程?
无论如何,最好的方法可能是使用JLayeredPane,在JLayeredPane中的模态层上弹出一个JLabel(需要自己设置它的大小),然后在工作时将其删除完成。
这不是答案,但也许可以做你想做的事:
package com.Whosebug.questions;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
/**
* Just an idea for the Whosebug question
*/
public class SO27822671 extends JFrame {
/**
* The Glasspane on which we'll draw the "please wait..." thing.
*/
private MyGlassPane myGlassPane;
/**
* Blank cursor to hide the cursor.
*/
private final Cursor blankCursor;
/**
* Init.
*/
public SO27822671() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setBounds(300, 300, 400, 400);
myGlassPane = new MyGlassPane();
setGlassPane(myGlassPane);
getContentPane().setLayout(new FlowLayout());
getContentPane().add(new JButton(new AbstractAction("Click Me!") {
@Override
public void actionPerformed(ActionEvent e) {
doMyStuff();
}
}));
//
blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(
new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB), new Point(0, 0), "blank cursor");
}
/**
* Do the heavy stuff.
*/
private void doMyStuff() {
// show our glasspane
myGlassPane.setVisible(true);
// save the current cursor
final Cursor currentCursor = getCursor();
// hide the cursor
setCursor(blankCursor);
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
// hard work here
Thread.sleep(2000);
return null;
}
@Override
protected void done() {
try {
get();
}
catch (Exception e) {
// do your exception handling here
e.printStackTrace();
}
finally {
// hide our glasspane
myGlassPane.setVisible(false);
// restore the cursor
setCursor(currentCursor);
}
}
}.execute();
}
/**
* This is our glasspane.
*/
class MyGlassPane extends JComponent {
/**
* To save the mouse X position.
*/
private int mouseXPosition;
/**
* To save the mouse Y position.
*/
private int mouseYPosition;
/**
* The text to show.
*/
private String text = "Please wait...";
/**
* Init.
*/
public MyGlassPane() {
// to get the cursor position
MouseAdapter mouseAdapter = new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
computeMousePositionAndRepaint(e);
}
@Override
public void mouseEntered(MouseEvent e) {
computeMousePositionAndRepaint(e);
}
};
addMouseMotionListener(mouseAdapter);
addMouseListener(mouseAdapter);
}
/**
* Compute the mouse position and invoke repaint on our glasspane.
* @param e
*/
private void computeMousePositionAndRepaint(MouseEvent e) {
mouseXPosition = e.getX();
mouseYPosition = e.getY();
repaint();
}
@Override
protected void paintComponent(Graphics g) {
// draw here what you want instead
int textHeight = g.getFontMetrics().getHeight();
int textWidth = g.getFontMetrics().stringWidth(text);
int textDescent = g.getFontMetrics().getDescent();
int x = mouseXPosition - textWidth / 2;
int y = mouseYPosition - textHeight / 2;
g.setColor(Color.white);
g.fillRect(x - 4, y - 4, textWidth + 8, textHeight + 8);
((Graphics2D) g).setRenderingHint(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.black);
g.drawString(text, x, y + textHeight - textDescent);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new SO27822671().setVisible(true);
}
});
}
}
那是一个想法。