Java Swing调用setText设置标签文本时出现多余组件如何修复
问题根因
你遇到的组件错位、出现多余重复组件的问题主要由以下几个错误导致:
- 布局约束绑定错误:给登录面板
p内部的组件配置SpringLayout约束时,错误地将参考对象设置为了整个窗口的contentPane,而非p自身。p本身在窗口中已经有(432,155)的偏移量,内部组件再基于整个窗口定位,会导致组件实际渲染位置超出面板范围,调用setText触发界面重绘后布局计算混乱,出现组件错位、重复绘制的问题,视觉上就像多了多余组件。 - 窗口布局冲突:JFrame默认使用BorderLayout布局,先后调用
f.add(p)和f.add(img)时都没有指定布局约束,两个组件都会被放到BorderLayout的CENTER区域,互相叠加产生绘制冲突。 - 半透明绘制异常:给面板
p设置了alpha值仅为5的半透明背景,但没有将面板设置为非不透明(opaque=false),Swing默认不会正确处理半透明容器的绘制,容易产生画面残留。 - 多余循环加重绘制问题:验证失败的分支里错误使用while循环修改标签文本,单次点击会触发3次文本修改和界面重绘,进一步加重了绘制异常。
- 尝试计数逻辑错误:计数变量
i定义在点击事件方法内部,每次点击登录都会被重置为0,无法实现累计3次尝试的限制逻辑。 - 废弃API使用:
JPasswordField.getText()方法已被官方废弃,存在安全风险,应当使用getPassword()获取密码字符数组后再转字符串比较。
修复步骤
- 调整SpringLayout约束的参考对象为面板
p自身,同步调整约束数值适配面板的400*450尺寸。 - 调整背景图和面板的层级:将背景图
img作为窗口底层组件,再将登录面板p设置为透明,叠加在背景图上层。 - 给面板
p添加setOpaque(false)配置,保证半透明效果正确渲染。 - 去掉无用的while循环,将计数变量
i改为类的成员变量,实现累计计数,达到3次尝试后锁定登录按钮。 - 替换废弃的密码获取API,同时保证Swing组件在事件分发线程初始化避免线程安全问题。
修复后完整代码
import java.awt.*; import java.awt.Font; import javax.swing.*; import java.awt.event.*; public class LoginGUI implements ActionListener{ //Variables JTextField tField1, tField2; JPasswordField pwField; JButton btn1, btn2; JLabel label1, label2, label3, label4; private ImageIcon bgImage; private JLabel img; simpleCal Calculator; // 登录尝试计数改为成员变量实现累计计数 int attemptCount = 0; int maxAttempt = 3; public LoginGUI(){ //Layout SpringLayout layout = new SpringLayout(); bgImage = new ImageIcon(this.getClass().getResource("/assets/loginBG.png")); img = new JLabel(bgImage); JFrame f = new JFrame("Login"); f.setSize(1280,800); // 把背景图设为内容面板,后续组件直接叠加在背景上 f.setContentPane(img); f.setLayout(new BorderLayout()); JPanel p = new JPanel(); p.setLayout(layout); p.setPreferredSize(new Dimension(400,450)); p.setBackground(new Color(101,168,223,5)); // 设置面板非不透明,解决半透明绘制异常问题 p.setOpaque(false); f.add(p, BorderLayout.CENTER); //Fonts Font font1 = new Font("calibri",Font.BOLD,20); Font font2 = new Font("calibri",Font.BOLD,14); //Label label1 = new JLabel("Username:"); label1.setFont(font1); label1.setForeground(new Color(55,55,55)); // 约束参考改为面板p自身 layout.putConstraint(layout.WEST, label1, 50, layout.WEST, p); layout.putConstraint(layout.NORTH, label1, 130, layout.NORTH, p); label2 = new JLabel("Password:"); label2.setFont(font1); label2.setForeground(new Color(55,55,55)); layout.putConstraint(layout.WEST, label2, 50, layout.WEST, p); layout.putConstraint(layout.NORTH, label2, 30, layout.SOUTH, label1); label3 = new JLabel(""); label3.setFont(font1); label3.setForeground(new Color(55,55,55)); layout.putConstraint(layout.WEST, label3, 70, layout.WEST, p); layout.putConstraint(layout.NORTH, label3, 40, layout.NORTH, p); label4 = new JLabel(""); label4.setFont(font1); label4.setForeground(new Color(55,55,55)); layout.putConstraint(layout.WEST, label4, 105, layout.WEST, p); layout.putConstraint(layout.NORTH, label4, 20, layout.SOUTH, label3); //TextField tField1 = new JTextField(""); tField1.setFont(font2); tField1.setColumns(15); tField1.setBackground(new Color(101,168,223)); layout.putConstraint(layout.WEST, tField1, 40, layout.EAST, label1); layout.putConstraint(layout.NORTH, tField1, 130, layout.NORTH, p); //PasswordField pwField = new JPasswordField(); pwField.setFont(font2); pwField.setColumns(15); pwField.setBackground(new Color(101,168,223)); layout.putConstraint(layout.WEST, pwField, 43, layout.EAST, label2); layout.putConstraint(layout.NORTH, pwField, 30, layout.SOUTH, tField1); //Button btn1 = new JButton("Log in"); btn1.setFont(font1); btn1.setSize(100,50); btn1.addActionListener(this); p.add(btn1); layout.putConstraint(layout.WEST, btn1, 80, layout.WEST, p); layout.putConstraint(layout.NORTH, btn1, 250, layout.NORTH, p); p.add(label3); p.add(label4); p.add(tField1); p.add(pwField); p.add(label1); p.add(label2); f.setVisible(true); f.setResizable(false); f.setLocationRelativeTo(null); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public void actionPerformed(ActionEvent e){ String user, pass; if(e.getSource()==btn1){ user = tField1.getText(); // 替换废弃的getText方法 pass = new String(pwField.getPassword()); if(user.equals("vince")&&pass.equals("123")){ Calculator = new simpleCal(); // 登录成功后可主动关闭登录窗口 // ((JFrame)SwingUtilities.getWindowAncestor(btn1)).dispose(); } else{ attemptCount++; label3.setText("登录凭据错误"); label4.setText("尝试次数: " + attemptCount); if(attemptCount >= maxAttempt){ btn1.setEnabled(false); label3.setText("尝试次数过多,登录已锁定"); } } } } public static void main(String[]args){ // 保证Swing组件在事件分发线程初始化,避免线程安全问题 SwingUtilities.invokeLater(() -> new LoginGUI()); } }
内容的提问来源于stack exchange,提问作者Vince Viloria
相关产品推荐
相关产品推荐

