Program unable to add text to JTextArea - java

I have made a program which makes a GUI called Window() and instructs my Finch robot to follow an object. When I run the program , there is no text added to JTextArea. It should say Please Tap Finch to Activate.
My program tells me that this line is the source of error:
NewOption5.feed.append("Please Tap Finch to Activate!");
Console :
Connecting to Finch...this may take a few seconds...
Exception in thread "main" java.lang.NullPointerException
at NewOption5.ProgramFollow(NewOption5.java:58)
at NewOption5.main(NewOption5.java:12)
Code :
import edu.cmu.ri.createlab.terk.robot.finch.Finch;
import java.awt.*;
import javax.swing.*;
public class NewOption5 {
static JTextArea feed;
static Finch myFinch = new Finch();
public static void main(String[] args) {
//Calling Window
// myFinch = new Finch();
Window();
ProgramFollow();
}
// Method for creating a GUI
//static Finch myFinch = new Finch();
public static void Window()
{
// Create the window
JFrame x = new JFrame("Finch Mission : Follow an Object!");
// How the window should be closed
x.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Adding a layout manager
x.setLayout(new FlowLayout());
// Adding components ( significantly a JTextArea being a feedback box )
x.add(new JButton("Halt!"));
x.add(new JButton("Exit"));
final JTextArea feed = new JTextArea(30,50);
JScrollPane feedscroll = new JScrollPane(feed);
x.add(feedscroll);
// Arrange components neatly inside the window
x.pack();
// Making the window visible once Window is called
x.setVisible(true);
// ProgramFollow();
}
public static void ProgramFollow() {
// Loop to wait for Finch to be tapped and an obstacle detected in front of the Finch
boolean StartProgram;
NewOption5.feed.append("Please Tap Finch to Activate!");
while (StartProgram = true)
{
// Sending message to the feedback box
feed.append("Please Tap Finch to Activate!");
// Conditional statement for same thing as mentioned above
if (myFinch.isTapped()==true && myFinch.isObstacleLeftSide()==true && myFinch.isObstacleRightSide()==true)
{
NewOption5.feed.append("Finch is activated! Object is detected");
myFinch.setLED(red,0,0);
myFinch.setWheelVelocities(leftVelocity, rightVelocity);
// Triggers RunAgain to true so the program doesnt stop in one run in order for Finch to move continuosuly
boolean RunAgain=true;
while(RunAgain)
{
// Calling Movement method for Finch movements
Movement();
// Inside while(RunAgain loop , there is a conditional statment which makes the Finch terminate the program after tapping it twice
if (myFinch.isTapped()==true && myFinch.isTapped()==true)
{
}
}
}
}
}
// Method for Finch movements
public static void Movement()
{
if (myFinch.isObstacleLeftSide()==false && myFinch.isObstacleRightSide()==false)
{
// send message to the feedback box ("Object is Detected! Following it now!");
NewOption5.feed.append("Following the Object now!");
StraightMovement();
}
else if (myFinch.isObstacleLeftSide()==true && myFinch.isObstacleRightSide()==false)
{
NewOption5.feed.append("Object detected on the left side");
LeftMovement();
}
else if (myFinch.isObstacleLeftSide()==false && myFinch.isObstacleRightSide()==true)
{
NewOption5.feed.append("Object detected on the right side");
RightMovement();
}
else if (myFinch.isObstacleLeftSide()==true && myFinch.isObstacleRightSide()==true)
{
NewOption5.feed.append("Stopped now");
StopMovement();
}
}
// Area of variables declaration for easy value modifications
static int Buzz = 340;
static int BuzzDuration = 10;
static int red = 255;
static int green = 255;
static int leftVelocity = 100;
static int rightVelocity = 100;
static int leftTurnV = -50;
static int rightTurnV = -50;;
// Area of variables declaration for easy value modifications
public static void StraightMovement()
{
myFinch.setLED(0, green, 0);
myFinch.setWheelVelocities(leftVelocity, rightVelocity);
myFinch.buzz(Buzz, BuzzDuration);
}
public static void LeftMovement()
{
myFinch.setLED(0, green, 0);
myFinch.setWheelVelocities(leftTurnV, rightVelocity);
myFinch.buzz(Buzz, BuzzDuration);
}
public static void RightMovement()
{
myFinch.setLED(0, green, 0);
myFinch.setWheelVelocities(leftVelocity, rightTurnV);
myFinch.buzz(Buzz, BuzzDuration);
}
public static void StopMovement()
{
myFinch.setLED(red, 0 , 0);
myFinch.stopWheels();
myFinch.buzz(Buzz, BuzzDuration);
}
}

You do not initialize feed correctly.
final JTextArea feed = new JTextArea(30,50);
This does not initialize the field feed but instead creates a new local variable of the same name.
Try turning final JTextArea feed = new JTextArea(30,50); into feed = new JTextArea(30,50);.

