Programmatically swap two JPanels in JFrame

2019-05-23 14:19发布

问题:

I am trying to accomplish the above functionality, and am having little success. I am using GridLayout with 2 columns and 2 rows to show the user a puzzle-like game, where there are 4 (200x200 pixel) JPanels (3 colored, 1 default bgColor) which fill the whole contentPane. Clicking on a colored panel resolves in an assessment if the panel is next to the gray panel. If so, they should swap. I have accomplished every step to the last one, where they swap. Here's the code:

public class MainClass extends JFrame {
//Generated
private static final long serialVersionUID = 4710628273679698058L;

private SpecialPanel redPanel;
private SpecialPanel greenPanel;
private SpecialPanel yellowPanel;
private SpecialPanel grayPanel;

public MainClass() {
    super("Puzzle");

    initPanels();

    setSize(410, 410);
    setLayout(new GridLayout(2, 2));

    this.add(redPanel);
    this.add(greenPanel);
    this.add(grayPanel);
    this.add(yellowPanel);
}
private void initPanels() {
    redPanel = new SpecialPanel();
    greenPanel = new SpecialPanel();
    yellowPanel = new SpecialPanel();
    grayPanel = new SpecialPanel();

    grayPanel.setGreyPanel(true);

    redPanel.setBackground(Color.RED);
    greenPanel.setBackground(Color.GREEN);
    yellowPanel.setBackground(Color.YELLOW);
    grayPanel.setBackground(this.getBackground());

    redPanel.setSize(200, 200);
    greenPanel.setSize(200, 200);
    yellowPanel.setSize(200, 200);
    grayPanel.setSize(200, 200);

    MouseAdapter ma = new MouseAdapter() {

        @Override
        public void mouseClicked(MouseEvent arg0) {
            super.mouseClicked(arg0);

            SpecialPanel sp = (SpecialPanel) arg0.getComponent();

            if (sp.getIsGray()) {
                //Do nothing
            } else if (checkIfNeighbourToGray(sp, grayPanel)) {
                //Swap them
                System.out.println("Swap notification");
                swap(sp, grayPanel);                
                //Update UI
            } else {
                //Again, do nothing for the clicked panel is diagonal to the gray panel
            }
        }

        private boolean checkIfNeighbourToGray(SpecialPanel sp, SpecialPanel grayPanel) {

            Point startPointSp = sp.getLocation();
            double x = startPointSp.getX();
            double y = startPointSp.getY();

            double width = sp.getWidth();
            double height = sp.getHeight();

            Point grayPoint = grayPanel.getLocation();
            double xG = grayPanel.getX();
            double yG = grayPanel.getY();

            double widthG = grayPanel.getWidth();
            double heightG = grayPanel.getHeight();

            //Gray panel is RIGHT of clicked one
            if (x + width == xG && y + height == yG + heightG) {
                return true;                    
            }
            //Gray panel is LEFT of clicked one
            else if (x - width == xG && y + height == yG + heightG) {
                return true;
            }
            //Gray panel is ABOVE of clicked one
            else if (x == xG && x + width == xG + widthG) {
                return true;
            }
            //Gray panel is UNDER of clicked one
            else if (xG == x && yG + widthG == x + width) {
                return true;
            }

            return false;
        }

        private void swap(SpecialPanel sp, SpecialPanel grayPanel) {
            //Swap logic
        }

    };
    redPanel.addMouseListener(ma);
    greenPanel.addMouseListener(ma);
    yellowPanel.addMouseListener(ma);
    grayPanel.addMouseListener(ma);

}
public static void main(String[] args) {
    MainClass mc = new MainClass();
    mc.setVisible(true);

}

}

The class SpecialPanel is extending JPanel with just a new Boolean property IsGrayPanel initially set to false + getter and setter. NOTE: This is being done in a "I have basic Swing skills" manner, although I have learned more in the meantime about java swing, I was just limited back then with basic swing functionality, so I should keep it that way. Therefore my question is how to properly swap the two panels which are next to each other, including UI update?

回答1:

  • there wouldn't need to move with JPanels into container, otherwise you woud need to use bunch of quite useless code to remove two JPanels from from contianer with two indexes then to layout back to container with swaping indexes,

  • (if is about Color only) only to swap setBackground(Color.Xxx) betweens two JPanels

  • puzzle-like game is about Images, puzzle or minesweaper is about, (not clear from your ...)

    1. put Images as Icon/ImageIcons to JLabel instead of JPanel and on Mouse Events to switch (setIcon()) with Icons betweens JLabels, load Icons to local variables

    2. (easiest of ways) JToggleButton and Icon, there is logic similair as for JLabel, but about showing Icon on setPressedIcon()



回答2:

I'm not sure if this works. It looks too easy.

JPanel tempPanel = sp;
sp = grayPanel;
grayPanel = tempPanel;

this.setVisible(false);
this.setVisible(true);
this.validate(); //try this first
this.repaint(); // if it doesnt work, add this function.