I have a c++ application which runs for a long time and I want to track the progress of it. I have a user interface for this application in java. Can anyone please tell me how to track the progress of the native application using JProgressBar. My native application returns an integer when it is done and I have a "Done" button that shows up when this integer is returned. But I want to have a progress bar that shows that the native application is running.
The only ways would be to either create a callback in java (meaning the code in c++ would call the java function) to inform of the current progress or create a function that the java code calls to get the current progress of your task.
http://www.codeproject.com/Articles/22881/How-to-Call-Java-Functions-from-C-Using-JNI
The java code would then use the value to update the jprogress bar.
Another possible simpler solution from Adam's is to have your C++ program output an update of progress to standard output, perhaps a String representation of the percent of progress. The Java program's Process would then have its OutputStream monitored by calling getInputStream() on the Process (yeah, it's not a typo; it's getInputStream()) in a thread background to the Swing thread, and use the information for updating the JProgressBar.
As others have said you need to have a way for your java application to know how far alone your c++ application is.
If you want a quick fix, use a JProgressBar and set it to interdeminate. It will animate the bar to show you something is happening. Once your process returns set the bar to 100%.
Easy way:
ProcessBuilder processBuilder = new ProcessBuilder(command);
JProgressBar progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
Process p = processBuilder.start();
p.waitFor();
progressBar.setIndeterminate(false);
progressBar.setValue(progressBar.getMaxValue());
Better way:
ProcessBuilder processBuilder = new ProcessBuilder(command);
JProgressBar progressBar = new JProgressBar();
processBuilder.redirectErrorStream(true);
Process p = processBuilder.start();
InputStream is = p.getInputStream();
try {
in = new BufferedReader(new InputStreamReader(is, "UTF-8"));
while ((line = in.readLine()) != null) {
//error checking
int progressValue = Integer.parseInt(line);
progressBar.setValue(progressValue);
} finally {
in.close();
}
}
progressBar.setValue(progressBar.getMaxValue());
Related
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
Here is an overview of what I am doing. I have a Java Swing application. On it I have a button called 'Ping'. What I want to happen is that when I click on the button Ping then it should ping a particular server. The server IPAddress details are in a text box.
So this is the code I have.
try {
Process p = Runtime.getRuntime().exec(strbf.toString());
if (Action.equalsIgnoreCase("PING"))
{
BufferedReader in = new BufferedReader(
new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = in.readLine()) != null)
{
mylogger.logInfo("Servers", "actionToBeTaken", "Ping line is" + line);
}
}
So the output of the ping goes into a logger file. Everything is good so far. But I don't want this behavior. Note that if I type in ping into the windows run prompt or dos prompt then a seperate ping window pops up. This is the way I want my code to function. Click on a button and the window automatically pops up. What changes do I make to my code? I tried different things but it does not seem to work. For example the below does not work. I don't know where the output of the ping command is getting eaten up. How do I ensure the command prompt windows pops up and the ping output is visible there.
try {
if (Action.equalsIgnoreCase("PING"))
{
Runtime.getRuntime().exec(strbf.toString());
}
Common question: Is it possible to wait for an application window to appear til i go on with the code? The application was invoked by Java Process/ProcessBuilder.
you can try this :
ProcessBuilder builder = new ProcessBuilder(command);
Process shell=builder.start();
shell.waitFor();
I am creating a small swing application which plots a set of points given in a file. Guidelines suggested me to invoke a new thread for the GUI, for which I used the following code.
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new View().setVisible(true);
}
});
One of the scenario in the application is to open a file (which is done using a JFileChooser).
private void openMenuItemActionPerformed(java.awt.event.ActionEvent evt) {
int returnVal = fileChooser.showOpenDialog(this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
//some heavy operations
} else {
System.out.println("File access cancelled by user.");
}
}
There are some heavy operations that are needed to be done, before proceeding to plot the points.
My questions are, is it advisable to place heavy codes in the GUI thread ? Is it possible to send the file object to the main thread for processing and send the results to GUI thread ?
Please note that I have no idea about Java Threading API.
use SwingWorker
SwingWorker proposes a way to solve it by performing the time-consuming task on another background thread, keeping the GUI responsive during this time.
take a look at this
http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html
http://www.theeggeadventure.com/wikimedia/index.php/SwingWorker_Example
http://weblogs.java.net/blog/mkarg/archive/2010/01/03/did-you-know-swingworker-can-send-progress-status
http://www.javaworld.com/javaworld/jw-06-2003/jw-0606-swingworker.html
If the result of the long running task modifies a Swing component, you can use SwingWorker. For more information, please see Worker Threads and SwingWorker.
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.