4

I have a Main JPanel, and its layout is set to the CardLayout.

Main JPanel has 4 Cards: Card1JPanel, Card2JPanel, Card3JPanel, Card4JPanel.

I also have a SwingWorker class called "MySwingy" that performs something forever while its loop flag is set to true.

When Card1JPanel is VISIBLE/SHOWN I want to execute MySwingy worker.

When Card1JPanel is NOT VISIBLE/HIDDEN I want to stop the MySwingy worker;

The following is the code I currently have and I am wondering if there is a better/cleaner way to tackle the problem above. In the following code example you will see that I use a ComponentListener for Card1JPanel to detect if it is shown or hidden, but what if I have many, many Cards each with its own ComponentListener event will these event listeners slow down my application?

Thank you very much

public class Card1JPanel extends JPanel{

    private MySwingy mySwingy;
    private JTable tableDatabase;

    public Card1JPanel(){
        initComponents();//tableDatabase is drawn here among other things
        this.addComponentListener(new myListener());
    }

    class myListener implements ComponentListener {

        @Override
        public void componentHidden(ComponentEvent e) {
            try{
                mySwingy.stopExecuting();//A flag inside of the worker gets set to false that terminates the while(true) loop.
            }catch(NullPointerException ex){
            }
        }

        @Override
        public void componentMoved(ComponentEvent e) {
        }

        @Override
        public void componentResized(ComponentEvent e) {
        }

        @Override
        public void componentShown(ComponentEvent e) {
            mySwingy = new MySwingy(tableDatabase);
            mySwingy.execute();
        }
    }
}

EDIT:Shows what mySwingy does:

MySwingy is used to parse data from an SQL database and to update the tableDatabase when the data in the database has changed. The tableDatabase is on the Card1JPanel and it is updated on the EDT from MySwingy using the SwingUtilities.InvokeLater. In my application I have many Cards (JPanels) with JTables and SwingWorkers that update their JTables on the EDT. Now, I am sure that the GUI would freeze if all of these JTables were updated constantly on the EDT from their SwingWorkers. Therefore, how do I stop the SwingWorker from updating the JTable when its JPanel is not Visible? That is my question.

public class MySwingy extends SwingWorker<Void,Void>{

    private JTable tableDatabase;
    private boolean isStopExecuting;
    private boolean isDatabaseDataChanged;

    public MySwingy(JTable tableDatabase){
        this.tableDatabase = tableDatabase
        isStopExecuting = false;
        isDatabaseDataChanged = false;
    }

    public void stopExecuting(){
        isStopExecuting = true;
    }

    @Override
    public Void doInBackground(){

        while(isStopExecuting == false){

            //Here is the code that parses some data from an SQL database and if the data in the SQL database
            //has changed the isDatabaseDataChanged boolean flag is set to true,
            //else isDatabaseDataChanged boolean flag is set to false;

            if(isDatabaseDataChanged == true){

                isDatabaseDataChanged = false;

                SwingUtilities.InvokeLater(new Runnable(){

                    @Override
                    public void run(){

                    //Update tableDatabase rows with new data

                    }
                });
            }
        }

    return null;

    }
}
jadrijan
  • 1,438
  • 4
  • 31
  • 48
  • _I am sure that the GUI would freeze_ - how did you reach that conclusion? Did you try/measure it? If not (or in other words: if in reality you are guessing), don't bother until you really see a performance penalty, then find the bottleneck and fix it – kleopatra Sep 09 '12 at 07:32
  • I have not measured it nor tried it in this project, I am just making an educated guess. Also, I prefer to eliminate these types of problems at the beginning, if possible, rather than having to go through hundreds of classes later. – jadrijan Sep 09 '12 at 15:39
  • 1
    only verifying by measuring would convert a guess to an educated guess :-) – kleopatra Sep 09 '12 at 15:44

1 Answers1

4

Don't toggle the worker; let it run. Instead, conditionally update a view only when it isVisible(), either directly via process() or indirectly via a property change.

Addenda: Several helpful comments merit closer examination.

  • As @Andrew notes, much depends on the worker's task. One might evolve a simulation's model on a background thread, but any rendering must take place on the event dispatch thread.

  • I'm no less confused than @mKorbel; you've asked for a critical appraisal of a solution without saying what problem it is meant to solve.

  • @kleopatra notes that SwingWorker is designed to be executed only once. Any attempt to control a doInBackground() loop from another thread will be awkward to synchronize. Also examine your task's anticipated latency, mentioned here. An instance of javax.swing.Timer, which exposes start() and stop() methods, may be an alternative.

  • Updated question: If your worker needs to poll a data source having variable latency, use a java.util.Timer in the background thread to perform the trigger query at a sustainable pace.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • 1
    *"Don't toggle the worker; let it run"* Not especially helpful if the worker is running the processes of a 2D shooter. ;) What *would* be helpful at this stage is more details from the OP as to what 'Swingy thingy' does. – Andrew Thompson Sep 08 '12 at 02:22
  • 1
    please I don't understand both descriptions, answer and comment too :-), – mKorbel Sep 08 '12 at 06:03
  • 1
    a bit more emphasis on _don't toggle_, please: it's explicitly _forbidden_ as per api doc :-) – kleopatra Sep 08 '12 at 06:29
  • 1
    Excellent comments; I've elaborated above. – trashgod Sep 08 '12 at 11:19
  • Please take a look at my example above, I have updated it to show what MySwingy does and I tried to explain what my question is. I am 100% sure that all of you came across this problem but I am wondering how you solved it. Thank you all so much for trying to help me, I really appreciate it. – jadrijan Sep 08 '12 at 22:29
  • 1
    You don't need any of that. Let the worker update each model in `process()`; the table will update when displayed. Use a `java.util.Timer` in the background thread to do the trigger query at a sustainable pace. – trashgod Sep 08 '12 at 23:58
  • _might evolve the model on a background thread_ hmm, what do you mean by that? Certainly _not_ any "model" attached to a Swing component? – kleopatra Sep 09 '12 at 07:28
  • @kleopatra: Right; I meant in terms of Andrew's notion of a game/simulation. Definitely worth an edit. – trashgod Sep 09 '12 at 12:16