I got a java progressbar which loads perfectly, but I can't see the process, only the result. (when the bar finished loading)
I want to see every percentage of the progress. When I run the code, the frame appears but the progressbar doesn't, only when it's on 100%. Where's the problem?
private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {
JFrame f = new JFrame("JProgressBar Sample");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container content = f.getContentPane();
progressBar = new JProgressBar();
progressBar.setStringPainted(true);
Border border = BorderFactory.createTitledBorder("Reading...");
progressBar.setBorder(border);
content.add(progressBar, BorderLayout.CENTER);
f.setSize(300, 100);
f.setVisible(true);
progressBar.setValue(0);
inc(); //fill the bar
//It fills, but I can't se the whole loading...
}
//Here's the filling path
public static void inc(){
int i=0;
try{
while (i<=100){
progressBar.setValue(i+10);
Thread.sleep(1000);
i+=20;
}
}catch(Exception ex){
//nothing
}
}
Your GUI is not updated while you are running a long process in the GUI's thread, like filling a progress bar and sleeping some seconds.
Just emerge a thread, which will handle the long operation.
Within this thread set the progress bar to the desired value within a SwingUtilities.invokeLater(new Runnable() {...}.
Runnable r = new Runnable() {
public void run() {
int i=0;
try{
while (i<=100){
final int tmpI = i+10;
SwingUtilities.invokeLater(new Runnable(){
public void run() {
progressBar.setValue(tmpI);
}
});
Thread.sleep(1000);
i += 20;
}
} catch(Exception ex){
//nothing
}
}
};
Thread t = new Thread(r);
t.start();
Related
I have a simple question relating to iPOJO.
When a component iPOJO sleeps, all remaining components will also disable although there are not dependencies between them. Why? Here's an example:
Component 1:
#Component(name="frame1", immediate=true)
#Instantiate(name="iframe1")
public class Frame1 implements Runnable{
String str;
Label lb = new Label();
TextField tf = new TextField();
Frame fr;
public void run() {
fr = new Frame("Frame1");
fr.setLayout(new BorderLayout());
fr.setSize(230, 200);
fr.setLocation(900,250);
fr.add(tf, BorderLayout.NORTH);
lb.setText("Result");
fr.add(lb, BorderLayout.CENTER);
Panel pn = new Panel();
fr.add(pn, BorderLayout.SOUTH);
pn.setLayout(new GridLayout(1,4,1,1));
Button bt = new Button("Printer 1");
pn.add(bt);
bt.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
System.out.println("start sleep");
Thread.sleep(5000);
System.out.println("stop sleep");
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
fr.setVisible(true);
}
#Validate
public void start() {
//this.delayService = dls;
Thread th = new Thread(this);
th.start();
}
#Invalidate
public void stop() {
System.out.println("stop");
fr.setVisible(false);
}
}
Component 2:
#Component(name="frame2", immediate=true)
#Instantiate(name="iframe2")
public class Frame2 implements Runnable{
String str;
Label lb = new Label();
TextField tf = new TextField();
Frame fr;
public void run() {
System.out.println("start component 2");
fr = new Frame("Frame2");
fr.setLayout(new BorderLayout());
fr.setSize(230, 200);
fr.setLocation(900,250);
fr.add(tf, BorderLayout.NORTH);
lb.setText("Result");
fr.add(lb, BorderLayout.CENTER);
Panel pn = new Panel();
fr.add(pn, BorderLayout.SOUTH);
pn.setLayout(new GridLayout(1,4,1,1));
Button bt = new Button("Printer 2");
pn.add(bt);
bt.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("in 2");
}
});
fr.setVisible(true);
}
#Validate
public void start() throws Exception {
//this.delayService = dls;
System.out.println("start thread 2");
Thread th = new Thread(this);
th.start();
//fr.setVisible(true);
}
#Invalidate
public void stop() throws Exception {
System.out.println("stop");
fr.setVisible(false);
}
}
Two components are deployed and running. There are two independent components. But I click the "Printer 1" button. "frame1" component is sleeping during 5s. And during these 5 seconds, i can't click "Printer 2" of "frame2" component.
This is not an ipojo issue. Swing uses one thread (and only one thread) in order to dispatch events such as clicks. When you click your first button, swing runs your actionPerformed in this thread. This method puts your thread to sleep for 5 seconds. This means that the thread responsible for event handling cannot do anything during this time. This is why your program does not respond to your second click.
Whenever you have a long computation in swing (and also osgi), it is often a good idea to run your code in a separate thread in order to avoid blocking the execution (here you have a useless Thread.sleep() but I guess you could have an http request or anything that may take a long time instead). You should probably use an executor service or anything similar.
My goal is creating a function that waits half second, set the jbutton's background to red for one second, and after this second the jbutton will return to normal. Cant make this work..
This is my Function
private void paint(final int num){
Timer timer = new Timer(500, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (num == 1){
btn.setBackground(Color.black);
}
}
});
timer.start();
}
Start a 500ms timer that will do two things when it goes off:
- change the color to red
- start a 1s timer that will change the color to normal, when it goes off
Well, this would do it (note, you would probably want to put the code from the first sleep onwards into a timer or it's own thread in a real application to avoid blocking the thread running the code):
public static void main(String[] args) throws Exception {
final JFrame jf = new JFrame();
final JButton jButton = new JButton("Hello");
final Color originalBackground = jButton.getBackground();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jf.getContentPane().add(jButton);
jf.pack();
jf.setVisible(true);
}
});
Thread.sleep(500);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
jButton.setBackground(Color.RED);
}
});
Thread.sleep(1000);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
jButton.setBackground(originalBackground);
}
});
I have a constructor of a JFrame where I have a Thread(t1) which is running thanks to a
while(true)
I would like to know how to implement my JFrame so it can kill the thread when I close it, because t1 need to be running when the JFrame is active
EDIT:
Here is the code:
public class Vue_Session extends JFrame {
private JPanel contentPane;
private int idsess;
private User u;
public Vue_Session(User us, int id) {
this.u = us;
this.idsess = id;
toServ t=new toServ(idsess);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setBounds((int) screenSize.getWidth() / 2 - 800 + (800 / 2), 90, 800,
600);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(new BorderLayout());
Vue_Idee vueIdee = new Vue_Idee(this.idsess, this.u);
contentPane.add(vueIdee, BorderLayout.SOUTH);
Vue_IdeeSession vueSess = new Vue_IdeeSession(this.idsess);
contentPane.add(vueSess, BorderLayout.CENTER);
Thread t1 = new Thread( new Runnable(){
public void run(){
while(true){
try{
Thread.sleep(500);
}catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.getIdee();
vueSess.act();
revalidate();
}
}
});
t1.start();
}
You can handle it with a boolean variable like
boolean end = false;
while (!end){...}
Also I suggest you use ExecutorService or ForkJoinPool so you can simply control your tasks, threads, etc
EDIT:
boolean end = false;
new Thread(() -> {
while (!end) {
//...
}
}).start();
and this is where you should end your tasks:
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosed(java.awt.event.WindowEvent evt) {
end = true;
System.exit(0);
// or this.dispose();
}
});
good luck :)
It's a controversial topic but in general I would replace the while (true) construct with
while(!Thread.currentThread().isInterrupted()){
try{
Thread.sleep(500);
}catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
t.getIdee();
vueSess.act();
revalidate();
}
More information on this topic can be found here:
http://www.javaspecialists.eu/archive/Issue056.html
Okay, here was the answer:
I needed to add en WindowListenne:
addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent b) {
t1.stop();
dispose();
}
});
And also:
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
First, you need to make the thread kill-able. To do this, instead of looping forever, loop as long as certain looping flag is true.
After that, you need to create a listener that gets called whenever the user closes the frame. You can use WindowAdapter to do this. When the listener is called, set the looping flag to false. Once the thread dies, you can safely terminate the program.
For example:
public class Vue_Session extends JFrame {
Thread thread = null;
boolean threadAlvie = true;
boolean threadDie = false;
public Vue_Session(User us, int id) {
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent) {
threadAlive = false;
// Wait until the thread dies
while (!threadDie) {
// Sleep for 100 milliseconds.
Thread.sleep(100);
}
System.exit(0);
}
});
thread = new Thread(new Runnable() {
public void run(){
while (threadAlive){
// do something
}
threadDie = true;
}
});
thread.start();
}
}
I have a JDialog being displayed on screen and I want to simulate its movement (Drag from one location to another) based on a condition. Is there any way this can be done ?
See this piece of code below. I have just tested it and it works fine. It is just a proof of concept.
private void startDialog() {
final JDialog d = new JDialog(this, "Test", true);
d.getContentPane().add(new JLabel("Something"));
d.setBounds(100, 100, 400, 300);
Thread t = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 50; i++) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Point p = d.getLocation();
d.setLocation(p.x + 10, p.y + 10);
}
});
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// ignore
}
}
}
});
t.start();
d.setVisible(true);
}
You can improve the code yourself:
use a Timer instead of a regular Thread
tweak the sleep times and the location jumps and so on
Just call this method from any Swing application and it will work.
I'm new to Swing and I was trying to do this:
On pressing a JButton, the program will start iterating over hundreds of items, taking 1 second to process each one, and after finishing each one he should update a label to show the number of items already processed.
The problem is, the label's text is not updated until the cycle finishes iterating over all the items.
I searched online and apparently it's because this is running in the same thread, so I created a new thread to process the data and to update the variable to be used in the label (number of processed files).
But it didn't work. Then I even made another thread, which I start after the previous one, that just repaints the label. Still nothing works.
The code is like this:
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try { SwingUtilities.invokeLater(validateFiles); }
}); }
Runnable validateFiles = new Runnable() {
#Override
public void run() {
while(x_is_not_100) {
processLoadsOfStuff();
label.setText(x); }
}
};
Can you help me with this?
Simple - use a SwingWorker. For more information, read the Tasks that Have Interim Results tutorial.
Here's a pretty generic example that will use a JLabel to display counting from 0 to 30 -
public final class SwingWorkerDemo {
private static JLabel label =
new JLabel(String.valueOf(0), SwingConstants.CENTER);
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
createAndShowGUI();
}
});
JLabelSwingWorker workerThread = new JLabelSwingWorker();
workerThread.run();
}
private static void createAndShowGUI(){
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(label);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static class JLabelSwingWorker extends SwingWorker<Void, Integer>{
#Override
protected Void doInBackground() throws Exception {
for(int i = 1; i < 31; i++){
Thread.sleep(1000);
publish(i);
}
return null;
}
#Override
protected void process(List<Integer> integers) {
Integer i = integers.get(integers.size() - 1);
label.setText(i.toString());
}
}
}
The background processing must be done in a separate thread. But the label update must be done in the event dispatch thread.
So your code should look like this:
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// start a new thread for the background task
new Thread(validateFiles).start();
});
}
Runnable validateFiles = new Runnable() {
#Override
public void run() {
while(x_is_not_100) {
processLoadsOfStuff();
// use SwingUtilities.invokeLater so that the label update is done in the EDT:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
label.setText(x);
}
});
}
};
But you might want to use the SwingWorker class, which is designed to do that in a simpler way. Its documentation is very well done and contains examples.