How can i make System.in read from a JTextField - java

I am trying to make System.in InputStream read from a JTextField.
What i need it to do, is to allow .read() to proceed once a user presses enter in a JTextField with a String in it.
The issue is that I don't know when .read() will be invoked, and i want it to block without freezing the main thread, until enter is pressed by the user in the JTextField where it will notify the thread waiting.
So far i tried the following:
public class InputStreamHandlerThread extends Thread {
private JTextField txt;
public InputStreamHandlerThread(JTextField txt) {
this.txt = txt;
start();
}
#Override
public void run() {
System.setIn(new FakeInputStream());
}
class FakeInputStream extends InputStream {
private int indx = 0;
#Override
public int read() throws IOException {
if (indx == txt.getText().length()) {
indx = 0;
try {
synchronized (this) {
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int byt = txt.getText().getBytes()[indx];
indx++;
return byt;
}
}
}
which is initialized and started by the GUI thread.
So once the GUI loads, it creates an instance of this class and keeps a pointer so that when the enter key is pressed on the keyboard within the JTextField, it is notified to read from it.
in = new JTextField();
in.addKeyListener(new KeyAdapter() {
#Override
public void keyTyped(KeyEvent a) {
if (a.getKeyChar() == '\n') {
inputStreamHandler.notify();
}
}
});
So currently there are three threads:
1. The main thread on what the GUI runs on
2. The InputStream handler thread (See above ^)
3. The thread that reads from System.in
The problem is that once i invoke inputStreamHandler.notify(); it throws a java.lang.IllegalMonitorStateException which according to the docs, is thrown if the thread is not the holder of the lock.
How do i resolve this?
Thank you :-)

String text;
...
in.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
text = in.getText();
}
});
Make sure you make text and in both fields.

Related

Returning a variable after actionPerformed

I am trying to make a simple class where the user can change the value of the string test by clicking the button and then return the changed string.
public class TestTest
{
private JFrame mainFrame;
private JPanel panelX;
private String test;
public static void main(String[] args)
{
TestTest run = new TestTest();
run.GUIinit();
run.addButton();
System.out.println(run.returnData()); // This returns null
}
// Method to return string value
public String returnData()
{
return test;
}
// Method to set string value
public void setData(String data)
{
test = data;
}
private void GUIinit()
{
mainFrame = new JFrame("Text");
mainFrame.setSize(200, 200);
mainFrame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent)
{
System.exit(0);
}
});
panelX = new JPanel();
mainFrame.add(panelX);
mainFrame.setVisible(true);
}
// Problematic part
private void addButton()
{
JButton testButton = new JButton("Text");
panelX.add(testButton);
testButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
setData("STRING BLABLA");
}
});
}
}
I know that I am doing something horribly wrong but I cannot grasp what,
my only guess is that the code skips to the println part without waiting for the actionEvent.
My question is: Am I assigning a value to the string with the actionEvent when I click the button and if not, how could I do that?
Could I implement some sort of delay or another class to get the result I want?
To answer your question - yes, you are assigning the value to the variable "test", but the main thread doesn't wait for you to click the button. That's why it prints null. You could make the main thread wait until the value is set, but that is a wrong way to use Swing. There are three kinds of threads in a Swing program:
Initial thread, the thread that executes initial application code. In your case this is the thread that runs the main() method.
Event dispatch thread (EDT), the thread where all event-handling code is executed. All program logic (unless it is time consuming) should be executed on this thread. In your case, whatever you need to do with the "test" variable, you should probably do it on this thread. Since action events are processed on this thread, you should do it in the actionPerformed() method of the listener.
Worker threads. If the work is time consuming, you should create a new thread and do the work on it. Even so, you should start it from EDT (event dispatch thread), not the main (initial) thread.
You can read more here: Lesson: Concurrency in Swing
If, however, for some unlikely reason you really need to access the "test" variable from the main (initial) thread, you can implement a waiting mechanism with Lock and Condition like so:
public class TestTest
{
private JFrame mainFrame;
private JPanel panelX;
private String test;
private static final Lock lock = new ReentrantLock();
private static final Condition valueAssigned = lock.newCondition();
public static void main(String[] args) throws InterruptedException
{
TestTest run = new TestTest();
run.GUIinit();
run.addButton();
// Acquire the lock.
lock.lock();
try {
while (run.returnData() == null) {
// Release the lock and wait for signal.
valueAssigned.await();
}
// Once String value is set, print it.
System.out.println(run.returnData());
} finally {
lock.unlock();
}
}
// Method to return string value
public String returnData()
{
return test;
}
// Method to set string value
public void setData(String data)
{
test = data;
}
private void GUIinit()
{
mainFrame = new JFrame("Text");
mainFrame.setSize(200, 200);
mainFrame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent)
{
System.exit(0);
}
});
panelX = new JPanel();
mainFrame.add(panelX);
mainFrame.setVisible(true);
}
// Problematic part
private void addButton()
{
JButton testButton = new JButton("Text");
panelX.add(testButton);
testButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
setData("STRING BLABLA");
// Acquire the lock.
lock.lock();
try {
// Send a signal to all waiting threads.
valueAssigned.signalAll();
} finally {
lock.unlock();
}
}
});
}
}
Read more about Locks and Conditions here:
Lock Objects

