JButtons work sometimes and not others when I change separate code - java

When I run my program the Jbuttons sometimes show up but other times they don't. For example, if I change something unrelated to the JButtons it will not show them. It will just show an empty jframe. PS sorry if I made formatting error's with the code i'm new to this site. Any tips on asking questions would be appreciated.Also it wont let me show the top of the code either.
package ca.seanmckee.digcraft;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Game extends JPanel {
public static String versionnumber = "0.0.1"; //For updating game version number
public static String gamename = "Digcraft ";
public static boolean dig = true;
public static int rocks = 0;
public static int sticks = 0;
public static int logs = 0;
public static void main(String[]a){
JFrame frame = new JFrame(gamename + versionnumber);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setSize(800,600);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
JPanel panel = new JPanel();
frame.add(panel);
JButton dig = new JButton("Dig"); //Dig mechanic allows players to find things
JButton stickscounter = new JButton("Sticks: " + sticks);
JButton rockscounter = new JButton ("Rocks: " + rocks);
JButton logscounter = new JButton("logs" + logs);
JButton craft = new JButton("Craft"); //uses things found by digging to create more advanced things
panel.add(dig);
panel.add(stickscounter);
panel.add(rockscounter);
panel.add(logscounter);
panel.add(craft);
dig.addActionListener( new ActionListener() {
#Override
public void actionPerformed( ActionEvent e ) {
dig();
}
});
}
public static void dig(){
int counter = 0;
while(counter < 5){
Random random = new Random();
int number;
number = 1+random.nextInt(50); //Gets random number to select what you dug up
switch(number){
case 1:
System.out.println("You find a rock");
rocks = rocks + 1;
break;
case 2:
System.out.println("You find a log");
logs = logs + 1;
break;
case 3:
System.out.println("You find a stick");
sticks = sticks + 1;
break;
default:
System.out.println("You dig deeper...");
break;
}
counter = counter + 1;
}
}
}

