JPanel меняет форму / положение в JFrame при нажатии JButton. Почему? - PullRequest
1 голос
/ 15 октября 2019

По сути, я добавил JPanel в JFrame, и всякий раз, когда я нажимаю кнопку внутри JPanel (которая изменяет видимость компонента в JPanel), меняются размер JPanel и расположение компонентов. Я не могу на всю жизнь понять, почему возникает эта проблема. Любая помощь приветствуется.

Google Searches

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() {

}
}

1 Ответ

1 голос
/ 15 октября 2019

Причина, по которой ваш пользовательский интерфейс изменяется, заключается в том, что ваш правильный взгляд (первоначальный внешний вид) на самом деле неправильный, а измененная версия - это "правильная" версия.

Как правило, вы вызываете pack() после добавления компонентов в контейнер, который пытается отобразить содержимое этого контейнера в их предпочтительных размерах. Чтобы увидеть правильный пользовательский интерфейс до и после нажатия кнопки, после вашего звонка на repaint() добавьте:

window.pack();

Вы можете подумать, что это выглядит ужасно (а это так), но это именно то, что запрашивает ваш кодfor и, следовательно, является «правильной» версией.

Обратите внимание, что вы пытаетесь установить размеры с явными вызовами setSize(), что является плохой практикой в ​​Swing. Самое большее, вы должны установить предпочтительные размеры и позволить менеджеру по расположению обрабатывать детали. Когда вы пытаетесь управлять размерами компонентов и их местоположением, вы часто можете заставить их хорошо выглядеть на одной платформе, но безоговорочно плохо на других. Помните, что Java должен быть языком «пиши один раз, беги куда угодно».

Если вам нужен больший контроль над макетом, вы должны явно указать и использовать менеджер макетов, а не просто принимать макет по умолчанию. Почти в каждом нетривиальном пользовательском интерфейсе GridBagLayout является вашей лучшей ставкой.

Наконец, вам не нужно явно вызывать repaint() в своем пользовательском интерфейсе, когда что-то меняется. Как правило, вы звоните paint() и repaint(), когда работаете с графикой. Позвольте Swing обрабатывать картину автоматически.

...