切换JPanels对角移动内容 [英] Switching JPanels moves content diagonally

查看:96
本文介绍了切换JPanels对角移动内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有btnShowLibrary,它显示了保存在图书馆中的书.然后,我有一个按钮btnReturn,它使用其中的btnShowLibrary重新创建了以前的JPanel.

I have btnShowLibrary, which shows the books kept in the library. And then I have a button btnReturn that recreates previous JPanel with the btnShowLibrary among them.

初始化contentPane:

Initializing 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:

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:

ShowLibrary contentPane:

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

btn返回:

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");

现在发生什么了:

初始化

首先单击btnShowLibrary

首先单击btnReturn

第二次单击bSL

第二次单击bR

第三次单击bSL

第三次单击bR

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

From the pictures you can so how it's "moving" and I have no idea why. Can someone explain why this happens and suggest how to fix it?

推荐答案

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

An easy way to manage multiple panels is with the CardLayout layout. This layout allows you to show one of a number of panels at a time, making it easy to move from one to the other in a window. Here is a demo with some events passing between the GUI panels and the main "controller". Ideally, the GUI classes would be in their own files. See also 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;
            }
        }
    }   
}

这篇关于切换JPanels对角移动内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