Reputation: 1296
I have a program with a static header (BorderLayout.NORTH) and footer (BorderLayout.SOUTH) and was attempting to cycle different JPanel's for the body (BorderLayout.CENTER) using action listeners on a JComboBox in my header. 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. That mostly happens, but the new CENTER retains the outline of the previous JPanel over the top of it (just the outline as I removeAll() from the panel).
I've been googling this expecting that I've done a common mistake, but all I'm seeing is people trying to negate the overwrite ability which I can't seem to trigger. Tried several different fixes (a single Jpanel declared as an instance variable and then changing it's content using removeAll/revalidate/repaint, creating separate panel's and adding them, etc...).
I'll include the majority of the code below but here is my constructor:
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); }
...and the method I use to modify the 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(); }
I know I should put more comments, etc... but I put those methods up separately because the rest is kinda messy right now and that seems to be the problem area. For completeness sake here's a screenshot of the problem and the rest of the code segment (I call UserInterface frame = new UserInterface(Current_User);
in my main and that's about it).
Note Tried to include the rest of my code but hit the character limit. If anyone want's me to post more of the content I'll reply with whatever method they think is an issue.
Update
Realized I was using JScrollPane, so I created an instance variable:
private JScrollPane pane = new JScrollPane();
so I could .removeAll() + revalidate() + repaint() pane
Now I've just got nothing in the body. Here's where my method is at:
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); }
}
Upvotes: 0
Views: 1324
Reputation: 324128
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.
No it doesn't overwrite the old content. The BorderLayout only keeps track of the last component added at any given constraint position. So when the layout manager is invoked, only that component is given a size/location.
However, any previous component will still have a size/location. Also because of how Z-Ordering works, the last component added is painted first. So the new component is painted and then the old component is painted over top of the new component.
To prevent this from happening you must remove the old panel first before adding the new panel.
attempting to cycle different JPanel's for the body
The better solution is to use a CardLayout
as it will manage the cycling of the panels for you. So add a panel using the CardLayout
to the CENTER of the BorderLayout. Then add all the swappable panels to the card layout panel. Read the section from the Swing tutorial on How to Use CardLayout for more information and examples.
Edit:
How would you "remove the old panel first"
Well, somewhere you must have code like:
panel.add(panel1, BorderLayout.CENTER);
So if you want to swap panels you need code like:
panel.remove(panel1);
panel.add(panel2, BorderLayout.CENTER);
panel.revalidate();
panel.repaint();
So it is up to you to manage the reference to the last component added to the CENTER so you can manually remove it. This is why the CardLayout is easier, it does the management for you.
Edit2:
Didn't notice the scroll pane before. This makes it even easier. When you create the frame you just use:
frame.add(scrollPane, BorderLayout.CENTER);
Then when you want to swap panels its one line of code:
scrollPane.setViewportView( panel2 );
Upvotes: 1