Related

Using multi-threading to pause my application does not behave as expected

I am designing a matching memory game, I am almost done with it and everything is working as it should be, however, when the user has opened two different cards the program won't pause(wait) few seconds so the user can see what the second card was.
I have tried using a long for loop operation but encountered the same problem. I have tried Thread.sleep, TimeUnit.SECONDS.sleep, Task and Platform.runLater.
The program opens the card and closes it instantly THEN it waits for the specified duration, keeping in mind that I am calling pauseThread after open and before close functions.
I have tried the above suggestions but they are leading me no where and I can't seem to find where the problem is with my code or where should I place the pauseThread. Thanks in advance.
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class MemoryMatchingGame extends Application{
private static Card selectedCard=null; // This is to save a reference for the first card to use in comparison
private static int numOfCorrectPairs = 0; // Keeping track of how many cards the user got correct
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
String[] images = {"C:\\Users\\userName\\Desktop\\Project#4\\1.png", // This is a string array to store images locations
"C:\\Users\\userName\\Desktop\\Project#4\\2.png",
"C:\\Users\\userName\\Desktop\\Project#4\\3.jpg",
"C:\\Users\\userName\\Desktop\\Project#4\\4.jpg",
"C:\\Users\\userName\\Desktop\\Project#4\\5.jpg",
"C:\\Users\\userName\\Desktop\\Project#4\\6.png",
"C:\\Users\\userName\\Desktop\\Project#4\\7.jpg",
"C:\\Users\\userName\\Desktop\\Project#4\\8.jpg"};
ArrayList<Card> listOfCards = new ArrayList<Card>();
for(int i=0; i<images.length; i++) { // This for loop will add each image twice to the array list
listOfCards.add(new Card(images[i]));
listOfCards.add(new Card(images[i]));
}
Collections.shuffle(listOfCards); // Shuffling the deck of cards
primaryStage.setTitle("Memory Matching Game");
HBox hb = new HBox();
VBox firstColoumn = new VBox();
for(int i=0; i<4; i++)
firstColoumn.getChildren().add(listOfCards.get(i));
VBox secondColoumn = new VBox();
for(int i=4; i<8; i++)
secondColoumn.getChildren().add(listOfCards.get(i));
VBox thirdColoumn = new VBox();
for(int i=8; i<12; i++)
thirdColoumn.getChildren().add(listOfCards.get(i));
VBox fourthColoumn = new VBox();
for(int i=12; i<16; i++)
fourthColoumn.getChildren().add(listOfCards.get(i));
hb.getChildren().addAll(firstColoumn, secondColoumn, thirdColoumn, fourthColoumn);
Scene scene = new Scene(hb, 460, 450);
primaryStage.setScene(scene);
primaryStage.show();
}
private class Card extends Button {
private String imageLocation; // To store the destination of the image
private Image img; // To store a reference of the image to be used when setting graphic on a button
public Card(String imageLocation) throws FileNotFoundException {
this.imageLocation = imageLocation;
FileInputStream fis = new FileInputStream(imageLocation);
img = new Image(fis);
setPrefSize(150, 150);
setOnMouseClicked(e -> {
if(isCardOpen()==true)
return; // To ensure no action is made once an image is already opened and the user clicked on it again
if(selectedCard==null) {// This will test if the user has a card open already for comparison or not, if not it will store a reference to the card to use to compare once another card is opened
selectedCard = this;
open();
}
else { // If we enter this statement, this means the user has a card open already and we are ready to perform comparison
open(); // First action taken is to reveal the second card then perform comparison
if(this.isEqual(selectedCard)) {
numOfCorrectPairs++;
System.out.println("Got one");
}
else {
//Get program to pause here
Hold pauseThread = new Hold();
pauseThread.run();
System.out.println("After pausing");
this.close();
selectedCard.close();
}
selectedCard=null; // This will nullify the variable so that we are able to perform comparison again for two other cards
} // End of else statement
}); // End of actionHandler
close(); // This will ensure whenever a card is created it is set face-down
}
private void close() {
setGraphic(null);
}
public void open() {
setGraphic(new ImageView(img));
System.out.println("Open");
}
private boolean isCardOpen() {
return this.getGraphic()!=null;
}
private boolean isEqual(Card selectedCard) {
return this.imageLocation.equals(selectedCard.imageLocation);
}
}
private class Hold extends Thread{
public void run() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Everything in your code is running in the JavaFX Application Thread. You don't want to pause this thread because it will lock your GUI. As has already been mentioned, you are starting another thread and putting it to sleep, but this doesn't add delay to your GUI that is running in the JavaFX Thread.
An alternative approach would be to use Platform.runLater(). The Hold thread can invoke a method in the JavaFX thread that implements a Platform.runLater() runnable. The runnable is a short lambda that holds the code to close the selected card. The timing may vary slightly from 3000 ms, but you don't have much going on in the JavaFX thread and it doesn't seem critical for this application.
Here are the modifications to try.
First modify the Hold class to include a constructor to pass in the Card object. Then call the closeAfterPause() method on card.
private class Hold extends Thread {
private Card card;
public Hold(Card card) {
this.card = card;
}
public void run() {
try {
TimeUnit.SECONDS.sleep(3);
card.closeAfterPause();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Then create the closeAfterPause() method in the MemoryMatchingGame class.
private void closeAfterPause() {
Platform.runLater(() -> {
System.out.println("After Pausing");
close();
selectedCard.close();
});
}
Then modify the else part of your if-else statement as follows
else {
//Get program to pause here
Hold pauseThread = new Hold(this);
new Thread(pauseThread).start();
}
FX comes with a rich set of Animation/Timeline support - there's no need for falling back onto bare Threads. The most simple form of getting wait-for-xx is to use a Timeline configured with xx and an actionHandler that does something when ready:
Timeline holdTimer = new Timeline(new KeyFrame(
Duration.seconds(2), e -> closeCards()));
Also it's a good idea to centralize all logic outside of a Control. Actually, you should never-ever extend a view for the purpose to include view-unrelated logic. So your long-time goal should be to
extract all single card logic from Card into a CardModel which exposes properties like f.i. image, id, open, disposed
use a plain Button, configure and bind its properties to model properties as appropriate
centralize all game logic like timing, selecting, when opening is allowed, when succeed into a game controller
As I don't want to spoil your fun in doing that - I'll just post a little outline in the direction of the last bullet. Its responsibilities so far
provide api to open a single card
provide api to end a turn: either match or close cards
internals to keep track of opened cards and timing
The snippets just re-mixes your code a bit, moving game logic from the button into the controller (aka: here simply the outer class) and setting the button's action handler to access the controller.
private Card firstCard;
private Card secondCard;
private Timeline holdTimer = new Timeline(new KeyFrame(
Duration.millis(2000), e -> closeCards()));
public void closeCards() {
if (firstCard == null || secondCard == null) {
System.out.println("error!!");
return;
}
if (firstCard.isEqual(secondCard)) {
System.out.println("success");
firstCard.setDisable(true);
secondCard.setDisable(true);
firstCard = null;
secondCard = null;
} else {
firstCard.close();
secondCard.close();
firstCard = null;
secondCard = null;
}
}
public void openCard(Card card) {
if (card.isCardOpen()) return;
if (holdTimer.getStatus() == Status.RUNNING) return;
if (firstCard == null) {
firstCard = card;
firstCard.open();
} else if (secondCard == null) {
secondCard = card;
secondCard.open();
holdTimer.playFromStart();
}
}
// Dont! dont, dont!!! ever extend a Control
//**TBD**: Move open/close state logic into a CardModel
// then configure a plain Button with the properies of that model
private class Card extends Button {
private String imageLocation; // To store the destination of the image
// private Image img; // To store a reference of the image to be used when setting graphic on a button
public Card(String imageLocation) throws FileNotFoundException {
this.imageLocation = imageLocation;
setPrefSize(150, 150);
setOnAction(e -> openCard(this));
}
public void close() {
setText("");
}
public void open() {
setText(imageLocation);
System.out.println("Open");
}
public boolean isCardOpen() {
return getText() != null && getText().length() > 0;//this.getGraphic()!=null;
}
private boolean isEqual(Card selectedCard) {
if (selectedCard == null) return false;
return this.imageLocation.equals(selectedCard.imageLocation);
}
}

Applet not running java

I'm wondering why my applet isn't running. I'm using netbeans, and the program works fine with no errors, but I can't seem to get the applet screen to appear to test all the functions of my program.I was wondering if someone can point out what I am doing wrong in starting my applet up. I haven't done to many things with applets, so I'm quite curious why it isn't upping and running for me. I really didn't want to post the full code of my program, but I've no idea if there's an error in my code, or I'm just not doing the right thing to actually start the applet or something.
I do not get any errors while running my program, that applet simply does not appear and run in itself. Otherwise I get no errors from neatbeans while running my program.
import java.awt.event.*;
import javax.swing.*;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.FlowLayout;
public class Program7 extends JApplet implements ActionListener, ItemListener
{
//static varaibles
private static int GuiHeight = 90;
private static int Square = 50;
//gui varaibles
private JRadioButton drawSquare;
private JRadioButton mess;
private JTextField messageFeild;
private JCheckBox color;
private JButton button;
private JComboBox location;
//modable global varaibles
private int width, height, drawX, drawY;
private Color drawColor;
private String draw;
#Override
public void init()
{
//creating the panels
JPanel drawChoice;
JPanel drawSet;
//setting group onject to link certain buttons together
ButtonGroup ObjGroup;
//setting layout to make things look nice
setLayout(new FlowLayout());
//ibtializing other varaibles
width = 0;
height = 0;
drawX = 0;
drawY= 0;
drawColor = Color.BLACK;
draw = "";
//intialzing the gui interface
drawSquare = new JRadioButton("Draw a Square!");
mess = new JRadioButton("Write a Message!");
location = new JComboBox(new String[]{"", "Random Pick", "Top Left"});
color = new JCheckBox("Draw in Color!");
button = new JButton("Draw it!");
//linking the buttons together
ObjGroup = new ButtonGroup();
ObjGroup.add(drawSquare);
ObjGroup.add(mess);
//adding event handlers to the buttons
location.addItem(this);
button.addActionListener(this);
color.addItemListener(this);
drawSquare.addActionListener(this);
mess.addActionListener(this);
messageFeild = new JTextField(20);
//adding to the first paels
drawChoice = new JPanel();
drawChoice.add(drawSquare);
drawChoice.add(mess);
drawChoice.add(messageFeild);
//adding to the applet
add(drawChoice);
//adding to the second panel
drawSet = new JPanel();
drawSet.add(new JLabel("Select where to draw!"));
drawSet.add(location);
drawSet.add(color);
drawSet.add(button);
//adding to the applet
add(drawSet);
}
#Override
public void paint(Graphics g)
{
//calling super constructor
super.paint(g);
//getting width
width = getWidth();
height = getHeight();
//setting graphics color
g.setColor(drawColor);
if (location.getSelectedItem() != "")
{
//ifstatement checking for inputs
if(draw == "Square"||draw == "square"||draw == "SQUARE")
{
//creating rectange
g.fillRect(drawX, drawY, width, height);
}
if(draw == "Message"|| draw == "MESSAGE"||draw == "message")
{
//writing message
g.drawString(messageFeild.getText(), drawX, drawY);
}
}
}
#Override
public void actionPerformed(ActionEvent e)
{
//repainting
repaint();
}
#Override
public void itemStateChanged(ItemEvent e)
{
//if statement checking for the various changes being made by the user in the pograms interface
//if statement check checking to see if there's a square or to write a message
if (e.getSource() == drawSquare && e.getStateChange() == ItemEvent.SELECTED)
{
draw = "Square";
messageFeild.setEnabled(false);
}
if (e.getSource() == mess && e.getStateChange() == ItemEvent.SELECTED)
{
draw = "Message";
messageFeild.setEnabled(true);
}
//if statement set checking for locational input
if (e.getSource() == location)
{
if(location.getSelectedItem() == "Random Pick")
{
drawX=(int)(Math.random()*(width+1));
drawY=(int)(GuiHeight+ Math.random()*(height-GuiHeight+1));
}
if(location.getSelectedItem() == "Top Left")
{
drawX=0;
drawY=GuiHeight;
}
}
//if statement to check for color change
if(e.getSource()==color && e.getStateChange()==ItemEvent.SELECTED)
{
drawColor = Color.GREEN;
}
if(e.getSource()==color && e.getStateChange()==ItemEvent.DESELECTED)
{
drawColor = Color.BLACK;
}
}
public static void main(String[] args) {
}
}

Adding text to JTextArea from another class

Basically , I'm trying to make a program that makes the Finch follow the object. I have made two classes : NewOption52 and FollowClass. Class NewOption52 contains a method which determines the properties of the GUI. Class FollowClass contains a main method which calls GUI method from class NewOption52 and it also contains several methods which dictates the Finch's behavior alongside with appending text to JTextArea feed.
When I connect the Finch and run the program , a GUI should appear and inside JTextArea should have text which says ""Please Place An Object in front of Finch And Then Tap Finch to Activate!\n". It didn't happen when I run the program.
Class NewOption52 :
import edu.cmu.ri.createlab.terk.robot.finch.Finch;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JOptionPane;
import javax.swing.*;
public class NewOption52 {
public static NewOption52 Op = new NewOption52();
public static JTextArea feed;
public static JButton halt;
public static JButton exit;
public static JFrame x ;
static protected Finch Grubert = new Finch();
//Method for determining the GUI
static void GUI()
{
final JFrame x = new JFrame("Finch Mission : Follow an Object!") ;
// How the window should be closed
x.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Adding a layout manager
x.setLayout(new FlowLayout());
x.setResizable(false);
x.setLocationRelativeTo(null);
// Adding components ( significantly a JTextArea being a feedback box ) and adding ActionListeners to each button
halt = new JButton("Halt!");
x.add(halt);
halt.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
feed.append("You have halted the program\n");
Grubert.stopWheels();
Grubert.setLED(0, 0, 0);
JOptionPane.showMessageDialog(x,"You have halted the program , click OK to go back and please wait for 3 seconds for Finch to start again");
Grubert.sleep(3000);
x.repaint();
}
});
exit = new JButton("Exit");
x.add(exit);
exit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
Grubert.quit();
System.exit(0);
}
});
feed = new JTextArea(30,60);
JScrollPane feedscroll = new JScrollPane(feed);
x.add(feedscroll);
// Arrange components neatly inside the window
x.pack();
// Making the window visible once Window is called
x.setVisible(true);
}
}
Class FollowClass :
import edu.cmu.ri.createlab.terk.robot.finch.Finch;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class FollowClass {
private static Finch Grubert = null;
private static int TapCount = 0;
public static JTextArea feed;
public static JButton halt;
public static JButton exit;
public static JFrame x ;
//public Finch Grubert = new Finch();
public static void main(String[] args)
{
//refers to first method to start program
NewOption52.GUI();
}
public static void Finch()
{
Grubert = new Finch();
ProgramFollow();
}
private static void ProgramFollow() {
// Loop to wait for Finch to be tapped and an obstacle detected in front of the Finch
boolean StartProgram = true;
NewOption52.feed.append("Please Place An Object in front of Finch And Then Tap Finch to Activate!\n");
while (StartProgram)
{
// Conditional statement for same thing as mentioned above
if (Grubert.isTapped()==true && Grubert.isObstacleLeftSide()==true && Grubert.isObstacleRightSide()==true)
{
feed.append("Finch is activated! Object is detected!\n");
Grubert.setLED(red,0,0);
Grubert.setWheelVelocities(leftVelocity, rightVelocity);
// Triggers RunAgain to true so the program doesnt stop in one run in order for Finch to move continuosuly
boolean RunAgain=true;
while(RunAgain)
{
// Calling Movement method for Finch movements
Movement();
// Inside while RunAgain loop , there is the incremental function called TapCount to determine how many times the Finch has been tapped
if (Grubert.isTapped()==true)
{
TapCount++;
feed.append("You have tapped the Finch. If TapCount = 3 , the program will terminate only if the object is not moving\n");
feed.append("Number of Taps:" + TapCount + "\n");
if (TapCount==3 && Grubert.isObstacleLeftSide()==false && Grubert.isObstacleRightSide()==false)
{
Grubert.stopWheels();
Grubert.setLED(0, 0, 0);
TapCount = 1;
JOptionPane.showMessageDialog(x,"You have tapped the Finch twice when the object is moving. Please click OK and wait for 3 seconds. Make sure the object is not moving in order for program to terminate when you have tapped it twice");
Grubert.sleep(3000);
}
if (TapCount==3 && Grubert.isObstacleLeftSide()==true && Grubert.isObstacleRightSide()==true)
{
Grubert.quit();
System.exit(0);
}
}
}
}
}
}
// Method for Finch movements
private static void Movement()
{
if (Grubert.isObstacleLeftSide()==false && Grubert.isObstacleRightSide()==false)
{
// send message to the feedback box ("Object is Detected! Following it now!");
feed.append("Following the Object now!\n");
StraightMovement();
}
else if (Grubert.isObstacleLeftSide()==true && Grubert.isObstacleRightSide()==false)
{
feed.append("Object detected on the left side\n");
LeftMovement();
}
else if (Grubert.isObstacleLeftSide()==false && Grubert.isObstacleRightSide()==true)
{
feed.append("Object detected on the right side\n");
RightMovement();
}
else if (Grubert.isObstacleLeftSide()==true && Grubert.isObstacleRightSide()==true)
{
StopMovement();
}
}
// Area of variables declaration for easy value modifications
static int Buzz = 500;
static int BuzzDuration = 10;
static int red = 255;
static int green = 255;
static int leftVelocity = 100;
static int rightVelocity = 100;
static int leftTurnV = -50;
static int rightTurnV = -50;;
// Area of variables declaration for easy value modifications
private static void StraightMovement()
{
Grubert.setLED(0, green, 0);
Grubert.setWheelVelocities(leftVelocity, rightVelocity);
Grubert.buzz(Buzz, BuzzDuration);
}
private static void LeftMovement()
{
Grubert.setLED(0, green, 0);
Grubert.setWheelVelocities(leftTurnV, rightVelocity);
Grubert.buzz(Buzz, BuzzDuration);
}
private static void RightMovement()
{
Grubert.setLED(0, green, 0);
Grubert.setWheelVelocities(leftVelocity, rightTurnV);
Grubert.buzz(Buzz, BuzzDuration);
}
private static void StopMovement()
{
Grubert.setLED(red, 0 , 0);
Grubert.stopWheels();
}
}

