Change/Display 带文本的光标

Change/Display Cursor with Text

我目前正在尝试将 JFrame 上显示的光标更改为某些文本,例如 "wait please your job is being done",而某个 buttonactionPerformed() 方法正在执行。到目前为止,我找到的唯一解决方案是将 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

这个解决方案不是必需的,我想要完成的是在执行某些 ButtonactionPerformed() 方法时向用户显示文本 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);
      }
    });
  }
}

那是一个想法