将JPanel添加到BorderLayout.Center时,以前的内容仍然可见

时间:2015-08-04 18:51:41

标签: java border-layout

我有一个带有静态标头(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);,这就是它。)

the residual "under construction" is from the default MyView panel

注意尝试包含我的其余代码但是达到了字符数限制。如果有人希望我发布更多内容,我会用他们认为有问题的方法回复。

更新 意识到我正在使用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); }
}

1 个答案:

答案 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 );