Question

Using MVC Pattern in java: I have 5 classes (View (GUI), Controller, Model, Class1 & Class2). When i click on a start button, the controller starts a thread in the Model which in turn starts 2 other threads T1 (implemented in Class 1) & T2(implemented in class2).

T1 should display some information onto a JTextArea-1 and then after 5 seconds T2 should remove the data from JTextArea-1 and paste it to JTextArea-2.

i have got T1 working. it displays the information onto the JTextArea-1. But my concern is regarding the starting of the next tread and its implementation.

How can T2 talk to the same Model and get the same update method of the View to be invoked but with different set of actions to be performed?

Thread T1 in class1:

public void run() {

    while(!R.isFinished()) {

    System.out.println("inside kitchen thread");
    String report="";int size =0;
    String str="";int tn=0;

    report = getOrderReport();
    size= report.length();

    for(int i=1;i<=size;i=i+43){
    try
    {
        Thread.sleep(1000);
        str = report.substring(i,i+43);
        tn=Integer.parseInt(str.substring(8,9));
        System.out.println("inside kitchen thread order seq num: " +OrderSeq.getInstance().getNext());
        OrderSeq.getInstance().setLog(str);
        R.receiveAnOrder(str,tn);
        }
    catch (Exception e) {
    System.out.println("Kitchen thread exception" + e.getStackTrace());
    }


}

In the above code: R.receiveAnOrder(str,tn) communicates with the model to update the view.

How can i call the same or maybe another function in the Model to update the view with details from another thread?

Was it helpful?

Solution

First, you need a couple of model classes

You'll need an Order

public Order {

  private String name;

  public Order(String name) {
    this.name = name;
  }

  public String toString() {
    return name;
  }
}

And a list of orders

public OrderList extends DefaultListModel<Order> {

}

And a cook to cook the orders

public void Cook extends Thread implements ActionListener {

  private OrderList waiting;

  private OrderList finished;

  private boolean keepCooking;

  public Cook(OrderList waiting, OrderList finished) {
    this.waiting = waiting;
    this.finished = finished;
    this.keepCooking = false;
  }

  public void run() {
    keepCooking = true;
    while (keepCooking) {
      if (orders.size() > 0) {
        try {
          currentOrder = orders.remove(0);
        } catch (Exception e) {
          // someone else emptied the list
        }
      }
      prepareOrder(order);
      if (keepCooking && orders.size() <= 0) {
        try {
          Thread.sleep(1000);
        } catch (Exception e) {
          // back to work
        }
      }
    }
 }

 public void prepareOrder(Order order) {
   try {
      Thread.sleep(Math.random() % 10000);
      finished.add(order);
    } catch (Exception e) {
      waiting.add(order);
    }
  }

  public void goHome() {
    keepCooking = false;
  }
}

and you'll need some customers to place the orders

public Customers extends Thread {

  private OrderList orders;

  public Customers(OrderList orders) {
    this.orders = orders;
  }

  public void run() {
    int number = 0;
    while (true) {
      number++;
      try {
        Thread.sleep(Math.random() % 10000)
        orders.add(new Order(String.format("Order %d", number)));
      } catch (Exception e) {
        return;
      }
    }
  }
}

Now a component to help configure the Controller

public CloseKitchen extends AbstractAction {

  private Cook cook;

  public CloseKitchen(Cook cook) {
    super("Close Kitchen");
    this.cook = cook;
  }

  public void actionPerformed(ActionEvent e) {
    cook.goHome();
  }
}

... in some block of code ...

// building the model
OrderList waiting = new OrderList();
OrderList finished = new OrderList();
Cook cook = new Cook(waiting, finished);
Customers customers = new Customers(waiting);

// attaching the view
somePanel.add(new JList(waiting));
somePanel.add(new JList(finished));

// building the controller plug-in
CloseKitchen closeKitchen = new CloseKitchen(cook);

// wiring the plugin into the controller
somePanel.add(new JButton(closeKitchen));

// show the view
somePanel.setVisible(true);

// start the cook and customers
cook.start();
customers.start();

and you will see the orders populate in one list and move to the other. That is, until you click the "Close Kitchen" button, after which the cook will goHome() and the Customers will keep ordering.

There are many ways to implement the Cook and Customers. I deliberately didn't use a ListDataListener implementation to avoid confusion about what the model needed to use. Basically, the real model doesn't have to use anything swing related for its internal coordination, provided it can be adapted to the correct [List|Table|Button|...]Model interface.

OTHER TIPS

You can let the Views observe the Model. That means each time your thread changes the Models data, all registered views update.

T1     ---  uses `Controller` to manipulate `Model` (e.g. `Model`.value1) -->  `Controller`
T2    ---   uses `Controller` to manipulate `Model` (e.g. `Model`.value1) -->  `Controller`
`View1`  --- observes `Model`, shows Model.value1 on update --> `Model`
`View2`  --- observes `Model`, shows Model.value2 on update --> `Model`

So following your explanation T2 would let the Controller read Model.value1, clear it and set the value to Model.value2. When the Controller changes the Models values, it says instructs the registered Views to update (2 Views in your case). So then View1 clear its JTextField because Model.value1 is empty and View2 updates its JTextField to Model.value2.

To implement the update mechanism of the View, read this tutorial for the observer pattern.

Further more, keep in mind that GUI operations (e.g. with SWING) from a thread have to be done by the EventDispatcherThread (EDT). SwingUtilities offer an function for this. Simply run all GUI related code from other threads like this:

SwingUtilities.invokeLater( new Runnable() {
    public void run() {
       //Do the gui stuff here
    }
});

Read more about the EDT and SwingUtitlities here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top