thread.sleep not doing what is supposed to [duplicate] - java

This question already has answers here:
Thread Sleeping Before GUI Updating (Java 6)
(2 answers)
Closed 6 years ago.
So, the program is for school and i am having some problems, the basic premise is to have to user choose shape, size and colour, then draw the shape or animate it to move across the screen.
My programs works fine without the thread.sleep (it moves across the screen instantly). When i added the thread.sleep it was not working and waited 10 seconds before immediately moving to the end.
After testing around, it seems to have some correlation with the for loop it was in as when the for loop was to 1000 it waited 10 seconds then moved 1000 spaces instantly but when the for loop was 100 it only took one second to move 100 spaces instantly.
My understanding was that it should just wait 10 milliseconds before going into the for loop again.
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class AppletAssignemntIsFucked extends Applet
implements ActionListener
{
int colourChoice;
int shapeChoice;
int location;
int x, y;
TextField height = new TextField ("00");
TextField width = new TextField ("00");
boolean animating = false;
//declare the two types of checkboxes
CheckboxGroup shape, colour;
//declare all the shape checkboxes
Checkbox buttonSquare, buttonCircle, buttonRectangle, buttonOval;
//declare all the colour checkboxes
Checkbox buttonRed, buttonBlue, buttonGreen, buttonYellow;
Button buttonDraw, buttonAnimate, buttonReset;
public void init ()
{
setBackground (Color.lightGray);
shape = new CheckboxGroup ();
colour = new CheckboxGroup ();
buttonCircle = new Checkbox ("Circle", shape, true);
add (buttonCircle);
buttonSquare = new Checkbox ("Square", shape, false);
add (buttonSquare);
buttonRectangle = new Checkbox ("Rectangle", shape, false);
add (buttonRectangle);
buttonOval = new Checkbox ("Oval", shape, false);
add (buttonOval);
buttonRed = new Checkbox ("Red", colour, true);
add (buttonRed);
buttonBlue = new Checkbox ("Blue", colour, false);
add (buttonBlue);
buttonGreen = new Checkbox ("Green", colour, false);
add (buttonGreen);
buttonYellow = new Checkbox ("Yellow", colour, false);
add (buttonYellow);
buttonDraw = new Button ("draw");
buttonDraw.addActionListener (this);
add (buttonDraw);
buttonAnimate = new Button ("animate");
buttonAnimate.addActionListener (this);
add (buttonAnimate);
buttonReset = new Button ("reset");
buttonReset.addActionListener (this);
add (buttonReset);
add (height);
add (width);
}
public void paint (Graphics g)
{
switch (colourChoice)
{
case 1:
g.setColor (Color.red);
break;
case 2:
g.setColor (Color.green);
break;
case 3:
g.setColor (Color.yellow);
break;
case 4:
g.setColor (Color.blue);
break;
}
switch (shapeChoice)
{
case 1:
g.fillOval (location, 80, x, x);
break;
case 2:
g.fillRect (location, 80, x, x);
break;
case 3:
g.fillRect (location, 80, x, y);
break;
case 4:
g.fillOval (location, 80, x, y);
break;
}
}
public void actionPerformed (ActionEvent evt)
{
y = Integer.parseInt (height.getText ());
x = Integer.parseInt (width.getText ());
//set the colour
if (evt.getSource () == buttonAnimate)
{
for (int i = 0 ; i < 1000 ; i++)
{
try
{
Thread.sleep (10);
}
catch (InterruptedException ex)
{
Thread.currentThread ().interrupt ();
}
location += 1;
repaint ();
}
}
if (evt.getSource () == buttonReset)
{
location = 10;
repaint ();
}
if (evt.getSource () == buttonDraw)
{
if (buttonRed.getState () == true)
{
colourChoice = 1;
}
else if (buttonGreen.getState () == true)
{
colourChoice = 2;
}
else if (buttonYellow.getState () == true)
{
colourChoice = 3;
}
else if (buttonBlue.getState () == true)
{
colourChoice = 4;
}
//set the shape
if (buttonCircle.getState () == true)
{
shapeChoice = 1;
}
else if (buttonSquare.getState () == true)
{
shapeChoice = 2;
}
else if (buttonRectangle.getState () == true)
{
shapeChoice = 3;
}
else if (buttonOval.getState () == true)
{
shapeChoice = 4;
}
repaint ();
}
}
}