How to use JButtons to Start and Pause SwingWorker thread

I'm trying to learn Threads in Swing.
I have a Frame with a JProgressBar (progress), five JButtons (Start, Suspend, Resume, Cancel, Close), and a JLabel (label1).
The frame opens. Only Start is enabled. Start calls my class Progressor:
Updated Again Once and For All
Progressor progressor; //declared as class variable, initialized new in constructor and again in overridden done method
Here's the ButtonListener class:
public class ButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == jbStart) {
progressor.execute();
label1.setText("Progressing ...");
jbCancel.setEnabled(true);
jbResume.setEnabled(true);
jbSuspend.setEnabled(true);
jbClose.setEnabled(true);
}
if(e.getSource() == jbCancel) {
progressor.cancel(true);
label1.setText("Progress Canceled");
}
if (e.getSource() == jbSuspend) {
label1.setText(progressor.suspendProgress());
}
if (e.getSource() == jbResume) {
label1.setText(progressor.resumeProgress());
}
if (e.getSource() == jbClose) {
dispose();
}
}
}//buttonlistener
Here's the SwingWorker class:
public class Progressor extends SwingWorker<Void, Integer> {
private volatile boolean suspend = false;
private Object lock = new Object();
#Override
protected Void doInBackground() {
for (int i = 0; i <= 10; i++) {
checkForSuspend();
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
}
publish(i);
}
return null;
}
#Override
protected void process(List<Integer> list) {
int value = list.get(list.size() - 1);
progress.setValue(value);
}
public void checkForSuspend() {
synchronized (lock) {
while (suspend) {
try {
lock.wait();
} catch (InterruptedException ie){
}
}
}
}//checkForSuspend
#Override
protected void done() {
label1.setText("All Done. Press close to exit");
progressor = new Progressor();
}
public synchronized String suspendProgress() {
suspend = true;
return "Progress suspended ...";
}
public synchronized String resumeProgress() {
synchronized (lock) {
suspend = false;
lock.notify();
return "Progress resumed ...";
}
}
}//Progressor class
Everything works except the cancel doesn't doesn't actually cancel the thread (the progress bar continues).
Should I suspend it before canceling?
This How to Pause and Resume a Thread in Java from another Thread question looks very similar to yours and has some nice examples in the answers.
As for your own code and why it does not work:
You create a new progressor on every click. You should be using and controlling one, instead of creating new ones every time.
When suspending your progressor finishes work instead of suspending. As the above question states - you should be looking at the flag at some points of your computation and acting on it. Example:
while (!cancel) {
if (!suspended) {
for (int i = 1; i <= 10; i++) {
Thread.sleep(1000);
publish(i);
}
}
}
The above code will suspend when it next reaches 10 (unless you resumed it before that), and finish when you press cancel (Cancel needs to be added as an extra flag in the obvious manner).
Your thread should run inside a while loop that looks for a boolean to change value from another object, then simply change the state with setPause(true/false) when you click the button:
while(true){
if(object_everyone_can_reference.getPause()){
Thread.sleep(1000);
}
}

