I am working a JFrame calculator, I am not to familiar with so I was following a tutorial, and I've double checked it a couple times.
It's not working, its not throwing any errors or anything, it will compile and run. Just nothing pops up.
I am using Eclipse, and it is giving two warnings,
one about my constructor not being used in my main
that my class says this: The serializable class Gui does not declare a static final serialVersionUID field of type long.
I'm not sure why those would come up, but my code seems to be like the tutorial.
Thank you in advanced.
Ps. excuse the all commons, I just making sure I can looking back at it without having to refer back to the tutorial.
// This will make the visuals of the calc
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Gui extends JFrame implements ActionListener {
JPanel[] row = new JPanel[5];
JButton[] button = new JButton[19];
String[] buttonString = {"7", "8", "9", "+", // This is a string for the buttons that we will later apply to
"4", "5", "6", "-", // the the buttons with a loop, instead of 19 lines for each one
"1", "2", "3", "*",
".", "/", "C", "√",
"-/+", "=", "0"};
int[] dimW = {300, 45, 100, 90}; // An Array for the different widths of the display and buttons
int[] dimH = {35, 40}; // An array for the different heights of the display and buttons
Dimension displayDimension = new Dimension(dimW[0], dimH[0]); // The dims for the display using the first ints of the arrays
Dimension regularDimension = new Dimension(dimW[1], dimH[1]); // The
Dimension rColumnDimension = new Dimension(dimW[2], dimH[1]);
Dimension zeroButDimension = new Dimension(dimW[3], dimH[1]);
Boolean[] function = new Boolean[4]; // A boolean array to tell, which operator we are using
double[] temp = {0, 0}; // A temp array for the calc, might not use when using my stack calc
JTextArea display = new JTextArea(1, 20); // This is the display where the text will be displayed
Font font = new Font("Ariel", Font.BOLD, 14);
Gui() {
super("Gui");
setDesign();
setSize(380, 250); // Set the frame size
setResizable(false); // Makes so it can't be resized, can mess up layout if it true
setDefaultCloseOperation(EXIT_ON_CLOSE); // What happens when it closes
GridLayout grid = new GridLayout(5, 5); // Since we need a grid of 5 by 5 for the buttons this makes the grid
setLayout(grid);
for (int i = 0; i < 4; i++) // Sets values for the function array, might use might not with my clac
{
function[i] = false;
}
FlowLayout f1 = new FlowLayout(FlowLayout.CENTER); // This will only be use to layout row 1
FlowLayout f2 = new FlowLayout(FlowLayout.CENTER, 1, 1); // The ints are used to give a 1 pt gap vert and horiztal
for (int i = 0; i < 5; i++) // Intinalizing the Jpanel row's so we can use them
{
row[i] = new JPanel();
}
row[0].setLayout(f1); // Since we need the first row to have the special layout of f1 we just assign it
for (int i = 1; i < 5; i++) // Since we already set the first row "Row[0]" to f1, we have to start with row 2 or row[1] for i
{
row[i].setLayout(f2);
}
// After this all the rows have the correct layout, we can set up the buttons
// And set the same thing to each button with a loop
for (int i = 0; i < 19; i++) {
button[i] = new JButton(); // Creates a new button for each button in the array
button[i].setText(buttonString[1]); // Sets text on the button with the text from the list, in ButtonString
button[i].setFont(font); // Makes it nice looking with the fancy font we used in the font line
button[i].addActionListener(this); // This is what makes the button actually work
}
// Buttons done we can move to the display set up
display.setFont(font); // Set the fancy font to the display too
display.setEditable(false); // Makes it so no input from the keyboard, will have to change this on final product
display.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); // Makes it pop in right to left
// With the fonts and everything intinlized we can start to set the sizes for the compents
display.setPreferredSize(displayDimension); // Sets the size of the display
// We can use a loop for the regular buttons, i think all but zero
for (int i = 0; i < 14; i++) {
button[i].setPreferredSize(regularDimension); // Sets the size of the regular buttons
}
for (int i = 14; i < 18; i++) {
button[i].setPreferredSize(rColumnDimension); // Sets the size of the right column of buttons, the operrantors
}
button[18].setPreferredSize(zeroButDimension); // Sets the size of the zero button since its bigger
// Now that we got evrything sized up time to add everything to the panel
row[0].add(display); // Adds the display to row 1
add(row[0]); // Adds row 1 to the panel
for (int i = 0; i < 4; i++) {
row[1].add(button[i]); // all the number buttons to the row
}
row[1].add(button[14]); // adds the operator button to the row
add(row[1]); // adds the row
for (int i = 4; i < 8; i++) {
row[2].add(button[i]); // all the number buttons to the row
}
row[2].add(button[15]); // adds the operator button to the row
add(row[2]); // adds the row
for (int i = 8; i < 12; i++) {
row[3].add(button[i]); // all the number buttons to the row
}
row[3].add(button[16]); // adds the operator button to the row
add(row[3]); // adds the row
row[4].add(button[18]);
for (int i = 12; i < 14; i++) {
row[4].add(button[i]); // all the number buttons to the row
}
row[4].add(button[17]); // adds the operator button to the row
add(row[4]); // adds the row
setVisible(true); // Makes so you can see it
}
// Not sure what this is
public final void setDesign() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception e) {
}
}
// Will be use to make actionlistener work
public void actionPerformed(ActionEvent ae) {
}
public void main(String[] arguments) {
Gui c = new Gui();
}
}
You should really have this in your main method
public static void main(String[] args){
Gui c = new Gui();
c.setVisible(true);
}
Related
I am trying to make a chessboard, that will randomize the place of its pieces throughout the board.
Below is what I have so far
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
public class ChessBoard extends JFrame {
JLayeredPane layeredpane;
JPanel chessboard;
JButton[][] chessboardButtons;
Color black;
JLabel [][] chessboardLabels;
UIManager Ui;
ChessBoard() {
Dimension Size = new Dimension(600, 600);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
pack();
setResizable(true);
setLocationRelativeTo(null);
setVisible(true);
setSize(600, 600);
setTitle("Chess Board");
layeredpane = new JLayeredPane();
getContentPane().add(layeredpane);
layeredpane.setPreferredSize(Size);
chessboard = new JPanel();
layeredpane.add(chessboard, JLayeredPane.DEFAULT_LAYER);
chessboard.setLayout(new GridLayout(8, 8));
chessboard.setPreferredSize(Size);
chessboard.setBounds(0, 0, Size.width, Size.height);
Ui = new UIManager();
chessboardButtons = new JButton[8][8];
black = Color.black;
ButtonHandler handler = new ButtonHandler();
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
chessboardButtons[i][j] = new JButton();
chessboardButtons[i][j].setBorderPainted(false);
if ((i + j) % 2 != 0) {
chessboardButtons[i][j].setBackground(black);
chessboardButtons[i][j].setOpaque(true);
}
chessboard.add(chessboardButtons[i][j]);
chessboardButtons[i][j].addActionListener(handler);
}
}
chessboardLabels = new JLabel[8][8];
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
chessboardLabels[i][j] = new JLabel();
chessboardLabels[i][j].setFont(new Font("Ariel", Font.BOLD, 20));
chessboardLabels[i][j].setText("H");
chessboardLabels[i][j].setHorizontalAlignment(JLabel.CENTER);
chessboardLabels[i][j].setVerticalAlignment(JLabel.CENTER);
chessboardLabels[i][j].setOpaque(true);
chessboardButtons[i][j].add(chessboardLabels[i][j]);
if(chessboardButtons[i][j].getBackground() == Color.black) {
chessboardLabels[i][j].setBackground(Color.black);
chessboardLabels[i][j].setForeground(Color.white);
}
}
}
}
private class ButtonHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == chessboardButtons[0][0]) {
System.out.println("Button 0,0");
}
if (e.getSource() == chessboardButtons[0][1]) {
System.out.println("Button 0,1");
}
}
}
}
Right now I have the letter H filling all my buttons. What I need it to do is to:
limit the number of "H"'s there are on the board to be 32, 16 "White" and 16 "black" and
randomize the placement throughout the board.
Any ideas will be helpful!
I tried exactly this years ago, and I ran into several problems. One of the biggest is that dragging a piece from one square (JComponent) to another hard to do, because each JComponent has its bounds, and its Graphics clipping prevents you from drawing outside of these bounds. There are workarounds, like adding an Image to a higher level in the JLayeredPane, but this is still very hard to get right.
You really want to make you GUI a custom JComponent/JPanel that draws the whole board and can get mouse events across the whole board.
But before that, the right place to start is by creating a ChessModel that encapsulates the logic of the game. If you do that first and test it thoroughly, adding a GUI on top of that is easier than the other way around.
public class ChessModel {
char[][] board = new char[8][8];
...
public Point[] getPossibleMoves(Point pieceLocation) {
...
}
}
Create an ArrayList with 64 Integers numbered from 0 - 63
Use Collections.shuffle(...) to shuffle the numbers randomly
Take the first 16 values from the ArrayList and add white pieces to the board based on the integer value.
Take the next 16 values from the ArrayList and add the black pieces to the board.
First, I would start by decoupling parts of the system, this will provide you with a lot more flexibility.
For example, you want to decouple the "visual" from the "virtual". Components aren't managed in a "grid", instead, they are maintained in a list, so, you want some way you can quickly and easily ascertain the location of various components on the screen and how the relate to the "virtual" concept of the game or grid.
This is at the core concept of "model-view-controller", where the model represents a "grid" of "pieces" and the view is used to visually represent the model to the user. So you end up with a little bit of translation going on.
Now, you can do something like...
int row = (value / 8);
int col = (value % 8);
which, given a component index, will give you the row/col that they represent, but I'm also lazy 😉, so, I'm going to isolate the concept of a Piece...
public class Piece extends JPanel {
private JLabel label;
private Point cell;
public Piece(int index) {
setLayout(new GridBagLayout());
label = new JLabel(Integer.toString(index));
label.setForeground(Color.RED);
add(label);
setOpaque(false);
}
public void setCell(Point cell) {
this.cell = cell;
}
public Point getCell() {
return cell;
}
}
This does several things for me, first, it gives me a simple building block which can be used to represent a piece of data as well as maintain the "virtual" position of the piece, so I can easily look it up, independently.
It also divorces the piece from the board, which will make it easier to maintain (IMHO).
Next, I build the board...
setLayout(new GridLayout(8, 8));
int index = 0;
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
JPanel panel = new JPanel(new GridBagLayout()) {
#Override
public Dimension getPreferredSize() {
return new Dimension(50, 50);
}
};
// Indexed via x/y
cells[col][row] = panel;
if (index % 2 == 0) {
panel.setBackground(Color.WHITE);
} else {
panel.setBackground(Color.BLACK);
}
add(panel);
index++;
}
index++;
}
There's nothing really fancy here, it's just GridLayout with a bunch of color panels laid out on it.
The "fancy" part is the idea that, instead of using something complicated, like JLayeredPane, I'm simply going to add the Pieces directly to each cell.
Which leads us to the heart of the problem, how to randomise the position of the cells. Essentially, I'm going to create a list of numbers from 0 to 63 inclusive, randomise the list and then pop each number of off the list till I'm done.
Now, you could use an array, but filling an array with random numbers is not a simple task (especially if you want to guarantee uniqueness 😉)
// Fill a list of numbers
int totalCells = 8 * 8;
List<Integer> locations = new ArrayList<>(totalCells);
for (int value = 0; value < totalCells; value++) {
locations.add(value);
}
// Randomise the list
Collections.shuffle(locations);
// For al the white pieces, randomise their positions
for (index = 0; index < 16; index++) {
int value = locations.remove(0);
// Virtual coordinates
int row = (value / 8);
int col = (value % 8);
Point cell = new Point(col, row);
Piece piece = new Piece(index);
whitePieces[index] = piece;
piece.setCell(cell);
// Get the component offset by the value (physical)
JPanel cellPane = (JPanel) getComponent(value);
cellPane.add(piece);
}
// Now you can continue with the black pieces, just like above
// and because you've removed the "used" cell indexes from the
// list, you won't end up with duplicate positions
Now you're probably scratching your head over all this. But simply put, when you want to move a "piece", you simply remove it from it's current parent container, calculate the position ((row * 8) + col), get the new parent component (like above) and add it, simple.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Test extends JFrame {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JPanel[][] cells = new JPanel[8][8];
private Piece[] whitePieces = new Piece[16];
public TestPane() {
setLayout(new GridLayout(8, 8));
int index = 0;
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
JPanel panel = new JPanel(new GridBagLayout()) {
#Override
public Dimension getPreferredSize() {
return new Dimension(50, 50);
}
};
// Indexed via x/y
cells[col][row] = panel;
if (index % 2 == 0) {
panel.setBackground(Color.WHITE);
} else {
panel.setBackground(Color.BLACK);
}
add(panel);
index++;
}
index++;
}
int totalCells = 8 * 8;
List<Integer> locations = new ArrayList<>(totalCells);
for (int value = 0; value < totalCells; value++) {
locations.add(value);
}
Collections.shuffle(locations);
for (index = 0; index < 16; index++) {
int value = locations.remove(0);
int row = (value / 8);
int col = (value % 8);
Point cell = new Point(col, row);
Piece piece = new Piece(index);
whitePieces[index] = piece;
piece.setCell(cell);
JPanel cellPane = (JPanel) getComponent(value);
cellPane.add(piece);
}
}
}
public class Piece extends JPanel {
private JLabel label;
private Point cell;
public Piece(int index) {
setLayout(new GridBagLayout());
label = new JLabel(Integer.toString(index));
label.setForeground(Color.RED);
add(label);
setOpaque(false);
}
public void setCell(Point cell) {
this.cell = cell;
}
public Point getCell() {
return cell;
}
}
}
Oh, and just in case it's important, you can make use of component based drag-n-drop as well
How to make draggable components with ImageIcon
JLayeredPanel layout manager free moving objects
But, needs drives wants 😉
I want it so every time a button is pressed in my 4x4 grid, that it increments moves by 1 . This is creating a 4x4 layout of buttons. Each time any of those buttons are pressed, I want moves to increment. Basically I'm creating the memory game, where you flip cards over to match each other. I just have to keep count of the total amount of moves a player does to solve the puzzle.
private int moves = 0;
private GridPane makeGridPane(){
ConcentrationModel c = new ConcentrationModel();
GridPane grid = new GridPane();
ColumnConstraints col1 = new ColumnConstraints();
col1.setPercentWidth( 50 );
grid.getColumnConstraints().addAll(col1, col1, col1, col1);
RowConstraints row1 = new RowConstraints();
row1.setPercentHeight( 50 );
grid.getRowConstraints().addAll(row1, row1, row1, row1);
for(int row = 0; row < 4; row ++){
for(int col = 0; col < 4; col++){
Button btn = new Button();
ImageView image = new ImageView(c.getCards().get(0).getImage());
image.setFitWidth(WIDTH/4);
image.setFitHeight(HEIGHT/4);
btn.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
btn.setGraphic(image);
grid.add(btn, col, row);
}
}
return grid;
}
You can create a single event handler and reuse it for all the buttons. Since you probably want the buttons to do other things too, I would recommend adding this as an event handler, instead of using the convenience method setOnAction(...):
EventHandler<ActionEvent> incrementMovesHandler = e -> moves++ ;
for(int row = 0; row < 4; row ++){
for(int col = 0; col < 4; col++){
Button btn = new Button();
btn.addEventHandler(ActionEvent.ACTION, incrementMovesHandler);
// ...
}
}
This is actually pretty simple. All you have to do is add this bit of code just before your grid.add(...):
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
moves++;
}
});
Or, equivalently, the Java 8 version:
btn.setOnAction((ActionEvent e) -> {moves++;});
(I can't currently test this, but it should work. If not, lemme know and I'll try to fix it.)
If you're concerned about memory, Christian points out below that this creates a new instance of EventHandler for every button. While this may not be too terrible, it's probably a bad habit to get into. The best way to handle (no pun intended) this is by making an object before your for loop:
EventHandler<ActionEvent> eh = new EventHandler<>() {
#Override public void handle(ActionEvent event) {
moves++;
}
};
Then, for each of your buttons, instead of the top-most code, you'd simply write:
btn.setOnAction(eh);
That way, a single EventHandler is being created and used to handle all the events. You'll want to use this one if you need to create more than just a few buttons, both because it's faster (doesn't need to allocate memory for each object) and more memory-efficient (...it, uh, doesn't need to allocate the memory for each object). In this case, I think it's pretty trivial, but it's good to know nonetheless.
You need to implement the ActionListener interface in your class.
Then in the actionPerformed function, just increment the moves variable.
You just have to call btn.addActionListener(this); for each of the button that
you created.
public class Sample extends JFrame implements ActionListener {
public Sample ()
{
}
private GridPane makeGridPane()
{
ConcentrationModel c = new ConcentrationModel();
GridPane grid = new GridPane();
ColumnConstraints col1 = new ColumnConstraints();
col1.setPercentWidth( 50 );
grid.getColumnConstraints().addAll(col1, col1, col1, col1);
RowConstraints row1 = new RowConstraints();
row1.setPercentHeight( 50 );
grid.getRowConstraints().addAll(row1, row1, row1, row1);
for(int row = 0; row < 4; row ++){
for(int col = 0; col < 4; col++){
Button btn = new Button();
ImageView image = new ImageView(c.getCards().get(0).getImage());
image.setFitWidth(WIDTH/4);
image.setFitHeight(HEIGHT/4);
btn.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
btn.setGraphic(image);
btn.addActionListener(this);
grid.add(btn, col, row);
}
}
return grid;
}
public void actionPerformed(ActionEvent e)
{
moves++;
}
}
This is what I am having trouble with. I am making a Keno game out of a Crystals code I was given. So far, I have been able to choose 20 of the 80 and turn them red. However, I have the button set to when I press it it says "Game is a draw" and the window closes.
I am trying to put in a code where it will randomly draw 20 numbers without repeating, and then they turn yellow, however, if the CPU and the human match a number, it will turn green. I have no idea how to start this code or how to go about doing it. Here is what I have:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import java.lang.String;
public class Kenogame {
// constants
public static final int WIDTH = 4;
public static final int HEIGHT = 20;
public static final int INITIAL = 0;
public static final int RED = 1;
public static final int YELLOW = 3;
public static final int CHECKED = 4;
private int turn = RED; // to track which player should play next
private int[][] playerGrid; // to record each player's move
private int[][] shadowGrid; // to keep track of which atoms have been FOUND
private int[][] crystalGrid; // to extract a single crystal from playerGrid
private int row, column; // position of most recently added atom
private int lowX, lowY, highX, highY; // corner coordinates of current crystal
private int player1Score = 0;
private int player2Score = 0;
// GUI related fields
private JButton[] buttonArray;
// private JTextField scoreField1;
// private JTextField scoreField2;
// private JLabel labelRED; // Label "Red" on GUI
// private JLabel labelYELLOW; // Label "Yellow" on GUI
private JLabel labelTurn; // Label displays whose turn is next
private int numberToSelect = 20;
Kenogame() {
createGUIAndPlay();
}
private void createGUIAndPlay() {
final JFrame f = new JFrame();
// create the panels
JPanel topPanel = new JPanel(new BorderLayout());
JPanel buttonPanel = new JPanel(new GridLayout(WIDTH, HEIGHT));
JPanel labelPanel = new JPanel();
// represents the 2D grid of buttons on the GUI
buttonArray = new JButton[WIDTH * HEIGHT];
// stores the positions of atoms in both player's crystals
playerGrid = new int[WIDTH][HEIGHT];
// shadowGrid keeps track of which atoms have been found
shadowGrid = new int[WIDTH][HEIGHT];
// used to store a crystal to determine if it is a perfect crystal
crystalGrid = new int[WIDTH][HEIGHT];
JButton endGameButton = new JButton("Start Draw");
// labelRED = new JLabel("Red");
// scoreField1 = new JTextField(3);
// scoreField1.setEditable(false);
//labelYELLOW = new JLabel("Yellow");
labelTurn = new JLabel(Integer.toString(numberToSelect), Label.LEFT);
Dimension dim = labelTurn.getPreferredSize();
labelTurn.setPreferredSize(new Dimension(dim.width + 100, dim.height + 10));
// scoreField2 = new JTextField(3);
// scoreField2.setEditable(false);
// scoreField1.setText("0");
// scoreField2.setText("0");
// create the buttons on which players will make their moves
for (int i = 0; i < HEIGHT * WIDTH; i++) {
buttonArray[i] = new JButton(Integer.toString(i + 1));
buttonPanel.add(buttonArray[i]);
}
final Color buttColor = buttonArray[0].getBackground();
// add the action listener to the buttons
for (int i = 0; i < HEIGHT * WIDTH; i++) {
buttonArray[i].setActionCommand(Integer.toString(i));
buttonArray[i].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JButton button = (JButton) e.getSource();
if (button.getBackground() == Color.RED) {
button.setBackground(buttColor);
numberToSelect++;
} else {
if (numberToSelect > 0) {
button.setBackground(Color.RED);
numberToSelect--;
}
}
// button.setEnabled(false);
int buttonIndex = Integer.valueOf(button.getActionCommand());
row = buttonIndex / WIDTH;
column = buttonIndex % WIDTH;
// playMove();
labelTurn.setText(Integer.toString(numberToSelect));
// updateGUI();
}
});
}
endGameButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String s;
// Need to add "ball draw here" for Keno
// 20 random numbers between 1 and 80
// each time a "ball" matches one selected on the Keno ticket add to a counter
// at end look up payout for the number of matches corresponding to the counter
if (player1Score > player2Score)
s = "RED wins the game";
else if (player1Score < player2Score)
s = "YELLOW wins the game";
else
s = "Game is a draw";
JOptionPane.showMessageDialog(f, s, "Game Over", JOptionPane.PLAIN_MESSAGE);
System.exit(1);
}
});
labelPanel.add(endGameButton);
labelPanel.add(labelTurn);
topPanel.add(labelPanel, BorderLayout.NORTH);
topPanel.add(buttonPanel, BorderLayout.CENTER);
f.add(topPanel);
f.setSize(1000, 400);
f.setTitle("Keno");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
private void playMove() {
playerGrid[row][column] = turn;
if (turn == RED) {
turn = YELLOW;
} else {
turn = RED;
}
}
private void initialize() {
highX = highY = Integer.MIN_VALUE;
lowX = lowY = Integer.MAX_VALUE;
for (int row = 0; row < HEIGHT; row++)
for (int column = 0; column < WIDTH; column++) {
crystalGrid[row][column] = INITIAL;
}
}
public static void main(String[] args) {
new Keno();
}
}
// green for a match, yellow for a no-match.
I have 4 lines towards the bottom where I am supposed to insert the code. I would really appreciate it if someone could give me a hand on this.
To draw 20 non-repeating numbers, you can do the following:
put your 80 numbers in a collection.
shuffle the collection
the elements are now in random order and you can loop over the collection to get the first 20 elements.
If you give me more details on what you are stuck, I can provide further information.
the basic aim is to have a JPanel filled with 9 white squares in a 3x3 pattern; The squares are 150x150 blank white .jpg files. It must be this way since later on, the program will have to change the blank squares to one of a selection of simple images, and must be able to change any square at any time.
The problem, simply, is I'm getting a NullPointerException. I have to assume it's something to do with initialising the array as null but NetBeans(yes, NetBeans...) seems to get angry with me if I don't do that. Same if I try to declare the size of the array. (That would be... "ArrayType[arraysize] arrayName;", yes?"
Egh, I'm just guessing wildly.
Edit - NullPointerException fixed, but now the blank(white) images are simply not appearing in the frame. Code below edited to reflect its new state, more potentially relevant lines added.
Here be all relevant code:
JFrame controller = new JFrame("SmartHome Interface");
controller.setVisible(true);
controller.setSize(480,500);
controller.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//[...]
JPanel labelPanel = new JPanel();
//[...]
labelPanel.setBackground(Color.GREEN);
//[...]
ImageIcon blank = new ImageIcon("../Images/blank.jpg");
//[...]
controller.add(labelPanel);
//[...]
JLabel[] labels = new JLabel[9];
for (int i = 0; i <= 8; i++)
{
int xLowBound;
int xUpBound;
int yLowBound;
int yUpBound;
//Maths for positioning the labels correctly. Should be 150px in size with 10px gaps each.
xLowBound = (i % 3) * 160;
xUpBound = xLowBound + 150;
yLowBound = (i / 3) * 160;
yUpBound = yLowBound + 150;
labels[i] = new JLabel();
labels[i].setIcon(blank);
labels[i].setBounds(xLowBound, yLowBound, xUpBound, yUpBound);
labelPanel.add(labels[i]);
}
Also.....is the filepath for the ImageIcon correct?
The code itself being located in "src/smarthome" and the images in "src/Images"
And apologies if I broke any forum conventions/codes of conduct/etc. Newby here, tried to be careful not to but I may have forgotten something.
Your problem reduces to this:
JLabel[] labels = null;
for (int i = 0; i <= 8; i++) {
labels[i].setIcon(blank);
}
This code fragment will fail because labels == null. Therefore labels[i] == null.
Use this instead:
JLabel[] labels = new JLabel[9];
for (int i = 0; i <= 8; i++) {
labels[i] = new JLabel();
labels[i].setIcon(blank);
}
Your filepath for imageIcons is incorrect. You should use:
ImageIcon img = new ImageIcon(getClass().getResource("../Images/blank.jpg"));
if your code is in static method use this:
ImageIcon img = new ImageIcon(YourClass.class.getResource("../Images/blank.jpg"));
There is a good answer about loading image icons(thanks to nIcE cOw).
You should call setVisible() and setSize() after adding all components to the frame.
Add components to frame's content pane(frame.getContentPane()).
You always should place your GUI code in separate thread.
So, your code will be:
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
JFrame controller = new JFrame("SmartHome Interface");
controller.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel labelPanel = new JPanel();
labelPanel.setBackground(Color.GREEN);
// !!!
ImageIcon blank = new ImageIcon(YourClass.class
.getResource("../Images/blank.jpg"));
// !!!
controller.getContentPane().add(labelPanel);
JLabel[] labels = new JLabel[9];
for (int i = 0; i <= 8; i++)
{
int xLowBound;
int xUpBound;
int yLowBound;
int yUpBound;
xLowBound = (i % 3) * 160;
xUpBound = xLowBound + 150;
yLowBound = (i / 3) * 160;
yUpBound = yLowBound + 150;
labels[i] = new JLabel();
labels[i].setIcon(blank);
labels[i].setBounds(xLowBound, yLowBound, xUpBound,
yUpBound);
labelPanel.add(labels[i]);
}
// !!!
controller.setVisible(true);
controller.setSize(480, 500);
}
});
I am creating a matching game using Netbeans, but not the GUI editor (it sucks). So, basically, I created a new class, called Card, that extends the JButton class. Upon construction, the button's size is set to 100px by 100px and an icon is set. When I add the button to a JPanel in a GridBagLayout, it is not the intended size.
Here is some of my code:
JFRAME CLASS:
package matchinggame;
... imports ...
public class MatchingGameWindow extends JFrame {
Card[] cards = new Card[16]; //16 game cards
public MatchingGameWindow() {
...
//Create new game panel (for the cards)
JPanel gamePanel = new JPanel(new GridBagLayout());
//gamePanel.setSize(500,500); removed as it is not needed.
...
this.add(gamePanel, BorderLayout.CENTER);
//Create 16 card objects
cards = createCards();
//Create new grid bag constraints
GridBagConstraints gbc = new GridBagConstraints();
//Add the cards to the game panel
int i=0;
for (int y = 0; y < 4; y++) {
gbc.gridy = y;
for (int x = 0; x < 4; x++) {
gbc.gridx = x;
gamePanel.add(cards[i], gbc);
i++;
}
}
}
public final Card[] createCards() {
Card[] newCards = new Card[16];
//New choices array
ArrayList<Integer> choices = new ArrayList();
int[] choiceValues = {0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7};
//Add the initial choice values to the arraylist
for (int i=0; i < choiceValues.length; i++) {
choices.add(choiceValues[i]);
}
//Create 16 cards
for (int i=0; i < 16; i++) {
//Initial value of -1 for error checking
int iconIndex = -1;
//Loop until card is created
while (iconIndex == -1) {
//Get a random number from 0 - 7
Random r = new Random();
int rInt = r.nextInt(8);
//If the random number is one of the choices
if (choices.contains(rInt)) {
//the icon # will be the random number
iconIndex = rInt;
//Get rid of that choice (it is used up)
choices.remove(new Integer(rInt));
//Create a new Card in the Card[]
newCards[i] = new Card(i,iconIndex);
//If all the choices are gone
} else if (choices.isEmpty()){
iconIndex = -1; //done creating this card (breaks out of loop)
}
}
}
//Return the created cards
return newCards;
}
}
CARD CLASS:
package matchinggame;
import javax.swing.ImageIcon;
import javax.swing.JButton;
public class Card extends JButton {
final static ImageIcon defaultIcon = new ImageIcon("cardback.jpg");
ImageIcon secretIcon;
boolean isRevealed = false;
...
public Card(final int cardIndex, int secretIconIndex) {
//Size is 100px by 100px
setSize(100, 100);
//Default icon is card back image
setIcon(defaultIcon);
//Get the secret icon behind the back of the card
secretIcon = icons[secretIconIndex];
}
}
And using this code I get a result of this:
Any ideas as to what I am doing wrong here?
EDIT:
I overrided the getPreferredSize method like Hovercraft Full Of Eels said, and it worked!
I added this code in the Card class:
#Override
public Dimension getPreferredSize() {
return new Dimension(100,100);
}
and got my desired result:
Now I must be doing something wrong with the icons, as they are not showing up as they should.
You should not use setSize(...) in the class's constructor but rather override the class's getPreferredSize() method to return a Dimension(100, 100). And in fact you should have setSize(...) no-where in your program. Instead use decent layout managers, call pack() on the JFrame after adding all components and before setting it visible, and let the layout managers size the GUI appropriately.