You are blocking the Event Dispatch Thread, so UI cannot get updated.
E.g. see Thread Sleeping Before GUI Updating.
Use a Swing Timer instead.

Related

How to change the value of a boolean from false to true using a button

I made a boolean for my while loop to make it run when the boolean is equal to true, I wanted to make the play button make the boolean = true which would trigger the while loop and run the game. But this isn't working for some reason.
Can someone help with making the boolean gameRunning = true;? I just can't figure out how to change its value from false to true.
I tried using atomic booleans but that didn't work
package panda.org;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.lang.Math;
import java.util.concurrent.atomic.AtomicBoolean;
public class NumberGame implements ActionListener{
JFrame frame;
JLabel rules;
JLabel rulesText;
JLabel rulesText2;
JButton play;
JButton exit;
Font myFont = new Font("Serif Plain", Font.BOLD, 15);
NumberGame() {
frame = new JFrame("NumberGame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 500);
frame.setLocationRelativeTo(null);
frame.setLayout(null);
frame.setResizable(true);
Image icon = Toolkit.getDefaultToolkit().getImage("C:\\Users\\Gaming MSI\\Pictures\\Saved Pictures\\download (1).png");
frame.setIconImage(icon);
rules = new JLabel("Rules: ");
rules.setFont(myFont);
rules.setBounds(50, 100, 100, 75);
rulesText = new JLabel("We will pick a random number in the range of 1 -> 50.");
rulesText.setBounds(100, 100, 315, 75);
rulesText2 = new JLabel("Your job is to guess that number!");
rulesText2.setBounds(100, 120, 315, 75);
play = new JButton("Play");
play.setBounds(150, 300, 100, 75);
boolean gameRunning = false;
play.addActionListener(e -> {
gameRunning = true;
});
while(gameRunning = true) {
JLabel label = new JLabel("Guess the number from 1 till 50");
label.setFont(myFont);
label.setBounds(150, 75, 315, 75);
JLabel hints = new JLabel("");
hints.setBounds(150, 180, 1000, 100);
JLabel hints2 = new JLabel("");
hints2.setBounds(150, 200, 1000, 100);
JTextField text = new JTextField();
text.setBounds(250, 150, 100, 25);
JButton check = new JButton("Check");
check.setBounds(150, 150, 75, 25);
double randomDouble = Math.random();
randomDouble = randomDouble * 50 + 1;
double randomDouble2 = Math.random();
randomDouble2 = randomDouble2 * (15 - 5 + 1) + 5 ;
double randomDouble3 = Math.random();
randomDouble3 = randomDouble3 * (15 - 5 + 1) + 5 ;
int randomHint = (int) randomDouble2;
int randomHint2 = (int) randomDouble3;
int randomInt = (int) randomDouble;
System.out.println("nb: " + randomInt);
System.out.println("hint: " + randomHint);
System.out.println("hint2: " + randomHint2);
JLabel status = new JLabel("");
status.setBounds(150, 160, 1000, 100);
JLabel closeness = new JLabel("");
closeness.setBounds(150, 220, 1000, 100);
closeness.setForeground(Color.blue);
final int[] failedAttempts = {0};
check.addActionListener(e1 -> {
String nb = text.getText();
int change = Integer.parseInt(nb);
frame.add(status);
if (randomInt == change) {
status.setText("You chose the correct number!");
status.setForeground(Color.green);
hints.setText("");
hints2.setText("");
}
if (randomInt > change) {
closeness.setText("Your answer is smaller than the correct answer");
}
if (randomInt < change) {
closeness.setText("Your answer is larger than the correct answer");
}
if (randomInt != change) {
status.setText("Wrong choice! Try again.");
status.setForeground(Color.red);
failedAttempts[0]++;
if (failedAttempts[0] == 3) {
int plus = randomInt + randomHint;
int minus = randomInt - randomHint2;
hints.setText("Hint: I see you are struggling, here is a low range to make it easier!");
hints2.setText("The lowered range is from " + plus + " to " + minus);
}
}
});
rules.setText("");
rulesText.setText("");
rulesText2.setText("");
frame.add(hints);
frame.add(hints2);
frame.add(label);
frame.add(check);
frame.add(closeness);
frame.add(text);
}
exit = new JButton("Exit");
exit.setBounds(350, 300, 100, 75);
exit.addActionListener(e -> {
int result = JOptionPane.showConfirmDialog(frame,"Are you sure want to exit?", "Exit",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE);
if(result == JOptionPane.YES_OPTION){
System.exit(0);
}
});
frame.add(play);
frame.add(exit);
frame.add(rules);
frame.add(rulesText);
frame.add(rulesText2);
frame.setVisible(true);
}
public static void main(String[] args) {
NumberGame number = new NumberGame();
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
You're still thinking in console applications, Swing is designed to work with events...
The user pressed a button? An event
Some timer triggered something in the background? An event
User typed something? An event
So, with the above in mind, you cannot expect your code here:
play.addActionListener(e -> {
gameRunning = true;
});
while(gameRunning = true) {
...
}
To be executed in that order, because you have no control of when the user is going to press the button, it could be either in 2 seconds, or could be in 2 hours
For this to happen, you might need to move the while loop to a method, and when the user presses the play button, you need to change gameRunning = true and then call that other method, something like this:
public void runGame() {
while(gameRunning) {
// Your code here
}
}
play.addActionListener(e -> {
if (!gameRunning) { //This validation is needed otherwise if you press the button multiple times you'll have multiple loops running
gameRunning = true;
runGame();
}
});
This way, you don't start your game until the user presses the play button.
Notice how I just wrote while(gameRunning) without ==, as mentioned in the comments above, if you have gameRunning = true you're assigning it a value instead of comparing it, when using boolean variables you can simply write them like that, it reduces the possibility of typos like that one.
if(true) is the same as if (true == true)
if(!false) is the same as if (false == false)
if(false) is the same as if (true == false)
And as I mentioned in my previous answer avoid the use of null-layout and setBounds and why are you implementing ActionListener and never using it? It's empty, so just remove implements ActionListener
You can not change the value of a local variable in a lambda function. As I am sure the compiler is telling you, they need to be final or effectively final which means they are only assigned once.
The solution is to use a type that can hold your Boolean and change the value that it is holding instead.
AtomicBoolean gameRunning = new AtomicBoolean(false);
play.addActionListener(e -> {
gameRunning.set(true);
});
...
while(gameRunning.get()) {
}

Second image not displaying when clicked in GuiApp, no one can figure out why?

public class Memory extends JFrame {
private static final long serialVersionUID = -2065145900871059367L;
private JPanel contentPane;
public static void main(String[] args) { //auto generated from WindowBuilder
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Memory frame = new Memory();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
JButton[] cards = new JButton[12];
int [] flippedNum = new int[12];
Icon [] catImg = new Icon[12];
{
catImg[0]= new ImageIcon(getClass().getResource("2faceszd.jpg"));
catImg[1] = new ImageIcon(getClass().getResource("blkctszd.jpg"));
catImg[2]= new ImageIcon(getClass().getResource("ct&mszd.png"));
catImg[3]= new ImageIcon(getClass().getResource("floofctszd.jpg"));
catImg[4]= new ImageIcon(getClass().getResource("orngctszd.jpg"));
catImg[5]= new ImageIcon(getClass().getResource("siamctszd.jpg"));
catImg[6]= new ImageIcon(getClass().getResource("2faceszd.jpg"));
catImg[7] = new ImageIcon(getClass().getResource("blkctszd.jpg"));
catImg[8]= new ImageIcon(getClass().getResource("ct&mszd.png"));
catImg[9]= new ImageIcon(getClass().getResource("floofctszd.jpg"));
catImg[10]= new ImageIcon(getClass().getResource("orngctszd.jpg"));
catImg[11]= new ImageIcon(getClass().getResource("siamctszd.jpg"));
} //6 images added twice
Icon photo = new ImageIcon(getClass().getResource("BG.png"));
static List<Integer> cats = new ArrayList<Integer>();{
cats.add(1); cats.add(1);
cats.add(2); cats.add(2);
cats.add(3); cats.add(3);
cats.add(4); cats.add(4);
cats.add(5); cats.add(5);
cats.add(6); cats.add(6);
}
static Random kitty = new Random();
public static int getCardAssignment(){
int cat = kitty.nextInt(cats.size());
int ucat = cats.get(cat);
cats.remove(cat);
return ucat;
} returns a random number to be assigned to an icon
//building the frame
public Memory() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 650, 500);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JPanel title = new JPanel();
title.setName("");
title.setFont(new Font("Tahoma", Font.PLAIN, 16));
title.setBackground(Color.PINK);
contentPane.add(title, BorderLayout.NORTH);
JLabel gameName = new JLabel("Memory Game");
title.add(gameName);
gameName.setFont(new Font("Arial Black", Font.PLAIN, 16));
gameName.setBackground(Color.PINK);
gameName.setEnabled(false);
JPanel cardDisplay = new JPanel();
cardDisplay.setBackground(Color.PINK);
cardDisplay.setFont(new Font("Arial Black", Font.PLAIN, 16));
cardDisplay.setBorder(new EmptyBorder(10, 10, 10, 10));
contentPane.add(cardDisplay, BorderLayout.CENTER);
cardDisplay.setLayout(new GridLayout(3, 4, 10, 10));
ButtonClickEventHandler clickIt = new ButtonClickEventHandler();
for(int i = 0; i < cards.length; i ++){
cards[i] = new JButton(); // new button
flippedNum[i] = getCardAssignment(); //card# assigned to cat icon
cards[i].setIcon(photo); //set background image
cards[i].addActionListener(clickIt); //when you click it
cardDisplay.add(cards[i]); //show them all
System.out.println("background displayed");
//sysprint statements are for testing the output stream only
}
}
private class ButtonClickEventHandler implements ActionListener{
private int q = 0; //# of clickes, like switch statement w/o userinput
private int l; // = 0; records number location when clicked
#Override
public void actionPerformed(ActionEvent e) {
for(int i = 0; i < 12; i ++){
if (q == 0){ //at zero all enabled cards/buttons are face up
if(cards[i] == e.getSource()){//first card clicked //start state
System.out.println("q is 0");
System.out.println("Selection was number " + i);
l = i; // record the click for the next state.
//sets the icon to a cat image w/num [flipped num]
cards[i].setEnabled(false);
// prevents user from clicking the same card twice for a match
cards[i].setIcon(catImg[flippedNum[i]])
cards[i].setDisabledIcon(catImg[flippedNum[i]]);
//prevents the icon from being grayed out when clicked
//setting the icon and THEN the disabled icon shows
//non gray'd out image when clicked that cannot be clicked again
q = 1;
System.out.println("q is now 1");
}
}
else if(q == 1) { //if one card is already clicked, second click
System.out.println("q was not 0, now is 1");
if(cards[i] == e.getSource()){
cards[i].setIcon(catImg[flippedNum[i]]);
System.out.println("first was " + flippedNum[l] + " Second was " + flippedNum[i]);
cards[i].setIcon(catImg[flippedNum[i]]);
q = 2;
}
if(q == 2){
System.out.println("Timer started");
cards[l].doClick(1500);
//i tried moving this up to before q=2, no luck
if(flippedNum[l] == flippedNum[i]){
System.out.println("They Match!!");
cards[i].setEnabled(false);
// permanenty sets the button as disabled
cards[l].setEnabled(false);
q=0;
System.out.println("end of turn q is zero, find another match");
}else {
System.out.println("Dont Match");
cards[i].setEnabled(true);
cards[l].setEnabled(true);
cards[i].setIcon(photo);
cards[l].setIcon(photo);
q = 0;
System.out.println("end of turn, back to start, q = 0");
}
}
}
}
}
}
}
The code SHOULD let the user click on one image where it is displayed and disabled so you can't click it a second time and match it to itself. the second click SHOULD reveal the second card (it doesn't) and start the timer (it does)
with in the q=2 section, the match check is still preformed on the image the user can't see and the timer still flips the first card back over after 1500mills. and if there is a match both cards should stay image side up (it does) and grayed out (it doesn't unless i remove the cards[i].setEnabled, even the previously unseen card turns gray when the .setEnabled is off in the q=0 statement)
I've had teachers, tutors, and friends look over this without any progress, PLEASE help. ty.
SAMPLE OUTPUT:
background displayed
// this is printed 12 times
//once for each card
Selection was number 1 // selected the 4th card in the first row
q is now 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
//selected the second card in the first row which did not "Show"
q was not 0, now is 1
q was not 0, now is 1
first was 6 Second was 1
Timer started
Don't Match// first card flipped back to background after 1.5 seconds
end of turn, back to start, q = 0
q is 0
Selection was number 2 // selected 3rd card in first row
q is now 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
q was not 0, now is 1
first was 6 Second was 6 // second image selected, didn't show
Timer started
They Match!! // both images are revealed! neither is gray'd out
end of turn q is zero, find another match
Basically, based on your code doClick(long) will make the button appear pressed, it will not delay the code and will cause actionPerformed to be called again ... when you really don't want it to be.
The solution you seem to be looking for is a Swing Timer, see How to use Swing Timers for more details
I butchered your code a little to get "something" working, it will at least display the second card 1.5 seconds.
private class ButtonClickEventHandler implements ActionListener {
private int q = 0; //# of clickes, like switch statement w/o userinput
private int l; // = 0; records number location when clicked
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < 12; i++) {
if (q == 0) { //at zero all enabled cards/buttons are face up
if (cards[i] == e.getSource()) {//first card clicked //start state
System.out.println("q is 0");
System.out.println("Selection was number " + i);
l = i; // record the click for the next state.
//sets the icon to a cat image w/num [flipped num]
cards[i].setEnabled(false);
// prevents user from clicking the same card twice for a match
cards[i].setIcon(catImg[flippedNum[i]]);
cards[i].setDisabledIcon(catImg[flippedNum[i]]);
//prevents the icon from being grayed out when clicked
//setting the icon and THEN the disabled icon shows
//non gray'd out image when clicked that cannot be clicked again
q = 1;
System.out.println("q is now 1");
break;
}
} else if (q == 1) { //if one card is already clicked, second click
System.out.println("q was not 0, now is 1");
if (cards[i] == e.getSource()) {
cards[i].setIcon(catImg[flippedNum[i]]);
System.out.println("first was " + flippedNum[l] + " Second was " + flippedNum[i]);
flipFlop(l, i);
q = 0;
break;
}
}
}
}
protected void flipFlop(int l, int i) {
Timer timer = new Timer(1500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Timer started");
//cards[l].doClick(1500);
//i tried moving this up to before q=2, no luck
if (flippedNum[l] == flippedNum[i]) {
System.out.println("They Match!!");
cards[i].setEnabled(false);
// permanenty sets the button as disabled
cards[l].setEnabled(false);
System.out.println("end of turn q is zero, find another match");
} else {
System.out.println("Dont Match");
cards[i].setEnabled(true);
cards[l].setEnabled(true);
cards[i].setIcon(photo);
cards[l].setIcon(photo);
System.out.println("end of turn, back to start, q = 0");
}
}
});
timer.setRepeats(false);
timer.start();
}
}
You actionPerformed method could use a little more optimising, once you have established some action, you should break out of the loop, as no further processing should be done, let's face it, once you know which button was clicked and if it was the first or second button, why should you keep iterating?

