0

I am currently trying to change the cursor shown on my JFrame to some text like "wait please your job is being done" while a certain button 's actionPerformed() method is executing. The only solution I have found as of yet is to change the Cursor with an Image which contains my desired Text. The code is below:

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);
    }
}

The problem with this code is Dimension dim = kit.getBestCursorSize(16, 16); this line always generates Cursor with size 32x32 on Windows and it is platform dependant. I can't use values more than 32x32 or else I get exception for the line cursor = kit.createCustomCursor(buffered, new Point(centerX, centerY), "myCursor"); . And because I use a reasonably long text (250x16) it won't allow me to show the text image as Cursor properly.

This solution not necessary, what I want to accomplish is to show text to users as Cursor while some Button 's actionPerformed() method is being executed. Is there any way I can do this? Thanks in advance.

halil
  • 800
  • 16
  • 33

4 Answers4

3

Check out Disabled Glass Pane for one approach.

If allows you to display the Glass Pane with text painted on a semi transparent background while using the "wait" cursor.

camickr
  • 321,443
  • 19
  • 166
  • 288
1

Unless you absolutely MUST use the text "Please wait," it might be a lot easier for you to just use the built in loading icon for your computer. If you use:

hasi.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
doProcessing();
hasi.setCursor(Cursor.getDefaultCursor());

It should have the same effect.

DHerls
  • 827
  • 9
  • 21
  • This is the right idea but you need to use SwingUtilities.invokeLater around your setCursor functions, and make sure to do `doProcessing()` in a non-ui thread – ControlAltDel Jan 07 '15 at 15:33
  • Only if the choice would have been mine, I would have used this too. However the requirements led me in search for the answer of my question above. After all this and the answer I'm looking for have no operational difference but visual difference. – halil Jan 08 '15 at 07:56
1

Do you want to block the UI thread or not?

In any case, the best way to do might be to use the JLayeredPane, pop up a JLabel (you need to set its size yourself) on the modal layer in the JLayeredPane, and then remove it when the job is done.

ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
  • There is an example about your answer which I found [here](http://alvinalexander.com/java/java-custom-mouse-cursor-xy-coordinates-position) for the ones interested in the subject. – halil Jan 08 '15 at 08:06
0

This is not the answer, but maybe can do what you want to:

package com.stackoverflow.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 Stackoverflow question http://stackoverflow.com/questions/27822671
 */
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();
      }
    }));

    // http://stackoverflow.com/a/1984117/3366578
    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);
      }
    });
  }
}

That's just an idea.

fscherrer
  • 218
  • 3
  • 8