I separated my GUI/JFrame from my Panel class so that I can keep the Swing components away from the rest of my code. However, I have a button that I would like to update my Frame in real time before I run a method from my Main class, but I can't get it to work. It looks something like (pseudocode):
public class GUI extends JFrame
{
public GUI()
{
//frame setup
Login login = new Login(this);
frame.add(login);
while(login.shouldContinue){login.panel.revalidate()}
//continue
}
}
public class Login
{
Jpanel panel;
Main main;
Frame frame;
boolean shouldContinue;
public Login(Frame frame)
{
this.frame = frame;
this.panel= new JPanel();
this.main = new Main();
//other panel elements
JButton btn1 = new JButton ("Login");
btn1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0){
JLabel label = new JLabel("Logging in");
panel.add(label);
frame.add(panel);
main.login();
panel.remove(label1);
JLabel label2 = new JLabel("Login Successful");
panel.add(label2);
frame.add(panel);
this.shouldContinue=false;
}
}
}
The other elements of the panel display just fine, but when I click the button, nothing happens. How can I make the frame display the updated panel before running main.login()? I tried revalidating/repainting the panel but it didn't work.
You are describing the functionality provided by (J)Dialog.setModal(). But these days, an even easier way to do this is to just use JOptionPane
Login l = new Login();
res = JOptionPane.showConfirmDialog(null, login, "login", JOptionPane.OK_CANCEL_OPTION);
if (res == JOptionPane.OK_OPTION) {
...
}
Related
I am new to swing and am wondering why my login panel isn't appearing in the frame. I believe it should show on the left side of the frame, is this correct? What needs to be changed to make the panel appear. Thanks.
Here is the GUIFrame code
public class GUIFrame extends JFrame {
private static final long serialVersionUID = 1L;
public GUIFrame(){
Container container = getContentPane();
Toolkit toolkit = Toolkit.getDefaultToolkit();
Dimension screenDimension = toolkit.getScreenSize();
setSize(screenDimension.width/2, screenDimension.height/2);
setLocation(screenDimension.width/4,screenDimension.height/4);
setLayout(new GridLayout(1,2));
add(new Login(this));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
}
Here is the panels code:
public class Login extends JPanel {
private JPanel panel = new JPanel();
private JButton cancel = new JButton("Cancel");
private JButton submit = new JButton("Submit");
private JLabel username_label = new JLabel("Username :");
private JLabel password_label = new JLabel("Password :");
private JTextField username_text = new JTextField();
private JPasswordField password_text = new JPasswordField();
private GUIFrame frame;
public Login(GUIFrame frame){
this.frame = frame;
setLayout(new GridLayout(3,2,20,40));
addComponents();
}
public void addComponents(){
panel.add(username_label);
panel.add(username_text);
panel.add(password_label);
panel.add(password_text);
panel.add(cancel);
panel.add(submit);
}
}
Here is the main method which displays the frame:
public class Project {
public static void main(String[] args){
Project project = new Project();
}
public Project() {
//Login login = new Login();
GUIFrame frame = new GUIFrame();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
frame.setVisible(true);
}
});
}
}
panel.add(username_label);
panel.add(username_text);
panel.add(password_label);
panel.add(password_text);
panel.add(cancel);
panel.add(submit);
You create a separate JPanel and add the component to this panel, but you never add the panel to your Login panel.
Your Login panel already is a JPanel, so there is no need to create another JPanel.
The code should just be:
add(username_label);
add(username_text);
add(password_label);
add(password_text);
add(cancel);
add(submit);
There is also no reason to pass the JFrame as a parameter to your Login class.
Also, you are using the invokeLater() incorrectly. All Swing components should be created on the Event Dispatch Thread (EDT). So you should also include the new GuiFrame() inside the invokeLater().
Generally there is no need to have a separate JFrame class. The logic in your Project class should simply create an instance of the frame and add the Login panel to the frame. In other words don't extend JFrame.
I've posted my code below. I have the simple task of creating a navigable GUI. I've spent the past few hours doing research on how to accomplish this, and this is the code that I've put together.
Originally I wanted to perform the navigation without any layouts or anything. I need the home panel to display after the user clicks on the "login" button on the welcome panel.
It displays the welcome card just fine, but when I get to the validateLogin method(which is activated when the login button is press, and upon successful login it should show the home panel within cards) it simply stays on the welcome panel even though I have validated that my program reaches the loop to change cards via the system.out.Println()
Please help. I spent my entire Saturday trying to solve this one problem through trials and research, but with no success. This is a last resort for me so if anyone can show me my flaws then I'll happily be on my way and fix it. Then apply that fix to the many other cards that are required for my program.
enter code here
public class mainGUI implements ActionListener{
JFrame main;
JPanel cards = new JPanel(new CardLayout());
CardLayout cl = (CardLayout)(cards.getLayout());
//Items for the welcome panel
JPanel welcome = welcomePanel();
JButton login;
JButton register;
JTextField username;
JTextField password;
//home panel
JPanel home = homePanel();
//WelcomePanel welcome = new WelcomePanel();
ArrayList<Student> students = new ArrayList<Student>();
Student workingStudent;
/**
* calls load() at start and save() on exit
*
*/
public mainGUI(){
load();
main = new JFrame();
main.setSize(900, 600);
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setTitle("MyCourses 2k16");
main.setContentPane(welcomePanel());
//fill out the cards
cards.add(welcome, "Welcome");
cards.add(home, "Home");
//display welcome card
cl.show(cards, "welcome");
main.setVisible(true);
saveState();
}
private JPanel welcomePanel() {
JPanel welcome = new JPanel();
welcome.setLayout(null);
welcome.setBackground(Color.DARK_GRAY);
JLabel hi = new JLabel("Welcome to MyCourses 2K16");
hi.setSize(800, 100);
hi.setLocation(50,50);
hi.setFont(new Font("Serif", Font.BOLD, 48));
hi.setForeground(Color.WHITE);
JLabel select = new JLabel("Fill in the information, then click login or register to proceed, no special characters allowed");
select.setSize(700,100);
select.setLocation(75,100);
select.setFont(new Font("Serif", Font.PLAIN, 18));
select.setForeground(Color.WHITE);
login = new JButton( "login");
login.setSize(100, 50);
login.setLocation(50, 200);
login.addActionListener(this);
register = new JButton( "register");
register.setSize(100,50);
register.setLocation(200, 200);
register.addActionListener(this);
JLabel un = new JLabel("username");
un.setSize(100, 30);
un.setLocation(50, 270);
un.setForeground(Color.WHITE);
username = new JTextField();
username.setSize(200, 30);
username.setLocation(50,300);
JLabel pw = new JLabel("password");
pw.setSize(100, 30);
pw.setLocation(50, 350);
pw.setForeground(Color.WHITE);
password = new JTextField();
password.setSize(200, 30);
password.setLocation(50,380);
welcome.add(hi);
welcome.add(select);
welcome.add(login);
welcome.add(register);
welcome.add(un);
welcome.add(username);
welcome.add(pw);
welcome.add(password);
return welcome;
}
private JPanel homePanel() {
JPanel home = new JPanel();
home.setLayout(null);
home.setBackground(Color.DARK_GRAY);
JLabel hi = new JLabel("HOME");
hi.setSize(800, 100);
hi.setLocation(50,50);
hi.setFont(new Font("Serif", Font.BOLD, 48));
hi.setForeground(Color.WHITE);
return home;
}
public void load(){
}
private void saveState(){
Iterator<Student> it = students.iterator();
while(it.hasNext()){
it.next().saveStudent();
}
}
public static void main(String[] args) {
new mainGUI();
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource()==login){
System.out.println("Logging in...");
validateLogin(students);
}
else if (e.getSource()==register){
}
}
private void validateLogin(ArrayList<Student> students){
boolean valid = false;
for(int i = 0; i < students.size(); i++){
if(username.getText().equals(students.get(i).getUsername())
&& password.getText().equals(students.get(i).getPassword()))
{
valid = true;
workingStudent=(students.get(i));
System.out.println("Successful Login!");
cl.show(cards, "home");
}
}
if(valid == false){
System.out.println("Invalid Login, try again");
}
}
}
You create a JPanel that uses CardLayout, cards, but you add it to nothing, so it will of course not display itself, nor its cards. Solution: add this JPanel to your GUI.
So instead of:
main.setContentPane(welcomePanel());
do:
main.setContentPane(cards);
Issue number 2:
Use String constants when using Strings as a type of key. Note that you add one JPanel to the cards JPanel thusly:
cards.add(home, "Home");
But then try to display it like so:
cl.show(cards, "home");
But Home isn't the same as home.
Instead declare a constant, HOME:
public static final String HOME = "home";
and use the same constant to add the JPanel and to display it.
For a simplistic example:
import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class MainGui2 extends JPanel {
private CardLayout cardLayout = new CardLayout();
private WelcomePanel welcomePanel = new WelcomePanel(this);
private HomePanel homePanel = new HomePanel();
public MainGui2() {
setLayout(cardLayout);
add(welcomePanel, WelcomePanel.NAME);
add(homePanel, HomePanel.NAME);
}
public void showCard(String name) {
cardLayout.show(this, name);
}
private static void createAndShowGui() {
MainGui2 mainPanel = new MainGui2();
JFrame frame = new JFrame("MainGui2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class WelcomePanel extends JPanel {
public static final String NAME = "welcome panel";
private MainGui2 mainGui2;
public WelcomePanel(final MainGui2 mainGui2) {
this.mainGui2 = mainGui2;
add(new JLabel(NAME));
add(new JButton(new AbstractAction("Logon") {
#Override
public void actionPerformed(ActionEvent e) {
mainGui2.showCard(HomePanel.NAME);
}
}));
}
}
class HomePanel extends JPanel {
public static final String NAME = "home panel";
public HomePanel() {
add(new JLabel(NAME));
}
}
I have to create a text field, a text area, and two buttons, but I am stuck on the text field because I cant get it to appear when I run my program. My JFrame keeps appearing empty.
public class SentanceBuilder extends JFrame {
private JTextField textField = new JTextField(50);
private JTextArea textArea = new JTextArea(200,200);
private JButton Submit = new JButton();
private JButton Cancel = new JButton();
public SentanceBuilder(){
textField.setVisible(true);
textField.setLocation(50, 50);
this.textField();
this.setSize(400, 300);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public void textField(){
String textContent = textField.getText();
}
}
You never add the textField variable to a container such as a JPanel that is held by the top-level window, such as a JFrame. In fact, in your code, you add nothing to your JFrame!
If this were my GUI, I'd
Create my JTextField
Create a main JPanel to hold my components.
Add it and other components to the main JPanel via the JPanel's add(...) method.
Add the main JPanel to the JFrame's contentPane via the JFrame's add(...) method.
Call pack() and then setVisible(true) on the JFrame, but only after adding all components to it, not before.
Read the Swing tutorials since this beats guessing every time. You can get links to the tutorials at the Swing Tag Info link.
e.g.,
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class MyFoo extends JFrame {
private static final long serialVersionUID = 1L;
private JTextField textField = new JTextField(10);
private JButton button = new JButton("Foo Button");
public MyFoo() {
super("My JFrame");
// so Java will end when GUI is closed
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// code to be called when button is pushed
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO code that runs when button is pushed.
}
});
// panel to hold everything
JPanel mainPanel = new JPanel();
// add all to the panel
mainPanel.add(new JLabel("Text Field:"));
mainPanel.add(textField);
mainPanel.add(button);
// add the panel to the main GUI
add(mainPanel);
}
// start up code
private static void createAndShowGui() {
JFrame mainFrame = new MyFoo();
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
public static void main(String[] args) {
// call start up code in a Swing thread-safe way
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I am trying to make a program that reads a file chosen by the user, and after reading the file - the suffix "txt" is changed to "gif" and the file is saved as a picture (which is in the same catalogue as the file). The thing is, this picture variable gets its value in the "actionPerformed-method" and after that I want to add it to a frame in another class- but it doesn't show. Here's the code in my OptionsPane-class:
public class OptionsPane extends JComponent implements ActionListener{
private JButton buttonOne = new JButton("Alt.1");
private JButton buttonTwo = new JButton("Alt.2");
private JButton buttonThree = new JButton("Alt.3");
private int option;
private JButton buttonChoose = new JButton("Choose file");
private FileHandler filehandler;
private String picture;
private JLabel picLabel;
public OptionsPane(){
JLabel label = new JLabel("Choose optimization method", SwingConstants.CENTER);
JPanel subPanel = new JPanel();
label.setForeground(Color.CYAN);
label.setFont(new Font("Tahoma", Font.BOLD, 15));
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
this.add(label);
buttonOne.addActionListener(this);
buttonTwo.addActionListener(this);
buttonThree.addActionListener(this);
buttonChoose.addActionListener(this);
subPanel.setBackground(Color.DARK_GRAY);
subPanel.add(buttonOne);
subPanel.add(buttonTwo);
subPanel.add(buttonThree);
subPanel.add(buttonChoose);
this.add(subPanel);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == buttonOne){
option = 1;
System.out.println("You clicked button 1!");
}else if(e.getSource() == buttonTwo){
option = 2;
System.out.println("You clicked button 2!");
}else if(e.getSource() == buttonThree){
option = 3;
System.out.println("You clicked button 3!");
}else if(e.getSource() == buttonChoose){
System.out.println("hello");
option = 4;
filehandler = new FileHandler();
filehandler.read();
picture = filehandler.getFilePath().replaceFirst("txt", "gif");
picLabel = new JLabel(new ImageIcon(picture));
this.add(picLabel);
}
}
}
The frame is in the "MainFrame"-class, which looks like this at the moment:
public class MainFrame extends JFrame{
private JFrame frame = new JFrame();
private String picture;
private JLabel picLabel;
public MainFrame(){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(1300, 800));
frame.getContentPane().setBackground(Color.DARK_GRAY);
frame.setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));
OptionsPane optionspane = new OptionsPane();
frame.add(optionspane);
frame.pack();
frame.setVisible(true);
frame.setResizable(true);
}
}
Why isn't the picture visible in the mainframe?
EDIT
It works now!
https://stackoverflow.com/a/22380387/3271504
Thank you for your help #arooaroo . I tried to write down some of what you wrote, but it still didn't work when I wanted to add an image based on what file the user had chosen (for example if the user chose file text1.txt i wanted the corresponding picture "text1.gif" to show up). With your help, the picture showed up when I typed a specific pathway with "/"-slashes, but when I chose a file and tried to load the picture from the file pathway, it didn't show and that is because it had backslashes in the pathways. This is how it should be (such an irritating problem):
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == buttonOne){
option = 1;
System.out.println("You clicked button 1!");
}else if(e.getSource() == buttonTwo){
option = 2;
System.out.println("You clicked button 2!");
}else if(e.getSource() == buttonThree){
option = 3;
System.out.println("You clicked button 3!");
}else if(e.getSource() == buttonChoose){
filehandler = new FileHandler();
filehandler.read();
filepath = filehandler.getFilePath();
picture = filepath.replaceFirst("txt", "gif");
picture = picture.replaceAll("\\\\", "/");
ImageIcon icon = new ImageIcon(picture);
mainFrame.setPicture(icon);
}
Thank you for your help!
Once you separate your GUI code in to separate classes - which is a Good Thing - you will find the eternal challenge for GUI programming is allowing for clean communication between them where there are inter-dependencies.
In this instance perhaps the simplest approach is to pass in a reference of MainFrame into OptionsPane.
Let's assume you create an additional method in MainFrame for setting the picture:
public class MainFrame extends JFrame{
// all instance vars as before
public MainFrame() {
// same as before except for this line...
OptionsPane optionspane = new OptionsPane(this);
}
public void setPicture(JLabel pictureLabel) {
// add code here for adding the picture...
// That's an exercise for yourself, or another question ;)
}
}
Then in your OptionsPane class:
....
private MainFrame mainFrame; // add a new instance var
public OptionsPane(MainFrame mainFrame) {
this.mainFrame = mainFrame;
// ... rest of the code same as before
}
#Override
public void actionPerformed(ActionEvent e) {
//...
picture = filehandler.getFilePath().replaceFirst("txt", "gif");
picLabel = new JLabel(new ImageIcon(picture));
mainFrame.setPicture(picLabel); // <-- This is where you communicate with the mainFrame instance
//...
}
EDIT
Although my original answer provided a valid and correct solution, it's clear that the OP requires a fully working example, including the code to load display the resulting image. Here's a sample program.
public class OptionsPane extends JComponent implements ActionListener {
private JButton buttonOne = new JButton("Alt.1");
private JButton buttonTwo = new JButton("Alt.2");
private JButton buttonThree = new JButton("Alt.3");
private int option;
private JButton buttonChoose = new JButton("Choose file");
private String picture;
private JLabel picLabel;
private MainFrame mainFrame;
public OptionsPane(MainFrame mainFrame) {
this.mainFrame = mainFrame;
JLabel label = new JLabel("Choose optimization method", SwingConstants.CENTER);
JPanel subPanel = new JPanel();
label.setForeground(Color.CYAN);
label.setFont(new Font("Tahoma", Font.BOLD, 15));
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
this.add(label);
buttonOne.addActionListener(this);
buttonTwo.addActionListener(this);
buttonThree.addActionListener(this);
buttonChoose.addActionListener(this);
subPanel.setBackground(Color.DARK_GRAY);
subPanel.add(buttonOne);
subPanel.add(buttonTwo);
subPanel.add(buttonThree);
subPanel.add(buttonChoose);
this.add(subPanel);
}
#Override
public void actionPerformed(ActionEvent e) {
// For sake of simplicity I'm ignoring the original button logic here
// and focussing on just getting an icon loaded in the parent frame...
ImageIcon icon = new ImageIcon("/path/to/test/image.png");
// Just pass the icon itself rather than a new label.
mainFrame.setPicture(icon);
}
}
public class MainFrame {
// No need to extend JFrame if you're using a JFrame instance variable
private JFrame frame = new JFrame();
private JLabel picLabel;
private JPanel mainPanel;
public MainFrame() {
mainPanel = new JPanel(new BorderLayout());
mainPanel.setBackground(Color.DARK_GRAY);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(1300, 800));
OptionsPane optionspane = new OptionsPane(this);
mainPanel.add(optionspane, BorderLayout.NORTH);
picLabel = new JLabel();
picLabel.setHorizontalAlignment(JLabel.CENTER);
mainPanel.add(picLabel, BorderLayout.CENTER);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setVisible(true);
frame.setResizable(true);
}
public void setPicture(ImageIcon icon) {
picLabel.setIcon(icon);
}
public static void main(String[] args) {
new MainFrame();
}
}
Note I've done a couple of things differently. Personally I always create a JPanel and set that up as the primary layer rather and add that directly to the frame rather than messing with the rootPane. And I used the BorderLayout in this example as it's much simpler.
The other thing is to add the JLabel which is to hold the picture to the GUI in the initial set up. Then you'll see I'm only changing its icon in the setPicture() method rather than adding a new JLabel on each instance.
I am implementing changes to a minesweeper game. One of these things is the difficulty. I have managed to do this and its working, but as the game board (in its own Jpanel) gets bigger & smaller (depending on the difficulty), I cannot get the JFrame to resize automatically. I am using:
setPreferredSize(new Dimension(WIDTH, HEIGHT));
to set the initial size of the window, but this makes it REALLY tiny, as in only showing the word 'File' from the JMenuBar. I have to resize it manually.
I tried setSize() and things like frame.pack() on the ActionListener event, but I cannot seem to get it to resize.
Any tips on what code/methods to use.
edit: code posted
package mines;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class SetupFrame extends JFrame {
private final int WIDTH = 600;
private final int HEIGHT = 500;
public JFrame frame;
public JMenuBar menubar;
public JMenu file;
public JMenu levels;
public JMenu help;
public JMenuItem login;
public JMenuItem save;
public JMenuItem resume;
public JMenuItem exit;
public JMenuItem easy;
public JMenuItem medium;
public JMenuItem hard;
private JLabel statusbar;
public JPanel main;
public JPanel buttonPanel;
public JPanel saved;
public JPanel game;
public Board mineGame;
public JButton ngButton;
public JButton undoButton;
public JButton redoButton;
public JTabbedPane tp;
public String[] levelPicker;
public JComboBox levelSelect;
public JFileChooser chooser;
public String filename;
public int difficulty;
public SetupFrame(){
frame = new JFrame();
String filename = JOptionPane.showInputDialog(frame, "Enter Your Name.");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setTitle("Minesweeper");
//menubar, menus, menu items
menubar = new JMenuBar();
setJMenuBar(menubar);
file = new JMenu("File");
help = new JMenu("Help");
menubar.add(file);
menubar.add(help);
login = new JMenuItem("Login..");
save = new JMenuItem("Save..");
resume = new JMenuItem("Resume..");
exit = new JMenuItem("Exit");
file.add(login);
file.add(save);
file.add(resume);
file.addSeparator();
file.add(exit);
statusbar = new JLabel("");
chooser = new JFileChooser(); // new File Chooser for saved tab
undoButton = new JButton(" Undo "); //undo Button for game panel
ngButton = new JButton(" New Game ");//new game Button for game panel
redoButton = new JButton(" Redo");//redo Button for game panel
main = new JPanel(new BorderLayout()); //new panel for main game
//main.add(mineGame, BorderLayout.CENTER); //add instance mineGame to main panel
game = new JPanel(new BorderLayout());// new panel for game tab
main.add(game, BorderLayout.CENTER); //add the mineGames panel to game panel
game.add(statusbar, BorderLayout.SOUTH); //add statusbar to bottom of game panel
//game.add(button, BorderLayout.NORTH); // add buttons (eventually be redo, undo, new game)
saved = new JPanel(); // create new panel for the saved tab
saved.add(chooser);//add the File Chooser to the saved tab
String[] levelPicker = {"Easy", "Medium", "Hard"};
levelSelect = new JComboBox(levelPicker);
levelSelect.setSelectedIndex(0);
//levelSelect.addActionListener(this);
buttonPanel = new JPanel();
buttonPanel.add(undoButton);
buttonPanel.add(ngButton);
buttonPanel.add(redoButton);
buttonPanel.add(levelSelect);
main.add(buttonPanel, BorderLayout.NORTH);
//create & add the tabs
tp = new JTabbedPane();
tp.addTab ("Game", main);
tp.addTab ("Saved", saved);
tp.addTab ("Statistics", null);
add(tp);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setResizable(true);
setVisible(true);
frame.pack();
class listener implements ActionListener{
public void actionPerformed (ActionEvent e)
{
if(e.getSource() == ngButton){
//JOptionPane.showInputDialog(frame, "Do You want To Save");
newMineGame();
}
JComboBox cb = (JComboBox)e.getSource();
String picker = (String)cb.getSelectedItem();
if (picker == "Easy"){
difficulty = 0;
newMineGame();
}
if (picker == "Medium"){
difficulty = 1;
newMineGame();
frame.pack();
}
if (picker == "Hard"){
difficulty = 2;
newMineGame();
frame.pack();
}
}
private void newMineGame() {
game.removeAll();
mineGame = new Board(statusbar, difficulty);
game.add(mineGame, BorderLayout.CENTER);
game.add(statusbar, BorderLayout.SOUTH);
repaint();
}
}
ngButton.addActionListener(new listener());
undoButton.addActionListener(new listener());
redoButton.addActionListener(new listener());
levelSelect.addActionListener(new listener());
}
public static void main(String[] args) {
new SetupFrame();
}
One of these things is the difficulty. I have managed to do this and
its working, but as the game board (in its own Jpanel) gets bigger &
smaller (depending on the difficulty), I cannot get the JFrame to
resize automatically.
and
tried setSize() and things like frame.pack() on the ActionListener
event, but I cannot seem to get it to resize.
JFrame.pack() works in case
that all JComponents representing mines (there is best of ways to use JToggleButton) returns properly PreferredSize back to its parent (JPanel)
parent (JPanel) laid by GridLayout (very simple)
and there are two ways how, when, where to JFrame.pack()
use CardLayout, the next code line after swithching Card is JFrame.pack()
remove old JPanel (from JFrame) and replace with new, then you need to call JFrame.(re)validate(), JFrame.repaint() and JFrame.pack() as last code lines
maybe there is another issue, important is code ordering in the case that is there settings for JFrame.setResizable(false);
after your edit
use Cardlayout
there you miss code lines (don't to extends JFrame, create this Object as Local variable) JFrame.(re)validate(), JFrame.repaint() and JFrame.pack() as last code lines in private void newMineGame() {
but I dont understand what you mean by: "there you miss code lines
(don't to extends JFrame, create this Object as Local variable) ;
code could be
import javax.swing.*;
public class SetupFrame {
private JFrame frame;
private JMenuBar menubar = new JMenuBar();
private Board mineGame;
public SetupFrame() {
//there add required JComponents
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setTitle("Minesweeper");
frame.setJMenuBar(menubar);
frame.add(mineGame);
//frame.setPreferredSize(new Dimension(WIDTH, HEIGHT));
//frame.setResizable(true);//not neccessary
frame.pack();
frame.setVisible(true);
}
private void newMineGame() {
//remove old Board
//add a new Board
frame.validate();
frame.repaint();
frame.pack();
}
private static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new SetupFrame();
}
});
}
}
Here is your mistake:
frame.pack();
Why do you need frame if your SetupFrame actually extends from JFrame? Change this line by just pack() and it will work.
#mKorbel already posted a complete and very useful explanation about pack() behavior (thank you).
Update
Also in your listener class you'll get this exception when a JButton is pressed:
java.lang.ClassCastException: javax.swing.JButton cannot be cast to javax.swing.JComboBox
You need make this little change to avoid this:
class listener implements ActionListener{
public void actionPerformed (ActionEvent e) {
if(e.getSource() == ngButton){
//JOptionPane.showInputDialog(frame, "Do You want To Save");
newMineGame();
} else if(e.getSource() instanceof JComboBox){ // add this else-if block
JComboBox cb = (JComboBox)e.getSource();
String picker = (String)cb.getSelectedItem();
if (picker.equals("Easy")){ // <-- picker == "Easy" is not the proper way to compare string, use equals() method instead
difficulty = 0;
newMineGame();
}
if (picker.equals("Medium")){
difficulty = 1;
newMineGame();
//frame.pack(); <--- again, just use pack();
pack();
}
if (picker.equals("Hard")){
difficulty = 2;
newMineGame();
//frame.pack(); <--- again, just use pack();
pack();
}
}
}
Or even better, implement an ItemListener to listen JComboBox selection changes instead using an ActionListener