首页 > 解决方案 > 当 JButton 被按下时,JPanel 在 JFrame 中改变形状/位置。为什么?

问题描述

基本上,我在 JFrame 中添加了一个 JPanel,每当我按下 JPanel 中的按钮(这会改变 JPanel 中组件的可见性)时,JPanel 的大小和组件的位置都会发生变化。我一生都无法弄清楚为什么会出现这个问题。任何帮助是极大的赞赏。

谷歌搜索

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class Main {

private JFrame window;
private JPanel loginPanel;
private JButton loginButton;
private JTextField usernameField;
private JPasswordField passwordField;
private JLabel usernameLabel, passwordLabel, errorMessage;


public static void main(String[] args) {
    Main program = new Main();
}

public Main() {
    createWindow();
    runProgram();
}

private void createWindow() {

    window = new JFrame("Dentist Program");
    window.setSize(1450, 900);
    window.setVisible(true);
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    loginPanel = new JPanel();
    loginPanel.setSize(300, 400);
    loginPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));

    usernameLabel = new JLabel("Username");
    usernameLabel.setSize(125, 20);
    usernameLabel.setLocation(loginPanel.getWidth()/2 - usernameLabel.getWidth()/2, 100);

    usernameField = new JTextField();
    usernameField.setSize(125, 25);
    usernameField.setLocation(loginPanel.getWidth()/2 - usernameField.getWidth()/2, usernameLabel.getY() + usernameLabel.getHeight());

    passwordLabel = new JLabel("Password");
    passwordLabel.setSize(125, 20);
    passwordLabel.setLocation(loginPanel.getWidth()/2 - passwordLabel.getWidth()/2, usernameField.getY() + usernameField.getHeight() + 10);

    passwordField = new JPasswordField();
    passwordField.setSize(125, 25);
    passwordField.setLocation(loginPanel.getWidth()/2 - passwordField.getWidth()/2, passwordLabel.getY() + passwordLabel.getHeight());

    loginButton = new JButton("Log In");
    loginButton.setSize(80, 25);
    loginButton.setLocation(passwordField.getX(), passwordField.getY() + passwordField.getHeight() + 15);
    loginButton.addActionListener(new ActionListener()
            {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                errorMessage.setText("");
                loginPanel.repaint();
            }
            });

    errorMessage = new JLabel("Username and/or password is incorrect");
    errorMessage.setSize(250, 25);
    errorMessage.setLocation(loginPanel.getWidth()/2 - errorMessage.getWidth()/2, loginButton.getY() + loginButton.getHeight() + 25);
    errorMessage.setForeground(Color.RED);

    loginPanel.add(usernameLabel);
    loginPanel.add(usernameField);
    loginPanel.add(passwordLabel);
    loginPanel.add(passwordField);
    loginPanel.add(loginButton);
    loginPanel.add(errorMessage);

    window.getContentPane().add(loginPanel);
    window.repaint();

}

private void runProgram() {

}
}

标签: javaswingjframejpanel

解决方案


您的 UI 更改的原因是因为您认为正确的外观(初始外观)实际上是错误的,调整大小的版本是“正确”的版本。

通常,您会pack()在将组件添加到容器后调用,该容器会尝试以其首选大小显示该容器的内容。要在按下按钮之前和之后查看正确的 UI,请在调用repaint()之后添加:

window.pack();

您可能认为这看起来很糟糕(确实如此),但这正是您的代码所要求的,因此是“正确”的版本。

请注意,您正在尝试通过显式调用来设置大小setSize(),这在 Swing 中是一种不好的做法。最多,您应该设置首选尺寸并让布局管理器处理细节。当您尝试对组件的尺寸和位置进行微观管理时,您通常可以让它在一个平台上看起来不错,但在其他平台上却是不可挽回的糟糕。请记住,Java 应该是“一次编写,随处运行”的语言。

当您想要对布局进行更多控制时,您应该明确指定并使用布局管理器,而不是仅仅接受默认布局。在几乎所有重要的 UI 中,GridBagLayout都是您最好的选择。

最后,当某些事情发生变化时,您不需要显式调用repaint()您的 UI。通常,您会paint()repaint()处理图形时调用。让 Swing 自动处理绘画。


推荐阅读