带有预览按钮的JPasswordField

问题描述 投票:0回答:1

我需要一个带有小按钮(或类似的东西)的 JPasswordField 和一个图标,当在该图标上按下鼠标左键时,该图标会显示到目前为止输入的密码。
这可以很容易地实现,创建一个由密码字段和右侧带有图标的标签组成的面板,如这个问题的答案中所建议的,但我更喜欢使用单个组件来完成这项工作。
经过一番分析,我找到了一个解决方案,就是带有特定边框的普通字段。该边框是原始边框的包装,并在显示图标的右侧放大。
由于我需要这样的组件,我认为其他人可能正在寻找同样的东西,我想分享我的解决方案。
请找到我的解决方案作为答案。

java swing passwords
1个回答
0
投票
/**********************************************************************************************************************
 * Package definition
 *********************************************************************************************************************/
package test;

/**********************************************************************************************************************
 * Import specifications
 *********************************************************************************************************************/
import java.awt.*;
import java.awt.event.*;
import java.net.URL;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.*;

/**********************************************************************************************************************
 * This class manages a password field with a little eye on the right side showing the password when the mouse is
 * pressed.
 *********************************************************************************************************************/
@SuppressWarnings("serial")
public class PreviewPasswordField extends JPasswordField
{
  /********************************************************************************************************************
   * The constructor initializes the object.
   *******************************************************************************************************************/
  public PreviewPasswordField()
  {
    // ---------------------
    // Initialize attributes
    // ---------------------
    requestedBorder = getBorder();
    requestedCursor = getCursor();
    imageCursor = new Cursor(Cursor.HAND_CURSOR);

    // --------------
    // Set new border
    // --------------
    setBorder(new PasswordBorder());

    // ---------------
    // Listen to mouse
    // ---------------
    PasswordMouseListener listener;
    listener = new PasswordMouseListener();
    addMouseListener(listener);
    addMouseMotionListener(listener);
    addCaretListener(listener);

    // ----
    // Done
    // ----
    objectConstructed = true;

  } // constructor

  /********************************************************************************************************************
   * This method sets the border of this component.
   *******************************************************************************************************************/
  @Override
  public void setBorder(Border border)
  {
    // ------------------------------------------------------------------------------------------
    // We're called also during the construction of the component when setting the default border
    // Therefore, do normal stuff if construction not completed yet
    // ------------------------------------------------------------------------------------------
    if (!objectConstructed)
    {
      super.setBorder(border);
      return;
    }

    // ----------------------------------------------------------
    // Save requested border and make sure user sees what happens
    // ----------------------------------------------------------
    requestedBorder = border;
    invalidate();

  } // setBorder

  /********************************************************************************************************************
   * This method sets the cursor of this component.
   *******************************************************************************************************************/
  @Override
  public void setCursor(Cursor cursor)
  {
    // ------------------------------------------------------------------------------------------
    // We're called also during the construction of the component when setting the default cursor
    // Therefore, do normal stuff if construction not completed yet
    // ------------------------------------------------------------------------------------------
    if (!objectConstructed)
    {
      super.setCursor(cursor);
      return;
    }

    // ----------------------------------------------------------
    // Save requested cursor and make sure user sees what happens
    // ----------------------------------------------------------
    requestedCursor = cursor;
    invalidate();

  } // setCursor

  /********************************************************************************************************************
   * This method sets the cursor to be shown when the mouse is above the preview image.
   * <br>It defaults to {@link Cursor#HAND_CURSOR}.
   *******************************************************************************************************************/
  public void setPreviewCursor(Cursor cursor)
  {
    // ----------------------------------------------------------
    // Save requested cursor and make sure user sees what happens
    // ----------------------------------------------------------
    imageCursor = cursor;
    invalidate();

  } // setPreviewCursor

  /********************************************************************************************************************
   * This method returns the cursor as it is be shown when the mouse is above the preview image.
   * <br>It defaults to {@link Cursor#HAND_CURSOR}.
   *******************************************************************************************************************/
  public Cursor getPreviewCursor()
  {
    return (imageCursor);
  }

