November 22, 2014
Hot Topics:

Creating Dynamic Swing Views with Reflection by Extending MVC

  • September 29, 2003
  • By Vlad Kofman
  • Send Email »
  • More Articles »
Often large GUI projects need to be deployed quickly and adhere to strict guidelines; therefore design and implementation process is assigned to multiple developer groups doing the work simultaneously. With the arrival of Model–View–Controller (MVC) architecture, several developer groups can work on business logic or model layer, data representation or views, and Controller independently; combining the pieces at the end. MVC has been used extensively in GUI and Web–Based applications; in this article I’ll show how to extend MVC architectural pattern to build a Swing GUI program by using Reflection to dynamically generate Views. The Controller will read a property file, generate Views, and corresponding Models, and execute simple business logic. Developers working on Views and following this design will only need to update properties file and their new class instances will automatically be added to the main project, without the need to modify Controller or any other part of the project. Reflection will be used to instantiate new objects and call required methods.

On a historical note, model–view–controller architectural pattern was conceived in the mid–1980's by developers of the Smalltalk-80 GUI library. It has since then been extensively used in most object oriented user interfaces, it has also been extensively covered in numerous books and publications. According to the MVC pattern, the model should be separated from the actual implementation of its view. The reason being, that there could be many representations of the same data and closely coupling views with the model would complicate project’s development, modifications and create maintenance nightmares.

In other words, you do not want to change your business logic every time you change your view.

When working on a large Swing GUI project, one way to represent views is to use Tabs or JTabbedPane as an underling class. Development of different modules should be assigned to different programmer groups and at the end and each Tab (view) has to be added to the main application. And before any coding is done, project architects usually come up with object relationship diagrams, use-case diagrams, object flow diagrams and hand out coding responsibilities. At the same time, GUI programmers or designers create appropriate screen prototypes for all sections.

Sample Project

In order to show how to extent MVC to create and coordinate views, I have created a simple GUI project that shows an application containing several tabs and several buttons with attached actions; this project has all the components of a template for a large–scale projects, and with small modifications can easily be reused in other GUI applications. The project contains – a controller that, as any MVC controller, deals with all data flow and coordinates object relationships, but on top of that it also literally creates all views. A model layer – represented by interface ModelInterface and several concrete classes extending it, and a view layer – represented by abstract class AbstractView (that by itself extends generic JPanel component) and several concrete tab classes extending AbstractView class. The model layer is actually a set of beans that perform some rudimentary business logic operations. The beans are not EJBs, but simply objects that manipulate data. The project also has one main property file.

In an enterprise level application properties are usually read as java.util.Properties and include data-store locations, connection pool information, environment variables, debug levels and other global information. For our purposes only views info in a text file will suffice. Additional services managed by controller like persistence, distribution or security, are also beyond the scope of this article.

Main Controller

The Controller is the brain of the project, its responsibility is to capture user events and to determine which actions each of these events imply, and in my case to instantiate new View objects and corresponding Model objects and coordinate actions between them. I called the controlled class “MainController”, it has three methods: init – where all the initialization and views instantiation takes place, execute – where an action from a View invokes some operation from a corresponding Model, and loadProperties method that reads a text file with names of the concrete Views to add. The text properties file is called smvc.property and has just three lines – the actual names of concrete views or tabs:

ConcreteView1
ConcreteView2
ConcreteView3

MainController also has three fields: a main JTabbedPane to add new Views too, an array of Tabs and a HashMap of to store Model objects.

In the init method I call the loadProperties("smvc.properties") to fill the array with tab names from the property file. As each view’s class name is read from the properties file, I use Java Reflection API to instantiate actual objects and add them to the main JTabbedPane. See listing 1 at the end of this article.

{
Class newClass = Class.forName((String) tabs.get(i));
//try to make an object – extending AbstractView
AbstractView anyTab = (AbstractView) newClass.newInstance();
//add our new view tab here, and set its name
mainPane.addTab(anyTab.getName(), anyTab);

// I also set a reference back to the Controller
// let each tab know who is its controller
anyTab.setParent(this);
}

As soon as I add all dynamic Tabs, we can see them:


Swing Views

As I said, each Tab (view) in the project is a subclass of AbstractView abstract class. The AbstractView itself has methods to set the Tab name, set parent component (reference to the controller object), and init method that automatically uses Class name as Tab name (you can change that of cause); very useful since concrete Views will inherent them all.

(See source listing for complete AbstractView code).

// get the name of the class - for tab name
String name = this.getClass().getName();
// get rig of all package info just leave class name
setViewName(name.substring(name.lastIndexOf('.') + 1));

I created several concrete view classes; each concrete View class calls an init method of its super class to set its name and adds a button to invoke a simple action from a corresponding Model, via MainConntoller object. Usually a view layer implements a rendering of the model, but in our case I will only call an action. The view is responsible for getting and showing information from the corresponding model that is appropriate based the model state. The view also gathers information to pass on to the model via controller. If I wanted too, I could’ve added some fields in the each Model and got their data when a matching action was requested from my Tab.
When the button on concrete View 1 is pressed, it will call MainController execute method (via its reference to parent we set earlier) and pass a String key or Model name to let the Controller know to which model it should delegate the request. Code below demonstrated this.

//inside anonymous class for action listener attached to a button
public void actionPerformed(java.awt.event.ActionEvent e) {
   ((MainController) ConcreteView1.this.parent).execute(ConcreteView1.this,"Model1");
}





Page 1 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel