Pass JButton to Utility class. Acceptable? - java

I have a JFrame that does things. I have a JButton hidden from view in that JFrame. In a SwingWorker i have a utility Class such as checkNDownloadFile of which I pass a JButton to it. So it can make it visible/usable when the process completes.
My question is, is this acceptable. I dont know of any other method to do this effect. (Keep in mind the checkNDownloadFile class is all static. Its only needed/ran once.)
Sudo Code
-----------------------------------------------------------------
myWorker Class
protected Void doInBackground() throws Exception {
//Loading time consuming data.
//Execute Dialog of the question variety.
//Loading more time consuming data.
//Create JFrame
AtomFrame frame = new AtomFrame();
frame.start();
checkNDownloadFile.setButton(frame.fileButton)
checkNDownloadFile.start();
return null;
}
-----------------------------------------------------------------
checkNDownloadFile Class
public static void start() {
//Do the other task at hand
if (complete && good) {
fileButton.setVisible(true);
} else {
//other stuff
}
}
Answer Code
-----------------------------------------------------------------
myWorker Class
protected Void doInBackground() throws Exception {
//Loading time consuming data.
//Execute Dialog of the question variety.
//Loading more time consuming data.
//Create JFrame
//Moved to Main Method to be created by EDT.
//AtomFrame frame = new AtomFrame();
//frame.start();
publish("Executing");
boolean returnedB = checkNDownloadFile.start();
if (returnedB) {
publish("Good");
} else {
//Maybe implement
//checkNDownloadFile.getError();
publish("Bad");
}
return null;
}
-----------------------------------------------------------------
checkNDownloadFile Class
public static void start() {
//Do the other task at hand
if (complete && good) {
return true
} else {
//Maybe implement
//setError("");
return false
}
}

Do not update the GUI from your implementation of doInBackground().
Do update the GUI from your implementation of process() or done(), as shown here, and here.
You may have to re-factor your checkNDownloadFile() method to provide the desired granularity for a sensible progress display.
See also Watching a Directory for Changes.

Related

JProgressBar doesn't update in real time within a loop [duplicate]

This question already has answers here:
Can a progress bar be used in a class outside main?
(3 answers)
Closed 7 years ago.
It is the first time I have to work with a progress bar and I'm facing a problem, besides I try to call its setValue(x) from everywhere it keeps on 0% and goes straight to 100% after my method routine finishes.
I tried to make an inner class that extends Thread, then after I tried to start a new Thread within my "main" method, then for the last I tried to use the Observer. These ones seems to have worked according to this posts but unfortunately not to me
Update JProgressBar from new Thread
Problem making a JProgressBar update values in Loop (Threaded)
please, could someone help me???
public class MainClass {
private void checkFiles() {
Task task = new Task();
task.start();
//here I have some Files validation...I don't think it is important to solve the progressbar problem
//so it will be ommited
//in this point I tried to call update to test the observer solution I found in another post here
//task.update(null, null);
JOptionPane.showMessageDialog(this, "Done!");
//here the bar jumps from 0% to 100%
}
private class Task extends Thread implements Observer {
public Task() {
}
//Dont bother with the calculum as I haven't finished working on them....
//The relevant thing here is that it starts a new Thread and I can see the progress
//increasing on console using system.out but my progress bar still don't change from 0%.
public void run() {
int maxSize = 100;
final int partsSize = maxSize / listaArquivosSelecionados.size();
while (listFilesValidated.size() != listFilesToValidate.size()) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
int progress = listFilesValidated.size() * partsSize;
System.out.println("Progress" + progress);
progressBar.setValue(progress);
}
});
try {
Thread.sleep(100);
}
catch (InterruptedException e) {}
}
}
//Just tried to set any value to check if it would update before the files validation thread finishes its work.
#Override
public void update(Observable arg0, Object arg1) {
progressBar.setValue(66);
}
}
You can create another class of ProgressBar (see Oracle tutorial) and use this:
ProgressBar pbFrame = new ProgressBar();
pbFrame.setVisible(true);
Executors.newSingleThreadExecutor().execute(new Runnable() {
#Override
public void run() {
// run background process
}
});
Or you can use SwingWorker, for example:
SwingWorker worker = new SwingWorker<MyReturnType, Void>() {
#Override
public MyReturnType doInBackground() {
// do your calculation and return the result. Change MyReturnType to whatever you need
}
#Override
public void done() {
// do stuff you want to do after calculation is done
}
};
I had the same question some years ago.

