You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

需求:实现带密码预览按钮的独立JPasswordField组件

带密码查看按钮的JPasswordField单组件实现

我需要一个集成了密码查看按钮的JPasswordField,按住鼠标左键点击按钮图标时可查看已输入密码,且希望用单个组件实现,而非密码框+图标标签的面板组合。下面是我实现的方案:

核心思路

通过自定义Border扩展JPasswordField的右侧区域,嵌入密码查看图标,并通过鼠标事件控制密码的显示/隐藏状态,全程保持组件为单个JPasswordField实例。

完整代码实现

import javax.swing.*;
import javax.swing.border.AbstractBorder;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class PasswordFieldWithToggle extends JPasswordField {
    private static final int ICON_SIZE = 16;
    private static final int ICON_PADDING = 4;
    private Icon eyeIcon;
    private Icon eyeOffIcon;
    private boolean isPasswordVisible = false;
    private Border originalBorder;

    public PasswordFieldWithToggle() {
        // 初始化图标,建议替换为专门的眼睛/闭眼图标
        eyeIcon = new ImageIcon("path/to/eye-icon.png");
        eyeOffIcon = new ImageIcon("path/to/eye-off-icon.png");

        originalBorder = getBorder();
        setBorder(new PasswordBorder());

        // 监听鼠标事件控制密码显示
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                if (isOverToggleIcon(e.getPoint())) {
                    isPasswordVisible = true;
                    setEchoChar((char) 0); // 显示明文
                    repaint();
                }
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                hidePassword();
            }

            @Override
            public void mouseExited(MouseEvent e) {
                hidePassword();
            }

            private void hidePassword() {
                if (isPasswordVisible) {
                    isPasswordVisible = false;
                    setEchoChar('•'); // 恢复隐藏状态
                    repaint();
                }
            }
        });
    }

    // 判断鼠标是否点击在图标区域
    private boolean isOverToggleIcon(Point point) {
        int toggleAreaStart = getWidth() - ICON_SIZE - ICON_PADDING * 2;
        return point.x >= toggleAreaStart && point.x <= getWidth() - ICON_PADDING
                && point.y >= (getHeight() - ICON_SIZE) / 2
                && point.y <= (getHeight() - ICON_SIZE) / 2 + ICON_SIZE;
    }

    // 自定义边框,扩展右侧空间并绘制图标
    private class PasswordBorder extends AbstractBorder {
        @Override
        public Insets getBorderInsets(Component c) {
            Insets originalInsets = originalBorder.getBorderInsets(c);
            // 扩展右侧边框,留出图标空间
            return new Insets(originalInsets.top, originalInsets.left,
                    originalInsets.bottom, originalInsets.right + ICON_SIZE + ICON_PADDING * 2);
        }

        @Override
        public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
            // 绘制原边框
            originalBorder.paintBorder(c, g, x, y, width - (ICON_SIZE + ICON_PADDING * 2), height);

            // 绘制图标区域的分隔线
            g.setColor(UIManager.getColor("Separator.foreground"));
            int separatorX = width - ICON_SIZE - ICON_PADDING * 2;
            g.drawLine(separatorX, y + 2, separatorX, height - 2);

            // 绘制当前状态的图标
            Icon icon = isPasswordVisible ? eyeIcon : eyeOffIcon;
            int iconX = width - ICON_SIZE - ICON_PADDING;
            int iconY = y + (height - ICON_SIZE) / 2;
            icon.paintIcon(c, g, iconX, iconY);
        }
    }

    // 测试示例
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("带查看按钮的密码框");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout(new FlowLayout());

            PasswordFieldWithToggle passwordField = new PasswordFieldWithToggle();
            passwordField.setColumns(20);
            frame.add(passwordField);

            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

关键细节说明

  • 图标替换:代码中使用ImageIcon加载本地图标,实际开发中请替换为项目中对应的眼睛/闭眼图标路径。
  • 边框处理:自定义Border包装原组件边框,不会破坏原有UI风格,同时扩展右侧空间放置图标。
  • 交互逻辑:鼠标按住图标时显示明文,松开或移出组件时自动恢复隐藏状态,符合常见的密码查看交互习惯。

内容的提问来源于stack exchange,提问作者Robert Kock

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 23:47:46