views:

511

answers:

3

So I have this nice spiffy MVC-architected application in Java Swing, and now I want to add a progress bar, and I'm confused about Good Design Methods to incorporate a JProgressBar into my view. Should I:

  • add a DefaultBoundedRangeModel to my controller's state, and export it?

    class Model {
      final private DefaultBoundedRangeModel progress
        = new DefaultBoundedRangeModel();
    
    
      public void getProgressModel() { return progress; }
      public void setProgressCount(int i) { progress.setValue(i); }
    }
    
    
    class Controller {
      Model model;
      int progressCount;
      void doSomething()
      {
         model.setProgressCount(++progressCount);
      }
    }
    
    
    class View {
      void setup(Model m)
      {
        JProgressBar progressBar = /* get or create progress bar */  ;
        progressBar.setModel(m.getProgressModel());
      }
    }
    
    
    /* dilemma: Model allows progress to be exported so technically
     all of the progress state could be set by someone else; should it be put
     into a read-only wrapper? */
    
  • use JGoodies Binding to try to connect the JProgressBar's visual state to my model's state?

    class Model {
      private int progress;
    
    
      public void getProgressCount() { return progress; }
      public void setProgressCount(int i) { progress = i; }
    }
    
    
    class View {
      void setup(Model m)
      {
        ProgressBar progressBar = /* get or create progress bar */  ;
        CallSomeMagicMethodToConnect(m, "progressCount", progressBar, "value");
        // is there something that works like the above?
        // how do I get it to automatically update???
      }
    }
    
  • or something else???

edit: more specifically: could someone point me to a Good Example of realistic source for an application in Java that has a status bar that includes a progress bar, and has a decent MVC implementation of it?

+3  A: 

I would say, something else.

The problem I have had with MVC, is to define the level of abstraction of the model.

  • Model could be some sort of objects for the UI components

  • Model could also be some other sort of objects for the program it self.

and

  • Model could be as high as business models.

In this case I would have separated model/component pairs for the progress bar and handle them in a separate controller class.

This article describes swing architecture and might clarify the way it uses models inside.

OscarRyz
+2  A: 

No (to 1) and NOOOO (to 2). At least in my opinion.

No (to 1): First, DefaultBoundedRangeModel is a javax.swing class. In my opinion, these classes have no place in models. For example, think about the model living on the server, being accessed via RMI - All of the sudden putting a javax.swing class there seems "not right". However, the real problem is that you're giving a part of your model (the bounded model) to someone else, with no control over events fired or queries made.

No (to 2): Ugh. Binding is fun but (at least in my opinion) should be used to synchronize between UI model and UI components, not between data model and UI model. Again, think what would happen if your data model lived on a remote server, accessed by RMI.

So what? Well, this is only a suggestion, but I'd add an event listener interface and add the standard event listener subscription methods (addListner(...), removeListener(...)). I'd call these listeners from within my model when I have updates going on. Of course, I'd make sure to document the calling thread (or say it cannot be determined) in order for the client (the UI in this case) to be able to synchronize correctly (invokeLater and friends). Since the listener service will be exposed by the controller, this will allow the model to live anywhere (even allowing for listeners to be remotely invoked or pooled). Also, this would decouple the model from the UI, making it possible to build more models containing it (translators / decorators / depending models).

Hope this helps.

Ran Biron
btw, you should look at SwingWorker - it deals with this issue (updating progress from a background task) specifically.
Ran Biron
+2  A: 

In our app (MVC, about 100 KLOC) we have it like that (pattern Observer, actually):

/**
 * Observer on progress changes
 */
public interface IProgressListener {
  public void setProgress(ProgressEvent e);
}

public class ProgressEvent extends ... {
  private int progressCount;
  // setter + getter
  ...
}

class Model {
  public void addProgressListener(IProgressListener l);
  protected void fireProgressChange(ProgressEvent e);   // call .setProgress() on listeners
}

class Controller {
  private Model model;
}

class View extends ProgressBar implements IProgressListener {
  ...
  // IProgressListener implementation
  public void setProgress(ProgressEvent e) {
    this.setValue(e.getProgress());
  }
  ...
}
Sergey Borodavkin