Setting up a progress bar in Java

I have a program currently and have tried to implement a progress bar with my code. Bellow is an example of the code currently. The main GUI is in its own class and instantiates other classes to then execute code within those classes' methods. An example is as follows:
class MainClass {
public javax.swing.JProgressBar progressBar;
private void combineActionPerformed(java.awt.event.ActionEvent evt) {
Combine combiner = new Combine();
combiner.Merge(folder);
}
}
It takes a folder listing and then goes to the Combine class which has the following code:
public class Combine extends SwingWorker<Integer,Integer>{
public void Merge(Folder []){ (for int i=0;i<folder.length;i++){
merge(folder[i]);
}
public void Merge(folder[]){
output stream;
}
}
How do I implement the swing worker properly in this example to make a progress update to the MainClass progress bar as each iteration of i occurs?
To begin, your worker is missing some methods it should implement, such as doInBackground() and done(). You also need a constructor to pass Folder[].
public class Combine extends SwingWorker<Integer,Integer>{
Folder[] folders;
public Combine (Folder[] folders)
{ this.folders = folders; }
private void Merge(Folder [])
{ (for int i=0;i<folder.length;i++)
{
merge(folder[i]);
//Send the message of progress here, it will be executed
//from doInBackground()
setProgress(....);
}
}
private void Merge(folder){
output stream;
}
protected Integer doInBackground()
{
merge(folders);
return null;
}
protected void done()
{ .... }
}
Then you would call this worker with
Combine combiner = new Combine(folders);
combiner.execute();
To track progress, this example is from SwingWorker API:
combiner.addPropertyChangeListener(
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
progressBar.setValue((Integer)evt.getNewValue());
}
}
});
Use the setProgress method as you are doing your processing to send the update. You could simply count how many files there are and call setProgress with (numberProcessed*100)/totalNumber. Note that the multiplication is done first to prevent rounding issues.
This will cause the PropertyChangeListeners to be notified of the changes, this will happen on the EDT so it will be safe to update your JProgressBar from it.

How to pause program having main() until a button from GUI is pressed?

