需求:实现带密码预览按钮的独立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
相关产品推荐
相关产品推荐

