切换JPanels对角移动内容

时间:2017-12-05 00:32:52

标签: java swing jpanel

我有btnShowLibrary,它显示了库中保存的书籍。然后我有一个按钮btnReturn重新创建以前的JPanel,其中包含btnShowLibrary。

初始化contentPane:

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(new MigLayout("", "[124px,grow,fill][124px,grow,fill][124px,grow,fill]", "[30px,grow,fill][30px,grow,fill][30px,grow,fill][30px,grow,fill][30px,grow,fill][30px,grow,fill][30px,grow,fill]"));

btnShowLibrary:

JButton btnShowLibrary = new JButton("Show Library");
btnShowLibrary.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        contentPane.removeAll();
        contentPane.add(new ShowLibrary().getPane());
        contentPane.updateUI();
    }
});
contentPane.add(btnShowLibrary, "cell 1 5");

ShowLibrary contentPane:

contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(new MigLayout("", "[grow]", "[grow,fill][grow][]"));

btnReturn:

Button btnReturn = new JButton("Return");
btnReturn.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        contentPane.removeAll();
        contentPane.add(new Library().getPane());
        contentPane.updateUI();
    }
});
contentPane.add(btnReturn, "cell 0 1,alignx center,aligny bottom");

现在发生了什么:

Initialization

First click on the btnShowLibrary

First click on the btnReturn

2nd click on the bSL

2nd click on the bR

3rd click on the bSL

3rd click on the bR

从图片中你可以看到它们如何移动"而且我不知道为什么。有人可以解释为什么会发生这种情况并建议如何解决它吗?

1 个答案:

答案 0 :(得分:0)

管理多个面板的简便方法是使用CardLayout布局。此布局允许您一次显示多个面板中的一个,从而可以轻松地在窗口中从一个面板移动到另一个面板。这是一个演示,其中一些事件在GUI面板和主控制器之间传递"。理想情况下,GUI类将位于自己的文件中。另请参阅https://docs.oracle.com/javase/tutorial/uiswing/layout/card.html

package Q47644243;

import java.awt.AWTEvent;
import java.awt.CardLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GraphicsConfiguration;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;

import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;

/**
 * Demonstrate multiple panels in a window using CardLayout
 *
 */
@SuppressWarnings("serial")
public class MultiplePanels extends JFrame implements VetoableChangeListener {

    public static void main(String[] args) {        
        new MultiplePanels();
    }

    // GUI components
    private MainMenuPanel mainMenuPanel = null;
    private DataEntryPanel dataEntryPanel = null;
    private JPanel contentPanel;
    private CardLayout cardLayout = new CardLayout();

    final static String MENUPANEL = "Main Menu";
    final static String DATAPANEL = "Enter Data";

    // State variables
    private int m_data = 0;