I am new at Java Swing.
I have two Java files. One having main() in it and the other is the GUI file.
Client
class Client
{
GUI gui;
public static void main(String args[])
{
//.......... do something.......
gui = new GUI();
// at thin point I want to have value of gui.s1 ....
//but main() actually do not wait for the user input.
}
}
GUI
class GUI extends JFrame implements ActionListener
{
String s1="";
GUI()
{
JTextField t1= new JTextField(20);
JButton j1= new JButton("submit");
j1.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
s1=t1.getText();
}
}
Please guide me, and if it is not appropriate question then please suggest me the article that you think I should read to get the concept.
Right now I'm at phone so I can't help you with code I will try to let you understand the concept: An user input, a button click is something which vould happen after 5 seconds like could happen after 30 minutes. So yes, you could let sleep the main for sometimes and hope for an input, wait until .s1 get a value and etc.
But, I don't see it like the right thing to do here. The best thing which could be used is a callback which is called when the user click the button. It's done using interfaces.
Well, first you declare an interface maybe named OnRequestClick where you implement onRequestClick(String message); method.
Message will be the text of s1.
Now in the GUI class create a new field of type OnRequestClick named listener and take it in your constructor.
Now where you create the GUI object the compiler ask to you to provide a code for OnRequestClick so do it and it willbe the code which will be executed when the user press tbe button.
Well, righr now what I said is false: it doesn't get fired since we didn't have done any call to listener.onRequestClick ()
So in your actionPerformed add listener.onRequestClick (s1.getText ()); so in your main you will get the ebemt and the text.
Replace GUI with a JOptionPane.showInputDialog(..) and not only will the code be a lot shorter, but the problem will be solved. E.G.
import javax.swing.*;
class UserInput {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
String name = JOptionPane.showInputDialog(null, "Name?");
if (name==null) {
System.out.println("Please input a name!");
} else {
System.out.println("Name: " + name);
}
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
You can use a Callback Mechanism.
I have already posted a sample code here JFrame in separate class, what about the ActionListener?. Please have a look.
interface Callback {
void execute(String value);
}
abstract class GUI extends JFrame implements ActionListener, Callback{
...
// do not provide the implementation of `execute` method here
...
public void actionPerformed(ActionEvent e) {
s1 = t1.getText();
// now callback method is called
execute(s1);
}
}
Your main class will look like:
public static void main(String args[]) {
gui = new GUI() {
#Override
public void execute(String value) {
System.out.println("Entered value:" + value);
}
};
}

JProgressBar not triggering propertyChange on setProgress

I've read many different articles about JProgressBar...including the dodgy code found over at Java; here.
Most indicate you need a SwingWorker to get things happening properly, which makes perfect sense, I understand that much. I am finding that when I call setProgress(value) to update the progressbar, it's not triggering the propertyChange event most of the time. I've checked the value I'm passing to setProgess and it definitely changes every time, so I'm not sure if it's just firing the event too quickly? Please see relevant code below, any help/explanation would be greatly appreciated.
class ProgBar extends SwingWorker
{
public ProgBar()
{
addPropertyChangeListener(new PropertyChangeListener()
{
#Override
public void propertyChange(PropertyChangeEvent evt)
{
if ("progress".equals(evt.getPropertyName()))
{
int value = (Integer)evt.getNewValue();
System.out.println("propertyChange called with: " + value);
loginProg.setValue(value);
}
}
});
loginProg.setStringPainted(true);
loginProg.setValue(0);
setProgress(0);
}
#Override
public Void doInBackground() throws InterruptedException
{
...
int count = 0;
for (Folder f : folders)
{
... // process 'f'
setProgress((int)Math.min(((double)count/folders.length)*100.0, 100.0));
}
...
return null;
}
#Override
public void done()
{
System.out.println("Done called.");
setProgress(100);
loginProg.setValue(100);
}
}
JProgressBar called with this;
private void jButtonActionPerformed(java.awt.event.ActionEvent evt)
{
// Create new thread to run progess bar.
// Otherwise won't be able to update progress bar.
ProgBar pb = new ProgBar();
pb.execute();
}
}
EDIT:
Yeah, so I should have read the Javadocs better;
Because PropertyChangeListeners are notified asynchronously on the Event Dispatch Thread multiple invocations to the setProgress method might occur before any PropertyChangeListeners are invoked. For performance purposes all these invocations are coalesced into one invocation with the last invocation argument only.
For example, the following invokations:
setProgress(1);
setProgress(2);
setProgress(3);
might result in a single PropertyChangeListener notification with the value 3.
I.E. my assumption that setProgress was firing too quickly was correct. A ProgressMonitor might be a better solution.
This isn't an answer but a demonstration sscce, to show you just what I meant:
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;
import javax.swing.*;
public class TestProgBar {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ProgBar progBar = new ProgBar();
// **** this is key and where your code may be deficient ***
JProgressBar prog = progBar.getProg();
progBar.execute();
JOptionPane.showMessageDialog(null, prog);
}
});
}
}
class ProgBar extends SwingWorker<Void, Void> {
private JProgressBar loginProg = new JProgressBar();
public ProgBar() {
addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
int value = (Integer) evt.getNewValue();
System.out.println("propertyChange called with: " + value);
loginProg.setValue(value);
}
}
});
loginProg.setStringPainted(true);
loginProg.setValue(0);
setProgress(0);
}
public JProgressBar getProg() {
return loginProg;
}
#Override
public Void doInBackground() throws InterruptedException {
int count = 0;
int max = 5;
Random random = new Random();
// simulate uploading files
while (count < 100) {
count += random.nextInt(max);
if (count > 100) {
count = 100;
}
setProgress(count);
Thread.sleep(400);
}
// for (Folder f : folders) {
// setProgress((int) Math.min(((double) count / folders.length) * 100.0,
// 100.0));
// }
return null;
}
#Override
public void done() {
System.out.println("Done called.");
setProgress(100);
loginProg.setValue(100);
}
}
Again, this code works fine, suggesting that the code you've loaded does not show the error. You need to do further work isolating the error and getting it into code so we can test it.
Yeah, so I should have read the Javadocs better;
Because PropertyChangeListeners are notified asynchronously on the Event Dispatch Thread multiple invocations to the setProgress method might occur before any PropertyChangeListeners are invoked. For performance purposes all these invocations are coalesced into one invocation with the last invocation argument only.
For example, the following invokations:
setProgress(1);
setProgress(2);
setProgress(3);
might result in a single PropertyChangeListener notification with the value 3.
I.E. my assumption that setProgress was firing too quickly was correct. A ProgressMonitor might be a better solution. I've confirmed this with the SSCCE and my program, both are simply firing setProgress too quickly and as a result, only the last value passed to setProgress is being passed through to the PropertyChange event.
If you want listeners to be called immediately, you can try the following (which worked for me):
setProgress(1);
firePropertyChange("progress", 0, 1);

