Search code examples
javalistenerjslider

How to make Java program wait while a listener is working?


I have a JSlider in my program. Program does something when the value of slider is changed. What I want to do is to increase the value of slider until its max value and I need to wait every time slider value is increased for the things that I do in the ChangeListener class.

Here is my related codes (svPlay is like a play button):

this.svPlay.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            for(int i=slider.getValue()+1;i<=slider.getMaximum();i++){
                slider.setValue(i);
                try{
                    Thread.sleep(1000);
                }catch (Exception ex){
                    ex.printStackTrace();
                }
            }
        }
    });

The problem is, for example if i=10, then program waits 10*1000(milisecond that I used with sleep() method) and it does all the changeListener jobs at the same time.

After slider.setValue(i), changeListener must work and then program should sleep for 1000 ms. How can I do that?

Edit: This is how I changed my program, according to above code. But now nothing is happening when slider value is changed and slider "freezes".

this.slider.addChangeListener(new ChangeListener() {
        @Override
        public void stateChanged(ChangeEvent e) {
            new Thread(() -> {
                try {
                    synchronized (lock) {
                        Thread.sleep(1234);
                        if(checkBox.isSelected()){
                            CyApplicationManager manager = adapter.getCyApplicationManager();
                            CyNetworkView networkView = manager.getCurrentNetworkView();
                            CyNetwork network = networkView.getModel();
                            CyTable table = network.getDefaultNodeTable();
                            FilterUtil filter = new FilterUtil(network,table);
                            ArrayList<CyNode> activities = filter.FilterRowByNodeType("activity", "nodeType");

                            CyColumn timeColumn = table.getColumn("startTime"); // Getting start time column
                            List<String> timeList = filter.getTimeFromColumn(timeColumn); // Gets value of start time column without null value
                            sliderVisualization.sortActivityTimes(timeList, activities);
                            sliderLabel.setText(timeList.get(slider.getValue()));
                            sliderVisualization.hideFutureNodes(timeList, filter, network, networkView);
                            networkView.updateView();
                        }
                        lock.notify();
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }).start();

        }
    });

    this.svPlay.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            new Thread(() -> {
                slider.setEnabled(false);
                for(int i=slider.getValue()+1;i<=slider.getMaximum();i++){
                    synchronized (lock) {
                        slider.setValue(i);
                        try {
                            lock.wait();
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
                }
                slider.setEnabled(true);
            }).start();
        }
    });

I put if statement before and after Thread.sleep() in addChangeListener method but both way did not worked. I do not know if I convert it well or not. Can you help through this code please?


Solution

  • This is what I understand from your question: you have long calculations going on in Slider change listener. You want to perform calculations for a range of values, and reflect that on the slider.

    If the above premise is correct, you don't want to sleep n seconds while calculations are going on -- you want to wait for them to finish and proceed asap. One way to do it, is using wait and notify commands on a lock (note, that recent Java comes with java.util.concurrent package, which contains higher level multithreading control and I think would be better to use, however I'm not familiar with it myself)

    package testas;
    
    import javax.swing.*;
    
    public class Slider {
    
        static class View {
    
            public JPanel panel;
            public JSlider slider;
            public JButton button;
            public JTextField tf;
    
            public View() {
                panel = new JPanel();
                button = new JButton("a");
                slider = new JSlider();
                tf = new JTextField(4);
                panel.add(button);
                panel.add(slider);
                panel.add(tf);
            }
    
    
        }
    
        static class Controller {
    
            private Object lock;
            private View view;
    
            public Controller() {
                lock = new Object();
            }
    
            private synchronized void buttonHandler() {
                new Thread(() -> {
                    view.slider.setEnabled(false);
                    for(int i=view.slider.getValue()+1;i<=view.slider.getMaximum();i++){
                        synchronized (lock) {
                            view.slider.setValue(i);
                            try {
                                lock.wait();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    view.slider.setEnabled(true);
                }).start();
            }
    
            private synchronized void sliderChangeHandler(int value) {
                new Thread(() -> {
                    try {
                        synchronized (lock) {
                            Thread.sleep(1234);//some long calculations
                            view.tf.setText(String.valueOf(value));
                            lock.notify();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    } 
                }).start();
            }
    
            public void setView(View v) {
    
                view = v;
                v.button.addActionListener(l -> buttonHandler());
                v.slider.addChangeListener(l -> {
                    JSlider slider = (JSlider) l.getSource();
                    if (!slider.getValueIsAdjusting())
                        sliderChangeHandler(slider.getValue());
                });
            }
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> {
                Controller c = new Controller();
                View v = new View();
                c.setView(v);
                JFrame f = new JFrame();
                f.add(v.panel);
                f.pack();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.setVisible(true);
            });
        }
    }