First, take frame.setVisible and make it the last statement of the main method...
public static void main(String[]a){
JFrame frame = new JFrame(gamename + versionnumber);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Take this...
//frame.pack();
//frame.setSize(800,600);
//frame.setLocationRelativeTo(null);
//frame.setVisible(true);
JPanel panel = new JPanel();
frame.add(panel);
JButton dig = new JButton("Dig"); //Dig mechanic allows players to find things
JButton stickscounter = new JButton("Sticks: " + sticks);
JButton rockscounter = new JButton ("Rocks: " + rocks);
JButton logscounter = new JButton("logs" + logs);
JButton craft = new JButton("Craft"); //uses things found by digging to create more advanced things
panel.add(dig);
panel.add(stickscounter);
panel.add(rockscounter);
panel.add(logscounter);
panel.add(craft);
dig.addActionListener( new ActionListener() {
#Override
public void actionPerformed( ActionEvent e ) {
dig();
}
});
// Put it here...
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
You'll also find calling pack and setLocationRelativeTo last will also help, as you will now have content in the frame that will allow pack to do it's job
Second, wrap you UI inside a EventQueue.invokeLater block...
public static void main(String[]a){
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame(gamename + versionnumber);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.add(panel);
JButton dig = new JButton("Dig"); //Dig mechanic allows players to find things
JButton stickscounter = new JButton("Sticks: " + sticks);
JButton rockscounter = new JButton ("Rocks: " + rocks);
JButton logscounter = new JButton("logs" + logs);
JButton craft = new JButton("Craft"); //uses things found by digging to create more advanced things
panel.add(dig);
panel.add(stickscounter);
panel.add(rockscounter);
panel.add(logscounter);
panel.add(craft);
dig.addActionListener( new ActionListener() {
#Override
public void actionPerformed( ActionEvent e ) {
dig();
}
});
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
See Initial Threads for more details
Third, get r

Use frame.setVisible(true) at the end of the main(String[]) method.Also,use frame.pack() at the end of the main(String[]) method after adding all the components to it.Your main method should be something like this:-
public static void main(String[]a){
JFrame frame = new JFrame(gamename + versionnumber);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800,600);
frame.setLocationRelativeTo(null);
JPanel panel = new JPanel();
frame.add(panel);
JButton dig = new JButton("Dig"); //Dig mechanic allows players to find things
JButton stickscounter = new JButton("Sticks: " + sticks);
JButton rockscounter = new JButton ("Rocks: " + rocks);
JButton logscounter = new JButton("logs" + logs);
JButton craft = new JButton("Craft"); //uses things found by digging to create more advanced things
panel.add(dig);
panel.add(stickscounter);
panel.add(rockscounter);
panel.add(logscounter);
panel.add(craft);
dig.addActionListener( new ActionListener() {
#Override
public void actionPerformed( ActionEvent e ) {
dig();
}
});
frame.add(panel);
frame.pack();
frame.setVisible(true);
}

Related

Writing a small app for a DnD puzzle and have trouble with a JButton array

After adding an object of class Puzzle to Main everything displays mostly as it should. when I click any of the buttons some indexes of state should swap to the opposite so from true to false or from false to true.
unfortunately button clicking doesn't want to register for any of the buttons from the array yet it does register for a single button that was initialized by itself. How can I fix the problem?
my code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
public class Puzzle extends JFrame implements ActionListener
{
int doors = 8;
boolean [] state = new boolean[doors];
JButton [] levers = new JButton[doors];
JButton weird = new JButton("weird lever");
JLabel display = new JLabel();
Puzzle()
{
reset();
this.setSize(new Dimension(1920, 1080));
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setVisible(true);
this.setResizable(false);
this.setLayout(null);
this.add(display);
this.add(weird);
int num = levers.length;
int start = 50;
int size = (1920-(num+1)*start)/num;
char label = 'A';
display.setBounds(size*2, 150, 2000, 300);
display.setFont(new Font("Arial Black", Font.PLAIN, 200));
Display();
for(JButton i : levers)
{
i = new JButton(String.valueOf(label));
label++;
i.setBounds(start, 500, size, size);
start+=(size+50);
i.addActionListener(this);
i.setFont(new Font("Arial black", Font.PLAIN, size/2));
i.setFocusable(false);
this.add(i);
}
weird.setFocusable(false);
weird.setBounds(550, 800, 800, 200);
weird.setFont(new Font("Arial Black", Font.PLAIN, size/2));
weird.addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent e)
{
/*if(e.getSource() == levers[0])
{
state[2] = Swap(state[2]);
Display();
}
if(e.getSource() == levers[1])
{
state[4] = Swap(state[4]);
state[6] = Swap(state[6]);
Display();
}
if(e.getSource() == levers[2])
{
state[2] = Swap(state[2]);
state[3] = Swap(state[3]);
state[6] = Swap(state[6]);
state[7] = Swap(state[7]);
Display();
}
if(e.getSource() == levers[3])
{
state[0] = Swap(state[0]);
state[2] = Swap(state[2]);
state[7] = Swap(state[7]);
Display();
}
if(e.getSource() == levers[4])
{
state[1] = Swap(state[1]);
state[3] = Swap(state[3]);
state[4] = Swap(state[4]);
state[5] = Swap(state[5]);
Display();
}
if(e.getSource() == levers[5])
{
state[0] = Swap(state[0]);
state[2] = Swap(state[2]);
state[6] = Swap(state[6]);
Display();
}
if(e.getSource() == levers[6])
{
state[1] = Swap(state[1]);
state[5] = Swap(state[5]);
Display();
}
if(e.getSource() == levers[7])
{
state[1] = Swap(state[1]);
state[2] = Swap(state[2]);
state[4] = Swap(state[4]);
state[5] = Swap(state[5]);
Display();
}
*/
if(e.getSource() == levers[0])
{
display.setText("A works");
}
if(e.getSource() == weird)
{
display.setText("test");
}
}
boolean Swap(boolean n)
{
return !n;
}
void Display()
{
StringBuilder toDisplay = new StringBuilder();
for (boolean j : state)
{
if (j)
{
toDisplay.append("| ");
} else
toDisplay.append("_ ");
}
display.setText(toDisplay.toString());
}
void reset ()
{
Arrays.fill(state, true);
}
}```
button clicking doesn't want to register for any of the buttons from the array yet it does register for a single button
System.out.println( levers[0] );
if(e.getSource() == levers[0])
{
display.setText("A works");
}
Add some debug code to your ActionListener and you will see that the value of levers[0] is "null".
for(JButton i : levers)
{
i = new JButton(String.valueOf(label));
label++;
i.setBounds(start, 500, size, size);
start+=(size+50);
i.addActionListener(this);
i.setFont(new Font("Arial black", Font.PLAIN, size/2));
i.setFocusable(false);
this.add(i);
}
You create the button, but you never add the instance of each button to the Array.
for(JButton i : levers)
Why would you use "i" as the variable name. Typically "i" is used as an index. Use a proper variable name, like "button". However, in this case you don't want to use a "for each" loop.
Instead you want a normal for loop so you can index your Array to add each button as you create it:
//for(JButton i : levers)
for (int i = 0; i < doors; i++)
{
JButton button = new JButton(String.valueOf(label));
levers[i] = button;
...
Other issues:
method names should NOT start with an upper case character.
components should be added to the frame BEFORE the frame is made visible.
components should be created on the Event Dispatch Thread (EDT).
Don't use a null layout and setBounds(). Swing was designed to be used with layout managers.
Don't hardcode screen sizes. Instead you can use frame.setExtendedState(JFrame.MAXIMIZED_BOTH);, so it will work for all screen sizes.
Introduction
Your code was too complex for me to understand. I like simple code. Short methods and simple classes.
Here's the GUI I came up with.
Here's the GUI after I clicked a couple of letter JButtons
Explanation
Oracle has a nifty tutorial, Creating a GUI With JFC/Swing, which will show you how to create a Swing GUI. Skip the Netbeans section.
Your code was missing a main method, so I added one. I started the Swing application with a call to the SwingUtilities invokeLater method. This method ensures that the Swing components are created and executed on the Event Dispatch Thread.
The first thing I did was create a PuzzleModel class to hold the boolean array. It's a good idea to separate your model from your view and controller classes. This pattern is the model / view / controller (MVC) pattern.
A Swing JFrame can contain many JPanels. I created a segment JPanel to hold a JLabel and a JButton aligned vertically. I used the GridBagLayout to align the JLabel and JButton. Swing layout managers help you to avoid absolute positioning and the problems that come with absolute positioning.
I created a main JPanel to hold 8 segment JPanels. These JPanels are aligned with a FlowLayout.
As you can see, my JFrame is smaller than yours. You create as small a JFrame as possible. If the user wants to make it bigger, that's what the rectangle in the upper right corner is for.
Swing is meant to be designed from the inside out. You don't specify a JFrame size and try to make the components fit. You create the components and let Swing determine the size of the JFrame. If you want the JFrame I created to be bigger, increase the font sizes. Hint: A fraction or multiple of 72 points looks better on most displays.
I created two ActionListener classes, one for the alphabet JButtons and one for the lever JButton. This makes it easier to focus on the alphabet JButtons. All you have to do in the ActionListener is swap the appropriate isVertical boolean values when each JButton is left-clicked. I just flipped the corresponding boolean as a demonstration.
Code
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class PuzzleGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new PuzzleGUI());
}
private JLabel[] leverLabel;
private final PuzzleModel model;
public PuzzleGUI() {
this.model = new PuzzleModel();
}
#Override
public void run() {
JFrame frame = new JFrame("Weird Lever");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.add(createButtonPanel(), BorderLayout.AFTER_LAST_LINE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
System.out.println(frame.getSize());
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
char c = 'A';
boolean[] isVertical = model.getIsVertical();
leverLabel = new JLabel[isVertical.length];
for (int i = 0; i < isVertical.length; i++) {
String labelText = (isVertical[i]) ? "|" : "-";
panel.add(createLeverButtonPanel(labelText, Character.toString(c), i));
c = (char) (((int) c) + 1);
}
return panel;
}
public void updateMainPanel() {
boolean[] isVertical = model.getIsVertical();
for (int i = 0; i < isVertical.length; i++) {
String labelText = (isVertical[i]) ? "|" : "-";
leverLabel[i].setText(labelText);
}
}
private JPanel createLeverButtonPanel(String labelText, String buttonText, int index) {
JPanel panel = new JPanel(new GridBagLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
Font font1 = new Font("Arial Black", Font.PLAIN, 144);
Font font2 = new Font("Arial Black", Font.PLAIN, 72);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
leverLabel[index] = new JLabel(labelText);
leverLabel[index].setFont(font1);
panel.add(leverLabel[index], gbc);
gbc.gridy++;
JButton button = new JButton(buttonText);
button.addActionListener(new AlphabetButtonListener());
button.setFont(font2);
panel.add(button, gbc);
return panel;
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
Font font2 = new Font("Arial Black", Font.PLAIN, 48);
JButton button = new JButton("Weird Lever");
button.addActionListener(new LeverButtonListener());
button.setFont(font2);
panel.add(button);
return panel;
}
public class AlphabetButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent event) {
JButton button = (JButton) event.getSource();
String text = button.getText();
char c = text.charAt(0);
int index = ((int) c - 'A');
model.swap(index);
updateMainPanel();
}
}
public class LeverButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent event) {
// TODO Auto-generated method stub
}
}
public class PuzzleModel {
private boolean[] isVertical;
public PuzzleModel() {
int doors = 8;
this.isVertical = new boolean[doors];
reset();
}
private void reset() {
Arrays.fill(isVertical, true);
}
public void swap(int index) {
isVertical[index] = !isVertical[index];
}
public boolean[] getIsVertical() {
return isVertical;
}
}
}

How to make JPanel fill the entire JFrame?

I am making an UI in a minecraft plugin. Everything is working, except I have a JPanel and it doesn't fill the whole JFrame. So what I want is the JPanel fill the entire JFrame even if we re-scale the window.
I use Layout manager (FlowLayout) for the JPanel.
I tried using a Layout manager for the JFrame, well it didn't solved my problem because it didn't resize the JPanel.. I tried setting the size of the JPanel to the JFrame's size, but when it's resized it doesn't scale with it.
So, how can I do this?
My plugin creates a button for every player and when I click the button it kicks the player.
My code (I can't really post less because I don't know where I need to change something):
public static JFrame f;
public static JTextField jtf;
public static JPanel jp;
public static void creategui()
{
System.out.println("GUI created.");
f = new JFrame("Players");
jp = new JPanel();
jp.setLayout(new FlowLayout(FlowLayout.LEFT));
jp.setBackground(Color.GRAY);
jtf = new JTextField("Reason");
jtf.setPreferredSize(new Dimension(200,20));
jtf.setToolTipText("Write the reason here.");
jp.setSize(new Dimension(200,200));
f.setLayout(null);
f.setSize(500,500);
f.setVisible(true);
jp.add(jtf);f.add(jp, BorderLayout.CENTER);
for (final Player p : Bukkit.getOnlinePlayers())
{
System.out.println("Looping.");
final JButton b = new JButton();
b.setName(p.getName());
b.setText(p.getName());
b.setToolTipText("Kick " + b.getText());
b.setBackground(Color.GREEN);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (!b.getBackground().equals(Color.RED))
{
Bukkit.getScheduler().runTask(main, new Runnable() {
public void run() {
Bukkit.getPlayer(b.getText()).kickPlayer(jtf.getText());
b.setBackground(Color.RED);
}
});
}
}
});
jp.add(b);
System.out.println("Button added.");
}
f.add(jp, BorderLayout.CENTER);
}
The question should include an mcve reproducing the problem so we can test it.
It could look like this :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.util.Arrays;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Mcve {
private static List<String> players = Arrays.asList(new String[]{"Player A", "Player B"});
public static void main(String[] args) {
creategui();
}
public static void creategui()
{
JPanel jp = new JPanel();
jp.setBackground(Color.GRAY);
JTextField jtf = new JTextField("Reason");
jtf.setPreferredSize(new Dimension(200,20));
jtf.setToolTipText("Write the reason here.");
jp.setSize(new Dimension(200,200));
jp.add(jtf);
for (final String p : players)
{
final JButton b = new JButton();
b.setText(p);
b.setBackground(Color.GREEN);
b.addActionListener(e -> {
if (!b.getBackground().equals(Color.RED))
{
b.setBackground(Color.RED);
}
});
jp.add(b);
}
JFrame f = new JFrame("Players");
f.setLayout(null);
f.setSize(500,500);
f.add(jp, BorderLayout.CENTER);
f.setVisible(true);
}
}
To make the JPanel fill the entire frame simply remove this line :
f.setLayout(null);
and let the default BorderLayout manager do its work.
Here is a modified version with some additional comments:
public class Mcve {
private static List<String> players = Arrays.asList(new String[]{"Player A", "Player B"});
public static void main(String[] args) {
creategui();
}
public static void creategui()
{
JPanel jp = new JPanel();
jp.setBackground(Color.GRAY);
JTextField jtf = new JTextField("Reason");
jtf.setPreferredSize(new Dimension(200,20));
jtf.setToolTipText("Write the reason here.");
jp.setPreferredSize(new Dimension(250,200)); // set preferred size rather than size
jp.add(jtf);
for (final String p : players)
{
final JButton b = new JButton();
b.setText(p);
b.setBackground(Color.GREEN);
b.addActionListener(e -> {
if (!b.getBackground().equals(Color.RED))
{
b.setBackground(Color.RED);
}
});
jp.add(b);
}
JFrame f = new JFrame("Players");
//f.setLayout(null); null layouts are bad practice
//f.setSize(500,500); let layout managers set the sizes
f.add(jp, BorderLayout.CENTER);
f.pack();
f.setVisible(true);
}
}
A 1x1 grid layout does the job quite nicely.
window = new JFrame();
panel = new JPanel();
window.setLayout(new java.awt.GridLayout(1, 1));
window.add(panel);
Either set the layout manager for jp (the JPanel in the code you posted) to BorderLayout and add jtf (the JTextField in the code you posted) to the CENTER of jp, as in:
f = new JFrame();
jp = new JPanel(new BorderLayout());
jtf = new JTextField(30); // number of columns
jp.add(jtf, BorderLayout.CENTER);
f.add(jp, BorderLayout.CENTER);
or dispense with jp and add jtf directly to f (the JFrame in the code you posted), as in:
f = new JFrame();
jtf = new JTextField(30);
f.add(jtf, BorderLayout.CENTER);
The key is that the CENTER component of BorderLayout expands to fill the available space.
So I fixed it somehow, this is the code:
public static void creategui()
{
System.out.println("GUI created.");
f = new JFrame("Players");
jp = new JPanel();
jp.setBackground(Color.GRAY);
jp.setSize(200,200);
jtf = new JTextField(30);
jtf.setToolTipText("Write the reason here.");
jp.add(jtf);
for (final Player p : Bukkit.getOnlinePlayers())
{
System.out.println("Looping.");
final JButton b = new JButton();
b.setName(p.getName());
b.setText(p.getName());
b.setToolTipText("Kick " + b.getText());
b.setBackground(Color.GREEN);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (!b.getBackground().equals(Color.RED))
{
Bukkit.getScheduler().runTask(main, new Runnable() {
public void run() {
getplr(b.getText()).kickPlayer(jtf.getText());
b.setBackground(Color.RED);
}
});
}
}
});
jp.add(b);
System.out.println("Button added.");
}
f.setLayout(new BorderLayout());
f.add(jp, BorderLayout.CENTER);
f.setSize(500,500);
f.pack();
f.setVisible(true);
}

Hangman actionListener graphics [duplicate]

I'm trying to create a hangman game and so far it's coming along GREAT, but the layout design just doesn't seem to fall into place! The alphabet is supposed to end up in a FlowLayout order on top of the Hangman picture with the buttons "Restart", "Help" "Add New Word" and "Exit" at the bottom! What am I doing wrong?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
public class Hangman extends JFrame
{
int i = 0;
static JPanel panel;
static JPanel panel2;
static JPanel panel3;
public Hangman()
{
JButton[] buttons = new JButton[26];
panel = new JPanel(new FlowLayout());
panel2 = new JPanel();
panel3 = new JPanel();
JButton btnRestart = new JButton("Restart");
btnRestart.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
}
});
JButton btnNewWord = new JButton("Add New Word");
btnNewWord.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
try
{
FileWriter fw = new FileWriter("Words.txt", true);
PrintWriter pw = new PrintWriter(fw, true);
String word = JOptionPane.showInputDialog("Please enter a word: ");
pw.println(word);
pw.close();
}
catch(IOException ie)
{
System.out.println("Error Thrown" + ie.getMessage());
}
}
});
JButton btnHelp = new JButton("Help");
btnHelp.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
String message = "The word to guess is represented by a row "
+ "of dashes, giving the number of letters and category of "
+ "the word. \nIf the guessing player suggests a letter "
+ "which occurs in the word, the other player writes it "
+ "in all its correct positions. \nIf the suggested "
+ "letter does not occur in the word, the other player "
+ "draws one element of the hangman diagram as a tally mark."
+ "\n"
+ "\nThe game is over when:"
+ "\nThe guessing player completes the word, or guesses "
+ "the whole word correctly"
+ "\nThe other player completes the diagram";
JOptionPane.showMessageDialog(null,message, "Help",JOptionPane.INFORMATION_MESSAGE);
}
});
JButton btnExit = new JButton("Exit");
btnExit.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
});
ImageIcon icon = new ImageIcon("D:\\Varsity College\\Prog212Assign1_10-013803\\images\\Hangman1.jpg");
JLabel label = new JLabel();
label.setIcon(icon);
String b[]= {"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"};
for(i = 0; i < buttons.length; i++)
{
buttons[i] = new JButton(b[i]);
panel.add(buttons[i]);
}
panel2.add(label);
panel3.add(btnRestart);
panel3.add(btnNewWord);
panel3.add(btnHelp);
panel3.add(btnExit);
}
public static void main(String[] args)
{
Hangman frame = new Hangman();
frame.add(panel, BorderLayout.NORTH);
frame.add(panel2, BorderLayout.CENTER);
frame.add(panel3, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}
Here are a few suggestions:
Use a GridLayout for the top panel; in this case, zero means the number of rows is determined by the specified number of columns and the total number of components in the layout:
JPanel north = new JPanel(new GridLayout(0, 9));
Here's an outline of how you can make your center panel have a reasonable initial size; note how you can draw relative to the current size:
JPanel center = new JPanel() {
private static final int N = 256;
private static final String S = "Todo...";
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int dx = (getWidth() - g.getFontMetrics().stringWidth(S)) / 2;
int dy = getHeight() / 2;
g.drawString(S, dx, dy);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(N, N);
}
};
You can construct your button names like this:
for (int i = 0; i < 26; i++) {
String letter = String.valueOf((char) (i + 'A'));
buttons[i] = new JButton(letter);
north.add(buttons[i]);
}
Make your panels instance variables and start on the event dispatch thread:
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Hangman frame = new Hangman();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.add(frame.north, BorderLayout.NORTH);
frame.add(frame.center, BorderLayout.CENTER);
frame.add(frame.south, BorderLayout.SOUTH);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
});
This problem is pretty well documented if you do some research - it seems all the panels (besides the CENTER one) aren't recalculated when resized. See How do I make this FlowLayout wrap within its JSplitPane? and http://www.velocityreviews.com/forums/t608472-wrap-flowlayout.html
But for a really quick fix, try changing your main method to this... (basically using a BoxLayout as your main container)
public static void main(String[] args)
{
TempProject frame = new TempProject();
Box mainPanel = Box.createVerticalBox();
frame.setContentPane(mainPanel);
mainPanel.add(panel);
mainPanel.add(panel2);
mainPanel.add(panel3);
frame.pack();
frame.setVisible(true);
}

how to put actionlistenerand actioncommand to multiple jbuttons

so i want my buttons to be labeled 1-9 but I dont want to list out all the action listeners and action-commands for each button. How can I do that
and also I cannot use add.ActionListener(this) so what can i use
JButton[] button = new JButton[9];
panel.setLayout(new GridLayout(3,3));
for (int i = 0; i < button.length; i++) {
button[i] = new JButton();
panel.add(button[i]);
String bu = Integer.toString(i);
button[i].setActionCommand(bu);
button[i].addActionListener(new ActionListener());
Sorry im new to java swing so its abit confusing still
I cannot use add.ActionListener(this) so what can i use
You create a class that implements an ActionListener.
Or better yet create a class that implement Action. An Action is the same as an ActionListener. The benefit is that an Action can be used with Key Bindings.
Here is a basic example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class CalculatorPanel extends JPanel
{
private JTextField display;
public CalculatorPanel()
{
Action numberAction = new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent e)
{
// display.setCaretPosition( display.getDocument().getLength() );
display.replaceSelection(e.getActionCommand());
}
};
setLayout( new BorderLayout() );
display = new JTextField();
display.setEditable( false );
display.setHorizontalAlignment(JTextField.RIGHT);
add(display, BorderLayout.NORTH);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout( new GridLayout(0, 5) );
add(buttonPanel, BorderLayout.CENTER);
for (int i = 0; i < 10; i++)
{
String text = String.valueOf(i);
JButton button = new JButton( text );
button.addActionListener( numberAction );
button.setBorder( new LineBorder(Color.BLACK) );
button.setPreferredSize( new Dimension(30, 30) );
buttonPanel.add( button );
InputMap inputMap = button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inputMap.put(KeyStroke.getKeyStroke(text), text);
inputMap.put(KeyStroke.getKeyStroke("NUMPAD" + text), text);
button.getActionMap().put(text, numberAction);
}
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("Calculator Panel");
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.add( new CalculatorPanel() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Now you can either click on the button or type the number and the value will be inserted into the text field.
Just add on main action performed method.
Example would be like this :
public void actionPerformed(ActionEvent e){
// your todo code here
}
Make sure to import the appropriate packages.
You have to implement the actionListener
public class Butt implements ActionListener
{
public JPanel method()
{
JPanel panel = new JPanel();
JButton[] button = new JButton[9];
panel.setLayout(new GridLayout(3, 3));
for (int i = 0; i < button.length; i++)
{
button[i] = new JButton(""+i);
panel.add(button[i]);
String bu = Integer.toString(i);
button[i].setActionCommand(bu);
button[i].addActionListener(this);
}
return panel;
}
#Override
public void actionPerformed(ActionEvent e)
{
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.add(new Butt().method());
frame.setVisible(true);
frame.setSize(500, 500);
}
}
see now there is no errors.
results
and also I cannot use add.ActionListener(this) so what can i use
I will interpret what you meant here as "you are not allowed to let the container class implements ActionListener, but still allowed to use ActionListener".
If that is the case, you have at least 2 more choices:
Create an anonymous class for the ActionListener
Create an inner class for the ActionListener
An example using GridLayout with inner-class Actionlistener:
how to put actionlistenerand actioncommand to multiple jbuttons
The following uses inner class to handle buttons' action.
class MainPanel extends JPanel //not implementing ActionListener here
{
private JButton[] btns;
public MainPanel(){
setPreferredSize(new Dimension(150, 150));
setLayout(new GridLayout(3, 3));
initComponents();
addComponents();
}
private void initComponents(){
btns = new JButton[9];
ButtonHandler bh = new ButtonHandler();
for(int x=0; x<btns.length; x++){
btns[x] = new JButton(Integer.toString(x+1));
btns[x].addActionListener(bh); //NOT using addActionListener(this)
}
}
private void addComponents(){
for(int x=0; x<btns.length; x++)
add(btns[x]); //Add in sequential order into grid layout
}
private class ButtonHandler implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e){
String s = ((JButton)e.getSource()).getText();
JOptionPane.showMessageDialog(null, "Button " + s + " was clicked.");
}
}
}
Finally, run your codes in the EDT:
class TestRunner
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
JFrame frame = new JFrame("Buttons Pad");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}

Cannot find a way to create a loading screen

I was just messing around with GUI in Java and created a little game. In it, 105 randomly placed buttons are created and then an instruction screen pops up, telling the user which button to find. I've tried to figure out how to program a "Loading..." JDialog, which will pop up while the buttons are being created in the background. The trouble is, when I run the program the JDialog doesn't load until AFTER all the buttons have been created, which kind of defeats the purpose of the box in the first place. How can I force the "Loading..." box to load BEFORE the buttons begin to be created??? Thanks in advance.
Because I've just been tinkering, my code is not perfect but here it is:
import java.util.Scanner;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.Random;
import java.awt.Color;
import javax.swing.JButton;
import javax.swing.ProgressMonitor;
public class ButtonGame {
private static int butNum = 1;
private static JFrame frame;
private static ActionListener notIt;
private static ActionListener it;
private static Random rand = new Random();
private static int butToFind = rand.nextInt(105);
private static JFrame frameToClose;
//private static int mouseClicks;
//private static double time;
public static void main(String[] args) {
//actionlistener for all incorrect buttons (buttons that are "not it")
notIt = new ActionListener() {
public void actionPerformed(ActionEvent e) {
Component component = (Component) e.getSource();
JFrame frame5 = (JFrame) SwingUtilities.getRoot(component);
frame5.dispose();
}
};
//actionlistener for the correct button (the button that's "it")
it = new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFrame youWin = new JFrame("YOU WON!");
//removes all panels to begin game again
JButton again = new JButton("Play again");
again.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
java.awt.Window windows[] = java.awt.Window.getWindows();
for(int i=0;i<windows.length;i++){
if (windows[i] != frame) { windows[i].dispose(); }
butToFind = rand.nextInt(105);
butNum = 1;
youWin.dispose();
}
frame.setVisible(true);
}
});
//quits game
JButton win = new JButton("Quit");
win.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
//layout
youWin.setSize(775, 300);
youWin.setLayout(new FlowLayout());
JLabel label1 = new JLabel("Fantastic!");
Font font1 = new Font("Courier", Font.BOLD,120);
label1.setFont(font1);
label1.setHorizontalAlignment(JLabel.CENTER);
JLabel label2 = new JLabel("You beat the game!");
Font font2 = new Font("Courier", Font.BOLD,60);
label2.setFont(font2);
label2.setHorizontalAlignment(JLabel.CENTER);
youWin.add(label1);
youWin.add(label2);
JPanel panel = new JPanel();
youWin.add(panel);
panel.add(again);
panel.add(win);
youWin.setLocation(260, 100);
youWin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
youWin.setVisible(true);
java.awt.Window windows[] = java.awt.Window.getWindows();
}
};
//start window
frame = new JFrame("Window");
frame.setLocation(400, 200);
JButton button1 = new JButton("Click to begin");
//button to begin game
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// JDialog load = new JDialog();
// load.setAlwaysOnTop(true);
// load.setSize(500,500);
// load.setVisible(true);
// load.add(new Label("Loading..."));
// load.pack();
frame.setVisible(false); // "start" window's visibility
// try {
// Thread.sleep(100000);
// } catch (Exception t) {
// }
// creates buttons
for (int i = 0; i < 105; i++) {
JFrame nextFrame = newFrame(butNum);
nextFrame.setVisible(true);
butNum++;
}
//creates instructions and tells user what button to find
JFrame instructions = new JFrame("How to play");
instructions.setSize(300,175);
instructions.setLayout(new GridLayout(4,1));
JPanel instPanel = new JPanel();
//button to remove instruction panel
JButton ok = new JButton("Ok");
ok.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
instructions.dispose();
}
});
instPanel.add(ok);
instructions.setLocation(400,200);
//layout of instruction panel
JLabel find = new JLabel("Your goal is to find Button " + butToFind + ".");
find.setHorizontalAlignment(JLabel.CENTER);
JLabel find2 = new JLabel("Click a button to make it disappear.");
find2.setHorizontalAlignment(JLabel.CENTER);
JLabel find3 = new JLabel("Good luck!");
find3.setHorizontalAlignment(JLabel.CENTER);
instructions.add(find);
instructions.add(find2);
instructions.add(find3);
instructions.add(instPanel);
instructions.setVisible(true);
}
});
frame.add(button1);
frame.setSize(150,100);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
//creates frame with button in it
public static JFrame newFrame(int num) {
JFrame frame2 = new JFrame();
JButton button = new JButton("Button " + num);
if (num == butToFind) {
button.addActionListener(it);
frameToClose = frame2;
} else {
button.addActionListener(notIt);
}
frame2.add(button);
frame2.setSize(randNum(90,200), randNum(50,100));
frame2.setLocation(rand.nextInt(1200), rand.nextInt(800));
frame2.getContentPane().setBackground(new Color(rand.nextInt(255),
rand.nextInt(255),
rand.nextInt(255)));
frame2.setVisible(true);
return frame2;
}
//provides random number between high and low
public static int randNum(int low, int high) {
int result = -1;
while (result < low || result > high) {
result = rand.nextInt(high);
}
return result;
}
}
Also, as a side-question, which of the variables defined before main should be static? And how can I get the program to compile without being static? Thanks!
First take a look at The Use of Multiple JFrames, Good/Bad Practice? and understand why I freaked out when I ran your code...
Instead of creating a bunch of frames, why not use something like JButton on another JPanel and add it to the current frame (this would also be a good use for a CardLayout)
JPanel panel = new JPanel(new GridLayout(10, 0));
Random rnd = new Random();
// creates buttons
for (int i = 0; i < 105; i++) {
JButton btn = new JButton(String.valueOf(i));
panel.add(btn);
//JFrame nextFrame = newFrame(butNum);
//nextFrame.setVisible(true);
//butNum++;
}
frame.getContentPane().removeAll();
frame.add(panel);
frame.revalidate();
frame.pack();
Alternatively, if you're really hell bent on using "frames", consider using a JDesktopPane and JInternalFrame instead.
See How to Use Internal Frames for more details
Also, as a side-question, which of the variables defined before main should be static? And how can I get the program to compile without being static?
As much as possible, none. Instead of trying to create the whole thing in the main method, use the classes constructor to initialise the UI and use another method to actually get the game rolling...
public class ButtonGame {
private int butNum = 1;
private JFrame frame;
private ActionListener notIt;
private ActionListener it;
private Random rand = new Random();
private int butToFind = rand.nextInt(105);
private JFrame frameToClose;
//private static int mouseClicks;
//private static double time;
public static void main(String[] args) {
ButtonGame game = new ButtonGame();
game.start();
}
public ButtonGame() {
//... All the code that was once in main...
frame.add(button1);
frame.setSize(150, 100);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void start() {
frame.setVisible(true);
}
Answering to your side questions:
a static method can only accept static global variables
You can put all your code in the constructor and use main to only run the program.
Constructor:
public ButtonGame() {
// All of your code goes here - except the static methods
}
You should also make all other methods non-static.
To run the program:
public static void main(String[] args) {
new ButtonGame();
}

Categories