Problem with Java GUI implementation

I have a problem with the code I am currently trying to run - I am trying to make 3 buttons, put them on a GUI, and then have the first buttons colour be changed to orange, and the buttons next to that colour change to white and green. Every click thereafter will result in the colours moving one button to the right. My code thus far is as follows, it is skipping colours in places and is not behaving at all as I expected. Can anyone offer some help/guidance please ?
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class ButtonJava extends JButton implements ActionListener {
private int currentColor=-1;
private int clicks=0;
private static final Color[] COLORS = {
Color.ORANGE,
Color.WHITE,
Color.GREEN };
private static ButtonJava[] buttons;
public ButtonJava( ){
setBackground( Color.YELLOW );
setText( "Pick ME" );
this.addActionListener( this );
}
public static void main(String[] args) {
JFrame frame = new JFrame ("JFrame");
JPanel panel = new JPanel( );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE);
buttons = new ButtonJava[3];
for(int i = 0;i<buttons.length ; i++){
buttons[i] = new ButtonJava();
panel.add(buttons[i]);
}
frame.getContentPane( ).add( panel );
frame.setSize( 500, 500);
frame.setVisible( true );
}
private void updateButton() {
clicks++;
changeColors();
// setText( );
}
private void changeColors( ) {
for (int i=buttons.length-1;i>=0;i--){
buttons[i].currentColor = nextColor(currentColor);
buttons[i].setBackground(COLORS[buttons[i].currentColor]);
buttons[i].setText(("# of clicks = " + buttons[i].getClicks() ) );
}
}
private Integer getClicks() {
return clicks;
}
private int nextColor( int curCol ) {
final int colLen = COLORS.length;
curCol--;
curCol = (colLen + curCol % colLen) % colLen;
return curCol;
}
private void firstClick( ActionEvent event ) {
int curCol = 0;
for (int i=buttons.length-1;i>=0;i--){
if ( buttons[i] == event.getSource() ) {
buttons[i].currentColor = curCol;
curCol++;
currentColor++;
}
}}
#Override
public void actionPerformed( ActionEvent event ) {
if ( -1 == currentColor ) {
firstClick( event );
}
updateButton( );
}
}
Thank you very much for the help :)
You have a couple issues with the code you posted, but they generally boil down to being clear about what is a member of the class(static) and what is a member of the instance.
For starters, you buttons array only exists inside your main method and can't be accessed by changeColors(). Along those same lines, since changeColors() is an instance method, setBackground() needs to be called directly on the button in your array. as written you are setting the color for one button 3 times.
Additionally, the logic in changeColors() is not properly rotating the currentColor index. You need to both increase the counter and ensure is wraps for the length of the color array. If the arrays are the same size, you need to make sure there is an extra addition to make the colors cycle.
private static void changeColors( ) {
for (int i=0;i<buttons.length;i++){
buttons[i].setBackground(COLORS[currentColor]);
currentColor = nextColor(currentColor);
}
if (buttons.length == COLORS.length) {
currentColor = nextColor(currentColor);
}
}
private static int nextColor(int currentColor) {
return (currentColor+1)% COLORS.length;
}
Edit for new code:
I'm not sure why you re-wrote nextColor(), as what I posted worked. But in general, I feel like you are running into issues because your code is not well partitioned for the tasks you are trying to achieve. You have code related to the specific button instance and code related to controlling all the buttons mixing together.
With the following implementation, the issue of how many times a button was clicked is clearly self-contained in the button class. Then every button press also calls the one method in the owning panel. This method knows how many buttons there are and the color of the first button. And each subsequent button will contain the next color in the list, wrapping when necessary.
public class RotateButtons extends JPanel {
private static final Color[] COLORS = { Color.ORANGE, Color.WHITE, Color.GREEN };
private static final int BUTTON_COUNT = 3;
private JButton[] _buttons;
private int _currentColor = 0;
public static void main(String[] args)
{
JFrame frame = new JFrame("JFrame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new RotateButtons());
frame.setSize(500, 500);
frame.setVisible(true);
}
public RotateButtons()
{
_buttons = new JButton[BUTTON_COUNT];
for (int i = 0; i < _buttons.length; i++) {
_buttons[i] = new CountButton();
add(_buttons[i]);
}
}
private void rotateButtons()
{
for (JButton button : _buttons) {
button.setBackground(COLORS[_currentColor]);
_currentColor = nextColor(_currentColor);
}
if (_buttons.length == COLORS.length) {
_currentColor = nextColor(_currentColor);
}
}
private int nextColor(int currentColor)
{
return (currentColor + 1) % COLORS.length;
}
private class CountButton extends JButton {
private int _count = 0;
public CountButton()
{
setBackground(Color.YELLOW);
setText("Pick ME");
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0)
{
_count++;
setText("# of clicks = " + _count);
rotateButtons();
}
});
}
}
}
2nd Edit:
Shows just the changes to shift _currentColor by the necessary amount on the first click.
public class RotateButtons extends JPanel {
...
private boolean _firstClick = true;
...
private void rotateButtons(CountButton source)
{
if (_firstClick) {
_firstClick = false;
boolean foundSource = false;
for (int i = 0; i < _buttons.length; i++) {
if (foundSource) {
_currentColor = nextColor(_currentColor);
} else {
foundSource = _buttons[i] == source;
}
}
}
...
}
private class CountButton extends JButton {
...
public CountButton()
{
...
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0)
{
...
rotateButtons(CountButton.this);
}
});
}
}
One thing that I noticed is you are using currentColor to assign the color, but the currentColor is initialized to 0 and the only manipulation is currentColor %= 2 which does not change it.
If I'm understanding what you are wanting to achieve, I'm thinking to change currentColor %= 2 to ++currentColor, and setBackground(COLORS[currentColor]); to buttons[i].setBackground(COLORS[(i + currentColor) % 3]);. That way, your colours should cycle around your buttons each time one is clicked.
EDIT: it's probably also worth calling changeColors from within main to initialise your button colours. And, as #unholysampler notes, your array buttons is local to main and should (for example) be refactored as a static member variable, and have changeColors become a static method.

