Java: JPanel 组件在切换面板时向一侧倾斜
Java: JPanel components tilt to the side when switching panels
我想使用 BorderLayout
(即使我可以尝试 CardLayout
,如果有必要)和固定组件位置以供个人将来参考。
在我的示例中,我创建了三个面板:
login_page
home_page
exit_page
如果登录信息正确,程序切换到home_page
。
如果登录信息不正确,程序切换到exit_page
。
我测试了所有可能的面板序列。当我尝试从第一个面板转到下一个面板时,下一个面板的组件似乎被拖到一边,如下所示:
当我尝试在 actionPerformed
方法的末尾再次设置布局时,我相信我遗漏了一些东西,但我在网上找到的几个例子都使用了这种方法。
如何将下一个面板的组件放到正确的位置?
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class LoginForm extends JFrame implements ActionListener
{
private JFrame frame; //main frame
private JPanel login_page; //3 different panels/pages/states
private JPanel home_page;
private JPanel exit_page;
private JLabel login_label; //login form components
private JLabel username_label;
private JLabel password_label;
private JTextField username_text;
private JPasswordField password_text;
private JButton login_button;
private JLabel home_label; //homepage components
private JButton logout_button;
private JLabel locked_label; //exit page components
private JButton exit_button;
LoginForm() //initialization for the components and panels
{
frame = new JFrame("Login Form frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//////////////////////////////////////////////////////
/////////login form components initialization/////////
//////////////////////////////////////////////////////
login_page = new JPanel();
login_label = new JLabel("Login label");
username_label = new JLabel("Username");
password_label = new JLabel("Password");
username_text = new JTextField();
password_text = new JPasswordField();
login_button = new JButton("Login");
login_button.addActionListener(this);
login_label.setBounds(100,30,400,30);
username_label.setBounds(80,70,200,30);
username_text.setBounds(300,70,200,30);
password_label.setBounds(80,110,200,30);
password_text.setBounds(300,110,200,30);
login_button.setBounds(150,160,100,30);
login_page.add(login_label);
login_page.add(username_label);
login_page.add(username_text);
login_page.add(password_label);
login_page.add(password_text);
login_page.add(login_button);
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////home page components initialization/////////
//////////////////////////////////////////////////////
home_page = new JPanel();
home_label = new JLabel("Home label");
logout_button = new JButton("Logout");
logout_button.addActionListener(this);
home_label.setBounds(100,30,400,30);
logout_button.setBounds(150,160,100,30);
home_page.add(home_label);
home_page.add(logout_button);
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////exit page components initialization/////////
//////////////////////////////////////////////////////
exit_page = new JPanel();
locked_label = new JLabel("You are now locked from the database");
exit_button = new JButton("Exit");
exit_button.addActionListener(this);
locked_label.setBounds(100,30,400,30);
exit_button.setBounds(150,160,100,30);
exit_page.add(locked_label);
exit_page.add(exit_button);
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
frame.setContentPane(login_page); //first page to get seen
frame.setSize(550,250); //size of the window
frame.setLayout(new BorderLayout());
frame.setVisible(true);
frame.setResizable(false);
}
@Override
public void actionPerformed(ActionEvent listener)
{
JButton button = (JButton) listener.getSource();
if(button == login_button)
{
String name = username_text.getText();
String password = new String(password_text.getPassword());
if(name.equals("x") && password.equals("x"))
{
frame.remove(login_page);
frame.setContentPane(home_page);
}
else
{
frame.remove(login_page);
frame.setContentPane(exit_page);
}
}
else if(button == logout_button)
{
frame.remove(home_page);
frame.setContentPane(login_page);
}
else if (button == exit_button)
{
frame.dispose();
}
frame.setLayout(new BorderLayout());
frame.validate();
frame.repaint();
}
public static void main(String args[])
{
LoginForm login = new LoginForm();
}
}
您的问题可能是frame.setSize(550,250);
在使用布局时,最好在添加所有组件和面板后使用 pack()
将所有 JPanels
的布局设置为空。默认情况下,将设置 FlowLayout
,这是导致问题的原因。
初始化后添加login_page.setLayout(null)
。
初始化后添加home_page.setLayout(null)
。
初始化后添加exit_page.setLayout(null)
。
这应该可以解决您的问题。虽然这是解决问题的快速方法,但这不是正确的解决方法。
在 java swings 中设置空布局是不可取的,因为:
A layout manager makes it easier to adjust to look-and-feel-dependent
component appearances, to different font sizes, to a container's
changing size, and to different locales. Layout managers also can be
reused easily by other containers, as well as other programs
所以总是使用布局管理器。因此,不要使用 setBounds()
语句手动设置组件的位置,而是使用布局管理器来定位组件。有关如何使用各种布局管理器的更多信息,请参阅 here。我更喜欢这里的 GridBagLayout
,因为它更灵活。
but several examples I found online used this exact way.
我对此表示怀疑,因为代码有很多问题,它只能偶然运行。
让我们从 Swing 的设计用途开始:
每个面板都应该使用布局管理器。布局管理器将设置添加到面板的每个组件的大小和位置。框架内容窗格的默认布局管理器是 BorderLayout
。 JPanel 的默认布局管理器是 FlowLayout
.
编码的正常顺序是创建面板和设置布局管理器。然后将组件添加到面板。然后将面板添加到框架中。
接下来在框架上调用 pack() 和 setVisible()。这将为所有添加到框架的面板调用布局管理器,组件将根据每个布局管理器的规则逻辑显示。
现在随着框架的大小调整,组件将grow/shrink基于布局管理器的规则,您已经为自己创建了一个漂亮的动态 GUI。
现在你在做什么:
您正在尝试使用 setBounds() 来设置每个组件的大小和位置。大小只是一个随机猜测。你不知道合适的尺寸应该是多少。如果您想将字体更改为更大的尺寸怎么办?现在您将开始截断文本。不要尝试设置 Swing 组件的边界。每个组件都有逻辑来确定自己的首选大小。
接下来设置框架的内容窗格(这很好),然后调用 setLayout() 和 validate()。你甚至知道那些声明的作用吗?
使用 setLayout() 的目的是告诉面板在向框架添加组件时使用什么布局管理器,但绝不会向框架添加任何面板。
接下来使用 validate()(使用 Swing 时应该是 revalidate())。该方法的目的是调用布局管理器。因此布局管理器将重置所有组件的 size/location 并完全忽略您使用的 setBounds() 语句。
您的代码只是偶然起作用,因为您在将面板添加到框架后将布局更改为 BorderLayout。由于在使用 BorderLayout 时您永远不会向框架添加任何组件,因此布局管理器无事可做。
所以解决方案是:
不要使用 setBounds()。
为您的 3 个面板中的每一个使用适当的布局管理器。
在框架上使用CardLayout
。然后您可以根据需要交换上述每个面板。不要试图重新发明轮子。
阅读 Layout Mangers 上的 Swing 教程,了解更多信息和工作示例。
我想使用 BorderLayout
(即使我可以尝试 CardLayout
,如果有必要)和固定组件位置以供个人将来参考。
在我的示例中,我创建了三个面板:
login_page
home_page
exit_page
如果登录信息正确,程序切换到home_page
。
如果登录信息不正确,程序切换到exit_page
。
我测试了所有可能的面板序列。当我尝试从第一个面板转到下一个面板时,下一个面板的组件似乎被拖到一边,如下所示:
当我尝试在 actionPerformed
方法的末尾再次设置布局时,我相信我遗漏了一些东西,但我在网上找到的几个例子都使用了这种方法。
如何将下一个面板的组件放到正确的位置?
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class LoginForm extends JFrame implements ActionListener
{
private JFrame frame; //main frame
private JPanel login_page; //3 different panels/pages/states
private JPanel home_page;
private JPanel exit_page;
private JLabel login_label; //login form components
private JLabel username_label;
private JLabel password_label;
private JTextField username_text;
private JPasswordField password_text;
private JButton login_button;
private JLabel home_label; //homepage components
private JButton logout_button;
private JLabel locked_label; //exit page components
private JButton exit_button;
LoginForm() //initialization for the components and panels
{
frame = new JFrame("Login Form frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//////////////////////////////////////////////////////
/////////login form components initialization/////////
//////////////////////////////////////////////////////
login_page = new JPanel();
login_label = new JLabel("Login label");
username_label = new JLabel("Username");
password_label = new JLabel("Password");
username_text = new JTextField();
password_text = new JPasswordField();
login_button = new JButton("Login");
login_button.addActionListener(this);
login_label.setBounds(100,30,400,30);
username_label.setBounds(80,70,200,30);
username_text.setBounds(300,70,200,30);
password_label.setBounds(80,110,200,30);
password_text.setBounds(300,110,200,30);
login_button.setBounds(150,160,100,30);
login_page.add(login_label);
login_page.add(username_label);
login_page.add(username_text);
login_page.add(password_label);
login_page.add(password_text);
login_page.add(login_button);
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////home page components initialization/////////
//////////////////////////////////////////////////////
home_page = new JPanel();
home_label = new JLabel("Home label");
logout_button = new JButton("Logout");
logout_button.addActionListener(this);
home_label.setBounds(100,30,400,30);
logout_button.setBounds(150,160,100,30);
home_page.add(home_label);
home_page.add(logout_button);
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////exit page components initialization/////////
//////////////////////////////////////////////////////
exit_page = new JPanel();
locked_label = new JLabel("You are now locked from the database");
exit_button = new JButton("Exit");
exit_button.addActionListener(this);
locked_label.setBounds(100,30,400,30);
exit_button.setBounds(150,160,100,30);
exit_page.add(locked_label);
exit_page.add(exit_button);
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
frame.setContentPane(login_page); //first page to get seen
frame.setSize(550,250); //size of the window
frame.setLayout(new BorderLayout());
frame.setVisible(true);
frame.setResizable(false);
}
@Override
public void actionPerformed(ActionEvent listener)
{
JButton button = (JButton) listener.getSource();
if(button == login_button)
{
String name = username_text.getText();
String password = new String(password_text.getPassword());
if(name.equals("x") && password.equals("x"))
{
frame.remove(login_page);
frame.setContentPane(home_page);
}
else
{
frame.remove(login_page);
frame.setContentPane(exit_page);
}
}
else if(button == logout_button)
{
frame.remove(home_page);
frame.setContentPane(login_page);
}
else if (button == exit_button)
{
frame.dispose();
}
frame.setLayout(new BorderLayout());
frame.validate();
frame.repaint();
}
public static void main(String args[])
{
LoginForm login = new LoginForm();
}
}
您的问题可能是frame.setSize(550,250);
在使用布局时,最好在添加所有组件和面板后使用 pack()
将所有 JPanels
的布局设置为空。默认情况下,将设置 FlowLayout
,这是导致问题的原因。
初始化后添加login_page.setLayout(null)
。
初始化后添加home_page.setLayout(null)
。
初始化后添加exit_page.setLayout(null)
。
这应该可以解决您的问题。虽然这是解决问题的快速方法,但这不是正确的解决方法。
在 java swings 中设置空布局是不可取的,因为:
A layout manager makes it easier to adjust to look-and-feel-dependent component appearances, to different font sizes, to a container's changing size, and to different locales. Layout managers also can be reused easily by other containers, as well as other programs
所以总是使用布局管理器。因此,不要使用 setBounds()
语句手动设置组件的位置,而是使用布局管理器来定位组件。有关如何使用各种布局管理器的更多信息,请参阅 here。我更喜欢这里的 GridBagLayout
,因为它更灵活。
but several examples I found online used this exact way.
我对此表示怀疑,因为代码有很多问题,它只能偶然运行。
让我们从 Swing 的设计用途开始:
每个面板都应该使用布局管理器。布局管理器将设置添加到面板的每个组件的大小和位置。框架内容窗格的默认布局管理器是
BorderLayout
。 JPanel 的默认布局管理器是FlowLayout
.编码的正常顺序是创建面板和设置布局管理器。然后将组件添加到面板。然后将面板添加到框架中。
接下来在框架上调用 pack() 和 setVisible()。这将为所有添加到框架的面板调用布局管理器,组件将根据每个布局管理器的规则逻辑显示。
现在随着框架的大小调整,组件将grow/shrink基于布局管理器的规则,您已经为自己创建了一个漂亮的动态 GUI。
现在你在做什么:
您正在尝试使用 setBounds() 来设置每个组件的大小和位置。大小只是一个随机猜测。你不知道合适的尺寸应该是多少。如果您想将字体更改为更大的尺寸怎么办?现在您将开始截断文本。不要尝试设置 Swing 组件的边界。每个组件都有逻辑来确定自己的首选大小。
接下来设置框架的内容窗格(这很好),然后调用 setLayout() 和 validate()。你甚至知道那些声明的作用吗?
使用 setLayout() 的目的是告诉面板在向框架添加组件时使用什么布局管理器,但绝不会向框架添加任何面板。
接下来使用 validate()(使用 Swing 时应该是 revalidate())。该方法的目的是调用布局管理器。因此布局管理器将重置所有组件的 size/location 并完全忽略您使用的 setBounds() 语句。
您的代码只是偶然起作用,因为您在将面板添加到框架后将布局更改为 BorderLayout。由于在使用 BorderLayout 时您永远不会向框架添加任何组件,因此布局管理器无事可做。
所以解决方案是:
不要使用 setBounds()。
为您的 3 个面板中的每一个使用适当的布局管理器。
在框架上使用
CardLayout
。然后您可以根据需要交换上述每个面板。不要试图重新发明轮子。阅读 Layout Mangers 上的 Swing 教程,了解更多信息和工作示例。