I created a JFrame which I named JMate. It should contain a button within a SettingsPanel, which when clicked, switches to PlayingPanel. When you are in the PlayingPanel and try to close the frame by pressing on X button it should bring the SettingsPanel back up.
Current Behaviour: When I launch the application, Frame with SettingsPanel opens. When I press the button in SettingsPanel, SettingsPanele closes and PlayingPanele opens. When I close PlayingPanel by Pressing on X, SettingsPanel opens for a few milliseconds and closes again. The process than remains active but no Frame is visible...
I got it resolved but since I use CardLayout instead of 2 JFrames, the Problem now reoccured.
Why is this happening?
This is how my classes currently look:
public class JMate extends JFrame {
public JPanel activePanel;
public JPanel container;
public JPanel settingsPanel;
public JPanel playingPanel;
public CardLayout cardLayout;
public JMate(){
setTitle("JMate v1.0.0");
setLocationRelativeTo(null);
setResizable(false);
container = new JPanel();
settingsPanel = new SettingsPanel(this);
playingPanel = new PlayingPanel(this);
cardLayout = new CardLayout();
container.setLayout(cardLayout);
container.add(settingsPanel, settingsPanel.getClass().getName());
container.add(playingPanel, playingPanel.getClass().getName());
cardLayout.show(container, settingsPanel.getClass().getName());
activePanel = settingsPanel;
add(container);
setSize(settingsPanel.getPreferredSize());
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
super.windowClosing(e);
if(activePanel == settingsPanel){
System.exit(0);
}
else{
cardLayout.show(container, settingsPanel.getClass().getName());
setSize(settingsPanel.getPreferredSize());
activePanel = settingsPanel;
//TODO: stop engine etc.
}
}
});
setVisible(true);
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel( new FlatDarkLaf() );
} catch( Exception ex ) {
System.err.println( "Failed to initialize LaF" );
}
EventQueue.invokeLater(JMate::new);
}
}
public class SettingsPanel extends JPanel {
private final JMate jMate;
private SwitchButton switchButton;
private EngineSelect engineSelect;
private VariantSelect variantSelect;
private JButton startButton;
public SettingsPanel(JMate jMate) {
this.jMate = jMate;
setLayout(new FlowLayout());
setPreferredSize(new Dimension(600,400));
initComponents();
setVisible(true);
}
private void initComponents(){
switchButton = new SwitchButton();
engineSelect = new EngineSelect();
variantSelect = new VariantSelect();
startButton = new JButton("Start");
engineSelect.setVariantsSelect(variantSelect);
variantSelect.setEngineSelect(engineSelect);
add(switchButton);
add(engineSelect);
add(variantSelect);
add(startButton);
startButton.addActionListener(e -> {
jMate.cardLayout.show(jMate.container, jMate.playingPanel.getClass().getName());
jMate.setSize(jMate.playingPanel.getPreferredSize());
jMate.activePanel = jMate.playingPanel;
//TODO: start Engine etc.
});
}
}
public class PlayingPanel extends JPanel {
private final JMate jMate;
public PlayingPanel(JMate jMate){
this.jMate = jMate;
setLayout(new FlowLayout());
setPreferredSize(new Dimension(300,600));
initComponents();
setVisible(true);
}
private void initComponents() {
}
}
CodePudding user response:
Apparently, one way to fix this issue, is to add the following line in JMate Class: setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
CodePudding user response:
Seems like this problem has now reoccured after using cardlayout. I updated this post
Well, it seems to work okay for, but
- Avoid using
setPreferredSize
. The size of the component should be calculated via the layout manager. You can affect the size by using things likeEmptyBorder
(to add additional padding) or via various layout settings (padding/etc) - Avoid resizing the window programmatically after it's shown, users will not thank you for it.
CardLayout
will determine the best size for the container from needs of the children. - Avoid extending from
JFrame
(or other top level containers), you're not adding any new functionality to the class and these classes tend to be complex structures which just add to the issues - I'd be concerned about the use of
WindowListener
in this case - what does it matter what view the user is on if they want the close the window?
Runnable example...
import java.awt.CardLayout;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new JMate());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public enum View {
SETTINGS, PLAYING
}
public interface Navigator {
public void show(View view);
}
public class JMate extends JPanel implements Navigator {
public JPanel activePanel;
public JPanel container;
public JPanel settingsPanel;
public JPanel playingPanel;
public CardLayout cardLayout;
public JMate() {
//setResizable(false);
//container = new JPanel();
settingsPanel = new SettingsPanel(this);
playingPanel = new PlayingPanel(this);
cardLayout = new CardLayout();
setLayout(cardLayout);
add(settingsPanel, View.SETTINGS);
add(playingPanel, View.PLAYING);
show(View.SETTINGS);
}
protected void add(JComponent component, View view) {
add(component, view.name());
}
@Override
public void show(View view) {
cardLayout.show(this, view.name());
}
}
public class SettingsPanel extends JPanel {
private final Navigator navigator;
private JButton switchButton;
private JButton engineSelect;
private JButton variantSelect;
private JButton startButton;
public SettingsPanel(Navigator navigator) {
this.navigator = navigator;
setLayout(new FlowLayout());
//setPreferredSize(new Dimension(600, 400));
initComponents();
//setVisible(true);
}
private void initComponents() {
switchButton = new JButton("Switch");
engineSelect = new JButton("Engine");
variantSelect = new JButton("Variant");
startButton = new JButton("Start");
//engineSelect.setVariantsSelect(variantSelect);
//variantSelect.setEngineSelect(engineSelect);
add(switchButton);
add(engineSelect);
add(variantSelect);
add(startButton);
startButton.addActionListener(e -> {
//jMate.cardLayout.show(jMate.container, jMate.playingPanel.getClass().getName());
//jMate.setSize(jMate.playingPanel.getPreferredSize());
//jMate.activePanel = jMate.playingPanel;
//TODO: start Engine etc.
navigator.show(View.PLAYING);
});
}
}
public class PlayingPanel extends JPanel {
private final Navigator navigator;
public PlayingPanel(Navigator navigator) {
this.navigator = navigator;
//setPreferredSize(new Dimension(300, 600));
initComponents();
// setVisible(true);
}
private void initComponents() {
setLayout(new GridBagLayout());
JLabel label = new JLabel("MATE!");
label.setFont(label.getFont().deriveFont(Font.BOLD, 48));
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
gbc.insets = new Insets(8, 8, 8, 8);
add(label, gbc);
JButton settings = new JButton("Settings");
add(settings, gbc);
settings.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
navigator.show(View.SETTINGS);
}
});
}
}
}