Weird. Query works in Fuseki HTML form but not from JAVA?

I would like to ask some questions regarding the use of threads. I have looked at a lot of posts and links suggested from those posts but still came up blank.
I have a NetBeans project that has a few classes. One of them is the Gui class that I use to just click a button and some processing gets performed. From the Gui I call an instance of another class that in turn calls other classes. One of these classes submits a Sparql query to a TDB backend database. All output is saved to files for now.
What I would like to do is to somehow make the class called from the Gui to run on another thread and also to be able to update an EditorPane and a TextArea on the Gui from one or more of the called classes. Up to now I have tried calling an instance of the Gui class and use a public method within but this does not work. I am calling the instance Gui with
Gui gui = new Gui();
gui.setEditorPaneText("File name is: " + fn);
and the method in the Gui class is
public void setEditorPaneText(final String string) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
setString(string);
EditorPane.setText(getString());
EditorPane.repaint();
}
});
}
I tried running the debugger but the processing skips from the first line of the method to the last curly bracket without processing the code within. My Gui class has the following as a main method. The commented part was a previous version of the event queue that I changed while I was reading through the numerous posts on the issue.
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Gui().setVisible(true);
throw new UnsupportedOperationException("Not supported yet.");
}
});
}
The following is the previous code of the main method that I replaced after reading some of the posts on this issue.
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Gui().setVisible(true);
}
});
Any helpful information will be much appreciated. Thank you.
I think your main error is that you create two instances of your Gui class. You have the following snippet twice: new Gui(). Take a look at my example code below to see an example how to pass the Gui to your worker thread.
// This is handwritte-untested-uncompiled code to show you what I mean
public class Main {
public static void main(String[]args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Gui g = new Gui();
g.show(); // show() is equal to setVisible(true)
g.doBackendAction(); // Normally this would be invoked by a button or sthg. I was to lazy
}
});
}
}
public class Gui extends JFrame {
private JTextArea area;
public Gui() {
// Just some code to create the UI. Not sure if this actually does sthg right :P
area = new JTextArea();
setContentPane(area);
pack();
}
public void setTextAreaContent(final String string) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
area.setText(string);
this.repaint(); // Not 100% sure if we need this
}
});
}
public void doBackgroundWork() {
BackgroundWorker w = new BackgroundWorker(this);
new Thread(w).start(); // Start a worker thread
}
}
public class BackgroundWorker implements Runnable {
private Gui gui;
public BackgroundWorker(Gui gui) {
this.gui = gui; // we take the initial instance of Gui here as a parameter and store it for later
}
public void run() {
try { Thread.sleep(10 * 1000); } catch (InterruptedException e) {; }
this.gui.setTextAreaContent("Hello World!"); // calls back to the Gui to set the content
}
}

Categories