Java Threading Issue with run()

I have 2 classes defined below:
public class TextsManager extends Thread {
LinkedList<String> lstOfPendingStr = new LinkedList<String>();
boolean stopLoop = false;
JTextArea txtArea;
public void run()
{
while (!stopLoop)
{
while (!lstOfPendingStr.isEmpty())
{
String tmp = lstOfPendingStr.getFirst();
this.txtArea.append(tmp);
lstOfPendingStr.removeFirst();
}
try {
Thread.sleep(0); // note: I had to force this code
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void AddNewStr(String newStr)
{
this.lstOfPendingStr.add(newStr);
}
}
And
public class ClientApp {
private JFrame frame;
private JTextField textField;
private JTextArea textArea;
static private TextsManager txtManager;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ClientApp window = new ClientApp();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public ClientApp() {
initialize();
/*
* Client app
*/
txtManager = new TextsManager(textArea);
txtManager.start();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
textArea = new JTextArea();
textField = new JTextField();
textField.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER)
{
txtManager.AddNewStr(textField.getText() + "\n");
textField.setText("");
}
}
});
}
}
The program will read User Input from textField, pass it into TextsManager.lstOfPendingStr. Then, on each loop inside TextsManager.run(), it will check for existed members in lstOfPendingStr and output them via txtArea.
The problem is that if I removed the code Thread.sleep(0) inside run(), the run() then apparently stopped working. Despite lstOfPendingStr had been successfully updated with new elements, codes inside the loop while(!lstOfPendingStr.isEmpty()) would not ever to be called.
I put hard codes such as System.out.println or Thread.sleep(0) (as in the provided code) inside the while(!stopLoop), then it worked fine.
Although, I managed to solve the problem by forcing the thread to sleep for a few miliseconds, I want to know the reason behind this issue.
I appreciate your wisdom.
Regard :)
You have a couple of problems.
You are calling methods on lstOfPendingStr from two threads, but initialized it with LinkedList, which is not thread-safe. You should use a thread safe class, LinkedBlockingQueue seems the best options as far as I understood from your code.
Inside the thread you are calling JTextArea#append(). As all AWT/Swing methods, you can not call them from arbitrary threads, but only from the AWT thread. Wrap the call inside an invokeLater block.
The fact that sleep appears to make your code work is just a sign of the concurrency problems.

How to make a checkbox do a continuous task, until it gets unchecked?

