Reputation: 13
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);
}
}```
Upvotes: 1
Views: 62
Reputation: 51567
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
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.
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;
}
}
}
Upvotes: 2
Reputation: 324167
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:
Event Dispatch Thread (EDT)
. frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
, so it will work for all screen sizes.Upvotes: 2