因此,我制作了一个类,该类在JPasswordField
中表现出一点眼睛,并允许屏蔽/取消屏蔽密码。
它看起来像这样:
问题是,尽管使用Windows L&F看起来不错,但是对于IntelliJ L&F来说,它看起来绝对可怕,因为我只是为JPanel
使用默认的PasswordField边框来容纳眼睛以及实际的JPasswordField
。现在我在想,是否有办法通过直接将眼睛涂在JPasswordField
上并且不忽略内部密码的范围来获得这种行为。意味着里面的文字永远不要画在眼后,光标也不能滑到眼后。
我想避免为此编写一个完全自定义的文本字段,因为这听起来像是在重新发明轮子。
答案 0 :(得分:0)
您可以像这样将SpringLayout
用作JLayeredPane
:
import java.awt.Dimension;
import java.awt.Font;
import javax.swing.AbstractButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPasswordField;
import javax.swing.SpringLayout;
import javax.swing.SwingUtilities;
public class Main {
private static void createAndShowGUI() {
final AbstractButton show = new JCheckBox("Show");
//Just hide every decorating colors:
show.setBorderPainted(false);
show.setContentAreaFilled(false);
show.setFocusPainted(false);
final JPasswordField pass = new JPasswordField(20);
pass.setFont(new Font(Font.MONOSPACED, Font.PLAIN, pass.getFont().getSize()));
final char echo = pass.getEchoChar();
show.addActionListener(e -> {
pass.setEchoChar(show.isSelected()? 0: echo);
pass.requestFocusInWindow();
});
//Put the fields in a JLayeredPane:
final JLayeredPane pane = new JLayeredPane();
pane.setLayout(new SpringLayout());
pane.add(pass, JLayeredPane.DEFAULT_LAYER);
pane.add(show, JLayeredPane.PALETTE_LAYER); //Layer over the DEFAULT_LAYER one.
//Setup the layout of the pane:
final SpringLayout layout = (SpringLayout) pane.getLayout();
layout.putConstraint(SpringLayout.WEST, pass, 0, SpringLayout.WEST, pane);
layout.putConstraint(SpringLayout.EAST, pass, 0, SpringLayout.EAST, pane);
layout.putConstraint(SpringLayout.NORTH, pass, 0, SpringLayout.NORTH, pane);
layout.putConstraint(SpringLayout.SOUTH, pass, 0, SpringLayout.SOUTH, pane);
layout.putConstraint(SpringLayout.EAST, show, 0, SpringLayout.EAST, pane);
layout.putConstraint(SpringLayout.NORTH, show, 0, SpringLayout.NORTH, pane);
layout.putConstraint(SpringLayout.SOUTH, show, 0, SpringLayout.SOUTH, pane);
//Set the preferred size of the pane (it's not automatic with SpringLayout):
final Dimension showPrefSz = show.getPreferredSize(),
passPrefSz = pass.getPreferredSize();
pane.setPreferredSize(new Dimension(showPrefSz.width + passPrefSz.width, Math.max(showPrefSz.height, passPrefSz.height)));
final JFrame frame = new JFrame("Unmaskable password field");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(pane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(Main::createAndShowGUI);
}
}
任何Component
都可以使用,因此您可以放置带有 eye 图标的JButton
而不是我使用的JCheckBox
。
如果需要的话,我假设您要转到按钮上的setBorderPainted(false)
,setContentAreaFilled(false)
和setFocusPainted(false)
。
请注意,根据docs,您不得在setOpaque(false)
上呼叫AbstractButton
,而应使用setContentAreaFilled(false)
。
以下是相关的Java教程:
我在MRE中使用的SpringLayout.putConstraint
命令首先告诉LayoutManager
用JLayeredPane
(整个4个第一个命令)填充整个JTextComponent
,然后告诉将JCheckBox
粘贴在JLayeredPane
的东侧,并用JLayeredPane
填充JCheckBox
的整个高度,这将使{{ 1}}组件垂直居中(最后3个命令)。
注意:您需要设置JCheckBox
的首选大小,因为JLayeredPane
不会根据组件告诉它首选大小(例如其他SpringLayout
会这样做) )。
答案 1 :(得分:0)
由于VGR建议我使用setMargin
,这没有影响,所以我发现我可以通过使用使用原始JPasswordField
边框的复合边框简单地实现相同的行为,外边框,以EmtpyBorder
作为内边框,以便为显示/隐藏按钮腾出空间。这样,边界是正确的,当我与显示/隐藏图标进行交互时,我可以轻松编写可更改工具提示,光标和其他内容的代码。然后只需在paint
的{{1}}方法中绘制图标即可。
更新
因此,显然,这种方法也不能很好地与L&F配合使用,我发现一种更安全的方法是重写JPasswordField
,因为它没有设置方法。
另一个解决方案可能是getInsets()
。