Automatically update JTextArea - java

Completely new to Java and I'm at a complete brick wall.
I have a JTextArea on my system that I'd like to have a live update, so when something is added to table2 (in my database), my server pulls the new values from the database and then updates the JTextArea.
I have absolutely no idea how to do this, though I have worked out that I need to use Thread to get it to work.
Any/all help is greatly appreciated (I'm a little pressed for time with this)

What you can do is have your thread poll your database at given periods of time, or else, have the process which is updating the database fire some kind of event which your GUI class can pick up.
Once this happens, you can then use the SwingUtilities.invokeLater() to update your JTextArea. Something like this should do:
if (eventIsFired)
{
final String jtextAreaText = ...
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
jTextArea.setText(jTextAreaText);
}
});
}
The assumption is that jTextArea is your actual JTextArea which is declared as a global variable. jTextAreaText will need to be declared final so that it can be accessed through the inner class.

Related

How to execute method right AFTER SwingWorker fills JTable?

I use SwingWorkers to fill several JTables with data from a mysql-database and use following code:
jT.setModel(DbUtils.resultSetToTableModel(results))
This works great. But right after each JTable-Model is set I need to execute different methods (methods may differ for each JTable) which e.g. put the row-count of a JTable into a JLabel or calculate sums of certain columns and put that sum into another JLabel...
My Problem:
I want the GUI to stay responsive (therefore the use of SwingWorkers to get the Data in the background), but I need to find a way to somehow "listen" to changes of the jTable (so I can execute the methods AFTER the Table is refreshed). I can't use the obvious solution to make different SwingWorker-classes for each JTable (which include the respective method of that JTable), because I need a general solution.
I already thought about putting each individual method into a TableModelListener and to add that to each respective JTable, so I tested following:
jT.getModel().addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
System.out.println("TableModelEvent: "+e);
// Probably I could add this jTable's method right here?
}
});
But I never get any Output...
I also tested the swingworker's .get()-method to wait for the set of the model (see first line of code) and then execute the method, but that lead to the same situation where I started from (GUI freezes and waits for execution of the swingworker... so no gain by using a swing worker..).
Any ideas?
The TableModelListener should work, and why might be the subject of another question, where you post your minimal example program, but one thing that likely will work in lieu of the TableModelListener is to use a PropertyChangeListener, add it to your SwingWorker before calling execute, and listen for changes to the SwingWorker state property. The new value you want to listener for is SwingWorker.StateValue.DONE.
mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("state")) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
// TODO: code that you want to call when SwingWorker is done
// **including** calling get() on the SwingWorker itself
// so you can trap and respond to exceptions thrown during its run.
}
}
}
});
mySwingWorker.execute();

Java: change JPanel while saving game

I'm making a small game and I've already implemented a save function in which the game is saved (by writing information to a new XML file). The saving takes a couple of seconds and I want to do the following: while the program is saving the game, I want to change the look of the JPanel, and when it is done saving, I want to go back to another page(show another JPanel).
I have the following code:
confirm.addActionListener(new ActionListener () {
#Override
public void actionPerformed(ActionEvent e){
String fileNaam = saveGame.getText();
//This method changes the look of the panel
changePanel();
//This method saves the game
model.saveGame(fileNaam);
//This method takes the user back to a previous page
controller.viewTeamPage();
}
});
What happens is that the game is saved and the user is taken back to the teampage, but the panel is never changed. The changePanel() method does work, so that is not the problem but it seems like it is never executed. I was wondering if somebody knows how I can fix this.
EDIT:
private void changePanel () {
panel.removeAll();
panel.repaint();
panel.revalidate();
}
This is the method to change the look of the panel, for now I just remove everything on the panel to keep it simple.
Also, the saving is not done in a separate Thread, is that something I should look at?
EDIT 2: I fixed it by using a thread to save the game and return to the teampage after the saving is done. See the code below.
confirm.addActionListener(new ActionListener () {
#Override
public void actionPerformed(ActionEvent e){
final String fileNaam = saveGame.getText();
changePanel();
Thread t = new Thread (new Runnable () {
#Override
public void run() {
model.saveGame(fileNaam);
controller.viewTeamPage();
}
});
t.start();
}
});
If you are changing the same panel and not intializing a new panel then the problem i think is that you need to call the panel.revalidate or panel.repaint i think. I made a demo for a Procedural generation project and i had to do this to make my panel change.
Call your save game method from a new thread but don't "join" or "try" to wait for this thread to finish from inside the method actionPerformed();
Make the call to controller.viewTeamPage() after the save game thread is done saving the game. One simple way of doing that would be passing the "controller" object to the constructor of your custom thread so you can make that call after saving the game.
The step 1 is very important in this case because all the calls you are making in the method actionPerformed() are being made in the UI thread, preventing the entire UI from refreshing until the method returns. Even calling repaint() alone, in changePanel(), wont be enough because it just "schedules" a refresh on you panel that will only happen after actionPerformed() returns. If you put the most time consuming call in a separate thread however, the actionPerformed() returns quickly allowing the UI to be refreshed while the game saving thread is doing its job.