  /********************************************************************************************************************
   * This class implements the border around the password field.
   *******************************************************************************************************************/
  private class PasswordBorder implements Border
  {
    /******************************************************************************************************************
     * This method returns the insets of the border for specified component.
     *****************************************************************************************************************/
    @Override
    public Insets getBorderInsets(Component c)
    {
      // ---------------------------------------------------------------------------
      // Just the original insets with an added part of the right side for the image
      // The latter equals the height of the field
      // ---------------------------------------------------------------------------
      Insets result;
      if (requestedBorder == null)
        result = new Insets(0, 0, 0, 0);
      else
        result = requestedBorder.getBorderInsets(c);
      result.right += getHeight();

      // ----
      // Done
      // ----
      return (result);

    } // getBorderInsets

    /******************************************************************************************************************
     * This method returns whether or not the border is opaque.
     *****************************************************************************************************************/
    @Override
    public boolean isBorderOpaque()
    {
      // -------------------------------------------------
      // Simply the original border's flag if specified
      // Otherwise, we take care of filling the background
      // -------------------------------------------------
      if (requestedBorder == null)
        return (true);
      else
        return (requestedBorder.isBorderOpaque());

    } // isBorderOpaque

    /******************************************************************************************************************
     * This method paints the border for the specified component with the specified position and size.
     *****************************************************************************************************************/
    @Override
    public void paintBorder(Component c,
                            Graphics  g,
                            int       x,
                            int       y,
                            int       width,
                            int       height)
    {
      // -----------------------------------------------------------------------
      // Determine where the icon starts
      // Equals the specified position plus the total width minus the icon width
      // The latter equals the component's height
      // -----------------------------------------------------------------------
      int iconWidth;
      int iconOffset;
      iconWidth = getHeight();
      iconOffset = x + width - iconWidth;

      // -----------------------------------------------------------------
      // Paint normal border around the field, leaving the image untouched
      // -----------------------------------------------------------------
      if (requestedBorder != null)
        requestedBorder.paintBorder(c, g, x, y, width - iconWidth, height);

      // -------------------------------------------
      // Set background where the image will be draw
      // -------------------------------------------
      Graphics iconGraph;
      iconGraph = g.create();
      iconGraph.setColor(getParent().getBackground());
      iconGraph.fillRect(iconOffset, y, iconWidth, height);

      // --------------------------------------------------------------------------------------------------
      // Make sure icon has correct size
      // When for instance a different border is set, the height of the component and therefore the size of
      // the image may change
      // --------------------------------------------------------------------------------------------------
      if ((scaledImage == null) || (scaledImage.getIconHeight() != height))
        scaledImage = new ImageIcon(previewImage.getImage().getScaledInstance(height, height, Image.SCALE_SMOOTH));

      // --------------
      // Now draw image
      // --------------
      scaledImage.paintIcon(c, iconGraph, iconOffset, y);

    } // paintBorder

  } // class PasswordBorder

  /********************************************************************************************************************
   * This class implements the listener for events.
   *******************************************************************************************************************/
  private class PasswordMouseListener extends MouseAdapter implements CaretListener
  {
    /******************************************************************************************************************
     * This method is called when the caret position is updated.
     *****************************************************************************************************************/
    @Override
    public void caretUpdate(CaretEvent e)
    {
      // ---------------------------
      // Keep track of last position
      // ---------------------------
      lastCaret = e.getDot();

    } // caretUpdate

    /******************************************************************************************************************
     * This method is called when the mouse moves within the component.
     *****************************************************************************************************************/
    @Override
    public void mouseMoved(MouseEvent e)
    {
      // --------------------------------------------------------------------------------------
      // Set cursor according to location within component
      // We intercept the default behavior so make sure we invoke the method of the super class
      // --------------------------------------------------------------------------------------
      if (isMouseAboveImage(e.getPoint()))
        PreviewPasswordField.super.setCursor(imageCursor);
      else
        PreviewPasswordField.super.setCursor(requestedCursor);

    } // mouseMoved