Anyone have any idea how to make check box do a task until it gets unchecked?
JCheckBox chckbxInspecAuto = new JCheckBox("Inspe. Auto.");
chckbxInspecAuto.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0)
{
try {
gimage = vision.grab();
cvSaveImage("image001.bmp", gimage);
ipanel.loadImage("image001.bmp");
} catch (com.googlecode.javacv.FrameGrabber.Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
EDIT: The code is over there now...
You could extend the SwingWorker class or even Thread to implement the functionality you want the checkbox to control. Create methods contiueWorking() and stopWorking() and in the run method check some boolean flag to see whether to do the task or sleep.
As Robin commented on a post below, swing components should only be accessed from the Event Worker Thread. I violated this rule in my example below because I wanted to produce something simple and since the running thread spends most of its time sleeping, it works fine.
I would use SwingWorker for a more time consuming task that I wish to update the user on as it executes. For instance, say we have a thread generate and then send a set of email messages, and for each e-mail, display some text in the UI that confirms the message was sent or indicates why it was undeliverable. Each message may lock the Thread up for a while. The UI will not be updated in sync with the Thread's execution of the e-mail task. SwingWorker to the rescue. The java2s.com site has a SwingWokerDemo.
import java.awt.BorderLayout;
import javax.swing.*;
import java.awt.event.*;
import java.util.ArrayList;
/**
* The sequence of prime integers is calculated and displayed on the screen.
* This little program demonstrates how a checkbox can be used
* to start and stop a thread.
*/
public class ThreadDemo extends JFrame {
JCheckBox runningCB;
JTextArea displayArea;
JTextField delayField;
PrimeCalcThread workerThread = null;
public ThreadDemo() {
super("Prime Numbers");
runningCB = new JCheckBox("Calculate Primes");
JPanel topPanel = new JPanel();
topPanel.add(runningCB);
topPanel.add(new JLabel("Dealy: "));
delayField = new JTextField(10);
delayField.setText("500");
topPanel.add(delayField);
getContentPane().add(topPanel,BorderLayout.NORTH);
displayArea = new JTextArea(30,80);
displayArea.setText("2, 3, 5, ");
displayArea.setLineWrap(true);
JScrollPane scroller = new JScrollPane(displayArea);
getContentPane().add(scroller,BorderLayout.CENTER);
pack();
runningCB.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(runningCB.isSelected() ) {
if(workerThread != null)
workerThread.contiueWorking();
else {
workerThread = new PrimeCalcThread();
workerThread.start();
}
}
else {
if(workerThread != null)
workerThread.stopWorking();
}
}
});
delayField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String input = delayField.getText().trim();
try {
int d = Integer.parseInt(input);
workerThread.setDelay(d);
}
catch(NumberFormatException nfe) { }
}
});
setVisible(true);
}
public static void main(String[] arg) {
ThreadDemo window = new ThreadDemo();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
/**
* When this thread is active it calculates prime numbers. The Thread
* continues until it is paused with stopWorking() or until the
* boolean field endThread is set to true.
*/
class PrimeCalcThread extends Thread {
ArrayList<Integer> primeList;
int delay = 500;
boolean active = true;
boolean endThread = false;
private int lastPrime;
public PrimeCalcThread() {
primeList = new ArrayList<> (1024);
primeList.add(2); primeList.add(3); primeList.add(5);
lastPrime=5;
}
public void run() {
while(!endThread) {
if(active) {
calcNextPrime();
displayArea.append(lastPrime + ", ");
}
try { sleep(delay); }
catch(InterruptedException whatever) { }
}
}
private void calcNextPrime() {
int p = lastPrime+2;
while(!isPrime(p))
p+=2;
primeList.add(p);
lastPrime = p;
}
/**
* Checks if p is prime by checking for divisibility by all primes in the
* calculated primeList so far. This method only works if sqrt(p) < lastPrime
*/
private boolean isPrime(int p) {
int maxCheck = (int) Math.sqrt(p) + 1;
for(int prime: primeList) {
if(p % prime == 0)
return false;
if(prime > maxCheck)
break;
}
return true;
}
public int getLastPrime() {
return lastPrime;
}
public ArrayList<Integer> getPrimeList() {
return primeList;
}
public int getDelay() {
return delay;
}
public void setDelay(int waitTime) {
if(waitTime>=0)
delay = waitTime;
}
public void contiueWorking() {
active=true;
}
public void stopWorking() {
active=false;
}
}
}
- Well create a Daemon Thread and run it in an infinite loop, let it keep checking whether the JCheckBox is checked or not using isSelected() method or ItemListener.
- And when the JCheckBox gets selected then create a Thread to execute the task, or use SwingWorker Class which properly synchronizes the UI and Non-UI thread's work.
It depends on the task.
If a task is on other process on other machine you could simply send the right messages.
If the task is a separated thread in the same application you could do what wxyz suggests or you could use some kind of Listener with the ability of start and stop the Thread (the thread is always the same or you are creating a new one every time you select the checkbox?).
My favorite one would be to use Observer pattern in the "PUSH" way, so you would use some kind of external signal to the thread which when sent would create and/or stop it.

How to Interrupt in Java

