Yes, this is homework. Yes, I am completely stuck.
Here is the gist. I have created a JFrame. There are 3 panels (top, middle, bottom). In the bottom panel are 3 buttons called: Red, Green, and Blue. In the top Panel are 3 text fields that give us the number of times we have clicked the respective button. The max we are allowed is 10 for each button. In the middle Panel is an 8 x 8 grid of Jbuttons numbered from 0 to 63. So far, so good.
Every time we click a button, a thread starts. No thread ever dies When a thread starts, a number from 0 to 63 is randomly chosen. The JButton corresponding to that number is painted the color that was clicked on. So if the red button was clicked, we should see a box with a white background turn red. But then the color of that JButton starts to fade until it becomes white. The process should take about 8 seconds.
Threads that you create should not have access to any Swing components. Rather, one has to maintain a data structure and update by threads according to their cycle of execution. On the other hand, periodically invoke repaint() methods from main thread to invite Swing Event Dispatcher thread to eventually visit the content of the data structure and display the GUI components accordingly.
........ I have gotten all the objects created and displayed. You can't click more than 10 times on a button. Here is where I am:
I have two arrays: one is an array of strings with size 64. They represent the buttons. I also have an array of ints. This is so that I know the order by which the threads were created. I have created the threads as a button is clicked, and I have started them. Here is my run method for the threads:
public void run() {
Random num = new Random(new Date().getTime());
while (true) {
Thread j = Thread.currentThread();
int randInt = num.nextInt(64);
synchronized (lock) {
if ((array[randInt].compareTo("red") == 0
|| array[randInt].compareTo("blue")
== 0 || array[randInt].compareTo("green") == 0))
{
randInt = num.nextInt(64);
}
for (int k = 0; k < 10; k++) {
if (threadarray[k] == -1) {
threadarray[k] = randInt;
break;
}
}
}
}
}
Even though we haven't covered it, I have tried to use a Timer object that immediately goes off right outside of the lock section. This takes me to the actionPerformed method. I have added all the appropriate registration.
public void actionPerformed(ActionEvent arg0) {
for (int i = 0; i < threadarray.length; i++) {
int num = threadarray[i];
if (num != -1) {
System.out.println(num);
String s = array[num];
System.out.println(s + "is ");
if (s.compareTo("red") == 0) {
button[num].setOpaque(true);
button[num].setBackground(Color.red);
while (button[num].getBackground() != Color.white) {
System.out.println("not white yet");
int g = button[num].getBackground().getGreen();
int b = button[num].getBackground().getBlue();
if (255 - (g + 1) >= 0) {
Color c = new Color(255, g + 1, b + 1, 1);
button[num].setOpaque(true);
button[num].setBackground(c);
System.out.println(c + " " + " c is");
} else {
button[num].setBackground(Color.white);
}
}
}
System.out.println(i + " i is " + button[num].getBackground()); //just some debugging info
threadarray[i] = -1; //clear the thread array
array[num] = "0"; //clear the string array
}
}
}
The actionPerformed method is handled by the Event Dispatch Thread. (Note the code immediately above is for the red threads only. The idea is to fade the color by inclemently increasing the green and blue colors till it becomes white.
Problems: no button ever changes color when I click the red button on bottom (yes, appropriate registration has been done.) I also have no idea how to control the timing with a multitude of threads going. Am I even going down the right road here?
Without giving away too much, this example illustrates a way to deal with color and buttons that ignore setBackground(). Examples here and here demonstrate how to fade the color. As both rely on a javax.swing.Timer thread, neither is a solution, but the techniques may prove useful.
Related
I have found some other similar questions but they do not really answer my question.
Currently I'm making a game and I want this object on the screen to cycle through the rainbow colours.
This class has a method called tick and render; each of these is run every game tick. I didnt even bother running the example below as i dont know how to approach this question.
Color c;
int r=0,g=0,b=0;
boolean ascending = true;
public void tick(){
while(ascending) {
if(r <= 255)
r++;
else
break;
if(g <= 255)
g++;
else
break;
if(b <= 255)
b++;
else
break;
}
}
I want this object on the screen to cycle through the rainbow colours.
Create an ArrayList of Color objects to represent the colors of the rainbow.
Create a Swing Timer for the animation.
Each timer the Timer fires you get the Color object at index 0 from the ArrayList at set the color of your component.
Then remove the Color object at index 0.
When the ArrayList is empty, you stop the Timer.
See: Timer doesn't stop. Trying to do clicks for n steps for a basic example that updates the time for 10 seconds and then stops.
So I'm working on a project and was wondering how to put multiple listeners on one button. I want to be able to setText of certain text fields and start the game in one button press. However, the text fields aren't updated until the game finishes. ( I only put the code I thought was relevant, which the button press, I only put in one case from the switch since they're pretty similar).
I was thinking that if the button could have multiple event listeners, it could run two separate methods to set text fields and play the game in one click. The input comes from a different event listener.
private void startActionPerformed(java.awt.event.ActionEvent evt) {
Scanner input = new Scanner(System.in);
/**Prompts the user for their name*/
System.out.println("What is your name?: ");
/**Plays the game*/
if((Hyd > 0 && Hung > 0) && (Temp > 0 && Rest > 0)){
try{
Deck cards = new Deck();
cardNum = ((int)(Math.random() * 5) + 1);;
/**Plays a specific card method depending on the randomly generated number*/
switch (cardNum)
{
case 1: question = ("You've run into a bear!");
greenChoice = ("Green Button: You RUN away!");
redChoice = ("Red Button: You FIGHT the bear!");
// i want to change this textfield as soon as the button is clicked
questionK.setText(question);
System.out.println("(Hold the button you choose until the game replies)");
/**Count down timer for the user*/
for (int i = 10; i >= 0; i--)
{
System.out.println("Timer: " + i);
Thread.sleep(i * 350);
}
The simple version is that I'm drawing Graphics2D 60 times a second on a JPanel and it uses the drawstring method to create a bunch of labels. How would I go about making so I can click on those labels and have something happen?
Explanation: As it currently stands I have a system setup that says for every object in the world draw a string to the side (So I can see a list of all objects in the world). This is done with a for loop and the Graphics2D drawstring method.
The JPanel is being updated 60 times a second so this is being redrawn 60 times a second. I want to be able to click on these object labels so I can select the items, how would I go about turning them into buttons?
I messed around with JButton for awhile but it didn't seem to do me any good because whenever I added it the JPanel would go blank and only the button would render (Plus it didn't render to the right size).
More Details:
I use a
for(int I=0; I < sceneObjects.size(); I++) {
}
loop to grab every object in an object ArrayList. Each object has a String variable "Name". Before the loop class I sent an int called YPosition, and for every object the YPosition goes up by 20 so that the labels don't all stack on top of each other. I'm using the g2d.DrawString method to achieve this. But I need to be able to select the object labels.
I apologize if I forgot something in my question, let me know.
For those who are curious, the code looks exactly like this (Can't be compiled as is):
g2d.setFont(new Font("Arial", Font.PLAIN, hierarchyWidth / 26));
g2d.setColor(Color.black);
int oYPos = 20;
// For every object in existence
for(int i=0; i < engine.sceneObjects.activeObjects.size(); i++) {
GameObject theObject = engine.sceneObjects.activeObjects.get(i);
// If the scrollbar is within range of the hierarchy
// (Based on HierarchyHeight so that it's resolution friendly)
if(oYPos >= hierarchyScroll && oYPos < hierarchyScroll + hierarchyHeight) {
// If the object has no parent
if(theObject.transform.parent == null) {
g2d.drawString(theObject.name, hierarchyPosition.x + 5, hierarchyPosition.y + oYPos);
} else { // If the object has a parent
}
}
oYPos += 20;
}
// Track the last oYPos so that the scrollbar can adjust itself accordingly
lastOYPos = oYPos;
My guess would be some sort of class create for each of these labels and a Boolean stored called isSelected, and then rendering the label according to the class, but this seems a bit more complicated than I'd like to do
Given a greenLightDuration and a yellowLightDuration, I need to switch lights (including red Light) based on duration. This all happens inside a run method for the traffic light. The reason for the run method is because it is used when running the entire simulation (trafficLight is an Agent).
//Run method for agents in Model
public void run(double duration) {
if (disposed)
throw new IllegalStateException();
for (int i=0; i<duration; i++) {
time++;
for (Agent a : agents.toArray(new Agent[0])) {
a.run(time);
}
super.setChanged();
super.notifyObservers();
}
}
In Light I have the run method...
public void run(double runTime){
double check_time = runtime - time;
if(check_time >= yellowLightDuration&& color == Color.RED){
color = Color.GREEN;
time = runtime;
}else if(check_time >= greenLightDuration&& color == Color.GREEN){
color = Color.RED;
time = runtime;
}
...but it was just something silly I did to get the lights switching from red/green and obviously does not work for yellow or is not proportionate to green/yellow light duration(I don't think).
For color I use
Color.RED, Color.YELLOW, Color.GREEN from java.awt.Color.
public void run(double runtime){
if(this.color == Color.GREEN){
if(time%greenLightDuration==0){
color = Color.YELLOW;
}
}
if(this.color == Color.YELLOW){
if(time%yellowLightDuration == 0){
color = Color.RED;
}
}
else
color = Color.GREEN;
}
Tried this but the three colors are blinking furiously. I set green to 200 and yellow to 40.
Since this is a cycle, you want to get the current phase of the cycle using the modulus operator. Something like: double phase = (runTime - startTime) % (greenDuration + yellowDuration + redDuration). You can take the modulus of a floating-point number in Java.
the three colors are blinking furiously.
The first/main cause of this is the simulator/model, and not necessarily the traffic light (though your traffic light my still be a problem). The issue is that your current model for time is just some sketchy for-loop, which will run however fast it runs... and it clearly runs a lot faster than your eyes would like.
What you can do is attempt to control the time in your simulation, using Thread.sleep() to delay the program momentarily. The following version will run an iteration roughly once per millisecond...
//Run method for agents in Model
public void run(double duration) {
if (disposed)
throw new IllegalStateException();
for (int i=0; i<duration; i++) {
time++;
try{ Thread.sleep(1); } //wait 1ms
catch(Exception e){} //just resume after interruption
for (Agent a : agents.toArray(new Agent[0])) {
a.run(time);
}
super.setChanged();
super.notifyObservers();
}
}
Now a duration of 300 for green lights takes roughly 0.3 seconds, which is brisk but not unobservable.
In my program, there is a button, "Display", and another button, "Reset".
The user enters the number of prime numbers they want in the text field and then clicks the "Display" button. Then, the first x prime numbers will appear in the text area.
In the code, I have:
Declarations:
Thread go;
Thread newThread;
JLabel howManyLabel;
JTextField howMany;
JButton display;
JButton reset;
JTextArea primes;
Action Event:
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == display) {
display.setEnabled(false);
if (go == null) {
go = new Thread(this);
go.start();
} else {
newThread = new Thread(this);
newThread.start();
}
} else if (source == reset) {
display.setEnabled(true);
howMany.setText(" ");
primes.setText(" ");
}
}
Run method:
public void run() {
int quantity = Integer.parseInt(howMany.getText());
int numPrimes = 0;
int candidate = 2; // candidate = the number that MIGHT be prime
primes.append("First " + quantity + " primes:");
while(numPrimes < quantity) {
if (isPrime(candidate)) {
primes.append(candidate + ", ");
numPrimes++;
}
candidate++;
}
}
The run() method is in the same class, and simply calculates the first x amount of prime numbers.
I am trying to create a new thread every time the "Reset" button is called. The thread runs the first time, but then does not run again after I click "Reset". Can the run() method only work once?
Thanks in advance.
The run() method is just like any other method and can be invoked any number of times. The method that cannot be invoked multiple times is start()(according to Thread).
Your explanation does not seem to fit with the code you gave. You say you want to spawn a new thread when a user clicks reset, yet you only construct or start threads if the source is Display. Did you mean, rather, that you want to cancel the last thread and enable controls for the user to start again? In that case you should use a Future, not a generic thread.
Another thing is that UI components are generally not thread-safe. Swing explicitly warns against it on every components JavaDoc. What you may be seeing is just components not updating their visible state when they are changed from a different thread. Have you tried using a debugger to see if a thread is actually not getting spawned, or it is being spawned, but not having the result you want?