    /******************************************************************************************************************
     * This method is called when a mouse button is pressed within the component.
     *****************************************************************************************************************/
    @Override
    public void mousePressed(MouseEvent e)
    {
      // -----------------------------
      // Ignore if not the left button
      // -----------------------------
      if (e.getButton() != MouseEvent.BUTTON1)
        return;

      // -----------------------
      // Save original echo char
      // -----------------------
      echoChar = getEchoChar();

      // ----------------------------------------------------------------
      // Show password and restore caret position if the icon was pressed
      // ----------------------------------------------------------------
      if (isMouseAboveImage(e.getPoint()))
      {
        if (getCaretPosition() != lastCaret)
          setCaretPosition(lastCaret);
        setEchoChar('\0');
      }

    } // mousePressed

    /******************************************************************************************************************
     * This method is called when a mouse button is released within the component.
     *****************************************************************************************************************/
    @Override
    public void mouseReleased(MouseEvent e)
    {
      // -----------------------------
      // Ignore if not the left button
      // -----------------------------
      if (e.getButton() != MouseEvent.BUTTON1)
        return;

      // -------------
      // Hide password
      // -------------
      setEchoChar(echoChar);

    } // mouseReleased

    /****************************************************************************************************************
     * This method returns if the specified position, relative to the component, is above the 'preview' image.
     ***************************************************************************************************************/
    private boolean isMouseAboveImage(Point relativePosition)
    {
      // -------------------------
      // Should be above component
      // -------------------------
      Dimension compSize;
      compSize = getSize();
      if ((relativePosition == null) ||
          (relativePosition.x < 0) || (relativePosition.x >= compSize.width) ||
          (relativePosition.y < 0) || (relativePosition.y >= compSize.height))
        return (false);

      // ----------------------------------------------------
      // Above image if it's within the last part
      // The width of the image equals the component's height
      // ----------------------------------------------------
      return (relativePosition.x >= (compSize.width - compSize.height));

    } // mouseAboveImage

    /******************************************************************************************************************
     * This attribute represents the character shown when the password is hidden.
     *****************************************************************************************************************/
    private char echoChar;

    private int lastCaret = 0;

  } // class PasswordMouseListener

  /********************************************************************************************************************
   * This attribute indicates if the object's construction has completed.
   * <br>We need it in order to be able to distinguish between setting the default border/cursor and a custom one.
   *******************************************************************************************************************/
  private boolean objectConstructed = false;

  /********************************************************************************************************************
   * This attribute represents the requested border of the component.
   *******************************************************************************************************************/
  private Border requestedBorder;

  /********************************************************************************************************************
   * This attribute represents the requested cursor when the mouse is above the component.
   *******************************************************************************************************************/
  private Cursor requestedCursor;

  /********************************************************************************************************************
   * This attribute represents the cursor when the mouse is above the image.
   *******************************************************************************************************************/
  private Cursor imageCursor;

  /********************************************************************************************************************
   * This attribute represents the icon to be shown next to the password, scaled to the correct size.
   *******************************************************************************************************************/
  private ImageIcon scaledImage = null;

  /********************************************************************************************************************
   * This attribute represents the icon to be shown next to the password.
   *******************************************************************************************************************/
  private static ImageIcon previewImage = null;

  /********************************************************************************************************************
   * This static initializer loads the image.
   *******************************************************************************************************************/
  static
  {
    // -------------------------------
    // Determine directory of the icon
    // -------------------------------
    String directory;
    directory = PreviewPasswordField.class.getPackage().getName().replace('.', '/');

    // ---------
    // Load icon
    // ---------
    URL name;
    name = ClassLoader.getSystemResource(directory + "/passwordPreview.png");
    previewImage = new ImageIcon(name);

  } // static initializer

} // class PreviewPasswordField
© www.soinside.com 2019 - 2024. All rights reserved.