I a making a Java Messenger. I did a login dialog and when I click on the connect button, an animated GIF appears while it's loading.
The problem is that the animated GIF stops moving while my MySQL connection and Query are processing.
I throw the MySQL connection and query in a new thread but still the same :
Thread connectionThread = new Thread(new Runnable() {
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//Database conection
OlaDB.createConnection();
...
What can I do to avoid my GIF freezing ?
When a Swing program needs to execute a long-running task, it usually uses one of the worker threads, also known as the background threads.
Have a look at SwingWorker and Using a Swing Worker Thread.
also Read up on on Concurrency in Swing for more information on why the GUI freezes and for a working example of using a Swing Worker. (via #camickr)
Related
I want to append some log strings to a textArea in my vaadin app.
VaadinSqlApplication.logger.info("Export start");
logTextArea.setValue("Export Start");
...
logTextArea.setValue("Export done");
but the textArea only changed after the whole function ended.
Is there any function like in JavaFX :
Platform.runLater(new Runnable() {
#Override
public void run() {
//change text
});
or in swing :
EventQueue.invokeLater(changer);
You need to enable "push" on the Vaadin UI, as by default all updates to the UI will be grouped and sent as a single response (like you say: when the function returns).
Have a look at this page, it explains the whole setup very nicely:
https://vaadin.com/docs/v8/framework/advanced/advanced-push.html
BTW, once push is enabled, you will need a similar technique as the SwingUtilities.invokeLater that you mentioned:
Making changes to a UI object from another thread and pushing them to
the browser requires locking the user session when accessing the UI.
Otherwise, the UI update done from another thread could conflict with
a regular event-driven update and cause either data corruption or
deadlocks. Because of this, you may only access an UI using the
access() method, which locks the session to prevent conflicts. It
takes a Runnable which it executes as its parameter.
For example:
ui.access(new Runnable() {
#Override
public void run() {
...
}
});
I'm creating a game modification that uses MySQL to get and store player data. It refreshes it's client data from the database every 4 seconds, but because it is blocking, it freezes about a second as it gets the data.
Is there any simple way to execute the command async?
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
//Your jdbc call here
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// Here, we can safely update the GUI
// because we'll be called from the
// event dispatch thread
MW.append(foo);
}
});
});
If you are not doing so already, use Threads. Override the run() method for things you want to run asynchronously in Java.
Also just making sure, you wait until the server returns the database data before performing another request right?
So as far as I understood, all the swing components should be created, modified and queried only from the EDT.
So if I happen to press a JButton "submit" let's say, that will pack up all the information from the text boxes, send that data to controller and then controller will send it to other controllers which will eventually send stuff to the server. What thread is the action for that button is running on? If it is running on EDT, how do I exit it to send the data to controller from the main thread? Should I even use main thread to send data to server from the controller?
So what I am saying is this
java.awt.EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
JButton button = new JButton("Submit");
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
// WHAT THREAD DO ACTIONS HERE RUN ON?
// AND HOW DO I MAKE THEM RUN ON MAIN THREAD?
// AND WHAT THREAD SHOULD I RUN THING ON HERE?
}
});
}
});
Any action triggered from Swing will run on the EDT. So the code in your actionPerformed method will already be executed on the EDT, without any special handling by you.
To start a long-running task, like sending data to a server, use a SwingWorker or a Callable and an ExecutorService.
I prefer using a SwingWorker when implementing a Swing UI, as has it a useful API for publishing updates and makes the callbacks when the task is done automatically happen on the EDT.
I have a simple client-server program. In one thread GUI is running, when I click "connect" button on GUI, I connect to server in new thread, after some time I receive some data from server and I want to pass it to GUI - how can I do that?
Pass a reference to your GUI object to the reading thread, and have the reading thread invoke a method of the GUI instance when he has received the data.
If the GUI is a Swing GUI, you'll need to wrap the call into SwingUtilities.invokeLater():
Thread readingThread = new MyReadingThread(gui);
readingThread.start();
and in the reading thread:
String data = readData();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
gui.dataHasBeenReceived(data);
}
});
Note that SwingWorker is designed specifically for this kind of use-case.
Generally - by passing a callback object to the new thread, and whenever you have results, invoke that callback, which in turn updates the GUI.
The "callback" can be an object implementing a custom interface of yours, that takes the result as argument.
BackgroundThread background = new BackgroundThread();
backgroundThread.setCallback(new Foo() {
public void updateGUI(Bar bar) {
//...
}
}
Than, when you have the information available in the background thread, you can just call:
getCallback().updateGUI(bar);
in my class I have an inline thread in the constructor that loads objects from a remote site:
Thread readSite = new Thread(new Runnable() {
public void run() {
site.loadStuff();
}
});
readSite.start();
I want to display a 'loading' message until the thread is finished. So before the above code I show a loading message.
After the above code I show the screen in which I would like to continue.
The code looks like this:
showLoadingView(); //tells the user it is waiting
Thread readSite = new Thread(new Runnable() {
public void run() {
site.loadStuff();
}
});
readSite.start();
showStuffView(); //works with the data retrieved from the site instance
Now, the main thread of course continues and the showStuffView() is directly executed.
I can now let the main thread wait for the readSite Thread, but then the user cannot accept the connection request ('is it ok to use airtime?') that is shown to the user (because the responsible thread is asleep I guess).
On the other side, I cannot execute the showStuffView() from the readSite Thread.
I hope you guys can explain how to wait for this thread. I looked into synchronized, but couldn't really find a nice solution.
I think this is a common problem with threads and this particular problem you can solver with boolean variable. but for general purpose i think observer pattern is good.