I've made my own kind of statusbar. With a statusbareditor I can set some message on the bar and it disappears after 10 sec. Because my GUI may not be blocked, this statusbareditor works on a second thread. This works fine. But after editing the statusbar I set a new panel on the form. This new panel only appears after 10 secs. This is strange because the statusbareditor works on a different thread.
public void HandleLoggedIn(Person account) {
StatusbarEditor reportThread = new StatusbarEditor(labelStatusbar, "Aangemeld als "
+ account.toString() + ".");
reportThread.start();
asideform = new Asideform();
asideform.AddFollower(this);
this.add(asideform, BorderLayout.WEST);
}
and the statusbareditor-class:
public class StatusbarEditor extends Thread{
private JLabel statusbar;
private String text;
public StatusbarEditor(JLabel statusbarlabel, String report){
statusbar = statusbarlabel;
text = report;
}
#Override
public void run() {
statusbar.setText(text);
try {
Thread.sleep(10000);
} catch (InterruptedException ex) {
Logger.getLogger(StatusbarEditor.class.getName()).log(Level.SEVERE, null, ex);
}
if(statusbar.getText().equals(text)){
statusbar.setText("");
}
}
}
thanks!
I can only imagine what goes wrong there:
asideform = new Asideform();
asideform.AddFollower(this);
this.add(asideform, BorderLayout.WEST);
Is this part updating your UI? If yes, you must take in consideration that your thread has most likely not come as far as you need it. Processing time is distributed approximately random as long as nothing else is defined.
EDIT
One more Thing:
private JLabel statusbar;
Doesn't this belong to your UI class?
without seeing "AsideForm" class it's hard to say but my guess is this is a race condition.
perhaps you need to prepare your asideForm object before starting the thread so the events will take place in the expected order.
Related
I am using SwingWorker to get some long running database calls done in the background. Right before executing the SwingWorker I launch a jpanel with label to inform user that the app is doing some background work. The problem is that if I use the SwingWorker get() method to fetch the results of the long running operations, my jpanel freezes and nothing gets displayed. If I don't use the get() method, the jpanel appears normally.
Can you please let me know what I may be doing wrong? I already spend hours on this without figuring out why. The SwingWorker gets executed after all jpanel creation is done, I don't understand why it's getting hang.
Thanks a lot!
Function that creates jpanel and starts SwingWorker:
private void snapshotOldVariables() {
JFrame loadingJFrame = new JFrame();
LoadingJPanel loadingJPanel = new LoadingJPanel();
Dimension d1 = new Dimension();
d1.setSize(500, 500);
loadingJFrame.setResizable(false);
loadingJFrame.setMinimumSize(d1);
loadingJFrame.setTitle("Loading...");
loadingJFrame.setLocationRelativeTo(null);
loadingJFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
loadingJFrame.add(loadingJPanel);
loadingJFrame.setVisible(true);
loadingJPanel.updateStatus("Creating snapshot of values...");
MySwingWorker worker = new MySwingWorker(tableRows, selectedItems);
worker.execute();
GMSnapshotVO snap = null;
try {
snap = worker.get();
} catch (InterruptedException | ExecutionException e) {
System.out.println(e);
}
loadingJPanel.updateStatus("Complete");
loadingJFrame.dispose();
productIds = snap.getProductIds();
oldLocationIds = snap.getOldLocationIds();
oldStatusIds = snap.getOldStatusIds();
}
Screenshot of jpanel freezed while function waits for worker.get():
Function with commented worker.get() code block:
private void snapshotOldVariables() {
JFrame loadingJFrame = new JFrame();
LoadingJPanel loadingJPanel = new LoadingJPanel();
Dimension d1 = new Dimension();
d1.setSize(500, 500);
loadingJFrame.setResizable(false);
loadingJFrame.setMinimumSize(d1);
loadingJFrame.setTitle("Loading...");
loadingJFrame.setLocationRelativeTo(null);
loadingJFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
loadingJFrame.add(loadingJPanel);
loadingJFrame.setVisible(true);
loadingJPanel.updateStatus("Creating snapshot of values...");
MySwingWorker worker = new MySwingWorker(tableRows, selectedItems);
worker.execute();
/* COMMENT STARTS HERE
GMSnapshotVO snap = null;
try {
snap = worker.get();
} catch (InterruptedException | ExecutionException e) {
System.out.println(e);
}
loadingJPanel.updateStatus("Complete");
loadingJFrame.dispose();
productIds = snap.getProductIds();
oldLocationIds = snap.getOldLocationIds();
oldStatusIds = snap.getOldStatusIds();
COMMENT ENDS HERE */
}
Screenshot of jpanel not freezed and appearing correctly:
As far as I know you should not call SwingWorker's get() method directly from UI thread unless you are sure it is done processing. Instead you should call it inside overriden MySwingWorker.done(), where you can be sure that background task finished executing.
It is not relevant, that all JPanel creation is done before blocking as Swing still needs its main UI thread for repainting and updating UI and to stay responsive. By calling get() you are blocking it.
From UI thread you should just call execute() and all the processing of results (productIds = snap.getProductIds(); oldLocationIds = snap.getOldLocationIds(); oldStatusIds = snap.getOldStatusIds(); in your case) should be done inside done() callback.
A simple example is available in this answer.
In your case it should go something like this:
//inside MySwingWorker
#Override
protected void done() {
try {
System.out.println("My long running database process is done. Now I can update UI without blocking/freezing it.");
GMSnapshotVO snap = get();
loadingJPanel.updateStatus("Complete");
loadingJFrame.dispose();
productIds = snap.getProductIds();
oldLocationIds = snap.getOldLocationIds();
oldStatusIds = snap.getOldStatusIds();
//..do other stuff with ids
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
Hope it helps.
My problem is that I cannot figure out a way of having a thread that "on the click of a button starts, and stops on the click of another button", and then if I click the same start button a NEW thread starts that does exactly the same operation as the first. So basically just a new instance.
In my program I have a Server app that has 2 buttons and 2 text fields. After the user has entered the correct username and password the Server app opens a new ServerSocket that listens for clients that want to connect. This is done in a separate Thread to prevent the GUI from freezing. After the stop button is pressed the Thread is stopped.
How can I get my program to start a new Thread, that does the same as the first one, when I press the start button again in the GUI? Must I perhaps make use of a loop?
Server App Code:
public class Server extends JFrame implements ActionListener {
JLabel instructionsLabel;
JLabel passwordLabel;
JPasswordField passwordTF;
JButton shutdownButton;
JButton startupButton;
JLabel usernameLabel;
JTextField usernameTF;
Thread MyThread = new Thread(new ServerRunnable());
public Server() {
super("Server");
initComponents();
}
// My problem is here
public void starterMeth() {
MyThread.start();
}
public void stopMeth() {
MyThread.interrupt();
}
// in these 2 methods
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
String f = "n";
ConnectionBean cb = new ConnectionBean();
char[] a = passwordTF.getPassword();
String b = new String(a);
String inputDetails = usernameTF.getText() + b;
Iterator it = cb.getDetails().iterator();
while (it.hasNext()) {
Object next = it.next();
if (inputDetails.equals(next)) {
f = "y";
if (source == startupButton) {
if (!MyThread.isInterrupted()) {
starterMeth();
JOptionPane.showMessageDialog(null,
"Congratulations! Server started.",
"Start-up Message",
JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(null,
"Please restart the server application.",
"Start-up Message",
JOptionPane.INFORMATION_MESSAGE);
}
} else if (source == shutdownButton) {
stopMeth();
JOptionPane.showMessageDialog(null,
"Server shut-down successfully!",
"Shut-down Message",
JOptionPane.INFORMATION_MESSAGE);
}
// only resets the text fields when the correct details are entered
passwordTF.setText("");
usernameTF.setText("");
}
}
if (f.equals("n")) {
JOptionPane.showMessageDialog(null, "Invalid username or password.", "Alert", JOptionPane.WARNING_MESSAGE);
}
cb.setCloseConnection(true);
}
private void initComponents() {
}
}
My Runnable Code:
public class ServerRunnable implements Runnable {
#Override
public void run() {
try {
ServerSocket ss = new ServerSocket(7777);
while(true) {
Socket cs = ss.accept();
new ClientThread(cs).start();
}
} catch (IOException ex) {
}
}
}
Overview
Although the creation of a thread is valid in Java, it is highly discouraged for numerous reasons. The most significant one is that the creation of a thread is quite costly and resource intensive. In addition, there are much safer/efficient models implemented in the standard library that could be used to simplify the issue. In this particular scenario, I would advise against this implementation because of the nature of the operation; start-stop reoccurring. Note, a thread cannot be restarted once it has been started and the only way to stop a thread while executing is to call interrupt(). Unfortunately, interrupting a thread requires the developer to implement error handling in the run() method. Below we will see the run() method of a Runnable or a Thread implementation.
public void run() {
try {
// Your connection logic would be here
yourLogic();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt(); // Maintain status
}
}
Lets assume you made your own thread implementation called MyThreadImpl. Below we will see how to utilize it:
public void starterMeth() {
Thread myThread = new MyThreadImpl(); // Create thread
myThread.start(); // Start execution in parallel
}
public void stopMeth() {
myThread.interrupt(); // Stop the thread
}
Alternatively if you implement your own Runnable like you are in this application, it would look like this:
public void starterMeth() {
Thread myThread = new Thread(new ServerRunnable()); // Create thread
myThread.start(); // Start execution in parallel
}
public void stopMeth() {
myThread.interrupt(); // Stop the thread
}
Although both of theses are valid, there are better approaches.
A better approach
My suggestion is to utilize the CompletableFuture class due to its robust implementation and desirable control. CompletableFutures utilize the global ForkJoinPool.common() for its threading so that the application can execute with more efficiency. In addition, you can receive the Future that is within the object for later use instead of attempting to re-create it each time. Lets investigate how this implementation would work below:
public class Server {
CompletableFuture<Void> myFuture;
...
public void starterMeth() {
myFuture = new CompletableFuture<Void>(); // Create future
myFuture.runAsync(new ServerRunnable()); // Start execution in parallel
}
public void stopMeth() {
myFuture.cancel(true); // Stop the future
}
...
}
Java does not allow to restart a Thread once it has finished executing.
Interrupting the Thread you created will simply finish its execution. The problem here is that you are using the same Thread that has finished executing (once the stop button has been clicked).
I suggest one of the following:
Improve your runnable so that when the user attempts to clicks the shutdownButton button, it stops what it was doing, and acquires some sort of semaphore to make it "sleep" until the startupButton is hit again.
(Easier) Always create a new thread on starterMeth. Don't forget to check if a Thread is running and interrupt it before starting a new thread.
I hope this helps.
I've been making a program that reads from a file, identifies common "posts" in the file, and makes a summary of these. My problem is that the GUI-event that allows the user to specify the name and search-term of the post, does not interrupt the running of the program, like I want it to.
I can make it stop, but then the GUI will not be correctly displayed. I have tried some solutions, which will be specified at the bottom of the post.
EDIT: removed codedump and added something resembeling an SSCCE:
class SSCCE{
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
new Gui();
}
});
}
}
class Gui implements ActionListener{
boolean runn=true;
JFrame wind2;
JTextField nameF, searchtermF;
JButton done;
Gui(){
runEx();
}
public void runEx(){
int i =0;
while(runn){
if(i==10) break;
System.out.println("Open window and record information given! One at the time!!!");
System.out.println(" ");
giveName("test");
i++;
}
}
public void giveName(String s){
JLabel nameL = new JLabel("Give this post a name:");
JLabel searchL = new JLabel("What do you want the searchterm to be?");
wind2 = new JFrame("EazyMoney");
wind2.setLayout(new BorderLayout());
JPanel all = new JPanel();
all.setLayout(new GridLayout(2,2));
searchtermF = new JTextField(30);
nameF=new JTextField(30);
all.add(nameL);
all.add(nameF);
all.add(searchL);
all.add(searchtermF);
done = new JButton("Press when you have filled in the information!");
done.addActionListener(this);
String prn = "The post in question: " + s;
JLabel header = new JLabel(prn);
wind2.add(header, BorderLayout.NORTH);
all.setVisible(true);
wind2.add(all, BorderLayout.CENTER);
wind2.add(done, BorderLayout.SOUTH);
wind2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
wind2.pack();
wind2.setLocationRelativeTo(null);
wind2.validate();
wind2.setVisible(true);
}
public void actionPerformed(ActionEvent e){
System.out.println("Action recorded, new window can now be shown. All information stored.");
System.out.println(" ");
}
}
The solutions I have tried is:
A simple block, that does a while(true){} and sets the variable to true after the first instance of g.giveName() have been called. I used the ActionListener to call a method that then changed the variable to false again, when the necessary input was given. This resulted in a gray box, with nothing in it.
Making a cyclic barrier that did the same as the block above. Used a separate thread to call g.giveName() and then call the await() from the action listener. Same result as above.
Making readFile be run by a separate thread and call invokeAndWait() on the g.giveName() function. Gave cannot call invokeAndWait() from the EDT-thread, even though it was run from a new thread.
I can not give examples of the code used in instances above, as I have tried a lot of different solutions and do not have it any more. Please take into account that it might have been implemented wrong, and thus might be a valid answer to my question, even though I could not seem to get it to work!
Final note: all work can be found here, if you wish to test the code:
https://github.com/Robiq/EazyMoneyWork
The way to avoid blocking the EDT if you need to execute something else on the same thread it is to temporarily create a new event queue. Here is some example code. In this case it blocks the current thread waiting for some other event to be signalled but you could replace this with whichever long running process is required.
First check if you are running on the EDT: SwingUtilities.isEventDispatchThread. Then if you are:
EventQueue tempEventQueue = new EventQueue();
Toolkit.getDefaultToolkit().getSystemEventQueue().push(tempEventQueue);
try {
wait();
} catch (InterruptedException ex) {
// stop waiting on interrupt
} finally {
tempEventQueue.pop();
}
Something similar to this is how modal dialogs work in Swing. However in general it's not good practice. Much better is to understand which events to listen for to perform specific actions. In your case the user event should not 'stop' your program - it should disable inappropriate components until the user has responded and then re-enable them.
hi im creating a flashing text frame by using threading handling method, here is my code:
import javax.swing.*;
public class FlashingText extends JApplet implements Runnable {
/**
*
*/
private static final long serialVersionUID = 1L;
private JLabel jlblText = new JLabel("welcome",JLabel.CENTER);
public FlashingText() {
add(jlblText);
new Thread(this).start();
}
#Override
public void run() {
try {
while(true) {
if(jlblText.getText() == null) {
jlblText.setText("Welcome");
Thread.sleep(2000);
} else
jlblText.setText(null);
}
} catch(InterruptedException ex) {
}
}
}
after i compiled and ran it, it seems the text does not flashing at all
is there anything wrong with my code?
thanks a lot!
There's a better solution, which updates the UI in Event Dispatcher Thread and does not block it.
final JLabel label = new JLabel("Some text");
final Runnable updater = new Runnable() {
#Override
public void run() {
label.setVisible(!label.isVisible());
}
};
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
executorService.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
SwingUtilities.invokeLater(updater);
}
}, 2, 2, TimeUnit.SECONDS);
From the code, it does not really seem that you are flashing anything. Some issues I see with your code:
If the label has no text, the getText() method will yield an empty string ("") and not null.
When updating visual components, you would need to go through the Event Dispatcher Thread (EDT). This is exposed to you through the SwingUtilities.invokeLater(Runnable runnable) class.
It is usually a bad idea to sleep() threads. If you make the changes through the EDT, you would be hanging the ED Thread which will cause the application UI to freeze, which is not desired.
You are swallowing exceptions. In your exception handling, you are not doing anything. It is considered bad practice to not handle exceptions (sometimes a simple log message will do).
According to me there is a problem in the following code block:
try {
while(true) {
if(jlblText.getText() == null) {
jlblText.setText("Welcome");
Thread.sleep(2000);
} else
jlblText.setText(null);
}
}
Because see at the first time the value is welcome, so it will enter the loop and go to else and set it null and then immediately it will check again, as there is no sleep in else so it will check again and enter the if block and set it to welcome, and this whole process will be done at a great speed so you would not be able to see the flashing effect. So I think that you should try putting a sleep at the end of the else block and see, according to me it should work then.
You should change:
else
jlblText.setText(null);
to
else{
jlblText.setText(null);
Thread.sleep(500);
}
or something like this
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Making FEST to wait for the application to load
NOTE: This question is basically identical to this question. Since there were no answers to that question, I decided to extend the example from there into a runnable SSCE, and provide some additional information, hoping to get some help.
So, the question is about how you should handle component lookups when the sought component might not yet exist. Look at this simple one label GUI.
public class MyFrame extends JFrame {
JLabel theLabel;
public MyFrame() {
this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
theLabel = new JLabel();
theLabel.setName("theLabelName");
computeLabelContentOnWorkerThread();
}
private void computeLabelContentOnWorkerThread() {
new SwingWorker<String, Void>() {
#Override
protected String doInBackground() throws Exception {
Thread.sleep(5000);
return "Info from slow database connection";
}
#Override
protected void done() {
try {
theLabel.setText(get());
add(theLabel);
pack();
setVisible(true);
} catch (InterruptedException ignore) {
} catch (ExecutionException ignore) {
}
}
}.execute();
}
}
And this test case:
public class TestOfDelayedComponent extends FestSwingJUnitTestCase {
FrameFixture frameWrapper;
#Before
public void onSetUp() {
MyFrame frame = GuiActionRunner.execute(new GuiQuery<MyFrame>() {
protected MyFrame executeInEDT() {
return new MyFrame();
}
});
frameWrapper = new FrameFixture(robot(), frame);
frameWrapper.show();
}
#Test
public void testLabelContent() {
String labelContent = frameWrapper.label("theLabelName").text();
assertTrue(labelContent.equals("Info from slow database connection"));
}
}
What happens? The construction of the label component is delegated to a slow worker thread. So the label will not appear right away when the GUI appears. When the test case is run, the label has not appeared, so when executing the component lookup at frameWrapper.label("theLabelName"), a ComponentLookupException is thrown.
The question is how do I prevent this exception from being thrown? If it was a top level component, I could do WindowFinder.findFrame("title").withTimeout(10000) to get a FrameFinder object which finds can find frames even if there is a delay before they appear. What I want is something similar to that, but for other types of components, such as e.g. a JLabel.
NOTE: Surely, it wouldn't be all that difficult to implement the functionality by yourself. It would be rather simple to do:
while(noComponentFound and notReachedTimeout){
look for component using FEST
sleep for a short delay
}
However, it would be nice to not be forced to clutter the test scripts with such loops. It feels as if waiting for components is not a too unusual task in test scripts. So, in my opinion, there ought to be support for doing this in FEST. Maybe this is not the case? Is it not possible to wait for components?
There is a way you can write Conditions for pausing and waiting. Here is the example for your needed while(noComponentFound and notReachedTimeout). This can be done with Pause.pause(new ComponentFoundCondition(...),timeout_milis). Example:
frame = WindowFinder.findFrame("frame0").using(robot);
//Wait for the event of loading tables in the GUI before we fail looking for them concurrently
final GenericTypeMatcher<JTable> matcher = new GenericTypeMatcher<JTable>(JTable.class) {
#Override protected boolean isMatching(JTable table){ return (table instanceof myTable && table.getColumnCount()<20); } //Condition has to be totally identitary for one particular component. If not, we will never reach condition and so a timeout will be thrown in next line
};
Pause.pause(new ComponentFoundCondition("Waiting for myTable to load before I look for it...", frame.robot.finder(), matcher, frame.target), 50000); //frame.target argument can be omitted. We also put an associated 50 sec timeout even if the condition is never satisfied
fixedTable = frame.table(matcher); //Look finally for the table now we are sure its loaded
You can play with different matchers. For example, if there were just one type of table myTable under the frame it would be much simple:
final ComponentMatcher matcher = new TypeMatcher(myTable.class); // We could use an easier TypeMatcher, because we would not need to add any additional distinction apart from the class type
Pause.pause(new Condition("Waiting for myTable to load...") { // If we are totally sure that there will be only one occurrence, we can use here the simplest form like above new ComponentFoundCondition("DebugMsg", frame.robot.finder(), matcher, frame.target)
#Override public boolean test() { return !frame.robot.finder().findAll(frame.target, matcher).size().isEmpty(); } // If not we need a custom condition that checks for >0 instead of =1 results like ComponentNotFound.
}, 50000);
The problem is too that (component->frame).table(matcher) does not accept a TypeMatcher, but just a GenericMatcher, so we should create GenericMatcher after all anyway
IF you can not find anything, theres always the alternative of fixing estatically a Pause.pause(5, TimeUnit.SECONDS);
I don't use Fest but Pause.pause looks interesting on this page:
http://www.pushing-pixels.org/2009/09/23/using-fest-swing-to-test-flamingo-components.html