Java Swing:当变为“可见”时,不会重新计算添加了尺寸等于0的隐藏JPanel
我有一个程序,其中有两个面板,一个在左侧有两个切换按钮,另一个在右侧显示标签。 选中后,每个按钮将其面板添加到右侧区域,并将另一个按钮设置为不可见。 当取消选择时,它们会将其删除。 在最后一种情况下,如果添加到容器中,我希望另一个面板变为可见。 代码基本正常,但如果在“开始”面板上取消选择第2个按钮,则不会出现第1个按钮。 我发现面板1的尺寸设置为0,如果手动设置此尺寸,则会显示面板。不幸的是,当我调整窗口或JSplitPanel的大小时,布局管理器停止处理面板尺寸,这很糟糕 如何在不手动设置其他面板尺寸的情况下解决此问题? 我知道CardLayout可以解决此类需求,但不幸的是,它不适用于我的问题 谢谢 编辑: 根据评论中的要求,这里有一系列简单的行动来解释问题: 我所期望的是: 启动应用程序->选择两个按钮,两个面板都添加到右侧容器中,只有面板2可见,因为按钮2是代码最后选择的。 取消选择按钮2->面板2从右侧容器中移除,面板1切换为可见并显示在右侧容器中。 实际发生的情况: 如期 面板1未显示,因为其尺寸均为0,无效和重新绘制不起作用 两个面板都添加到右侧容器中,只有面板2可见 这是不正确的。您正在使用BorderLayout。问题是每个位置只能有一个组件。第一个被踢出的对象不再存在于容器中,只剩下最后一个添加的对象,您正在尝试将这两个对象都添加到中心 因此,您认为通过移除第二个面板,第一个面板将在调用setVisible时自动显示,这是不正确的。该组件实际上需要再次添加 根据这些新信息,尝试并调试您的问题。也可以使用重新验证而不是失效 面板1未显示,因为其尺寸均为0 与此无关。BorderLayout不关心大小。它将拉伸面板以适合 旁白:这是CardLayout的最佳情况。我不太清楚为什么不能使用它,但也许你应该深入挖掘实现它的可能性 更新 我想这可能就是你要找的。只需切换另一个按钮的状态即可Java Swing:当变为“可见”时,不会重新计算添加了尺寸等于0的隐藏JPanel,java,swing,jpanel,layout-manager,repaint,Java,Swing,Jpanel,Layout Manager,Repaint,我有一个程序,其中有两个面板,一个在左侧有两个切换按钮,另一个在右侧显示标签。 选中后,每个按钮将其面板添加到右侧区域,并将另一个按钮设置为不可见。 当取消选择时,它们会将其删除。 在最后一种情况下,如果添加到容器中,我希望另一个面板变为可见。 代码基本正常,但如果在“开始”面板上取消选择第2个按钮,则不会出现第1个按钮。 我发现面板1的尺寸设置为0,如果手动设置此尺寸,则会显示面板。不幸的是,当我调整窗口或JSplitPanel的大小时,布局管理器停止处理面板尺寸,这很糟糕 如何在不手动设置其
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test {
public static void main(final String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
final JFrame frame = new JFrame();
frame.setSize(800, 800);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel buttonsPanel = new JPanel(new FlowLayout());
final JToggleButton btn1 = new JToggleButton("Button 1");
final JToggleButton btn2 = new JToggleButton("Button 2");
buttonsPanel.add(btn1);
buttonsPanel.add(btn2);
final JPanel containerPanel = new JPanel(new BorderLayout());
final JPanel pan1;
final JPanel pan2;
pan1 = new JPanel(new BorderLayout());
pan2 = new JPanel(new BorderLayout());
pan1.add(new JLabel("panel 1"));
pan2.add(new JLabel("panel 2"));
pan1.setBackground(Color.WHITE);
pan2.setBackground(Color.RED);
btn1.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(final ItemEvent e) {
final int state = e.getStateChange();
if (state == ItemEvent.SELECTED) {
containerPanel.add(pan1, BorderLayout.CENTER);
containerPanel.remove(pan2);
btn2.getModel().setSelected(false);
} else {
containerPanel.add(pan2, BorderLayout.CENTER);
containerPanel.remove(pan1);
btn2.getModel().setSelected(true);
}
containerPanel.revalidate();
containerPanel.repaint();
}
});
btn2.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(final ItemEvent e) {
final int state = e.getStateChange();
if (state == ItemEvent.SELECTED) {
containerPanel.add(pan2, BorderLayout.CENTER);
containerPanel.remove(pan1);
btn1.getModel().setSelected(false);
} else {
containerPanel.add(pan1, BorderLayout.CENTER);
containerPanel.remove(pan2);
btn1.getModel().setSelected(true);
}
containerPanel.revalidate();
containerPanel.repaint();
}
});
btn1.setSelected(true);
btn2.setSelected(true);
final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
true,
buttonsPanel,
containerPanel);
splitPane.setResizeWeight(0.5);
frame.add(splitPane);
frame.setVisible(true);
}
});
}
}
我知道CardLayout可以解决此类需求,但不幸的是,它不适用于我的问题。为什么不呢?因为要这样做,我需要对我无法控制的代码进行大规模重构。如果有一个我可以控制的解决方案,它将是我最喜欢的。你用两个切换按钮在两个面板之间切换似乎很奇怪。切换按钮有两种状态,应该有两个决策,每个状态一个。那么,为什么需要两个切换按钮来在面板之间切换呢?只需将常规按钮与操作侦听器一起使用,或者只使用一个切换按钮。@peeskillet一个切换按钮无法处理两个面板都已插入但只有一个面板可见以及我需要处理的所有事务的情况。这个例子是一个非常复杂的应用程序的简化版本。你能用一个简单编号的事件序列编辑你的文章吗。对于你期望发生的事情,以及2。对于实际发生的事情。我真的不明白你的博文。这个答案的某些部分是不正确的:1。第一个面板没有被踢出,代码能够在容器中找到它并调用.setVisibletrue,而没有NullPointerException;2.如果在第一个面板上调用.setSize,那么您可以尝试该代码。无论如何,正如您所说,删除并再次添加面板是有效的,并且它的尺寸由LayoutManager处理。我也会尝试重新验证。是的,我想你是对的。在重新验证不起作用之前从来不用担心它。无论如何,谢谢你,我认为正如你所说的,问题在于FlowLayout不能为一个位置处理多个组件,即使其他组件没有从容器中踢出,并且一旦第一个组件被移除,它也无法重新计算其他组件的维度。我不知道是使用删除/添加技巧还是重构和使用CardLayout让我难过。我说的是CardLayout。你所做的事情似乎很奇怪。原因很简单,每个切换按钮有两种状态。所以你需要解释四个州。但你只有两种观点。因此,试图让四个状态执行两个操作似乎过于复杂了,请参见我的更新。测试一下。我想那可能就是你想要的。让我知道
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test {
public static void main(final String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
final JFrame frame = new JFrame();
frame.setSize(800, 800);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel buttonsPanel = new JPanel(new FlowLayout());
final JToggleButton btn1 = new JToggleButton("Button 1");
final JToggleButton btn2 = new JToggleButton("Button 2");
buttonsPanel.add(btn1);
buttonsPanel.add(btn2);
final JPanel containerPanel = new JPanel(new BorderLayout());
final JPanel pan1;
final JPanel pan2;
pan1 = new JPanel(new BorderLayout());
pan2 = new JPanel(new BorderLayout());
pan1.add(new JLabel("panel 1"));
pan2.add(new JLabel("panel 2"));
pan1.setBackground(Color.WHITE);
pan2.setBackground(Color.RED);
btn1.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(final ItemEvent e) {
final int state = e.getStateChange();
if (state == ItemEvent.SELECTED) {
containerPanel.add(pan1, BorderLayout.CENTER);
containerPanel.remove(pan2);
btn2.getModel().setSelected(false);
} else {
containerPanel.add(pan2, BorderLayout.CENTER);
containerPanel.remove(pan1);
btn2.getModel().setSelected(true);
}
containerPanel.revalidate();
containerPanel.repaint();
}
});
btn2.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(final ItemEvent e) {
final int state = e.getStateChange();
if (state == ItemEvent.SELECTED) {
containerPanel.add(pan2, BorderLayout.CENTER);
containerPanel.remove(pan1);
btn1.getModel().setSelected(false);
} else {
containerPanel.add(pan1, BorderLayout.CENTER);
containerPanel.remove(pan2);
btn1.getModel().setSelected(true);
}
containerPanel.revalidate();
containerPanel.repaint();
}
});
btn1.setSelected(true);
btn2.setSelected(true);
final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
true,
buttonsPanel,
containerPanel);
splitPane.setResizeWeight(0.5);
frame.add(splitPane);
frame.setVisible(true);
}
});
}
}