How does Java applet use the item selected in a JComboBox

The goal of the current program is to create a line, of varying thickness, between two points in a window frame. So far, so good.
Next, I would like the program to recognize that the user has made a selection from the JComboBox.
This post, and the code, have been updated. (a) the itemStateChanged method was removed. It was not executed, and so, did not need to be in the program. (b) the actionPerformed method was updated to update whenever any of the objects were modified. (c) the color choice was implemented in perhaps one of the ugliest switch/case statements ever. (there must be a better way). And (d) I implemented the suggestion from Itamar Green, regarding the definition of the JComboBox. Thank you.
What don't I know?
Notes: Java 8.111. O/S: Windows 8.1. IDE: Ecilpse Java EE 4.6.0
All responses towards improving the code or the question are gratefully accepted.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class ThickPen extends JApplet implements ActionListener
{
private static final long serialVersionUID = 1L;
JLabel xStartLabel = new JLabel("X Start");
JLabel yStartLabel = new JLabel("Y Start");
JLabel xStopLabel = new JLabel("X Stop");
JLabel yStopLabel = new JLabel("Y Stop");
JLabel thickLabel = new JLabel("Thickness");
JComboBox<String> myColour;
String theColour = "black";
TextField xStartField = new TextField(4);
int xStart = 0;
TextField yStartField = new TextField(4);
int yStart = 0;
TextField xStopField = new TextField(4);
int xStop = 0;
TextField yStopField = new TextField(4);
int yStop = 0;
TextField thicknessField = new TextField(4);
int thick = 0;
String[] colourString = {"black","blue","cyan","darkgray","gray","green",
"lightGray","magenta","orange","pink","red","white","yellow"};
int theIndex = 0;
public void init()
{
setSize(550,500);
Container content = getContentPane();
setLayout(new FlowLayout());
xStartField.addActionListener(this);
yStartField.addActionListener(this);
xStopField.addActionListener(this);
yStopField.addActionListener(this);
thicknessField.addActionListener(this);
add(xStartLabel);
add(xStartField);
add(yStartLabel);
add(yStartField);
add(xStopLabel);
add(xStopField);
add(yStopLabel);
add(yStopField);
add(thickLabel);
add(thicknessField);
myColour = new JComboBox<String>(colourString);
// JComboBox<String> myColour = new JComboBox<String>(colourString);
myColour.setSelectedIndex(0); // start with black
myColour.addActionListener(this);
add(myColour);
content.setBackground(Color.white);
content.setForeground(Color.black);
}
public void paint(Graphics g)
{
super.paint(g);
Dimension d = getSize();
int fullWidth = d.width;
int fullHeight = d.height;
int deltaX = 0;
int deltaY = 0;
boolean xAxis = false;
System.out.println("So far Start x y: "+xStart+" "+yStart+" color: "+theColour);
if (xStart < 1 || xStart > fullWidth
|| yStart < 1 || yStart > fullHeight
|| xStop < 1 || xStop > fullWidth
|| yStop < 1 || yStop > fullHeight
|| thick < 1 || thick > fullHeight || thick > fullWidth) {
String outStr = "Start and stop numbers must be within this window frame";
String outStr2 = "Current width: "+fullWidth+" height: "+fullHeight;
g.setColor(Color.white);
g.fillRoundRect(d.width/4, d.height/4, 300, 40, 4, 4);
g.setColor(Color.red);
g.drawString(outStr, d.width/4+10, d.height/4+15);
g.drawString(outStr2, d.width/4+10, d.height/4+30);
g.drawString("The index: "+theIndex, d.width/4, 300);
} else {
g.drawString("", d.width/4, 260);
deltaX = Math.abs(xStart - xStop); // determine absolute delta of two Xs
deltaY = Math.abs(yStart - yStop); // determine absolute delta of two Ys
if (deltaX > deltaY) // make line thickness based on x axis if
xAxis = false; // the x axis has the most 'room'.
else // else, use the y axis.
xAxis = true;
pickAColour(g, theColour);
drawMyLine(g, xStart, yStart, xStop, yStop, thick, xAxis);
}
g.drawString("The index: "+theIndex, d.width/4, 300);
g.drawString("The color "+ theColour, d.width/4, 330);
}
public void drawMyLine(Graphics g, int xStart, int yStart,
int xStop, int yStop, int thick, boolean xAxis)
{
int count = 0;
while (count < thick)
{
g.drawLine(xStart, yStart, xStop, yStop);
count++;
if (xAxis) {
xStart++;
xStop++;
} else {
yStart++;
yStop++;
}
}
}
public void pickAColour(Graphics g, String theColour)
{
switch (theColour) {
case "black" :
g.setColor(Color.black);
break;
case "blue" :
g.setColor(Color.blue);
break;
case "cyan" :
g.setColor(Color.cyan);
break;
case "darkgray" :
g.setColor(Color.darkGray);
break;
case "gray" :
g.setColor(Color.gray);
break;
case "green" :
g.setColor(Color.green);
break;
case "lightGray" :
g.setColor(Color.lightGray);
break;
case "magenta" :
g.setColor(Color.magenta);
break;
case "orange" :
g.setColor(Color.orange);
break;
case "pink" :
g.setColor(Color.pink);
break;
case "red" :
g.setColor(Color.red);
break;
case "white" :
g.setColor(Color.white);
break;
case "yellow" :
g.setColor(Color.yellow);
break;
} // end of case statement
} // end of pickAColour
public void actionPerformed (ActionEvent ae)
{
Object source=ae.getSource();
// xStart
// if (source==xStartField)
// {
try {
xStart=Integer.parseInt(
xStartField.getText());
}
catch (NumberFormatException x) {
xStart= -1;
}
// }
// yStart
// else if (source==yStartField)
// {
try {
yStart=Integer.parseInt(
yStartField.getText());
}
catch (NumberFormatException x) {
yStart= -1;
}
// }
// xStop
// else if (source==xStopField)
// {
try {
xStop=Integer.parseInt(
xStopField.getText());
}
catch (NumberFormatException x) {
xStop= -1;
}
// }
// yStop
// else if (source==yStopField)
// {
try {
yStop=Integer.parseInt(
yStopField.getText());
}
catch (NumberFormatException x) {
yStop= -1;
}
// }
// thickness
// else if (source==thicknessField)
// {
try {
thick=Integer.parseInt(
thicknessField.getText());
}
catch (NumberFormatException x) {
thick= -1;
}
// } else {
if (source==myColour) {
JComboBox<String> cb = (JComboBox<String>)ae.getSource();
// String theColour = (String)cb.getSelectedItem(); ///can;
// Integer theIndex = (int)cb.getSelectedIndex();
theColour = (String)cb.getSelectedItem();
theIndex = (int)cb.getSelectedIndex();
}
// }
repaint();
} // end of ActionEvent
} // end of class
Simply put this
myColour = new JComboBox<String>(colourString);
instead of this
JComboBox<String> myColour = new JComboBox<String>(colourString);
in your init method.
The problem is the difference between the myColour defined here (in member section)
JComboBox<String> myColour;
and the one created in the init(). You are initializing the one in the Init but not the one in the member section, so when you are trying to use myColour in actionPreformed, Java is trying to call methods from a reference with no object.

Can not complete drawline on JButton [closed]

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

Programmatically swap two JPanels in JFrame

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.

Categories

Resources