    public MultiplePanels() {

        try {
            // Initialize
            jbInit();
        } catch(Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

        try {
            setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
            showCenterScreen(this);
            setCursor(Cursor.getDefaultCursor());
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }   
    }

    private void jbInit() {

        enableEvents(AWTEvent.WINDOW_EVENT_MASK);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // Create the GUI panels
        mainMenuPanel = new MainMenuPanel();
        dataEntryPanel = new DataEntryPanel();

        // Use property changes to communicate with the GUI
        addPropertyChangeListener(DataEntryPanel.PROPERTY_Data, dataEntryPanel);

        // Use vetoable changes to listen to the GUI
        mainMenuPanel.addVetoableChangeListener(this);
        dataEntryPanel.addVetoableChangeListener(this);

        this.setTitle("Multiple Panes Example");    
        cardLayout.setHgap(5);
        cardLayout.setVgap(5);

        // Add the panels
        contentPanel = (JPanel) this.getContentPane();
        contentPanel.setLayout(cardLayout);
        contentPanel.add(mainMenuPanel, MENUPANEL);
        contentPanel.add(dataEntryPanel, DATAPANEL);

        // Bring the menu to the front
        cardLayout.show(contentPanel, MENUPANEL);       
    }

    /**
     * Receive events from the GUI and process them. There are two expected:<br>
     * <ol>
     * <li>a change to the total seconds field. This is validated and accepted or vetoed 
     * if the new value is not an integer >=0; and <br>
     * <li>a request to perform the calculation.
     * </ol>
     */
    @Override
    public void vetoableChange(PropertyChangeEvent pce)
            throws PropertyVetoException {

        // The GUI is signaling a change that the "controller/model" needs
        // to deal with
        if (DataEntryPanel.PROPERTY_Data.equals(pce.getPropertyName())) {
            // Test to see if the data is valid
            int newData = 1;
            try {
                     newData = Integer.parseInt((String) pce.getNewValue());
            } catch (NumberFormatException e) {
                newData = -1;
            }
            if (newData <= 0) {
                // Signals the GUI to reject the entered value.
                throw new PropertyVetoException("Please enter a valid integer that is greater than zero.", pce);
            }
            // Save the state or data - bind with a database or
            // some other action.  Here we'll just update a "state" variable
            m_data = newData;
        }

        // Data entry completed - validate and switch back to main menu
        if (DataEntryPanel.PROPERTY_Done.equals(pce.getPropertyName())) {
            if (m_data <= 0) {
                // Request better data
                throw new PropertyVetoException("Please enter a valid integer that is greater than zero.", pce);
            }
            // Switch back to the Main menu
            cardLayout.show(contentPanel, MENUPANEL);
        }

        // Button pressed on the main menu
        if (MainMenuPanel.PROPERTY_MenuButton.equals(pce.getPropertyName())) {
            // This is a command to do something.  Using a vetoable change event
            // provides a nice mechanism to pass a message back to the GUI 
            // if required.
            cardLayout.show(contentPanel, DATAPANEL);
        }
    }

    /**
     *  Show in the center of the screen.
     *  (pack, set location and set visibility)
     *  @param window Window to position
     */
    private void showCenterScreen(Window window) {
        positionScreen (window);
        window.setVisible(true);
        window.toFront();
    }   //  showCenterScreen

    /**
     *  Position window in center of the screen
     *  @param window Window to position
     */
    private void positionScreen (Window window)
    {
        window.pack();
        // take into account task bar and other adornments
        GraphicsConfiguration config = window.getGraphicsConfiguration();
        Rectangle bounds = config.getBounds();
        Dimension sSize = bounds.getSize();
        Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(config);
        sSize.width -= (insets.left + insets.right);
        sSize.height -= (insets.top + insets.bottom);

        Dimension wSize = window.getSize();
        //  fit on window
        if (wSize.height > sSize.height)
            wSize.height = sSize.height;
        if (wSize.width > sSize.width)
            wSize.width = sSize.width;
        window.setSize(wSize);
        //  Center
        int x = (sSize.width - wSize.width) / 2;
        int y = (sSize.height - wSize.height) / 2;
        //
        window.setLocation(bounds.x + x + insets.left, bounds.y + y + insets.top);
    }   //  positionScreen

/*****************************************************************************/

    /**
     * A simple demo GUI for the a main menu with a button.  This should be in its own file
     * but for stack overflow, its presented as a subclass.
     *
     */
    public class MainMenuPanel extends JPanel implements ActionListener, PropertyChangeListener {

        /**
         *  Constructor
         */
        public MainMenuPanel () {

            try {
                jbInit();
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(1);
            }
        }

        public final static String PROPERTY_MenuButton = "MenuButton";

        private GridBagLayout gridBagLayout = new GridBagLayout();

        private JLabel      lTitle = new JLabel();
        private JButton     bOption1 = new JButton();

        private void jbInit() {

            setLayout(gridBagLayout);

            // Label
            lTitle.setToolTipText("Click a Menu Button");
            lTitle.setText("Main Menu");

            // Menu Button
            bOption1.setToolTipText("Show the Data Entry Panel");
            bOption1.setText("Enter Data");
            bOption1.addActionListener(this);

            // Layout the fields
            this.add(lTitle,    new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
                ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(5, 5, 2, 5), 0, 0));

            this.add(bOption1,      new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0
                ,GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(2, 5, 2, 5), 0, 0));

        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == bOption1) {
                try {
                    fireVetoableChange(PROPERTY_MenuButton,0,1);
                } catch (PropertyVetoException e1) {
                    e1.printStackTrace();
                }
            }
        }

        // Property Change receives events from the controller
        // Doesn't do anything in this case but could be used to
        // change the menu based on state, show different entries
        // etc...
        @Override
        public void propertyChange(PropertyChangeEvent pce) {
            /* Example
            if (PROPERTY_APropertyName.equals(pce.getPropertyName())) {
                // do something relevant
            }
            */
        }
    }


