I am trying to create a 2D array of buttons but the buttons I created are all in the same line. I can change lines in 2D arrays of int and float by using System.out.println(). What should I so for buttons? (line 67 to 75)
As well, I don't know how to create actionListeners for buttons in a loop. Should I create a method for acctionLisener? Do they share the same action listener?
import java.awt.*;
import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JInternalFrame;
public class Hanoi {
private JFrame frame;
JButton[][] buttons= new JButton[3][3];
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Hanoi window = new Hanoi();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Hanoi() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 901, 696);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panelone = new JPanel();
frame.getContentPane().add(panelone, BorderLayout.CENTER);
panelone.setBackground(Color.WHITE);
GridBagLayout gbl_panelone = new GridBagLayout();
gbl_panelone.columnWidths = new int[]{0};
gbl_panelone.rowHeights = new int[]{0};
gbl_panelone.columnWeights = new double[]{Double.MIN_VALUE};
gbl_panelone.rowWeights = new double[]{Double.MIN_VALUE};
panelone.setLayout(gbl_panelone);
JPanel paneltwo = new JPanel();
frame.getContentPane().add(paneltwo, BorderLayout.NORTH);
paneltwo.setBackground(Color.WHITE);
JLabel lblFunHanoiTower = new JLabel("Fun Hanoi Tower");
lblFunHanoiTower.setForeground(Color.BLACK);
lblFunHanoiTower.setBackground(SystemColor.activeCaption);
lblFunHanoiTower.setFont(new Font("Viner Hand ITC", Font.PLAIN, 36));
paneltwo.add(lblFunHanoiTower);
//JButton[][] buttons = new JButton[3][3];
for(int row = 0; row < buttons.length ; row++) {
for(int col= 0; col < buttons[0].length ;col++) {
buttons[row][col] = new JButton(String.valueOf((row+3)+(col*3)));
buttons[row][col].setFont(new Font("Tempus Sans ITC", Font.BOLD, 16));
buttons[row][col].setBackground(SystemColor.controlHighlight);
buttons[row][col].setSize(66, 66);
panelone.add(buttons[row][col]);
}
}
}
}
Rather than modify your code, I have provided an example of GridLayout.
GridLayout divides the area of the JPanel into a grid, i.e. a table of rows and columns, where each "cell" in the grid can contain one component and each cell has the same size. Here is a complete, compilable and runnable example.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class Hanoi implements Runnable {
#Override // java.lang.Runnable
public void run() {
showGui();
}
private JPanel createGridPanel() {
// Number of rows will be calculated depending on total number
// of components added but each row will contain no more than
// three components.
GridLayout gridLayout = new GridLayout(0, 3);
JPanel gridPanel = new JPanel(gridLayout);
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
int number = (row + 3) + (col * 3);
String text = String.valueOf(number);
JButton button = new JButton(text);
gridPanel.add(button);
}
}
return gridPanel;
}
private void showGui() {
JFrame frame = new JFrame("Hanoi");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(createGridPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
Hanoi instance = new Hanoi();
EventQueue.invokeLater(instance);
}
}
And here is a screen capture of the running application.
(Note that I am using JDK 12 on Windows 10.)
You can use a grid layout, i change your original code (as you can see below). I recommend to use some designer for the gui, it more easy and clean. Net beans have a nice grafic interface builder.
public class Hanoi {
private JFrame frame;
JButton[][] buttons= new JButton[3][3];
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Hanoi window = new Hanoi();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Hanoi() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 901, 696);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panelone = new JPanel();
panelone.setLayout(new GridLayout(3,3));
frame.getContentPane().add(panelone);
panelone.setBackground(Color.WHITE);
/*GridBagLayout gbl_panelone = new GridBagLayout();
gbl_panelone.columnWidths = new int[]{0};
gbl_panelone.rowHeights = new int[]{0};
gbl_panelone.columnWeights = new double[]{Double.MIN_VALUE};
gbl_panelone.rowWeights = new double[]{Double.MIN_VALUE};*/
// panelone.setLayout(gbl_panelone);
JPanel paneltwo = new JPanel();
frame.getContentPane().add(paneltwo, BorderLayout.NORTH);
paneltwo.setBackground(Color.WHITE);
JLabel lblFunHanoiTower = new JLabel("Fun Hanoi Tower");
lblFunHanoiTower.setForeground(Color.BLACK);
lblFunHanoiTower.setBackground(SystemColor.activeCaption);
lblFunHanoiTower.setFont(new Font("Viner Hand ITC", Font.PLAIN, 36));
paneltwo.add(lblFunHanoiTower);
//JButton[][] buttons = new JButton[3][3];
for(int row = 0; row < buttons.length ; row++) {
for(int col= 0; col < buttons[0].length ;col++) {
buttons[row][col] = new JButton(String.valueOf((row+3)+(col*3)));
buttons[row][col].setFont(new Font("Tempus Sans ITC", Font.BOLD, 16));
buttons[row][col].setBackground(SystemColor.controlHighlight);
buttons[row][col].setSize(66, 66);
panelone.add(buttons[row][col]);
}
}
}
}
Related
I'm having trouble with the functionality of dispose for my checkerboard (called Checkers) . For each checkerboard that I have, i want to be able to remove it by using dispose before calling another instance of my interface. Here is my progress so far:
Checkers class:
import java.awt.*;
import javax.swing.*;
import java.awt.Color.*;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.util.Random;
public class Checkers extends JFrame
{
Random random = new Random();
private final int ROWS = 2;
private final int COLS = 5;
private final int GAP = 2;
private final int NUM = ROWS * COLS;
private int i;
public int score;
private JPanel pane = new JPanel(new GridLayout(ROWS,COLS, GAP,GAP));
private JPanel pane2 = new JPanel();
private JPanel pane3 = new JPanel();
private JButton btn1 = new JButton("Play A Game");
private JButton btn2 = new JButton("Exit");
private JButton btn3 = new JButton("Easy");
private JButton btn4 = new JButton("Intermediate");
private JButton btn5 = new JButton("Difficult");
private JLabel lbl1 = new JLabel ("score: " + score);
private JLabel gameLost = new JLabel("You lose! You got: " + score + " points");
private MyPanel [] panel = new MyPanel[NUM];
private Color col1 = Color.RED;
private Color col2 = Color.WHITE;
private Color col3 = Color.GREEN;
private Color tempColor;
public Checkers()
{
super("Checkers");
setSize(600,600);
setVisible(true);
setBackground(Color.BLACK);
setBoard();
}
public void setBoard()
// roates colors on the checkbaord
{
for (int i = 0; i < panel.length; i++) {
panel[i] = new MyPanel(this);
pane.add(panel[i]);
if (i % COLS == 0) {
tempColor = col1;
col1 = col2;
col2 = tempColor;}
if (i % 2 == 0) {
panel[i].setBackground(col1);}
else {
panel[i].setBackground(col2);}
}
//pane background colour and the size of this pane.
pane.setBackground(Color.BLACK);
pane.setPreferredSize(new Dimension(300,300));
//pane background colour and size of this pane.
pane2.setBackground(Color.white);
pane2.setPreferredSize(new Dimension(300,300));
//directions on the board where these panes appear.
add(pane, BorderLayout.WEST);
add(pane2, BorderLayout.EAST);
pane2.add(lbl1);
pane2.setLayout(new BoxLayout(pane2, BoxLayout.PAGE_AXIS));
}
public void incrementScore(){
score++;
lbl1.setText("Score: " + Integer.toString(score));
}
//This is the method for resetting via dispose - only works once.
public void restartBoard(){
this.dispose();
new Checkers();
}
}
And also the MyPanel class
public class MyPanel extends JPanel implements MouseListener {
private final Checkers checkers;
public MyPanel(Checkers checkers) {
this.checkers = checkers;
addMouseListener(this);
}
#Override
public void mouseClicked(MouseEvent e) {
setBackground(Color.BLACK);
checkers.incrementScore();
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
EXPECTED RESULT - What i'd like to do is be able to close the current version of interface by using the dispose method, and then opening a new instance of said interface.
ACTUAL RESULT - When opening an interface, then calling dispose method, it will work once. once you try to remove the 2nd interface when creating a 3rd interface, dispose will not function, and I cant see why this is.
Any help is welcome.
For what it's worth, this is an MCVE that shows your likely problem:
import java.awt.Dimension;
import javax.swing.*;
public class CheckersTest {
private static void createAndShowGui() {
Checkers checkers = new Checkers();
JButton restartButton = new JButton("Restart");
restartButton.addActionListener(event -> checkers.restartBoard());
JPanel restartPanel = new JPanel();
restartPanel.setPreferredSize(new Dimension(400, 400));
restartPanel.add(restartButton);
JFrame frame = new JFrame("Checkers Test");
frame.add(restartPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class Checkers extends JFrame {
public Checkers() {
setPreferredSize(new Dimension(200, 200));
pack();
setLocationByPlatform(true);
setVisible(true);
}
public void restartBoard(){
this.dispose();
new Checkers();
}
}
The restart button refers to the original Checkers instance and so will not close any new instances created. The solution would be to get the restart method out of Checkers, create a Checkers field, and make sure the restart method refers to the visible Checkers instance:
import java.awt.Dimension;
import javax.swing.*;
public class CheckersTest {
private static Checkers checkers = new Checkers(); // holds reference
private static void restartBoard() {
if (checkers != null) {
checkers.dispose();
checkers = new Checkers(); // assign to reference field
}
}
private static void createAndShowGui() {
// !! Checkers checkers = new Checkers();
JButton restartButton = new JButton("Restart");
// !! restartButton.addActionListener(event -> checkers.restartBoard());
restartButton.addActionListener(event -> restartBoard());
JPanel restartPanel = new JPanel();
restartPanel.setPreferredSize(new Dimension(400, 400));
restartPanel.add(restartButton);
JFrame frame = new JFrame("Checkers Test");
frame.add(restartPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class Checkers extends JFrame {
public Checkers() {
setPreferredSize(new Dimension(200, 200));
pack();
setLocationByPlatform(true);
setVisible(true);
}
}
Notes:
Again a much better design is not to swap JFrames but rather JPanel views
Note that the MCVE has code that reproduces the problem but avoids code not related to the problem. So it shows the restartBoard method, it compiles, but avoids game code since this is not relevant to the problem.
I have created 2 classes that are working together to show pictures by clicking different buttons. In my EventEvent class I tried to make it so that when you press the "Picture 1" button, the variable ImageIcon xpic gets the value of ImageIcon vpic (which holds an image), after xpic has the same value as vpic my frame is supposed to somehow refresh so that xpic's new value applies and gets then shows the picture.
Why doesn't my image show up even though the button press repaints the JPanel the image is in?
Main class:
import java.awt.*;
import javax.swing.*;
public class EventMain extends JFrame{
EventEvent obje = new EventEvent(this);
// Build Buttons
JButton picB1;
JButton picB2;
JButton picB3;
JButton picB4;
JButton picB5;
//Build Panels
JPanel row0;
//Build Pictures
ImageIcon xpic;
ImageIcon vpic;
public EventMain(){
super("Buttons");
setLookAndFeel();
setSize(470, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GridLayout layout1 = new GridLayout(3,4);
setLayout(layout1);
picB1 = new JButton("Picture 1");
picB2 = new JButton("Picture 2");
picB3 = new JButton("Picture 3");
picB4 = new JButton("Picture 4");
picB5 = new JButton("Picture 5");
vpic = new ImageIcon(getClass().getResource("Images/vanessa.png"));
// Set up Row 0
row0 = new JPanel();
JLabel statement = new JLabel("Choose a picture: ", JLabel.LEFT);
JLabel picture = new JLabel(xpic);
// Set up Row 1
JPanel row1 = new JPanel();
// Set up Row 2
JPanel row2 = new JPanel();
//Listeners
picB1.addActionListener(obje);
FlowLayout grid0 = new FlowLayout (FlowLayout.CENTER);
row0.setLayout(grid0);
row0.add(statement);
row0.add(picture);
add(row0);
FlowLayout grid1 = new FlowLayout(FlowLayout.CENTER);
row1.setLayout(grid1);
row1.add(picB1);
row1.add(picB2);
add(row1);
FlowLayout grid2 = new FlowLayout(FlowLayout.CENTER);
row2.setLayout(grid2);
row2.add(picB3);
row2.add(picB4);
row2.add(picB5);
add(row2);
setVisible(true);
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.NimbusLookAndFeel");
} catch (Exception exc) {
}
}
public static void main(String[] args) {
EventMain con = new EventMain();
}
}
Class containing events:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class EventEvent implements ActionListener {
EventMain gui;
public EventEvent(EventMain in){
gui = in;
}
public void actionPerformed(ActionEvent event) {
String command = event.getActionCommand();
if (command.equals("Picture 1")){
gui.xpic = gui.vpic;
gui.row0.repaint();
}
}
}
You're confusing variables with objects. Just because you change the object associated with the xpic variable, don't assume that this will change the object (the Icon) held by the JLabel. There is no magic in Java, and changing the object that a variable refers to will have no effect on the prior object.
In other words, this:
gui.xpic = gui.vpic;
gui.row0.repaint();
will have no effect on the icon that the picture JLabel is displaying
To swap icons, you must call setIcon(...) on the JLabel. Period. You will need to make the picture JLabel a field, not a local variable, and give your GUI class a public method that allows outside classes to change the state of the JLabel's icon.
Also, you should not manipulate object fields directly. Instead give your gui public methods that your event object can call.
Edit
For example:
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class MyGui extends JPanel {
public static final String IMAGE_PATH = "https://duke.kenai.com/cards/.Midsize/CardFaces.png.png";
private static final int ROWS = 4;
private static final int COLS = 13;
private BufferedImage largeImg;
private List<ImageIcon> iconList = new ArrayList<>();
private JLabel pictureLabel = new JLabel();
private JButton swapPictureBtn = new JButton(new SwapPictureAction(this, "Swap Picture"));
private int iconIndex = 0;
public MyGui() throws IOException {
add(pictureLabel);
add(swapPictureBtn);
URL imgUrl = new URL(IMAGE_PATH);
largeImg = ImageIO.read(imgUrl);
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
int x = (j * largeImg.getWidth()) / COLS;
int y = (i * largeImg.getHeight()) / ROWS;
int w = largeImg.getWidth() / COLS;
int h = largeImg.getHeight() / ROWS;
iconList.add(new ImageIcon(largeImg.getSubimage(x, y, w, h)));
}
}
pictureLabel.setIcon(iconList.get(iconIndex));
}
public void swapPicture() {
iconIndex++;
iconIndex %= iconList.size();
pictureLabel.setIcon(iconList.get(iconIndex));
}
private static void createAndShowGui() {
MyGui mainPanel;
try {
mainPanel = new MyGui();
JFrame frame = new JFrame("MyGui");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class SwapPictureAction extends AbstractAction {
private MyGui myGui;
public SwapPictureAction(MyGui myGui, String name) {
super(name);
this.myGui = myGui;
}
#Override
public void actionPerformed(ActionEvent e) {
myGui.swapPicture();
}
}
See the createAction() method below and how it creates an AbstractAction. See also the tutorial related to using actions with buttons. http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html
import javax.swing.*;
import javax.swing.plaf.nimbus.NimbusLookAndFeel;
import java.awt.*;
import java.awt.event.ActionEvent;
public class EventMain {
private static final ImageIcon PICTURE_1 = new ImageIcon(EventMain.class.getResource("images/v1.png"));
private static final ImageIcon PICTURE_2 = new ImageIcon(EventMain.class.getResource("images/v2.png"));
private JFrame frame;
EventMain create() {
setLookAndFeel();
frame = createFrame();
frame.getContentPane().add(createContent());
return this;
}
void show() {
frame.setSize(470, 300);
frame.setVisible(true);
}
private JFrame createFrame() {
JFrame frame = new JFrame("Buttons");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
return frame;
}
private Component createContent() {
final JLabel picture = new JLabel();
JButton picB1 = new JButton(createAction("Picture 1", picture, PICTURE_1));
JButton picB2 = new JButton(createAction("Picture 2", picture, PICTURE_2));
JButton picB3 = new JButton(createAction("Picture 3", picture, PICTURE_1));
JButton picB4 = new JButton(createAction("Picture 4", picture, PICTURE_2));
JButton picB5 = new JButton(createAction("Picture 5", picture, PICTURE_1));
JLabel statement = new JLabel("Choose a picture: ", JLabel.LEFT);
// Create rows 1, 2, 3
JPanel panel = new JPanel(new GridLayout(3, 4));
panel.add(createRow(statement, picture));
panel.add(createRow(picB1, picB2));
panel.add(createRow(picB3, picB4, picB5));
return panel;
}
/**
* Create an action for the button. http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html
*/
private Action createAction(String label, final JLabel picture, final Icon icon) {
AbstractAction action = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
picture.setIcon(icon);
}
};
action.putValue(Action.NAME, label);
return action;
}
private Component createRow(Component... componentsToAdd) {
JPanel row = new JPanel(new FlowLayout(FlowLayout.CENTER));
for (Component component : componentsToAdd) {
row.add(component);
}
return row;
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel(new NimbusLookAndFeel());
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new EventMain().create().show();
}
});
}
}
Currently displays a GUI with an 8x8 grid of randomized colored buttons. The newButton is to reset the score display to 0 and reset the grid with a fresh like it does on startup after being clicked. I haven't been able to find many solutions other than that it's to do with the way Java displays it's buttons and the way layering works. Here are the 2 classes I'm using.
import javax.swing.JFrame;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.JPanel;
import java.awt.Color;
public class ShinyButtonsApp extends JFrame implements ActionListener {
private static byte ROWS = 8;
public int useThis;
ShinyButtons shiny = new ShinyButtons();
public static ImageIcon[] icons = {new ImageIcon("RedButton.png"),
new ImageIcon("OrangeButton.png"),
new ImageIcon("YellowButton.png"),
new ImageIcon("GreenButton.png"),
new ImageIcon("BlueButton.png"),
new ImageIcon("LightGrayButton.png"),
new ImageIcon("DarkGrayButton.png")};
public ShinyButtonsApp(String title) {
super(title); // Set title of window
setDefaultCloseOperation(EXIT_ON_CLOSE); // allow window to close
setSize(578, 634); // Set size of window
setResizable(false);
getContentPane().setLayout(null);
JLabel aLabel = new JLabel("Score: ");
aLabel.setLocation(10, 570);
aLabel.setSize(80,30);
getContentPane().add(aLabel);
JTextField scoreField = new JTextField();
scoreField.setText(Integer.toString(shiny.score));
scoreField.setEditable(false);
scoreField.setHorizontalAlignment(JTextField.RIGHT);
scoreField.setLocation(60, 570);
scoreField.setSize(120,30);
scoreField.setBackground(Color.WHITE);
getContentPane().add(scoreField);
JButton newButton = new JButton("New Game");
newButton.addActionListener(this);
newButton.setLocation(348,570);
newButton.setSize(110,30);
getContentPane().add(newButton);
JButton quitButton = new JButton("Quit");
quitButton.setLocation(468,570);
quitButton.setSize(80,30);
getContentPane().add(quitButton);
resetButtons2();
}
public void actionPerformed(ActionEvent e) {
shiny.score = 0;
shiny.resetButtons();
resetButtons2();
}
public void resetButtons2() {
for (int r=0; r<ROWS; r++) {
for (int c=0; c<ROWS; c++) {
ImageIcon image1 = icons[(int)shiny.getButton(r,c)];
JButton button = new JButton(image1);
button.setLocation(10+(69*r),10+(69*c));
button.setSize(69,69);
button.setBorder(BorderFactory.createLineBorder(Color.GRAY,1));
getContentPane().add(button);
}
}
}
public static void main(String[] args) {
ShinyButtonsApp frame;
frame = new ShinyButtonsApp("Shiny Buttons"); // Create window
frame.setVisible(true); // Show window
}
}
and
import javax.swing.JFrame;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.JPanel;
import java.awt.Color;
public class ShinyButtons extends JPanel{
public static byte RED = 0;
public static byte ORANGE = 1;
public static byte YELLOW = 2;
public static byte GREEN = 3;
public static byte BLUE = 4;
public static byte LIGHT_GRAY = 5;
public static byte DARK_GRAY = 6;
public static byte ROWS = 8;
public byte[][] buttonTable;
public int score = 0;
public ShinyButtons() {
buttonTable = new byte[ROWS][ROWS];
resetButtons();
}
public void resetButtons() {
for (int r=0; r<ROWS; r++)
for (int c=0; c<ROWS; c++)
buttonTable[r][c] = (byte)(Math.random()*7);
}
public byte getButton(int r, int c) { return buttonTable[r][c]; }
public int getScore() { return score; }
}
Building on to what this answer points out (using layout managers instead of setting size, as you should be doing) you could reset the the images just by looping through the components (JLabels) of the JPanel and changing their icons.
This particular example uses JLabels with MouseListeners but it could easily be switched to JButtons with ActionListeners
newGame.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
reset(iconPanel, icons); <--- call reset method from below
score = 0;
scoreField.setText(String.valueOf(score));
}
});
....
private void reset(JPanel panel, ImageIcon[] icons) {
Component[] comps = panel.getComponents();
Random random = new Random();
for(Component c : comps) {
if (c instanceof JLabel) {
JLabel button = (JLabel)c;
int index = random.nextInt(icons.length);
button.setIcon(icons[index]);
}
}
}
Here's the complete running code. You just need to replace the image paths.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
public class CircleImages {
private int score = 0;
private JTextField scoreField = new JTextField(10);
public CircleImages() {
scoreField.setEditable(false);
final ImageIcon[] icons = createImageIcons();
final JPanel iconPanel = createPanel(icons, 8);
JPanel bottomLeftPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
bottomLeftPanel.add(new JLabel("Score: "));
bottomLeftPanel.add(scoreField);
JPanel bottomRightPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
JButton newGame = new JButton("New Game");
bottomRightPanel.add(newGame);
JButton quit = new JButton("Quit");
bottomRightPanel.add(quit);
JPanel bottomPanel = new JPanel(new GridLayout(1, 2));
bottomPanel.add(bottomLeftPanel);
bottomPanel.add(bottomRightPanel);
newGame.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
reset(iconPanel, icons);
score = 0;
scoreField.setText(String.valueOf(score));
}
});
JFrame frame = new JFrame();
frame.add(iconPanel);
frame.add(bottomPanel, BorderLayout.PAGE_END);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void reset(JPanel panel, ImageIcon[] icons) {
Component[] comps = panel.getComponents();
Random random = new Random();
for(Component c : comps) {
if (c instanceof JLabel) {
JLabel button = (JLabel)c;
int index = random.nextInt(icons.length);
button.setIcon(icons[index]);
}
}
}
private JPanel createPanel(ImageIcon[] icons, int gridSize) {
Random random = new Random();
JPanel panel = new JPanel(new GridLayout(gridSize, gridSize));
for (int i = 0; i < gridSize * gridSize; i++) {
int index = random.nextInt(icons.length);
JLabel label = new JLabel(icons[index]);
label.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e) {
score += 1;
scoreField.setText(String.valueOf(score));
}
});
label.setBorder(new LineBorder(Color.GRAY, 2));
panel.add(label);
}
return panel;
}
private ImageIcon[] createImageIcons() {
String[] files = {"blackcircle.png",
"bluecircle.png",
"greencircle.png",
"greycircle.png",
"orangecircle.png",
"redcircle.png",
"yellowcircle.png"
};
ImageIcon[] icons = new ImageIcon[files.length];
for (int i = 0; i < files.length; i++) {
icons[i] = new ImageIcon(getClass().getResource("/circles/" + files[i]));
}
return icons;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new CircleImages();
}
});
}
}
You are creating a new set of buttons in resetButtons2() and placing them on top (or rather under) of the already existing set of buttons in the same locations. You should create the set of buttons once and only update their icons upon reset.
You should do a number of things:
Use a proper layout manager, e.g., GridLayout
Create the 8x8 grid of buttons only once and replace their icons when needed
Call invalidate/repaint to refresh the content pane
And for a JFrame you don't need getContentPane().add(...), you can directly do add(...)
Two things.
First, make sure you remove the existing buttons first. Alternatively, you could simply update the state of the buttons. This would require you to create an array or List of buttons first, which your reset method would then iterate over and update their properties as required.
Second, make use of an appropriate layout manager. A null layout ias a very bad idea. You do not control the font metrics of the underlying platform and this will change how your buttons look on different systems, making your UI less dynamic then it should be
I have a simple app, showing picture made of tiled images(named u1, u2,...,u16.jpg). Now I'd like to add some Events to it, so that I can show these images only when proper button is clicked. I've tried doing it on my own, but it's not working. Where am I doing something wrong?
Original code :
import java.awt.GridLayout;
import javax.swing.*;
import javax.swing.border.BevelBorder;
public class Tiles_2 {
public static void main(String[] args) {
final JFrame f = new JFrame("Usmiech");
JPanel panel = new JPanel(new GridLayout(4, 4, 3, 3));
JLabel l = new JLabel();
for (int i = 1; i < 17; i++) {
String path = "u"+ i+".jpg";
l = new JLabel(new ImageIcon(path));
l.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
panel.add(l);
}
f.setContentPane(panel);
f.setSize(300, 300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
New code :
import java.awt.GridLayout;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.awt.event.*;
public class Zad_8_1 implements ActionListener {
public void actionPerformed(ActionEvent e) {
JButton b = (JButton)(e.getSource());
String i = b.getText();
b = new JButton(new ImageIcon("u"+i+".jpg"));
}
public static void main(String[] args) {
final JFrame f = new JFrame("Smile");
JPanel panel = new JPanel(new GridLayout(4, 4, 3, 3));
JButton l = null;
for (int i = 1; i < 17; i++) {
String path = "u"+ i+".jpg";
l = new JButton(""+i);
l.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
l.setSize(53,53);
panel.add(l);
}
f.setContentPane(panel);
f.setSize(300, 300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
This should work like this :
this http://img535.imageshack.us/img535/3129/lab8a.jpg
Try registering the buttons to listen for the event like this:
for (int i = 1; i < 17; i++) {
String path = "u"+ i+".jpg";
l = new JButton(""+i);
l.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
l.setSize(53,53);
l.addActionListener(this);
panel.add(l);
}
You need to have constructor to add event listeners.
import java.awt.GridLayout;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.awt.event.*;
import java.awt.*;
public class Demo {
public static void main(String args[]) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
render("Window");
}
});
}
public static void render(String s){
JFrame f = new JFrame("Smile");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Pane pan = new Pane();
f.add(pan);
f.setSize(300,300);
f.setVisible(true);
}
}
class Pane extends JPanel implements ActionListener {
Pane(){
setLayout(new GridLayout(4, 4, 3, 3));
JButton l = null;
for (int i = 1; i < 17; i++) {
l = new JButton(""+i);
l.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
l.addActionListener(this);
l.setSize(53,53);
add(l);
}
}
public void actionPerformed(ActionEvent e) {
JButton b = (JButton)(e.getSource());
String i = b.getText();
b.setIcon(new ImageIcon("u"+i+".jpg"));
}
}
b = new JButton(new ImageIcon("u"+i+".jpg"));
Creating a new button doesn't do anything the button just sits there in memory as it hasn't been added to the GUI.
The simple solution is to just reset the icon:
b.setIcon( new ImageIcon(...) );
Instead of reassigning b a new instance of JButton, you should simply reset the icon:
b.setIcon(new ImageIcon("u"+i+".jpg"));
(take a look at pass by reference/pass by value concepts in Java, well explained here)
on top of that, you need to follow Vincent's advice and actually register with all of the buttons as an ActionListener
l.addActionListener(this);
how can i open a new applet window from a applet itself?
To open a new Java window (JFrame) from an applet, see the following extract from the Java tutorial:
//1. Create the frame.
JFrame frame = new JFrame("FrameDemo");
//2. Optional: What happens when the frame closes?
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//3. Create components and put them in the frame.
//...create emptyLabel...
frame.getContentPane().add(emptyLabel, BorderLayout.CENTER);
//4. Size the frame.
frame.pack();
//5. Show it.
frame.setVisible(true);
To open a new browser window which also contains an applet showDocument(URL, "_blank"):
URL url = new URL(getCodeBase().getProtocol(),
getCodeBase().getHost(),
getCodeBase().getPort(),
"/next.html");
getAppletContext().showDocument(url, "_blank");
package com.ashok.test;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
public class ChessBoardWithColumnsAndRows {
private final JPanel gui = new JPanel(new BorderLayout(3, 3));
private JButton[][] chessBoardSquares = new JButton[8][8];
private JPanel chessBoard;
private final JLabel message = new JLabel(
"Chess Champ is ready to play!");
private static final String COLS = "ABCDEFGH";
ChessBoardWithColumnsAndRows() {
initializeGui();
}
public final void initializeGui() {
// set up the main GUI
gui.setBorder(new EmptyBorder(5, 5, 5, 5));
JToolBar tools = new JToolBar();
tools.setFloatable(false);
gui.add(tools, BorderLayout.PAGE_START);
tools.add(new JButton("New")); // TODO - add functionality!
tools.add(new JButton("Save")); // TODO - add functionality!
tools.add(new JButton("Restore")); // TODO - add functionality!
tools.addSeparator();
tools.add(new JButton("Resign")); // TODO - add functionality!
tools.addSeparator();
tools.add(message);
gui.add(new JLabel("?"), BorderLayout.LINE_START);
chessBoard = new JPanel(new GridLayout(0, 9));
chessBoard.setBorder(new LineBorder(Color.BLACK));
gui.add(chessBoard);
// create the chess board squares
Insets buttonMargin = new Insets(0,0,0,0);
for (int ii = 0; ii < chessBoardSquares.length; ii++) {
for (int jj = 0; jj < chessBoardSquares[ii].length; jj++) {
JButton b = new JButton();
b.setMargin(buttonMargin);
// our chess pieces are 64x64 px in size, so we'll
// 'fill this in' using a transparent icon..
ImageIcon icon = new ImageIcon(
new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB));
b.setIcon(icon);
if ((jj % 2 == 1 && ii % 2 == 1)
//) {
|| (jj % 2 == 0 && ii % 2 == 0)) {
b.setBackground(Color.WHITE);
} else {
b.setBackground(Color.BLACK);
}
chessBoardSquares[jj][ii] = b;
}
}
//fill the chess board
chessBoard.add(new JLabel(""));
// fill the top row
for (int ii = 0; ii < 8; ii++) {
chessBoard.add(
new JLabel(COLS.substring(ii, ii + 1),
SwingConstants.CENTER));
}
// fill the black non-pawn piece row
for (int ii = 0; ii < 8; ii++) {
for (int jj = 0; jj < 8; jj++) {
switch (jj) {
case 0:
chessBoard.add(new JLabel("" + (ii + 1),
SwingConstants.CENTER));
default:
chessBoard.add(chessBoardSquares[jj][ii]);
}
}
}
}
public final JComponent getChessBoard() {
return chessBoard;
}
public final JComponent getGui() {
return gui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
ChessBoardWithColumnsAndRows cb =
new ChessBoardWithColumnsAndRows();
JFrame f = new JFrame("ChessChamp");
f.add(cb.getGui());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
// ensures the minimum size is enforced.
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}