Make a main method wait on a smaller method (java)

i really need to find better ways to word my questions.
Basically I've created a program that takes information from a webpage and displays it nicely across the screen.
When the user closes the program, they actually hide it.
I also have another method which constantly loops checking for information to see if tis been updated.
unfortunately the problem im having is that it loops to fast, i only want it to check for information every 40 seconds or so.
What i tried was inserting a wait(1000,1000) in the method itself and in the main of the program. but both of these cause IllegalMonitorStateException.
Is this the correct way to make the thread wait properly? or is there a better way?
note: the only thread i have is the main.
MAIN
class Marquee
{
public static void main(String[] args) throws InterruptedException
{
MyFrame frame = new MyFrame();
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
frame.setVisible(true);
frame.setAlwaysOnTop(true);
frame.setBackground(Color.BLACK);
frame.setResizable(true);
while(true)
{
// this doesnt work
frame.wait(1000,1000);
frame.notifyAll();
frame.checkForNewUpdate();
System.out.println(" ____________________________next line _______________________________");
}
}
}
CHECK FOR UPDATES
public String[] checkForNewUpdate()
{
//setVisible(true);
String tempUpdate = getEngineersUpdate();
if (latestUpdate[0] != tempUpdate)
{
// do nothign
setVisible(false);
}
else if(latestUpdate[0]==tempUpdate)
{
latestUpdate[0] = tempUpdate;
//show the page again
setVisible(true);
}
else if(latestUpdate[0]!= "NULL")
{
// do nothing
//latestUpdate[0] = tempUpdate;
}
else
{
latestUpdate[0] = tempUpdate;
}
return latestUpdate;
}
1: WHat am i doing wrong to get this exception
2: Is there any other way to make a gap of time in a method
3: Am i going to have to put all these methods into another thread? Please say no
// my constructor which I failed to mention has a timer in it. only i dont know hwo to use it
class MyFrame extends JFrame implements ActionListener
{
private ActionListener listener;
private Timer t1;
private String [] latestUpdate = new String[1];
public MyFrame()
{
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();// gets the maximum size of the screen
setSize(d.width,(d.height/100)*10);//sets it to max. need to change this
// this shit find the max size of screen and puts it bottom left
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice defaultScreen = ge.getDefaultScreenDevice();
Rectangle rect = defaultScreen.getDefaultConfiguration().getBounds();
int x = (int)rect.getMinX();
int y = (int)rect.getMaxY()-getHeight();
setLocation(x,y-30);
setTitle("ALERT::OUTAGE");
MyPanel panel = new MyPanel();
add(panel);
listener = this;
t1 = new Timer(50,listener);
t1.start();
}
by request, here is getEngineersUpdate()
public String getEngineersUpdate() //gets data from page and sets it to string.
{
String update = "blank";
final WebClient webClient = new WebClient();
webClient.setJavaScriptEnabled(false);// javascript causes some serious problems.
webClient.setCssEnabled(false);
String forChecking;
HtmlPage page;
try
{
URL outageURL = new URL("file:\\C:\\Users\\0vertone\\Desktop\\version control\\OUTAGE\\Outages.html"); //local drive at home
page = webClient.getPage(outageURL);
//All this crap can be gone if we just give the table an id
Object[] dates = page.getByXPath("//span[#id='date']/text()").toArray();
Object[] sites = page.getByXPath("//span[#id='site']/text()").toArray();
Object[] issues = page.getByXPath("//span[#id='issue']/text()").toArray();
System.out.println("" + dates[0].toString());
System.out.println("" + sites[0].toString());
System.out.println("" + issues[0].toString());
update = (dates[0].toString() + " " + sites[0].toString() + " " +issues[0].toString());
forChecking = dates[0].toString();
/**some examples of the getCellAt() method*/
//update = table.getCellAt(0,0).asText(); // This returns DATE/Time
//update = table.getCellAt(1,0).asText(); // This return the actual date
//update = table.getCellAt(0,1).asText(); // This returns, SITE/Sector
//update = table.getCellAt(1,1).asText(); // This returns the actual site issue
}
catch (FailingHttpStatusCodeException a)
{
System.out.println("Failing HTTP Status Execution");
a.printStackTrace();
}
catch (MalformedURLException b)
{
System.out.println("Malformed URL");
b.printStackTrace();
}
catch (IOException c)
{
System.out.println("IO PROBLEMS!");
c.printStackTrace();
}
webClient.closeAllWindows();
return update;
}
I've changed your code so it should work as you intended. I'm not clear on what getEngineersUpdate() does, so I can't say for sure if it will work, but I've given you a start. I've included 2 options for how to handle it, with explanation in the comments. You can see how to use a Timer properly in the constructor, also. Finally, I don't have your full code, so I had to rig something together to simulate it.
class Marquee {
public static void main(String[] args) throws InterruptedException {
MyFrame frame = new MyFrame();
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
frame.setVisible(true);
frame.setAlwaysOnTop(true);
frame.setBackground(Color.BLACK);
frame.setResizable(true);
}
}
class MyFrame extends JFrame {
private String [] latestUpdate = new String[1];
private static final int DISPLAY_TIME = 3000;
private Timer displayTimer;
/*
* Option #1:
* Ideally, you'd have the thread that generates the "Engineers Update" messages call this
* method. If you can't make this event based, then you should use option #2
*/
public void newUpdate(String message) {
setVisible(true);
// change this to whatever you need to.
text.setText(message);
displayTimer.restart();
}
// I used this to test it
private JTextField text;
public MyFrame() {
// gets the maximum size of the screen
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
//sets it to max. need to change this
setSize(d.width, (d.height / 100) * 10);
// this shit find the max size of screen and puts it bottom left
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice defaultScreen = ge.getDefaultScreenDevice();
Rectangle rect = defaultScreen.getDefaultConfiguration().getBounds();
int x = (int) rect.getMinX();
int y = (int) rect.getMaxY() - getHeight();
setLocation(x, y - 30);
setTitle("ALERT::OUTAGE");
//MyPanel panel = new MyPanel();
//add(panel);
text = new JTextField("Initial Text");
add(text);
// this creates a timer that when it goes off, will hide the frame
displayTimer = new Timer(DISPLAY_TIME, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
}
});
// sets the timer not to repeat
displayTimer.setRepeats(false);
//This code is for option #2:
updateTimer = new Timer(UPDATE_INTERVAL, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
checkForNewUpdate();
}
});
updateTimer.start();
}
// This is for option #2
private static final int UPDATE_INTERVAL = 1000;
private Timer updateTimer;
/*
* Option #2:
* Not ideal, but this should work.
*/
public String[] checkForNewUpdate() {
// I don't know how getEngineersUpdate() works
// which would have made it much easier to help you.
String tempUpdate = getEngineersUpdate();
// String comparison doesn't work like this in java.
// you also had a sleeping NullPointerException here
if (!tempUpdate.equals(latestUpdate[0])) {
// this is when you have a new update, correct?
newUpdate(tempUpdate);
latestUpdate[0] = tempUpdate;
} else if (tempUpdate.equals(latestUpdate[0])) {
// it's the same update as last time, so do nothing
} else if (tempUpdate.equals("NULL")) {
// You need to handle this according to what getEngineersUpdate() does
}
return latestUpdate;
}
// This code is rigged to show how it would work
private static int i = 0;
private String getEngineersUpdate() {
// 1 in 6 chance of returning "NULL"
if (Math.random() * 6 - 1 < 0)
return "NULL";
// probability of 1 in 4 of generating a new update
if(Math.random() * 4 - 1 < 0)
return "UPDATE #"+i++;
else
return "UPDATE #"+i;
}
}
I think you can't call wait() on an JFrame, but I am not sure.
You have to call wait() within a snychronized-block. (Example below)
Thread.sleep(1000l) can be used, if it runs in a Thread, but look for the class Timer
It would be much better design, if you create a thread, which checks for updates. You can notify the GUI (JFrame) with some kind of event-listener about the new date to display.
Take a look at the Timer and Callable.
You should create another thread, you should call checkforNewUpdate method from this thread. And also do not forget use SwingUtilities.invokeLater method to update your UI inside checkforNewUpdate method. here is the some part of the code;
public class Marque {
private JFrame frame;
class CheckForUpdate implements Runnable {
public void run() {
while(true) {
checkForNewUpdate();
try {
Thread.sleep(40000);
} catch (InterruptedException e1) {
e1.printStackTrace();
throw new RuntimeException(e1);
} }
}
public String[] checkForNewUpdate() {
//your code
// user interface interaction code
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
}
}
public Marque() {
frame = new JFrame();
//....frame related code
new Thread(new CheckForUpdate()).start();
}
public static void main(String[] arg) {
Marque marque = new Marque();
}

Categories

Resources