我有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");
现在发生了什么:
First click on the btnShowLibrary
从图片中你可以看到它们如何移动"而且我不知道为什么。有人可以解释为什么会发生这种情况并建议如何解决它吗?
答案 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;
}
}
}
}