I am creating a Transliterating tool in Java. It's almost complete.
But, when I type so fast the GUI freezes.
So, I debugged the application to pinpoint the command where it is happening.
The call to method JTextField.modelToView(pos) causes this, which further calls TextUI.modelToView(JTextComponent c, int pos).
It appears, this method first acquires lock on text component's document by calling AbstractDocument::readLock() method, whose source code is:
public synchronized final void readLock() {
try {
while (currWriter != null) {
if (currWriter == Thread.currentThread()) {
// writer has full read access.... may try to acquire
// lock in notification
return;
}
wait();
}
numReaders += 1;
} catch (InterruptedException e) {
throw new Error("Interrupted attempt to aquire read lock");
}
}
Which calls wait() if current thread is not the writer thread.
But, I am only mutating document when space key is pressed, which I believe happens in EDT. And, Swing would also be mutating it in EDT. Also, I am calling JTextField.modelToView(pos) when DocumentListener.insertUpdate(DocumentEvent) is invoked.
Then, what is the reason, the application freezes!
Here are the screenshots:
The application screenshot
When Application freezes
If I minimize and maximize the window
I am calling JTextField.modelToView(pos) when DocumentListener.insertUpdate(DocumentEvent) is invoked.
The Document has not been updated completely when the DocumentEvent is fired. Wrap your code in the DocumentListener in a SwingUtilities.invokeLater(...). This should cause your event code to be executed after the Document has finished updating itself.
Related
So I am trying to do a chat type program using JavaFX for the GUI. I have it so a class that acts as a server will loop and keep adding client connections to it.
public void serverconnection()
{
// portnumber was saved from constructor
try (ServerSocket socket = new ServerSocket(this.portnumber))
{
// loop is a bool set to true
while (loop)
{
// this class extends Thread and has its own overwritten start method
new myclass(socket.accept()).start();
}
}
catch (IOException e)
{
System.exit(404);
}
}
so the problem is (I am assuming) was, this loop keeps looping until the program closes. but since I was calling this within the JavaFX's initialize method
public void initialize(URL url, ResourceBundle rb)
{
// constructor, nothing here is needed for this post
myclass z = new myclass(45234);
// problem here, since this has a loop, but
z.serverconnection();
// gui wont load till after this is done
// but serverconnection is only done after program ends
}
the problem with this is, apparently, the GUI will not load until AFTER initialize has finished, but it will not finish until program closes. After google searching, I could not find any fix for this. I need a way to call a method that will do all this, AFTER initialize method has finished. My client side class is similar to this, but the methods to connect on that are activated on events when clicking a login button. For this serverside one, I am trying to start without any interaction with the user. so is there a way to call a method or make this work AFTER initialize method has ran?
You might want to run this loop in a thread, so do something like
Thread t = new Thread(z::serverconnection)
t.start()
If you do this at the end of your initialization() method, it will run exactly then.
This will start a thread which runs forever; you might want to add a feature for interrupting the thread when the program is supposed to be terminated.
Remember that for changing anything in the GUI you need to sumbit a task via Platform.runLater(). This is because the GUI may only be modified from within that one thread. So in order to modify anything, you have to wrap that in a Runnable and submit it for execution.
You can do that in this way:
Platform.runLater(new Runnable() {
#Override
public void run() {
doWhateverNeedsToBeDone();
}
});
In Java 8, you can do anything of the following, depending on the extent of the work to be done:
Platform.runLater(() -> {
doWhateverNeedsToBeDone();
});
Platform.runLater(() -> doWhateverNeedsToBeDone());
Platform.runLater(this::doWhateverNeedsToBeDone);
The latter only works if doWhateverNeedsToBeDone() is a method of this.
What I am trying to do is check if a check box is enabled from another method that is also running on another thread. I am fairly new to Java so I apologise in advanced if my code isn't how Java is usually written (or if it is written badly).
So I've made a method that created a iframe then adds a check box to it. I've removed the part which creates the jframe just to keep my code minimal - you can see it below:
private void initialize() {
chckbxEnabled.setHorizontalAlignment(SwingConstants.LEFT);
chckbxEnabled.setForeground(Color.WHITE);
chckbxEnabled.setBounds(98, 123, 81, 23);
frame.getContentPane().add(chckbxEnabled);
}
I've then created a new method in a new thread and called it from another method which I haven't shown here.
static Thread thread = new Thread(new Runnable() {
public void getPing() throws IOException, InterruptedException {
while (true) {
System.out.println(chckbxEnabled.isEnabled());
if(chckbxEnabled.isEnabled()) {] // Part I am having trouble with
String apiKey = "exmapleApiKey";
URL url = new URL("http://example.com/ping.php?mode=get&apikey="+apiKey);
URLConnection yc = url.openConnection();
BufferedReader in = new BufferedReader(
new InputStreamReader(
yc.getInputStream()));
String inputLine;
inputLine = in.readLine();
}
Thread.sleep(1000);
}
}
public void run() {
try {
getPing();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
As you can see I am trying to access chckbxEnabled.isEnabled(). This worked because just after I made my main class I added private static JCheckBox chckbxEnabled = new JCheckBox("Enabled");. So I can access it but it always returns true when I print it even though the check box is sometimes checked.
So my question is what is a better way of doing this as I expect that way I have experimented with is 'messy' and not the way it should be done?
You are mixing up methods:
isEnabled is for checking if the user can interact with the user (think greyed out elements)
isSelected is what you are looking for (check for the checkmark inside the box). You might want to take a look at ItemListener (example)
Also: keep in mind that you can draw to the api only form the gui thread.
Update:
So: most gui frameworks allow only one thread to draw the gui, since synchronisation is very complex. Therefore most of swing is not thread safe. A good answer outlining this (actually related to swing), can be found here
Quote:
A note on thread safety: It may seem strange that such an important
part of the Java platform is not thread safe. It turns out that any
attempt to create a thread-safe GUI library faces some fundamental
problems. For more on this issue, see the following entry in Graham
Hamilton's blog: MultiThreaded toolkits: A failed dream?
Given that we have to draw the gui from a single thread, what does this mean?
Update operations, i.e. changing a labels text should not be done from a thread you spawned, but should be done from the main thread that runs your gui code (in swing it is called event dispatch thread(in the swing trail).
A tutorial on how to have worker threads that update the gui can be found i.e. here. the basic idea is to have a backgound thread do the calculations and return the result. There is SwingWorker to help with this. The gui thred will then update the gui.
A introduction to concurreny and swing is i.e. here
public class Test {
public void buildGUI()
{
JFrame frame = new JFrame();
JButton send = new JButton("Send");
send.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
send();
frame.dispose();
}
});
frame.add(send);
frame.pack();
frame.setVisible(true);
}
}
if the method send() throws MyException how would I have that exception migrate its way out of the Swing thread to my class?
What I want to do with the Exception that's generated is have another class that instantiates it catch the exception like so.
public class AnotherTest
{
public AnotherTest()
{
Test t = new Test();
try
{
t.buildGUI();
}
catch(MyException e)
{
//do stuff.
}
}
}
That's what I want to happen conceptually, however I know that buildGUI will end before actionPerformed is ever called. So, how would I catch the potential exception in actionPerformed in AnotherTest?
A class may not thow an exception. Only methods can.
And a class isn't something that can be executed. A method can be executed.
And what executes the action listener method is the Swing event dispatch thread. The only thing you can do if some method throws an exception in a listener is to catch it and display it somehow : by opening an error dialog box, or putting the exception message in a text area, or anything.
public void actionPerformed(ActionEvent e) {
try {
send();
}
catch (MyException e) {
someTextArea.setText(e.getMessage());
}
}
If you in fact want to communicate from the Swing EDT with the main thread, you could use a BlockingQueue, and have the main thread call take on the queue and the listener offer the exception to the queue.
Any other thread communication mechanism would do. But make sure not to block the EDT, or the whole GUI will freeze.
A class cannot throw an exception, only methods can so the very first line is a mistake. Second thing, you can surround send() with try...catch() block to handle that exception in which you can either take some error recovery action or display an error message or something like that and that would still serve your purpose.
Well, why just don't do it? And instead make send() call some other thread where your logic runs? And if that thread encounters exception, you can handle it there.
There's no way to throw exception across thread boundaries. You can make send() pass info about occurred exception to outer world by setting some outer flag, which is visible to other threads of your app.
Swing isn't Thread safe, then idea to build Swing GUI inside try - catch - finally block is more that contraproductive, you have to preparing all us-safe code blocks separatelly
1) I'm starting with very bad way -> your idea must be wrapped into invokeLater(), if is there hard and long running Stream, File I/O, DB Conenction then to try wrap that into invokAndWait()
but you loading these data from some GUI that there exist, you have lots of time for
2) prepare and load data (Stream, File I/O, DB Conenction) before you needed them, then to put these Object to the GUI, when you needed (would be wrapped into invokeLater)
3) create GUI (would be wrapped into invokeLater), show this Container, then load data (Stream, File I/O, DB Conenction) if with success, then add a show these data in the GUI
3) create GUI (would be wrapped into invokeLater), show this Container, load data only for one of JComponents, if with success, then show this JComponent, same for 2nd. and so on ...
for all three options is required to redirect (Stream, File I/O, DB Conenction) load these data, value for JComponent(s), to the Background Task(s), you have two correct ways how to do it,
by using
Runnable#Thread
SwingWorker
I have an applet that calls a JDialog that contains a JProgressBar component. I subclass the JDialog to expose a method to update the JProgressBar, something like:
public class ProgressDialog extends javax.swing.JDialog {
public void setProgress(double progress) {
jProgressBar1.setValue(jProgressBar1.getMinimum() + (int) (progress * jProgressBar1.getMaximum()));
}
...
}
I use this dialog in the following manner:
public void test() throws Exception {
progressDialog = new ProgressDialog(null, true);
try {
progressDialog.setLocationRelativeTo(null);
// show the dialog
EventQueue.invokeLater(new Runnable() {
public void run() {
progressDialog.setVisible(true);
}
});
// business logic code that calls progressDialog.setProgress along the way
doStuff();
} finally {
progressDialog.setVisible(false);
progressDialog.dispose();
}
}
It works fine on Windows/any browser. However, when invoking the above function on Firefox 2/3/3.5 on a Mac, the progressDialog is displayed indefinitely, i.e. it doesn't close.
I suspected that calling setVisible(true) inside the EventQueue was causing the problem, since it's a blocking call and might block the queue completely, so I tried changing it to:
// show the dialog
new Thread() {
public void run() {
progressDialog.setVisible(true);
}
}.start();
With this change, the progressDialog now closes correctly, but a new problem emerged - the contents of the dialog (which included the progressbar, an icon and a JLabel used to show a message string) were no longer shown inside the dialog. It was still a problem only on Mac Firefox.
Any ideas? I realize it's probably some AWT threading issue, but I've been at this for a couple of days and can't find a good solution. Wrapping the doStuff() business logic in a separate new Thread seems to work, but it's not easy to refactor the actual business logic code into a separate thread, so I'm hoping there's a simpler solution.
The envt is:
Mac OSX 10.5
Java 1.5
Firefox 2/3/3.5
Found out that the problem was that the applet function was executing inside the AWT dispatcher thread, therefore the thread blocks and no events are processed until the applet function finishes execution.
Solution was to move the processing logic into a separate thread spawned by the ProgressDialog object before calling setVisible(true). setVisible(true) would block the main thread but still allow the event dispatcher to continue processing, hence rendering the contents of the dialog until the spawned thread calls setVisible(false) to hide the dialog.
I want to fire a command line executible with the parameters entered in GUI.
Process class can be used to fork my required command line process from the Java application, and I used the getInputStream() method of Process object to get the result and got it displayed in the GUI.
private void confirmActionPerformed(java.awt.event.ActionEvent evt) {
String output;
try {
Process p = Runtime.getRuntime().exec("my command line exe with parameters");
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((output = stdInput.readLine()) != null) {
TextField.setText(TextField.getText()+output+"\n");
}
} catch (IOException e) {
System.out.println("Exception in Process");
e.printStackTrace();
}
}
This is my code which is an event listener of a button pressed event and I attempted to display the result of the process in the text field (java swing component).
This process actually runs for quite a long time and shows some statistics as and when it runs when run in command line, but when i attempt it in GUI with the above code I'm getting the entire consolidated result only after the process finish running. I'm not getting the TextField updated as and when it is executing.
What would be the cause of this issue?
This is because the whole thing is done by the Swing event-handling thread.
Perhaps should you consider creating a separate thread and update the TextField with a SwingUtilities.invokeLater().
As Maurice already pointed out, you shouldn't be doing intensive processing on the UI thread. The SwingWorker class helps with that. It's part of the standard API since 1.6. There is also a backport to 1.5 if you can't use 1.6.
This class makes it easier to put some processing task on another thread and display the result later so that your GUI doesn't block in the meantime. You can also use SwingUtilities.invokeLater() directly, of course, as suggested by Maurice, but for me SwingWorker is the way to go as it is quite easy and apparently the new standard way of doing this kind of thing.