I am trying to accomplish the above functionality, and am having little success.
I am using GridLayout with 2 columns and 2 rows to show the user a puzzle-like game, where there are 4 (200x200 pixel) JPanels (3 colored, 1 default bgColor) which fill the whole contentPane. Clicking on a colored panel resolves in an assessment if the panel is next to the gray panel. If so, they should swap. I have accomplished every step to the last one, where they swap. Here's the code:
public class MainClass extends JFrame {
//Generated
private static final long serialVersionUID = 4710628273679698058L;
private SpecialPanel redPanel;
private SpecialPanel greenPanel;
private SpecialPanel yellowPanel;
private SpecialPanel grayPanel;
public MainClass() {
super("Puzzle");
initPanels();
setSize(410, 410);
setLayout(new GridLayout(2, 2));
this.add(redPanel);
this.add(greenPanel);
this.add(grayPanel);
this.add(yellowPanel);
}
private void initPanels() {
redPanel = new SpecialPanel();
greenPanel = new SpecialPanel();
yellowPanel = new SpecialPanel();
grayPanel = new SpecialPanel();
grayPanel.setGreyPanel(true);
redPanel.setBackground(Color.RED);
greenPanel.setBackground(Color.GREEN);
yellowPanel.setBackground(Color.YELLOW);
grayPanel.setBackground(this.getBackground());
redPanel.setSize(200, 200);
greenPanel.setSize(200, 200);
yellowPanel.setSize(200, 200);
grayPanel.setSize(200, 200);
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
super.mouseClicked(arg0);
SpecialPanel sp = (SpecialPanel) arg0.getComponent();
if (sp.getIsGray()) {
//Do nothing
} else if (checkIfNeighbourToGray(sp, grayPanel)) {
//Swap them
System.out.println("Swap notification");
swap(sp, grayPanel);
//Update UI
} else {
//Again, do nothing for the clicked panel is diagonal to the gray panel
}
}
private boolean checkIfNeighbourToGray(SpecialPanel sp, SpecialPanel grayPanel) {
Point startPointSp = sp.getLocation();
double x = startPointSp.getX();
double y = startPointSp.getY();
double width = sp.getWidth();
double height = sp.getHeight();
Point grayPoint = grayPanel.getLocation();
double xG = grayPanel.getX();
double yG = grayPanel.getY();
double widthG = grayPanel.getWidth();
double heightG = grayPanel.getHeight();
//Gray panel is RIGHT of clicked one
if (x + width == xG && y + height == yG + heightG) {
return true;
}
//Gray panel is LEFT of clicked one
else if (x - width == xG && y + height == yG + heightG) {
return true;
}
//Gray panel is ABOVE of clicked one
else if (x == xG && x + width == xG + widthG) {
return true;
}
//Gray panel is UNDER of clicked one
else if (xG == x && yG + widthG == x + width) {
return true;
}
return false;
}
private void swap(SpecialPanel sp, SpecialPanel grayPanel) {
//Swap logic
}
};
redPanel.addMouseListener(ma);
greenPanel.addMouseListener(ma);
yellowPanel.addMouseListener(ma);
grayPanel.addMouseListener(ma);
}
public static void main(String[] args) {
MainClass mc = new MainClass();
mc.setVisible(true);
}
}
The class SpecialPanel is extending JPanel with just a new Boolean property IsGrayPanel initially set to false + getter and setter.
NOTE: This is being done in a "I have basic Swing skills" manner, although I have learned more in the meantime about java swing, I was just limited back then with basic swing functionality, so I should keep it that way.
Therefore my question is how to properly swap the two panels which are next to each other, including UI update?
there wouldn't need to move with JPanels into container, otherwise you woud need to use bunch of quite useless code to remove two JPanels from from contianer with two indexes then to layout back to container with swaping indexes,
(if is about Color only) only to swap setBackground(Color.Xxx) betweens two JPanels
puzzle-like game is about Images, puzzle or minesweaper is about, (not clear from your ...)
put Images as Icon/ImageIcons to JLabel instead of JPanel and on Mouse Events to switch (setIcon()) with Icons betweens JLabels, load Icons to local variables
(easiest of ways) JToggleButton and Icon, there is logic similair as for JLabel, but about showing Icon on setPressedIcon()
I'm not sure if this works. It looks too easy.
JPanel tempPanel = sp;
sp = grayPanel;
grayPanel = tempPanel;
this.setVisible(false);
this.setVisible(true);
this.validate(); //try this first
this.repaint(); // if it doesnt work, add this function.
Related
Hi I'm working on a program that requires to a take a random number of dice 1-6
I want to show a picture for any number show .
Here I initialized the pictures with jlable
JLabel diceNumber;
Random r = new Random();
int roll;
ImageIcon dicePic1 = new ImageIcon("dice1_.png");
ImageIcon dicePic2 = new ImageIcon("dice2.png");
ImageIcon dicePic3 = new ImageIcon("dice3.png");
ImageIcon dicePic4 = new ImageIcon("dice4.png");
ImageIcon dicePic5 = new ImageIcon("dice5.png");
ImageIcon dicePic6 = new ImageIcon("dice6.png");
JLabel diceNum1 = new JLabel("", dicePic1, JLabel.CENTER);
JLabel diceNum2 = new JLabel("", dicePic2, JLabel.CENTER);
JLabel diceNum3 = new JLabel("", dicePic3, JLabel.CENTER);
JLabel diceNum4 = new JLabel("", dicePic4, JLabel.CENTER);
JLabel diceNum5 = new JLabel("", dicePic5, JLabel.CENTER);
JLabel diceNum6 = new JLabel("", dicePic6, JLabel.CENTER);
this is the panel where one picture will appear
with if statements and I have to initialize diceNumber
JPanel panel6 = new JPanel();
diceNumber = new JLabel("1");
if (diceNumber.getText().equals("1")) {
panel6.add(diceNum1);
}
else if (diceNumber.getText().equals("2")) {
panel6.add(diceNum2);
}
else if (diceNumber.getText().equals("3")) {
panel6.add(diceNum3);
}
else if (diceNumber.getText().equals("4")) {
panel6.add(diceNum4);
}
else if (diceNumber.getText().equals("5")) {
panel6.add(diceNum5);
}
else if (diceNumber.getText().equals("6")) {
panel6.add(diceNum6);
}
here when I start rolling
public void actionPerformed(ActionEvent e) {
if (e.getSource() == dice) {
roll = r.nextInt(6) + 1;
if (roll == 1) {
diceNumber.setText("1");
}
else if (roll == 2) {
diceNumber.setText("2");
}
else if (roll == 3) {
diceNumber.setText("3");
}
else if (roll == 4) {
diceNumber.setText("4");
}
else if (roll == 5) {
diceNumber.setText("5");
}
else if (roll == 6) {
diceNumber.setText("6");
}
the problem is thath diceNumber always takes the value "1" and never change
any help ?
diceNumber = new JLabel("1");
immediately precedes the logical checks on the diceNumber text. At this stage, you have initiated a JLabel with the text "1", hence it will always be "1" at this stage. You don't change the text until much later, at which stage you no longer check to set the Dice image. The approach you have taken resembles a Rube Goldberg machine; triggering a series of events to perform a relatively simple task. A simple solution would be:
List<JLabel> disc = new ArrayList<>();
for (int i = 1; i <= 6; i++) {
disc.add(new ImageIcon(String.format("dice%d_.png", i));
}
Then when you need to change the image you call:
int roll = r.nextInt(6) + 1;
panel.add(disc[roll]);
Regardless, there are many improvements that can be made to the code as it is; I would recommend that you change the excessive amount of if statements to:
diceNumber.setText(roll.toString()); or
diceNumber.setText(roll + "");
In your actionPerformed() method, you change the text of the diceNumber label, and that's all you're doing. You don't change the image displayed by the image label.
You should really really learn about arrays, and store your 6 images in an array. Your logic should be:
init() {
// add a label displaying the number (1 by default)
// add a label displaying the icon (1 by default)
}
actionPerformed() {
// choose a random number
// change the text of the number label
// change the icon of the image label
}
And to do that, ni need for big chain of if statements: it should just be
imageLabel.setIcon(images[randomRoll - 1]);
I am trying to make a GUI which will take a value from one JPanel, and then when a button is pressed it will move on to the next panel, which uses information that was input from the previous panel. Since one panel is dependent on the value the user has input from the previous panel I don't think CardLayout will work here as it refers to the panels as strings.
As an example of the mechanism that I'm trying to implement, I have attempted to create a JFrame where
the first panel will ask the user to input a number,
the second panel will then display to the user the first number that the user selected and ask them to pick a second number,
the third panel will show the both the first and second number that the user selected and ask for a third number.
Finally, the fourth panel will display the sum of the three numbers that the user input in each JPanel, and allow the user to reset the JFrame.
I first created four separate classes that create the four JPanels I want to be able to move between. As can be seen from the code, I have tested each of these JPanels in a separate JFrame to see if they produce the desired effect.
Here is the code for PanelThree, PanelFour and the overall GUI. Panels one and two are very similar to panel three:
Panel Three:
import javax.swing.*;
import java.awt.*;
public class PanelThree extends JPanel {
JPanel row1 = new JPanel();
JPanel row2 = new JPanel();
JPanel row3 = new JPanel();
JSlider slider = new JSlider(0, 10, 5);
JButton next = new JButton("Find the total of all three numbers");
public PanelThree(int num0, int num1) {
BorderLayout lay = new BorderLayout();
setLayout(lay);
JLabel one = new JLabel("Choose your last number on the slider, the
slider goes from one to ten. Your first number was: " + num0 + ". Your
second number was: " + num1);
row1.add(one);
row2.add(slider);
row3.add(next);
add(row1, BorderLayout.NORTH);
add(row2, BorderLayout.CENTER);
add(row3, BorderLayout.SOUTH);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800,600);
PanelThree panelThree = new PanelThree(7, 2);
frame.setContentPane(panelThree);
frame.setVisible(true);
}
}
Panel Four:
import javax.swing.*;
import java.awt.*;
public class PanelFour extends JPanel {
JPanel row1 = new JPanel();
JPanel row2 = new JPanel();
JButton reset = new JButton("Reset");
public PanelFour(int num0, int num1, int num2) {
BorderLayout lay = new BorderLayout();
setLayout(lay);
int tot = num0 + num1 + num2;
JLabel total = new JLabel("All of your numbers add up to: " + tot);
row1.add(total);
row2.add(reset);
add(row1, BorderLayout.CENTER);
add(row2, BorderLayout.SOUTH);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800,600);
PanelFour panelFour = new PanelFour(7, 2, 9);
frame.setContentPane(panelFour);
frame.setVisible(true);
}
}
Now this is the problem, the class which tries to knit the four JPanels together and to have it react based on what the inputs were to the last JPanel in the JFrame. The issue seems to lie specifically with the actionPerformed method which is unable to access the components in the Frame constructor. Here is the code:
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Frame extends JFrame implements ActionListener {
int x, y, z;
public void Frame() {
super("Number Adder");
int i = 1;
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
PanelOne panelOne = new PanelOne();
panelOne.next.addActionListener(this);
PanelTwo panelTwo = new PanelTwo(x);
panelTwo.next.addActionListener(this);
PanelThree panelThree = new PanelThree(x, y);
panelThree.next.addActionListener(this);
PanelFour panelFour = new PanelFour(x, y, z);
panelFour.reset.addActionListener(this);
if (i == 1) {
add(panelOne);
} else if (i == 2) {
add(panelTwo);
} else if (i == 3) {
add(panelThree);
} else {
add(panelFour);
}
}
public actionPerformed(ActionEvent e) {
if (e.getSource() == panelOne.next) {
return x = int panelOne.slider.getValue();
return i = 2;
} else if (e.getSource() == panelTwo.next) {
return y = int panelTwo.slider.getValue();
return i = 3;
} else if (e.getSource() == panelThree.next) {
return z = int panelThree.slider.getValue();
return i = 4;
} else {
return i = 1;
}
repaint();
}
public static void main(String[] args) {
Frame frame = new Frame();
}
}
What can I do to fix this or improve this?
I don't think CardLayout will work here as it refers to the panels as strings
Why not?
You have a sequence of events.
Enter a number,
Display another panel.
There is no reason the second panel can't access the first number entered. That has nothing to do with a CardLayout.
Your second panel, just needs a way to access the data from the first panel. So maybe when you create the second panel you pass in the reference to the first panel. So when you display the second panel you can know access the number entered on the first panel.
So I have my images stored as ImageIcon's on JButtons. I want the user to click on the JButton of the piece they want to use and then click on another JButton to move it there, how would I do this?
I've tried using an actionListener to get the ImageIcon but its proving very complicated especially because I have an 2d array of JButton Images.
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
System.out.println(actionEvent.getActionCommand());
}
};
JButton[][] squares = new JButton[8][8];
Border emptyBorder = BorderFactory.createEmptyBorder();
for (int row = 0; row < squares.length; row++) {
for (int col = 0; col < squares[row].length; col++) {
JButton tempButton = new JButton();
tempButton.setBorder(emptyBorder);
tempButton.setSize(64, 64);
squares[row][col] = tempButton;
squares[row][col].addActionListener(actionListener);
panel.add(squares[row][col]);
squares[0][0].setIcon(new ImageIcon(BoardGUI.class.getResource("castle.png"), "castle"));
}
}
Try the following code. I don't know the exact code for working with ImageIcons on JButtons, but this gets the ideas across:
JButton pieceToMoveButton = null; //variable that persists between actionPerformed calls
public void actionPerformed(ActionEvent actionEvent)
{
JButton button = (JButton)actionEvent.getSource();
if (pieceToMoveButton == null) //if this button press is selecting the piece to move
{
//save the button used in piece selection for later use
pieceToMoveButton = button;
}
else //if this button press is selecting where to move
{
//move the image to the new button (the one just pressed)
button.imageIcon = pieceToMoveButton.imageIcon
pieceToMoveButton = null; //makes the next button press a piece selection
}
}
Not sure if this is what you are looking for but is one way of moving the position of a JButton to another:
Now as an example pretend that there is already code declaring and initializing a JButton (JButton thatotherbutton = new JButton...etc.). Moving it to a certain location can be done as such:
Rectangle rect = thatotherbutton.getBounds();
xcoordinate = (int)rect.getX();
ycoordinate = (int)rect.getY();
chesspiecebutton.setBounds(xcoordinate, ycoordinate, xlengthofbutton, ylengthofbutton);
Use these coordinates to set the new bounds (in other words, the position) of your JButton upon clicking on another JButton.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
So I am making a simple tic tac toe game and ran into a problem at the last minute
I am trying to draw a line at the win location but on the final win location(index), the line gets hidden behind the JButton not entirly sure why it is doing this.
I know alot of people say do not use getGraphics(), and I am wondering if that is the source of my issues they say to override the paintComponent method but that is not working for me either
I have attached a pic of what the result is looking like and code snips of how I am trying to perform these actions
PS I am using a JFrame, if any more code is needed I will be glad to show it
if(win[i] == 264){ // if one of the the combinations equal 'X','X','X' which equals 264, then there is a winner
System.out.println("X is the winner!!!");
System.out.println("Game Over!");
number = i;
draw(); }// call draw method
private void draw(){ // drawing a line at winning location
Graphics2D g1 = (Graphics2D) GUI.getFrame().getGraphics(); // declaring graphics on our Jframe
Stroke stroke3 = new BasicStroke(12f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER); // make our strokes cap off round
if(number == 0){ // statements will determine the win location, so at win0, XXX,
g1.setStroke(stroke3); // we will add stroke to our line
g1.drawLine(0,104,500,104); // draw the line starting at the 0,104 and end it at coordinates 500,104
}
here is a more runnable code, it is alot though
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ButtonModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class tic implements Runnable {
final static int row = 3; // our rows
final static int col = 3; // our col
final static int sizeOfBoard = row * col;
// the size of our board is not going to change so we make it final
static JButton[] clickButton;
char[] templateOfBoard; // our board, TicTacToe field, static
char userTurn; // users turn , only one letter, tracks whether it is a X or O
int count; // keeps track of user moves
static JFrame frame; // our JFrame
int number;
public tic(JFrame frame) {
tic.frame = new JFrame("TicTacToe GAME");
clickButton = new JButton[9];
count = 0; // number of turns starts at 0;
number = 0;
setUserTurn('X'); // first turn will always be X
setTemplateOfBoard(new char[sizeOfBoard]); // size of the board we are going to make it
try{
for(int spaces=0; spaces<sizeOfBoard; spaces++){ // size of Board is in the GUI class
getTemplateOfBoard()[spaces] = ' '; // the board is being created, looping through all rows and col
//every index of the board not has a char value equal to a space
//determine if everything came out correctly
//should equal of a total of 9
// 3x3
}
System.out.println("Board template created"); // means the board now has all spaces
}
catch(Exception e){
System.out.println("Could not initalize the board to empty char");
e.printStackTrace();
}
}
public static void main(String[] args){
try{
SwingUtilities.invokeLater(new tic(frame)); // run
}
catch(Exception e){ // wanted to test to ensure that Runnable could be invoked
System.out.println("Could not excute Runnable application");
e.printStackTrace();
}
}
public void run() {
setup(); // going to run out setup method, what our game is made out of
}
public void setup() {
// setting up the Board
// board is composed of JButton
// and a 3x3 frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // when the user closes the window JFrame will exit
//going to design the board now
//the dimensations of the board = sizeOfBoard
getFrame().setLayout(new GridLayout(row, col)); // this is the outline rows * col
// sizes out row * col based on what we define those numbers as
//i.e 3x3
getFrame().setBounds(0,0,500,500); // location at 0,0, size 500 x 500
Border border = new LineBorder(Color.DARK_GRAY, 2); // color of JButton border
System.out.println("Your board game is being created!");
try{
getFrame().setVisible(true); // shows the board,
// this is going to display everything to the screen
System.out.println("Board is now visable");
}
catch(Exception e){
System.out.println("Board was not displayed");
}
// 9 different buttons, for every index there will be a button
for(int i =0; i<sizeOfBoard;i++){ // going to fill the board with clickableButtons by looping through every index and placing a button there
final int move = i;
clickButton[i] = new JButton(); // at a certain index there is a new button
clickButton[i].setSize(250,250); // size of each button
clickButton[i].setBackground(Color.WHITE); // color of the JButton
getFrame().add(clickButton[i]); // we are going to add the actual the button at that index on the frame
clickButton[i].setFont(new Font("Arial", Font.BOLD, 70)); // size of the text
clickButton[i].setBorder(border); // adding border
clickButton[i].getModel().addChangeListener(new ChangeListener() { //going to overRide what happens when we rollover and press a Butotn
public void stateChanged(ChangeEvent e) {
ButtonModel button = (ButtonModel) e.getSource(); // manages the state of the button, i.e lets me control what happens to the button
if(clickButton[move] != null){ // if we do not include this argument
// the buttons are not made yet on the new game, meaning clickButton[i] = null
//so boolean(!button.isRollover()) will return true, since on the new game you can not have your mouse hovered over
// but when it returns true, it will return a null value, giving a null pointer exception
// so best thing to do, is to only run these cases below when the buttons are not null
if (button.isRollover()) { // when the mouse hovers over the index
clickButton[move].setBackground(Color.BLACK); // color will equal black
}
else if(!button.isRollover()){ // when the button is not hovered over
clickButton[move].setBackground(Color.WHITE); // color will be whte, just like our background
}
}
}
});
clickButton[i].addActionListener(new ActionListener() {
//our click events, going to override to let it know what we want to happen
//once we click on the button
public void actionPerformed(ActionEvent e) {
clickButton[move].setEnabled(false); //going to disable the button after it is clicked
//ORDER: button gets clicked first, then the test is added
mouseListener(e, move); // our mouseListenerEvent in game class
//
}
});
}
}
public static void playAgain() {
try{
System.out.println("NEW GAME");
SwingUtilities.invokeLater(new tic(frame)); // run the run(class) again
}
catch(Exception e){ // wanted to test to ensure that Runnable could be invoked
System.out.println("Could not excute Runnable application");
e.printStackTrace();
}
}
public static JFrame getFrame() {
return frame;
}
public tic userMove(int moveMade){
getTemplateOfBoard()[moveMade] = getUserTurn();
// index of the board, or in simpler terms, where the user
// inserts there turn i.e X or O, 0-8
//System.out.println(userMove);
//boolean statement to determine the turns
// So user X starts first
//if the turn is X, the nextTurn is now O,
if(getUserTurn() == 'X'){
setUserTurn('O');
}
else {
setUserTurn('X');
}
count++;
return this; // going to return the userTurn
// issue actually entering the userTurn is not giving right value, but using 'this' does
}
// for some odd reason the toString is causing some issues, keep getting #hash code
//saw online to override it like this
// will make the board out of emepty strings
// going to return a string representation of an object
public String toString(){
return new String(getTemplateOfBoard());
}
public void mouseListener(ActionEvent e, int moveMade){
// mouse click events
// what happens after a button is clicked
if(getTemplateOfBoard()[moveMade] == ' '){ // the user can only space a click, so an letter on the field if it is empty
((JButton)e.getSource()).setText(Character.toString(getUserTurn())); // when the button is clicked, we want an X placed there
if (getUserTurn() == 'X'){
UIManager.getDefaults().put("Button.disabledText",Color.RED); // when the but gets disabled the test will turn red
}
else{
UIManager.getDefaults().put("Button.disabledText",Color.BLUE);
}
//calling the method userTurn to determine who goes next
//problem is that is expects a String
//going to override the toString method
userMove(moveMade); // calling userMove in moveMade, moveMade is the index at which the user put either an X or a O
winner(); // we want to check each time to ensure there was/was not a winner
}
}
public tic winner() { // determines who is the winner
//list below defines all the possible win combinations
// the index of where a X or O can be place
// placed the locations to a int value
int win1 = templateOfBoard[0] + templateOfBoard[1] + templateOfBoard[2];
int win2 = templateOfBoard[3] + templateOfBoard[4] + templateOfBoard[5];
int win3 = templateOfBoard[6] + templateOfBoard[7] + templateOfBoard[8];
int win4 = templateOfBoard[0] + templateOfBoard[3] + templateOfBoard[6];
int win5 = templateOfBoard[1] + templateOfBoard[4] + templateOfBoard[7];
int win6 = templateOfBoard[2] + templateOfBoard[5] + templateOfBoard[8];
int win7 = templateOfBoard[0] + templateOfBoard[4] + templateOfBoard[8];
int win8 = templateOfBoard[2] + templateOfBoard[4] + templateOfBoard[6];
int[] win = new int[]{win1,win2,win3,win4,win5,win6,win7,win8};
// making a array to go through all the possibile wins
//possible total of wins is 8
for(int i = 0;i<win.length;i++){
// looping through the win possibilities
if(win[i] == 264){ // if one of the the combinations equal 'X','X','X' which equals 264, then there is a winner
System.out.println("X is the winner!!!");
System.out.println("Game Over!");
number = i;
draw(); // call draw method
return this; // if statement is true, it will return this(gameOver)
}
else if(win[i] == 237 ){ // if one of the the combinations equal 'O','O','O' which equals 234, then there is a winner
System.out.println("O is the winner!!!");
System.out.println("Game Over!");
number = i;
//draw(); // call draw method
return this;
}
if (count == 9) {
// if none of the statements above are true, it automatically comes done to here
//so if there is nine moves and no win, it is a draw
}
}
return this;
// going to return this method ;
}
private void draw(){ // drawing a line at winning location
Graphics2D g1 = (Graphics2D) getFrame().getGraphics(); // declaring graphics on our Jframe
Stroke stroke3 = new BasicStroke(12f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER); // make our strokes cap off round
if(number == 0){ // statements will determine the win location, so at win0, XXX,
g1.setStroke(stroke3); // we will add stroke to our line
g1.drawLine(0,104,500,104); // draw the line starting at the 0,104 and end it at coordinates 500,104
}
else if(number == 1){
g1.setStroke(stroke3);
g1.drawLine(0,257,500,257);
}
else if(number == 2){
g1.setStroke(stroke3);
g1.drawLine(0,411,500,411);
}
else if(number == 3){
g1.setStroke(stroke3);
g1.drawLine(88,0,88,500);
}
else if(number == 4){
g1.setStroke(stroke3);
g1.drawLine(250,0,250,500);
}
else if(number == 5){
g1.setStroke(stroke3);
g1.drawLine(411,0,411,500);
}
else if(number == 6){
g1.setStroke(stroke3);
g1.drawLine(-22,0,500,500);
}
else if(number == 7){
g1.setStroke(stroke3);
g1.drawLine(520,0,0,500);
}
}
// want to be able to access the private variables
//so we will make getter and setter methods for the ones that we need
public char getUserTurn() { // getter method for userTurn
return userTurn;
}
public void setUserTurn(char userTurn) { // setter method
this.userTurn = userTurn;
}
public char[] getTemplateOfBoard() { //getter method
return templateOfBoard;
}
public void setTemplateOfBoard(char[] templateOfBoard) { // setter method
this.templateOfBoard = templateOfBoard;
}
}
Painting over the top of components can be troublesome, you can't override the paintComponent method of the container which contains the components, because this paints in the background, you can't override the paint method of the container, as child components can be painted without the parent container been notified...
You could add a transparent component over the whole lot, but this just introduces more complexity, especially when a component already already exists ...
public class ConnectTheDots {
public static void main(String[] args) {
new ConnectTheDots();
}
public ConnectTheDots() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
PaintPane pp = new PaintPane();
JFrame frame = new JFrame("Test");
frame.setGlassPane(pp);
pp.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DotsPane(pp));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PaintPane extends JPanel {
private List<JButton[]> connections;
private JButton lastSelected;
public PaintPane() {
setOpaque(false);
connections = new ArrayList<>(25);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (lastSelected != null) {
g2d.setColor(Color.RED);
int x = lastSelected.getX() + ((lastSelected.getWidth() - 8) / 2);
int y = lastSelected.getY() + ((lastSelected.getHeight() - 8) / 2);
g2d.fillOval(x, y, 8, 8);
}
for (JButton[] group : connections) {
g2d.setColor(Color.BLUE);
Point startPoint = group[0].getLocation();
Point endPoint = group[1].getLocation();
startPoint.x += (group[0].getWidth() / 2);
startPoint.y += (group[1].getHeight()/ 2);
endPoint.x += (group[0].getWidth() / 2);
endPoint.y += (group[1].getHeight()/ 2);
g2d.draw(new Line2D.Float(startPoint, endPoint));
}
g2d.dispose();
}
protected void buttonClicked(JButton btn) {
if (lastSelected == null) {
lastSelected = btn;
} else {
connections.add(new JButton[]{lastSelected, btn});
lastSelected = null;
}
revalidate();
repaint();
}
}
public class DotsPane extends JPanel {
private PaintPane paintPane;
public DotsPane(final PaintPane pp) {
paintPane = pp;
ActionListener al = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JButton btn = (JButton) e.getSource();
paintPane.buttonClicked(btn);
}
};
setLayout(new GridLayout(6, 6));
for (int index = 0; index < 6 * 6; index++) {
JButton btn = new JButton(".");
add(btn);
btn.addActionListener(al);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
Take a look at How to Use Root Panes for more details
Using NetBeans GUI editor to create a bowling program for school. Is it possible for me to add a JPanel to a JList? if so how?
It's not really possible (meaning it won't behave as you'd expect) - what you actually want is a list LayoutManager that will lay out the components in a vertical or horizontal list. So instead of using JList, you'd use a JPanel with a list-like layout manager.
Try these:
BoxLayout will put all the JPanels in a single column/row
GridLayout will put all the JPanels in a single column/row and make them all the same size
Try This. it's works for me.
class PanelRenderer implements ListCellRenderer {
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
JPanel renderer = (JPanel) value;
renderer.setBackground(isSelected ? Color.red : list.getBackground());
return renderer;
}
}
public void ShowItemList(List<JPanel> paneList, JPanel container) {
DefaultListModel model = new DefaultListModel();
for (JPanel pane:paneList) {
model.addElement(pane);
}
final JList list = new JList(model);
list.setFixedCellHeight(40);
list.setSelectedIndex(-1);
list.setCellRenderer(new JPanelToJList.PanelRenderer());
JScrollPane scroll1 = new JScrollPane(list);
final JScrollBar scrollBar = scroll1.getVerticalScrollBar();
scrollBar.addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(AdjustmentEvent e) {
System.out.println("JScrollBar's current value = " + scrollBar.getValue());
}
});
container.add(scroll1);
}
goto this tutorial:
it has the same concept with your problem...
http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html#renderer
(EDIT: I've used this for a while now and am surprised. Fastest list component I've seen so far. Why haven't I seen this before?)
I just whipped up something that is not a JList, so it lacks a lot of features, but you can rather easily add those.
But what you get is this: A list (All members equal size.) that can easily hold ~2 billion panels with no memory or performance problems - see demo code. Also, the JPanels can contain anything you want, those components will work normally.
In the demo, the JPanel members have no inner JPanels and are completely transparent to mouse events (except for the JButtons, and that's good): A listener added to the overall container receives them, as shown in the demo. If you add more component hierarchy, things might get tricky, IDK.
Anyway, this thing is lightning fast and, most of all, gets the job done: JPanels in a list that you can operate but also select. (No selection code built-in, but like I said: Easy to do. Mouse hover demo code inside.)
Demo class:
final public class FastPanelListDemo {
private static JFrame window = null;
private static FastPanelList panelList = null;
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> {
setLookAndFeelDefault();
panelList = new FastPanelList(FastPanelList.FPLOrientation.VERTICAL,
FastPanelListDemo::supplyPanel,
0.1,
0.95,
false,
80,
Integer.MAX_VALUE);
final Container contentPane = panelList.container;
contentPane.setPreferredSize(new Dimension(300, 800));
contentPane.setBackground(Color.GRAY);
window = new JFrame("FastPanelList demo");
window.setContentPane(contentPane);
window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
window.pack();
window.setLocationRelativeTo(null);
window.setVisible(true);
contentPane.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(final MouseEvent e) {
final JPanel itemUnderMouse = panelList.getItemUnderMouse(e);
if (itemUnderMouse != null) {
itemUnderMouse.setBackground(new Color((float) Math.random(),
(float) Math.random(),
(float) Math.random()));
}
}
});
});
}
private static JPanel supplyPanel(final int panelIndex) { // Just supply something that extends JPanel. You can put as much data in as you want. E.g. "boolean isMouseHovering" etc.
final JLabel label = new JLabel("panel " + panelIndex);
label.setHorizontalAlignment(SwingConstants.CENTER);
label.setVerticalAlignment(SwingConstants.CENTER);
final JButton button = new JButton("click me");
button.addActionListener(e -> {
JOptionPane.showMessageDialog(window,
"That was button " + panelIndex + ".",
"* CLICK *",
JOptionPane.INFORMATION_MESSAGE);
});
final JPanel panel = new JPanel(new BorderLayout(0,
0));
panel.setBorder(BorderFactory.createEmptyBorder(10,
10,
10,
10));
panel.setBackground(new Color((float) Math.random(),
(float) Math.random(),
(float) Math.random()));
panel.add(label, BorderLayout.CENTER);
panel.add(button, BorderLayout.EAST);
return panel;
}
private static void setLookAndFeelDefault() {
setLookAndFeel("Windows",
UIManager.getSystemLookAndFeelClassName(),
UIManager.getCrossPlatformLookAndFeelClassName(),
"Windows Classic",
"Nimbus",
"Metal",
"CDE/Motif");
}
/**
* #param intendedLAFIs ANYTHING, but ideally a LookAndFeel name or several. The first value that equalsIgnoreCase
* an installed LookAndFeelInfo.getName() will be used.
*/
private static void setLookAndFeel(final String... intendedLAFIs) {
if (intendedLAFIs != null && intendedLAFIs.length > 0) {
final UIManager.LookAndFeelInfo[] installedLAFIs = UIManager.getInstalledLookAndFeels();
LAFILOOP:
for (String intendedLAFI : intendedLAFIs) {
for (final UIManager.LookAndFeelInfo lafi : UIManager.getInstalledLookAndFeels()) {
if (lafi.getName().equalsIgnoreCase(intendedLAFI)) {
try {
UIManager.setLookAndFeel(lafi.getClassName());
break LAFILOOP;
} catch (Exception e) {
continue LAFILOOP;
}
}
}
}
} else {
throw new IllegalArgumentException("intendedLAFIs is null or empty.");
}
}
}
FastPanelList class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
/**
* FastPanelList v[2pre1, 2019-05-28 10!00 UTC] by Dreamspace President
*/
final public class FastPanelList<T extends JPanel> {
public enum FPLOrientation {
HORIZONTAL(Adjustable.HORIZONTAL),
VERTICAL(Adjustable.VERTICAL);
final public int orientationAsConstant;
FPLOrientation(final int orientationAsConstant) {
this.orientationAsConstant = orientationAsConstant;
}
}
final public FPLOrientation orientation;
final private Function<Integer, T> panelSupplier;
final private double fractionOfExtentToScrollPerArrowClick;
final private double fractionOfExtentToScrollPerTrackClick;
final private double fractionOfExtentToScrollPerMouseWheelStep;
final private boolean hideScrollbarWhenUnnecessary;
final private JScrollBar scrollBar;
final private int scrollBarWidth; // The default width it normally has in any GUI.
final public JPanel container; // The container of it all.
private int panelSize = 0; // The horizontal or vertical extent of each contained panel.
private int panelCount = 0; // The amount of panels, indeed max Integer.MAX_VALUE.
private long contentSize = 0; // The sum total extent of all "contained panels". (They're not really contained, but nobody will see that.)
private long actualScrollPosition = 0; // The true scroll position, think contentSize.
private Dimension lastKnownContainerSize = new Dimension(0, 0);
private Map<Integer, T> knownPanels = new HashMap<>(); // All panels of which some pixels are currently potentially visible are cached here.
/**
* #param orientation Whether horizontal or the more common vertical arrangement.
* #param panelSupplier Your code that supplies the panels as needed on the fly. The
* argument will NEVER be null - and your return value, too, must never
* be null.
* #param fractionOfExtentToScrollPerArrowClick E.g. 0.1 for 10% of the visible area to become hidden/shown when you
* click a scrollbar arrow.
* #param fractionOfExtentToScrollPerTrackClick E.g. 0.95 for 95% of the visible area to become hidden/shown when
* you click in the scrollbar track.
* #param hideScrollbarWhenUnnecessary Guess.
* #param panelSize Can later also be done via setter. (Not tested.) KEEP IN MIND THAT
* THIS IS NOT YET SCALED, so if you have Desktop scaling 200% and are
* running Java 8, you need to double the value (e.g. use my GUIScaling
* class to automate this).
* #param panelCount dto.
*/
public FastPanelList(final FPLOrientation orientation,
final Function<Integer, T> panelSupplier,
final double fractionOfExtentToScrollPerArrowClick,
final double fractionOfExtentToScrollPerTrackClick,
final double fractionOfExtentToScrollPerMouseWheelStep,
final boolean hideScrollbarWhenUnnecessary,
final int panelSize,
final int panelCount) {
if (orientation == null) {
throw new IllegalArgumentException("orientation is null.");
}
if (panelSupplier == null) {
throw new IllegalArgumentException("panelSupplier is null.");
}
this.orientation = orientation;
this.panelSupplier = panelSupplier;
this.fractionOfExtentToScrollPerArrowClick = Math.max(0, fractionOfExtentToScrollPerArrowClick);
this.fractionOfExtentToScrollPerTrackClick = Math.max(0, fractionOfExtentToScrollPerTrackClick);
this.fractionOfExtentToScrollPerMouseWheelStep = Math.max(0, fractionOfExtentToScrollPerMouseWheelStep);
this.hideScrollbarWhenUnnecessary = hideScrollbarWhenUnnecessary;
setPanelSize(panelSize);
setPanelCount(panelCount);
scrollBarWidth = determineScrollBarDefaultWidth();
scrollBar = new JScrollBar(orientation.orientationAsConstant, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
scrollBar.addAdjustmentListener(e -> update());
container = new JPanel(null); // NULL: We want to layout everything manually.
// container.add(scrollBar);
container.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(final ComponentEvent e) {
update();
}
});
container.addMouseWheelListener(this::mouseWheelEvent);
}
public void mouseWheelEvent(final MouseWheelEvent e) {
final int rotation = e.getWheelRotation();
final int extent = scrollBar.getModel().getExtent();
final int increment = (int) Math.max(1, Math.min(extent,
extent * fractionOfExtentToScrollPerMouseWheelStep));
scrollBar.setValue(scrollBar.getValue() + (rotation * increment));
}
private int determineScrollBarDefaultWidth() { // Called only ONE time.
final JScrollPane dummyForDefaultSize = new JScrollPane(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
dummyForDefaultSize.setPreferredSize(new Dimension(1000, 1000));
dummyForDefaultSize.setSize(dummyForDefaultSize.getPreferredSize());
dummyForDefaultSize.doLayout();
return dummyForDefaultSize.getVerticalScrollBar().getSize().width;
}
/**
* FastPanelList requires each item to have the exact same size. This is where you define it (if you reconsidered
* after your constructor call).
*
* #param panelSize Will become >=1
*/
public void setPanelSize(final int panelSize) {
this.panelSize = Math.max(1, panelSize);
}
/**
* FastPanelList easily manages Integer.MAX_VALUE (about 2 billion) panels with no memory or performance problems.
* You define the amount here. You don't add/remove panels in this thing: Instead, you will be asked to provide
* panels as required depending on screen layout etc.
*
* #param panelCount Will become >=0
*/
public void setPanelCount(final int panelCount) {
this.panelCount = Math.max(0, panelCount);
}
/**
* Clears the internal JPanel cache. Necessary if you want to repopulate the list. Setting the panel count and
* calling update() is not sufficient. (Call update AFTER this method.)
*/
public void clear() {
knownPanels.clear();
}
public T getItemUnderMouse(final MouseEvent e) {
return getItemUnderMouse(e.getX(), e.getY());
}
public T getItemUnderMouse(final int xInComponent,
final int yInComponent) {
final long realPositionUnderMouse = (actualScrollPosition + (orientation == FPLOrientation.HORIZONTAL ? (long) xInComponent : (long) yInComponent));
final int indexUnderMouse = (int) (realPositionUnderMouse / panelSize);
return knownPanels.get(indexUnderMouse);
}
/**
* This method is very lenient.
*
* #param index Anything.
* #param callSupplierIfNotCached Depends on what you're trying to achieve. E.g. use FALSE if you want to set the
* background color of one of the visible JPanels. The method would return null if
* the panel is not visible, because then it is also no longer cached.
* #return NULL if index is NULL, or is less than 0, or is equal to or greater than panelCount. Else the cached
* JPanel (or whatever it secretly is via "extends"), meaning one of the panels that are currently visible or at the
* edge of visibility. In all other cases, either null will be returned - or your supplier will be called, so you
* get your own JPanel spat right back at you.
*/
public T getItem(final Integer index,
final boolean callSupplierIfNotCached) {
T ret = null;
if (index != null && index >= 0 && index < panelCount) {
ret = knownPanels.get(index);
if (ret == null && callSupplierIfNotCached) {
ret = panelSupplier.apply(index);
if (ret == null) {
throw new IllegalArgumentException("panelSupplier returned null for index " + index);
}
}
}
return ret;
}
/**
* #return a NEW Map containing the Map entries of the internal knownPanels map. These maps contain all panels that
* are currently visible on screen. The index is identical to the number handed to your Supplier.
* <p>
* The purpose of that internal map is to not request EVERY panel anew every time, but only the panels that are
* scrolled in at the edge of the screen. Obviously, this is also very useful to you, because you can call this
* method to get all panels to change their look, data, whatever. And ONLY THOSE panels need to be changed. All
* others ... don't exist. They only exist in the fantasy of the user. Until they scroll there, then some have
* become real while others have fallen out of existence.
*/
public Map<Integer, T> getCachedItems() {
return new HashMap<>(knownPanels);
}
/**
* This layouts the component. This is done automatically when the scrollbar is moved or the container is resized,
* but any other action would require YOU to call this.
*/
public void update() {
container.removeAll();
lastKnownContainerSize = container.getSize();
final int containerSize;
if (orientation == FPLOrientation.HORIZONTAL) {
scrollBar.setLocation(0, lastKnownContainerSize.height - scrollBarWidth);
scrollBar.setSize(lastKnownContainerSize.width, scrollBarWidth);
containerSize = lastKnownContainerSize.width;
} else {
scrollBar.setLocation(lastKnownContainerSize.width - scrollBarWidth, 0);
scrollBar.setSize(scrollBarWidth, lastKnownContainerSize.height);
containerSize = lastKnownContainerSize.height;
}
contentSize = (long) panelCount * (long) panelSize;
final long invisibleStuff = contentSize - containerSize;
actualScrollPosition = Math.max(0, Math.min(invisibleStuff,
(long) (getScrollBarPosRatio() * (invisibleStuff))
));
final int extent;
if (contentSize > 0) {
final double visibleRatio = containerSize / (double) contentSize;
extent = (int) Math.max(0, Math.min(Integer.MAX_VALUE, Integer.MAX_VALUE * visibleRatio));
} else {
extent = Integer.MAX_VALUE;
}
final int unitIncrement = (int) Math.max(1, Math.min(extent,
extent * fractionOfExtentToScrollPerArrowClick));
final int blockIncrement = (int) Math.max(1, Math.min(extent,
extent * fractionOfExtentToScrollPerTrackClick));
scrollBar.getModel().setExtent(extent);
scrollBar.setUnitIncrement(unitIncrement);
scrollBar.setBlockIncrement(blockIncrement);
scrollBar.setVisible(!hideScrollbarWhenUnnecessary || extent < Integer.MAX_VALUE);
final Dimension panelSizes = getPanelSize();
long n = actualScrollPosition;
final long endOfScreen = actualScrollPosition + containerSize + panelSize;
final Map<Integer, T> newKnownPanels = new HashMap<>();
while (n < endOfScreen) { // Loop ongoing = need more panels to fill the view.
// Calc index of current panel.
final long panelIndex = n / panelSize;
if (panelIndex > Integer.MAX_VALUE) {
throw new Error();
} else if (panelIndex >= panelCount) {
break;
}
final int panelIndexInt = (int) panelIndex;
// Obtain current panel - if possible from cache, else from external provider (which might likely create it from scratch).
T panel = knownPanels.get(panelIndexInt);
if (panel == null) {
panel = panelSupplier.apply(panelIndexInt);
if (panel == null) {
throw new IllegalArgumentException("panelSupplier returned null for index " + panelIndex);
}
}
newKnownPanels.put(panelIndexInt, panel);
// Set position and size.
final int panelPos = (int) ((panelIndex * panelSize) - actualScrollPosition);
final Point location;
if (orientation == FPLOrientation.HORIZONTAL) {
location = new Point(panelPos, 0);
} else {
location = new Point(0, panelPos);
}
panel.setLocation(location);
panel.setSize(panelSizes);
n += panelSize;
}
knownPanels = newKnownPanels; // Will now contain all panels needed for display. All panels that were in the map, but are no longer needed, are now gone forever.
// Layout.
container.add(scrollBar);
for (JPanel panel : newKnownPanels.values()) {
container.add(panel);
panel.revalidate();
}
container.repaint(); // required
}
/**
* #return the correct width&height a contained JPanel needs to have. Is applied by update() automatically.
*/
public Dimension getPanelSize() {
if (orientation == FPLOrientation.HORIZONTAL) {
return new Dimension(panelSize,
lastKnownContainerSize.height - (scrollBar.isVisible() ? scrollBarWidth : 0));
} else {
return new Dimension(lastKnownContainerSize.width - (scrollBar.isVisible() ? scrollBarWidth : 0),
panelSize);
}
}
/**
* #return 0 to 1, expressing position of scroll bar handle.
*/
public double getScrollBarPosRatio() {
final int scrollRangeSize = Integer.MAX_VALUE - scrollBar.getVisibleAmount(); // Which should really be named getExtent(). Or rather the other way round.
return scrollBar.getValue() / (double) scrollRangeSize;
}
}