/*****************************************************************************/

    /**
     * A simple demo GUI for the a data entry with a button.  This should be in its own file
     * but for stack overflow, its presented as a subclass.
     *
     */
    public class DataEntryPanel extends JPanel implements ActionListener, PropertyChangeListener {

        /**
         *  Constructor
         */
        public DataEntryPanel () {

            try {
                jbInit();
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(1);
            }
        }

        // Property definitions
        public final static String PROPERTY_Done = "DoneButton";
        public final static String PROPERTY_Data = "myData";

        private GridBagLayout gridBagLayout = new GridBagLayout();

        private JLabel              lData = new JLabel();
        private JFormattedTextField fData = new JFormattedTextField("0");
        private JButton             bDone = new JButton();

        private String lastGoodData = "0";
        private boolean m_settingValue;

        private void jbInit() {

            setLayout(gridBagLayout);

            // Label
            lData.setToolTipText("Enter a positive integer");
            lData.setText("Enter number:");

            // Field
            fData.setText(lastGoodData);
            fData.setEditable(true);
            fData.setHorizontalAlignment(SwingConstants.RIGHT);
            fData.addPropertyChangeListener("value", this);
            fData.setColumns(15);

            // Button
            bDone.setToolTipText("Save the data and return to the menu.");
            bDone.setText("Save/Done");
            bDone.addActionListener(this);

            // Layout the fields
            this.add(lData,    new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
                ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
            this.add(fData,    new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
                    ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));

            //grab extra space when window is maximized
            JPanel filler = new JPanel();
            filler.setOpaque(false);
            filler.setBorder(null);
            this.add(filler,        new GridBagConstraints(0, 1, 1, 1, 0.0, 1.0
                    ,GridBagConstraints.WEST, GridBagConstraints.VERTICAL, new Insets(0, 0, 0, 0), 0, 0));

            this.add(bDone,        new GridBagConstraints(1, 2, 2, 1, 0.0, 0.0
                ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(15, 5, 10, 5), 0, 0));

        }

        @Override
        public void actionPerformed(ActionEvent e) {
            // Ignore button events while a field is setting its value
            // This can happen if the field focus is lost to a button click
            if (e.getSource() == bDone && !m_settingValue) {
                try {
                    fireVetoableChange(PROPERTY_Done,0,1);
                } catch (PropertyVetoException pve) {
                    JOptionPane.showMessageDialog(null,
                              pve.getMessage(), "Error Massage",
                              JOptionPane.ERROR_MESSAGE);
                }
            }
        }

        // Property Change receives events from the controller or fields
        @Override
        public void propertyChange(PropertyChangeEvent pce) {

            m_settingValue = true;
            // The "value" property signals a change in a field value
            // Send the new value to the controller/model for validation
            if (fData.equals(pce.getSource()) && "value".equals(pce.getPropertyName())) {
                // Record the old value in case the change is vetoed. Don't use 
                // the pce.getOldValue(), it isn't always accurate.
                String oldValue = lastGoodData;             
                String newValue = (String) pce.getNewValue();

                try {
                    fireVetoableChange(PROPERTY_Data, oldValue, newValue);
                    lastGoodData = newValue;
                } catch (PropertyVetoException e) {
                    JOptionPane.showMessageDialog(null,
                              e.getMessage(), "Error Massage",
                              JOptionPane.ERROR_MESSAGE);
                    // Reset fData outside of the "value" event thread/loop
                    // Otherwise the value is not updated to the oldValue
                    EventQueue.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            fData.setText(lastGoodData);
                        }
                    });
                }
                m_settingValue = false;
            }
        }
    }   
}