将 JPanel 添加到 BorderLayout.Center 之前的内容仍然可见
When adding JPanel to BorderLayout.Center previous content remains visible
我有一个带有静态 header (BorderLayout.NORTH) 和页脚 (BorderLayout.SOUTH) 的程序,并试图为 body (BorderLayout.CENTER) 在我的 header 中的 JComboBox 上使用动作侦听器。据我了解 BorderLayout,每次我将 JPanel(或任何组件)添加到 CENTER(或布局中的任何其他位置)时,它都会覆盖旧内容。这通常会发生,但新的 CENTER 会在其顶部保留先前 JPanel 的轮廓(只是我从面板中删除 All() 时的轮廓)。
我一直在谷歌搜索这个以为我犯了一个常见的错误,但我所看到的只是人们试图否定我似乎无法触发的覆盖能力。尝试了几种不同的修复方法(将单个 Jpanel 声明为实例变量,然后使用 removeAll/revalidate/repaint 更改其内容,创建单独的面板并添加它们,等等)。
我将在下面包含大部分代码,但这是我的构造函数:
public UserInterface(Operator o, LocalDate d) {
DefaultDateModel model = new DefaultDateModel(d);
user = o;
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//setup Menus
if (user.getAccessPrivs().equalsIgnoreCase("OPRTR")) {
OperatorMenus menu = new OperatorMenus();
setJMenuBar(menu); }
else if (user.getAccessPrivs().equalsIgnoreCase("ADMIN")) {
AdminMenus menu = new AdminMenus();
setJMenuBar(menu); }
else {
GalileoMenus menu = new GalileoMenus();
setJMenuBar(menu); }
//creates header with navigation buttons
add(new NavButtons(model), BorderLayout.NORTH);
//loads content
viewConstructor(model);
//creates footer
JPanel footer = new JPanel();
footer.setLayout(new BorderLayout());
footer.setBackground(Color.BLACK);
focusPoint = new JLabel(DateTimeFormatter.ofPattern("E, dd MMM yyyy").format(model.getDate()));
focusPoint.setForeground(Color.RED);
footer.add(focusPoint, BorderLayout.WEST);
JLabel loggedIn = new JLabel(user.getName(), JLabel.RIGHT);
loggedIn.setForeground(Color.CYAN);
footer.add(loggedIn, BorderLayout.EAST);
add(footer, BorderLayout.SOUTH); }
...以及我用来修改 body:
的方法
public void viewConstructor(DefaultDateModel m) {
DefaultDateModel model = m;
//removeAll();
body.removeAll();
body.revalidate();
body.repaint();
getContentPane().remove(body);
//body = new JPanel();
//body.revalidate();
//body.repaint();
//body.updateUI();
//body.setOpaque(false);
//set window frame's title
if (panelZone == MYVIEW) { setTitle("My View"); }
else if (panelZone == OPERTR) { setTitle("Operations"); }
else if (panelZone == SHIFTS) { setTitle("Scheduling"); }
else if (panelZone == FISCAL) { setTitle("Fiscal Report"); }
//builds body panel
if (panelZone == MYVIEW) {
add(new JScrollPane(buildMyView(model.getDate())), BorderLayout.CENTER); }
else if (panelZone == OPERTR) {
add(new JScrollPane(buildOperatorView(model.getDate())), BorderLayout.CENTER); }
else if (panelZone == SHIFTS) {
add(new JScrollPane(buildSchedulingView(model.getDate())), BorderLayout.CENTER); }
else if (panelZone == FISCAL) {
add(new JScrollPane(buildFiscalView(model.getDate())), BorderLayout.CENTER); }
validate();
revalidate();
repaint();
pack(); }
我知道我应该发表更多评论,等等...但我将这些方法分开放置,因为现在剩下的有点乱,这似乎是问题所在。为了完整起见,这里是问题的屏幕截图和代码段的其余部分(我在主程序中调用 UserInterface frame = new UserInterface(Current_User);
,仅此而已)。
注意 试图包含我的其余代码但达到了字符数限制。如果有人想让我 post 更多内容,我会用他们认为有问题的任何方式回复。
更新
意识到我正在使用 JScrollPane,所以我创建了一个实例变量:
private JScrollPane pane = new JScrollPane();
所以我可以 .removeAll() + revalidate() + repaint() pane
现在 body 我什么都没有了。这是我的方法所在的位置:
public void viewConstructor(DefaultDateModel m) {
DefaultDateModel model = m;
pane.removeAll();
//set window frame's title
if (panelZone == MYVIEW) { setTitle("My View"); }
else if (panelZone == OPERTR) { setTitle("Operations"); }
else if (panelZone == SHIFTS) { setTitle("Scheduling"); }
else if (panelZone == FISCAL) { setTitle("Fiscal Report"); }
//builds body panel
// JScrollPane pane = new JScrollPane();
if (panelZone == MYVIEW) {
// add(new JScrollPane(buildMyView(model.getDate())), BorderLayout.CENTER); }
pane.setViewportView(buildMyView(model.getDate())); }
else if (panelZone == OPERTR) {
// add(new JScrollPane(buildOperatorView(model.getDate())), BorderLayout.CENTER); }
pane.setViewportView(buildOperatorView(model.getDate())); }
else if (panelZone == SHIFTS) {
// add(new JScrollPane(buildSchedulingView(model.getDate())), BorderLayout.CENTER); }
pane.setViewportView(buildSchedulingView(model.getDate())); }
else if (panelZone == FISCAL) {
// add(new JScrollPane(buildFiscalView(model.getDate()))); }
pane.setViewportView(buildFiscalView(model.getDate())); }
//validate();
// body.revalidate();
// body.repaint();
pane.revalidate();
pane.repaint();
//repaint();
pack(); }
SSCCE
package interfaceComponents;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.*;
import javax.swing.*;
public class SSCCE extends JFrame {
private static final long serialVersionUID = -5249508445298805323L;
private JScrollPane pane = new JScrollPane();
private int stage = 0;
public SSCCE() {
JPanel header = new JPanel();
JButton cycler = new JButton("Cycle");
cycler.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
stage++;
if (stage == 3) { stage = 0; }
buildBody(); }
});
header.add(cycler);
add(header, BorderLayout.NORTH);
add(pane, BorderLayout.CENTER);
buildBody();
JPanel footer = new JPanel();
footer.add(new JLabel("Random Text"));
add(footer, BorderLayout.SOUTH); }
public void buildBody() {
JPanel body = new JPanel();
if (stage == 0) { body.setBackground(Color.RED); }
else if (stage == 1) { body.setBackground(Color.WHITE); }
else { body.setBackground(Color.BLUE); }
pane.setViewportView(body); }
}
As I understood BorderLayout, each time I added a JPanel (or any component) to the CENTER (or anywhere else in the layout) it would overwrite the old content.
不,它不会覆盖旧内容。 BorderLayout 仅跟踪在任何给定约束位置添加的最后一个组件。因此,当布局管理器被调用时,只有那个组件被赋予 size/location.
但是,任何先前的组件仍将具有 size/location。也因为 Z-Ordering 的工作原理,最后添加的组件首先被绘制。所以新组件被绘制,然后旧组件被绘制在新组件之上。
为防止这种情况发生,您必须先删除旧面板,然后再添加新面板。
attempting to cycle different JPanel's for the body
更好的解决方案是使用 CardLayout
,因为它会为您管理面板的循环。因此,使用 CardLayout
添加一个面板到 BorderLayout 的中心。然后将所有可交换面板添加到卡片布局面板。阅读 Swing 教程中有关如何使用 CardLayout 的部分以获取更多信息和示例。
编辑:
How would you "remove the old panel first"
嗯,在某个地方你必须有这样的代码:
panel.add(panel1, BorderLayout.CENTER);
所以如果你想交换面板,你需要像这样的代码:
panel.remove(panel1);
panel.add(panel2, BorderLayout.CENTER);
panel.revalidate();
panel.repaint();
因此,您需要管理对添加到 CENTER 的最后一个组件的引用,以便您可以手动将其删除。这就是 CardLayout 更简单的原因,它会为您进行管理。
编辑2:
之前没有注意到滚动窗格。这使它更容易。创建框架时,您只需使用:
frame.add(scrollPane, BorderLayout.CENTER);
然后当你想交换面板时,它的一行代码:
scrollPane.setViewportView( panel2 );
我有一个带有静态 header (BorderLayout.NORTH) 和页脚 (BorderLayout.SOUTH) 的程序,并试图为 body (BorderLayout.CENTER) 在我的 header 中的 JComboBox 上使用动作侦听器。据我了解 BorderLayout,每次我将 JPanel(或任何组件)添加到 CENTER(或布局中的任何其他位置)时,它都会覆盖旧内容。这通常会发生,但新的 CENTER 会在其顶部保留先前 JPanel 的轮廓(只是我从面板中删除 All() 时的轮廓)。
我一直在谷歌搜索这个以为我犯了一个常见的错误,但我所看到的只是人们试图否定我似乎无法触发的覆盖能力。尝试了几种不同的修复方法(将单个 Jpanel 声明为实例变量,然后使用 removeAll/revalidate/repaint 更改其内容,创建单独的面板并添加它们,等等)。
我将在下面包含大部分代码,但这是我的构造函数:
public UserInterface(Operator o, LocalDate d) {
DefaultDateModel model = new DefaultDateModel(d);
user = o;
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//setup Menus
if (user.getAccessPrivs().equalsIgnoreCase("OPRTR")) {
OperatorMenus menu = new OperatorMenus();
setJMenuBar(menu); }
else if (user.getAccessPrivs().equalsIgnoreCase("ADMIN")) {
AdminMenus menu = new AdminMenus();
setJMenuBar(menu); }
else {
GalileoMenus menu = new GalileoMenus();
setJMenuBar(menu); }
//creates header with navigation buttons
add(new NavButtons(model), BorderLayout.NORTH);
//loads content
viewConstructor(model);
//creates footer
JPanel footer = new JPanel();
footer.setLayout(new BorderLayout());
footer.setBackground(Color.BLACK);
focusPoint = new JLabel(DateTimeFormatter.ofPattern("E, dd MMM yyyy").format(model.getDate()));
focusPoint.setForeground(Color.RED);
footer.add(focusPoint, BorderLayout.WEST);
JLabel loggedIn = new JLabel(user.getName(), JLabel.RIGHT);
loggedIn.setForeground(Color.CYAN);
footer.add(loggedIn, BorderLayout.EAST);
add(footer, BorderLayout.SOUTH); }
...以及我用来修改 body:
的方法public void viewConstructor(DefaultDateModel m) {
DefaultDateModel model = m;
//removeAll();
body.removeAll();
body.revalidate();
body.repaint();
getContentPane().remove(body);
//body = new JPanel();
//body.revalidate();
//body.repaint();
//body.updateUI();
//body.setOpaque(false);
//set window frame's title
if (panelZone == MYVIEW) { setTitle("My View"); }
else if (panelZone == OPERTR) { setTitle("Operations"); }
else if (panelZone == SHIFTS) { setTitle("Scheduling"); }
else if (panelZone == FISCAL) { setTitle("Fiscal Report"); }
//builds body panel
if (panelZone == MYVIEW) {
add(new JScrollPane(buildMyView(model.getDate())), BorderLayout.CENTER); }
else if (panelZone == OPERTR) {
add(new JScrollPane(buildOperatorView(model.getDate())), BorderLayout.CENTER); }
else if (panelZone == SHIFTS) {
add(new JScrollPane(buildSchedulingView(model.getDate())), BorderLayout.CENTER); }
else if (panelZone == FISCAL) {
add(new JScrollPane(buildFiscalView(model.getDate())), BorderLayout.CENTER); }
validate();
revalidate();
repaint();
pack(); }
我知道我应该发表更多评论,等等...但我将这些方法分开放置,因为现在剩下的有点乱,这似乎是问题所在。为了完整起见,这里是问题的屏幕截图和代码段的其余部分(我在主程序中调用 UserInterface frame = new UserInterface(Current_User);
,仅此而已)。
注意 试图包含我的其余代码但达到了字符数限制。如果有人想让我 post 更多内容,我会用他们认为有问题的任何方式回复。
更新
意识到我正在使用 JScrollPane,所以我创建了一个实例变量:
private JScrollPane pane = new JScrollPane();
所以我可以 .removeAll() + revalidate() + repaint() pane
现在 body 我什么都没有了。这是我的方法所在的位置:
public void viewConstructor(DefaultDateModel m) {
DefaultDateModel model = m;
pane.removeAll();
//set window frame's title
if (panelZone == MYVIEW) { setTitle("My View"); }
else if (panelZone == OPERTR) { setTitle("Operations"); }
else if (panelZone == SHIFTS) { setTitle("Scheduling"); }
else if (panelZone == FISCAL) { setTitle("Fiscal Report"); }
//builds body panel
// JScrollPane pane = new JScrollPane();
if (panelZone == MYVIEW) {
// add(new JScrollPane(buildMyView(model.getDate())), BorderLayout.CENTER); }
pane.setViewportView(buildMyView(model.getDate())); }
else if (panelZone == OPERTR) {
// add(new JScrollPane(buildOperatorView(model.getDate())), BorderLayout.CENTER); }
pane.setViewportView(buildOperatorView(model.getDate())); }
else if (panelZone == SHIFTS) {
// add(new JScrollPane(buildSchedulingView(model.getDate())), BorderLayout.CENTER); }
pane.setViewportView(buildSchedulingView(model.getDate())); }
else if (panelZone == FISCAL) {
// add(new JScrollPane(buildFiscalView(model.getDate()))); }
pane.setViewportView(buildFiscalView(model.getDate())); }
//validate();
// body.revalidate();
// body.repaint();
pane.revalidate();
pane.repaint();
//repaint();
pack(); }
SSCCE
package interfaceComponents;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.*;
import javax.swing.*;
public class SSCCE extends JFrame {
private static final long serialVersionUID = -5249508445298805323L;
private JScrollPane pane = new JScrollPane();
private int stage = 0;
public SSCCE() {
JPanel header = new JPanel();
JButton cycler = new JButton("Cycle");
cycler.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
stage++;
if (stage == 3) { stage = 0; }
buildBody(); }
});
header.add(cycler);
add(header, BorderLayout.NORTH);
add(pane, BorderLayout.CENTER);
buildBody();
JPanel footer = new JPanel();
footer.add(new JLabel("Random Text"));
add(footer, BorderLayout.SOUTH); }
public void buildBody() {
JPanel body = new JPanel();
if (stage == 0) { body.setBackground(Color.RED); }
else if (stage == 1) { body.setBackground(Color.WHITE); }
else { body.setBackground(Color.BLUE); }
pane.setViewportView(body); }
}
As I understood BorderLayout, each time I added a JPanel (or any component) to the CENTER (or anywhere else in the layout) it would overwrite the old content.
不,它不会覆盖旧内容。 BorderLayout 仅跟踪在任何给定约束位置添加的最后一个组件。因此,当布局管理器被调用时,只有那个组件被赋予 size/location.
但是,任何先前的组件仍将具有 size/location。也因为 Z-Ordering 的工作原理,最后添加的组件首先被绘制。所以新组件被绘制,然后旧组件被绘制在新组件之上。
为防止这种情况发生,您必须先删除旧面板,然后再添加新面板。
attempting to cycle different JPanel's for the body
更好的解决方案是使用 CardLayout
,因为它会为您管理面板的循环。因此,使用 CardLayout
添加一个面板到 BorderLayout 的中心。然后将所有可交换面板添加到卡片布局面板。阅读 Swing 教程中有关如何使用 CardLayout 的部分以获取更多信息和示例。
编辑:
How would you "remove the old panel first"
嗯,在某个地方你必须有这样的代码:
panel.add(panel1, BorderLayout.CENTER);
所以如果你想交换面板,你需要像这样的代码:
panel.remove(panel1);
panel.add(panel2, BorderLayout.CENTER);
panel.revalidate();
panel.repaint();
因此,您需要管理对添加到 CENTER 的最后一个组件的引用,以便您可以手动将其删除。这就是 CardLayout 更简单的原因,它会为您进行管理。
编辑2:
之前没有注意到滚动窗格。这使它更容易。创建框架时,您只需使用:
frame.add(scrollPane, BorderLayout.CENTER);
然后当你想交换面板时,它的一行代码:
scrollPane.setViewportView( panel2 );