Call procedures of a declared object from a class that is in no way connected

I've been attempting to write a server program for a game and one issue that I am experiencing is writing to my 'log' (which is just a JTextArea's caption) from another class/thread. Basically, the setup is this:
MainWindow:
-JTextArea with the log.
Threads are started from MainWindow. They may need to output something, and basically what I am after is instead of printing whatever these threads need to output to System.out I can print them to my log, in my MainWindow (which is a JFrame). Is there a way to access the MainWindow from the threads? I don't really know how else to explain this.
Thanks
SwingUtilities.invokeLater() is made for that purpose.
final String labelText = "current label text";
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// Write your GUI updater code here
// like this
labelOnTheGui.setText(labelText);
}
});
This is the only way you can manipulate the GUI starting the action from a different thread.

JButtons AWT control java

I have two basic questions.
I have a GUI project with Java Swing. When I put buttons on the frame and I double clicked them, I had the code of the actionPerformed, but it is blocked.
How can I put there a button and then use it on a actionListener?
My Project is about Server-client (multithread and sockets)
I call one method to reiceve one string that we can write on a JtextField and it stays on a while cicle with PrintWriter and a getOutputStream.
Something like:
do{
...
}while(thisstring!=null || thisstring!="exit")
So.. when I write something and press the button to send it, it stays on the cicle and the button blocks. How can I unblock the button to write something else?
Edit:
I understood the EDT problem, but I can't solve it.
I tried use the Timer but without success, something like that:
int delay = 1000; //milliseconds
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
//My action calling the Thread class with the while cicle that has the PrintWriter
}
};
new Timer(delay, listener).start();
How can I handle this to do the timer when I press the button?
How can I stay on the that cicle (read the comment line) to send the information by OutputStream every time that one user enter something on the text field?
I know that for example for a console application I use a BufferedReader and then I use the ReadLine() to wait for anything sent from the console, but with GUI interface it freezes all time..
There is a fundamental concept in Java GUI development surrounding which thread in which the developer implements user-interaction processing such as button clicks.
In short, you need to perform your processing outside of the thread that calls your action handling method. This single thread is known as the Event Dispatch Thread (EDT), and if you have logic that runs much more than a few milliseconds, it will prevent the UI from continuing to draw things like the button releasing, etc.
You'll want to move your long-running, socket code off the EDT. Doing so will allow the button to release and let the user interact with other controls (or even the same button).
To avoid duplicating other discussions on the topic, I direct you to this pretty good one. Additionally, this article gives a short overview of threading concepts in Swing.
Regards,
ScottH
According to your comment you have some naming issues there. You need a class that implements the ActionListener-interface like so: class YourListenerClass implements ActionListener, but you could also do that via an anonymous class like new ActionListener {
public void actionPerformed(ActionEvent e) {
//your code for your button here
}
});
when you set your ActionListener.
The crucial thing is that you need to name your method the correct way. It MUST be public void actionPerformed(ActionEvent e) and you definitely have to implement the ActionListener-interface.
The next thing is that you have to register your listener in your button like:
yourButton.addActionListener(new YourListenerClass);
or
insert an anonymous class like I showed to you before.
The 2nd thing sounds like an multithreading issue like I mentioned in my comment. I didnt follow scotth's link, but according to his description this might be a source you want to read to solve any further blocking issues.
EDIT:
Well, at first I didn't want to explain it, because it's quite a chunk of code, but as the problem persists I want to add something about SwingWorkers in my answer.
If you have long running code, it wont help to use a Timer as the code invoked by it will also be on the EDT as it's triggered by an event.
Instead of that you could use a SwingWorker to solve this. This needs some extra code, though.
Here's a simple approach you could follow:
public class WorkingHard{
SwingWorker<String, String> worker;
JButton yourButton = ...;
...
//do some cool stuff, as register those listeners!
...
public void actionPerformed(ActionEvent evt){
if(evt.getSource().equals(yourButton);
// Construct a new SwingWorker
worker = new SwingWorker<String, Void>(){
#Override
protected String doInBackground(){
//do your reading in this method, it will be executed in an own thread
String readText = "i will be read".
/*your reading algorithm, you could also call publish(...) to post your results,
e.g. likewise), then you also have to override process(...). this process will be
thread save, too*/
readText += ... ;
...
return readText;
}
#Override
protected void done(){
try {
//do sth. with your result, now thread safe.
someGuiElement.setText(get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
};
// Execute the SwingWorker; the GUI will not freeze
worker.execute();
}
}
If you want to know more about those workers... there several threads dealing about it, e.g. this one.

How can I get wait/sleep to work the way I want in java?

I'm trying to accomplish something very simple. First, load my layout (main.xml). Then wait 1 second, modify an image, wait 1 second and modify it to a third image. (My end goal is more complex, of course, but I can't even get this to work).
Basically, I get a black screen when the app loads. It stays that way until all the waiting is over, then it shows the final image. Here's my code:
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageCard[0] = (ImageView)findViewById(R.id.imageView11);
Thread.sleep(1000);
ImageCard[0].setImageDrawable(getResources().getDrawable(R.drawable.secondimage));
Thread.sleep(1000);
ImageCard[0].setImageDrawable(getResources().getDrawable(R.drawable.thirdimage));
ImageCard[0] is the image I'm trying to change. It loads in main.xml and shows fine if I remove the rest of the code.
If I change the sleep time to 5000, it then takes 10 seconds before it finally comes away from the black screen and shows the third image. This is how I know it's not just loading slow, but that it's actually waiting.
It's like it's not running sequentially. I'm no java expert, so I'm assuming I'm doing something dumb...
Thanks for any help!
I think you are blocking the UI Thead. Try Handler.postDelayed on a static Handler object.
Ok heres your problem, you can never do a sleep(...) when you are in the UIThread. The UIThread is never suppose to be locked up, it causes a lot of very bad things to happen in android. But there is a very easy way around it, just get off the UIThread and hop back on it when you need to. Heres what i would recommend:
public void onCreate(...)
{
super.onCreate(...);
myActivity.setContentView(R.layout.main);
new Thread(this).start();
}
public void run()
{
try
{
changeLayout(R.layout.main2);
Thread.sleep(5000);
changeLayout(R.layout.main3);
Thread.sleep(10000)
changeLayout(R.layout.main4);
}catch(Exception e){}
}
public void changeLayout(int id)
{
this.id = id;
myActivity.post(new Runnable()
{
public void run()
{
myActivity.setContentView(id);
}
});
}
private int id;
Of course with this example your class must implement Runnable to work. Only the UIThread can access the UI, no other thread can. Thats why you have to hop on and off the UIThread. Hope this worked!
Try adding ImageCard[0].invalidate() when you want it to draw.
I think Hovercraft Full of Eels is pointing you in the right direction. Essentially, you're not doing any multi-threading, you're telling the main thread to wait which means that it never completes the drawing. I'm not sure about Android, but Swing uses double-buffering by default (to avoid screen flashes), but that means that what is drawn, is actually drawn on to a buffer, not the window itself which is why you don't see anything. You could try disabling the double buffering (which Android is likely using) but that could cause other issues.
You might want to actually do multi-threading, or, I'm sure Android likely has a Timer component. If it does, I'd suggest you use it over Thread.sleep or actual multi-threading. Using a Timer you can have it fire an event after one second. That event will execute the other code.
do you have that code in constructor or in init() function? if yes, draw just the first picture and the Thread.sleep() function move after the place which the constructor or the init() function was called from.
then call repaint() function or something.

Categories

Resources