我有一个带有静态标头(BorderLayout.NORTH)和页脚(BorderLayout.SOUTH)的程序,并试图使用我标题中的JComboBox上的动作侦听器为主体(BorderLayout.CENTER)循环不同的JPanel。据我了解BorderLayout,每次我将一个JPanel(或任何组件)添加到CENTER(或布局中的任何其他位置)时,它都会覆盖旧内容。这种情况经常发生,但是新的CENTER保留了之前JPanel的轮廓(仅仅是从面板中删除所有()的轮廓)。
我一直在谷歌上搜索,因为我做了一个常见的错误,但我所看到的只是人们试图否定我无法触发的覆盖能力。尝试了几个不同的修复程序(单个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); }
...以及我用来修改身体的方法:
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);
,这就是它。)
注意尝试包含我的其余代码但是达到了字符数限制。如果有人希望我发布更多内容,我会用他们认为有问题的方法回复。
更新
意识到我正在使用JScrollPane,所以我创建了一个实例变量:
private JScrollPane pane = new JScrollPane();
所以我可以.removeAll()+ revalidate()+ repaint()pane
现在我身体里什么都没有。这是我的方法所在:
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); }
}
答案 0 :(得分:1)
据我了解BorderLayout,每次我将一个JPanel(或任何组件)添加到CENTER(或布局中的任何其他位置)时,它都会覆盖旧内容。
不,它不会覆盖旧内容。 BorderLayout仅跟踪在任何给定约束位置添加的最后一个组件。因此,当调用布局管理器时,只给该组件一个大小/位置。
但是,任何先前的组件仍将具有大小/位置。同样由于Z-Ordering的工作原理,最后添加的组件也是先涂上的。因此,新组件被绘制,然后旧组件被绘制在新组件的顶部。
为防止这种情况发生,您必须先删除旧面板,然后再添加新面板。
尝试为身体循环不同的JPanel
更好的解决方案是使用CardLayout
,因为它将为您管理面板的循环。因此,使用CardLayout
将面板添加到BorderLayout的CENTER。然后将所有可交换面板添加到卡布局面板中。阅读有关如何使用CardLayout的Swing教程中的部分以获取更多信息和示例。
编辑:
你如何“首先删除旧面板”
嗯,某处你必须有如下代码:
panel.add(panel1, BorderLayout.CENTER);
因此,如果您想交换面板,则需要以下代码:
panel.remove(panel1);
panel.add(panel2, BorderLayout.CENTER);
panel.revalidate();
panel.repaint();
因此,您需要管理对添加到CENTER的最后一个组件的引用,以便您可以手动删除它。这就是为什么CardLayout更容易,它为您管理。
EDIT2:
之前没有注意到滚动窗格。这使它更容易。当您创建框架时,您只需使用:
frame.add(scrollPane, BorderLayout.CENTER);
然后,当您想要交换面板时,只需一行代码:
scrollPane.setViewportView( panel2 );