In Java, let's say I have a GUI with 2 buttons, Go and Pause.
When I press Go, "Hello" gets printed out over and over again. When I press Pause, "Hello" no longer gets printed to the screen.
Example: User presses Go button. "Hello" gets printed out for 1 minute until the user presses "Pause."
What is the proper way to express this approach in Java? Is it equivalent to my commented pseudocode within the goButton source?
public void actionPerformed(ActionEvent e) {
if(e.getSource() == goButton)
{
// while user has not pressed the pause button
printHello();
}
else if(e.getSource() == pauseButton)
{
pause();
}
}
Thanks
In order to get this to work, in reasonable fashion, you will need a Thread. This is executed in the background until such time as you decide to cancel/pause it.
This is an EXTREMELY basic example. Normally I'd wrap the task and the GUI up in appropriate classes rather then accessing static references, but it gives a basic idea
public class TestHello {
private static HelloTask task;
public static void main(String[] args) {
Thread thread = new Thread((task = new HelloTask()));
thread.setDaemon(true);
thread.start();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
JButton goButton = new JButton("Go");
JButton stopButton = new JButton("Stop");
goButton.setActionCommand("Go");
stopButton.setActionCommand("Stop");
ActionHandler handler = new ActionHandler();
goButton.addActionListener(handler);
stopButton.addActionListener(handler);
frame.add(goButton);
frame.add(stopButton);
frame.setVisible(true);
}
public static class ActionHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Go")) {
task.start();
} else if (e.getActionCommand().equals("Stop")) {
task.pause();
}
}
}
public static class HelloTask implements Runnable {
private static final Object WAIT_LOCK = new Object();
private boolean dump = false;
public void start() {
synchronized (WAIT_LOCK) {
dump = true;
WAIT_LOCK.notify();
}
}
public void pause() {
synchronized (WAIT_LOCK) {
dump = false;
WAIT_LOCK.notify();
}
}
#Override
public void run() {
while (true) {
while (dump) {
System.out.println("Hello");
}
try {
synchronized (WAIT_LOCK) {
WAIT_LOCK.wait();
}
} catch (Exception e) {
}
}
}
}
}
Some further read:
Java Concurrency
Concurrency in Swing
Caveats
NEVER try and modify the GUI from any thread other then the Event Dispatching Thread.
To have responsive UI you would usually have to run printHello() in separate thread. Then as you do processing in this thread, for example, after every print statement, you check some flag boolean isPaused; and stop execution if it is true. When pause button is clicked you set the value of this flag to true.
You need to implement your loop in a separate thread. Otherwise the GUI will become irresponsive and the user might not be able to click the Pause button at all.
With this threaded approach, you also need a flag which indicates whether or not to print out the message. The printing loop can simply stop executing the thread when the flag is set to no longer print.
what about htis:
boolean flag=true;
public void actionPerformed(ActionEvent e) {
if(e.getSource() == goButton)
{
while(true)
{
printHello();
}
}
else if(e.getSource() == pauseButton)
{
pause();
}
}
You can do this in a few ways the simplest being:
You have a boolean flag, keepPrinting and you set it to true when you push the Go button, false when you push the Pause. Next you have a thread somewhere executing a while loop which will print nothing when keepPrinting is false.
The threading here is really important, without it you're going to have your GUI freeze once the user pushes a button as the program prints hello and happily ignores anything else.
Pseudo Code
//GUI
public ThreadedPrinter greeter;
void ButtonGoPushed(args){
greeter.keepPrinting = true;
}
void ButtonPausePushed(args){
greeter.keepPrinting = false;
}
//ThreadedPrinter
boolean keepPrinting
void run(){
while(true){
if(keepPrinting){
print("Hello");
}
sleep(5); //Make sure that this thread yields if the system doesn't do it automatically
}
The good news about java concurrency versus say C++ is that this will just work, you don't have to worry about the boolean being crazy and inconsistent because in java variable sets are atomic. If you want to do more than just set the variable, make a synchronized method that sets the variable and does anything else you want.
Basically to keep UI responsive such task need to be performed in other thread.
There can be various ways in which you can implement this mechanism in java.
I have used simple mechanism of Runnalbe and volatile flag which ensure that thread exists when you call cancelPrint() method
public void actionPerformed(ActionEvent e) {
if(e.getSource() == goButton)
{
//start the thread here
}
else if(e.getSource() == pauseButton)
{
//call cancel here
}
}
public class HelloPrinter implements Runnable {
volatile boolean cancel = false;
#Override
public void run() {
while (!cancel) {
printHello();
}
}
public void cancelPrint() {
cancel = true;
}
}
I assume you want to do more than just printouts. Take a look at Swing Worker.
It allows you to pretty easily write your GUI-related code that gets executed in the AWT Event Thread and your long-executing code in other thread(s) and pass values back and forth. This will help prevent any GUI lockup issues you might experience.

Categories

Resources