CS410G: GUI Programming The Model/View/Controller design pattern provides a clean distinction between the your application s data (model), your GUI (view), and the how they interact (controller). Many swing components follow the MVC pattern, easing use and implementation, and providing a clean abstract for multiple looks and feels. Model/View/Controller The MVC design pattern Basic MVC widgets Swing tables and trees The Model/View/Controller Pattern MVC is a popular architecture for building GUIs There are three participants in the MVC pattern Model: Underlying logical representation of the data being displayed View: The visual representation of the data (widgets) Controller: Specifies how to handle user input Usually updates the View and Model accordingly When Model changes, it notifies its views You can easily have multiple views of the same data Copyright c 2002-2005 by David M. Whitlock. Permission to make digital or hard copies of part or all of this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advantage and that copies bear this notice and full citation on the first page. To copy otherwise, to republish, to post on servers, or to redistribute to lists, requires prior specific permission and/or fee. Request permission to publish from whitlock@cs.pdx.edu. 1 You can create views without changing the model The Observer and Observable interfaces have been around since JDK 1.0 2 Model The model maintains a component s state Is a button pressed? The character data in a label The model does not know about the view and the controller Communicates with them indirectly using broadcasts (events) View The view determines the visual representation of the model The view is the look of the component The view renders itself based on indirect messages from the model and direct messages from the controller Controller The controller determines how the component should react to input events The controller is the feel of the component Controller receives direct message from the view and indirect messages from the model Example: User clicks a button The button s controller determines that the click was meant for it Controller sends a message to the model The model updates itself accordingly and broadcasts that it has changed View receives broadcast and updates itself based on the new state of the model In MVC a model is bound to a single controller. The controller may have multiple views of same model. 3 4
MVC in Swing Swing combines the View and Controller into an object called a delegate Model and Delegate for Buttons All Swing buttons (JButtons, JCheckboxes, JRadioButtons, etc.) are subclasses of AbstractButton A delegate displays the model and adjusts the model based on user input A JComponent always has a model and delegate (UI) associated with it The View part of the delegate determines the widget s look and feel The look and feel (L&F) can be changed Windows L&F, Motif L&F, custom L&F A ButtonModel defines the model for a button Methods for adding ActionListeners and ItemListeners ispressed, isselected A DefaultButtonModel knows about a button s group, etc. A javax.swing.plaf.buttonui is responsible for the button s L&F A button invokes methods of it ButtonUI when it needs to be painted or updated ButtonUI determines the size of the button Your programs need not invoke these methods 5 6 More About UI Delegates All UI delegates are a subclass of ComponentUI The static createui factory method creates a ComponentUI for a given JComponent There is usually one ComponentUI instance per component type One MetalButtonUI that is used by all JButtons The installui and uninstallui methods add/remove listeners that connect the component (or its model) to the UI A ComponentUI is also involved with laying out a component getpreferredsize(jcomponent), getminimumsize, getmaximumsize The javax.swing.plaf package contains a hierarchy of abstract classes for UIs ButtonUI, MenuBarUI, FileChooserUI, etc. Pluggable Look and Feel Because Swing widgets adhere to the MVC pattern, they provide a pluggable look and feel A Swing GUI can look like its running on Windows, Motif, etc., or you can define a custom L&F The LookAndFeel class maps JComponents to their UIs and specifies a L&F A UIManager maintains the current L&F Has methods like getfont, geticon getlookandfeel returns current L&F setlookandfeel sets L&F using class name If you are changing L&F in the middle of your program (not recommended), your GUI can be updated by invoking SwingUtilities.updateComponentTreeUI See edu.pdx.cs410g.mvc.looksandfeels 7 8
An MVC Example Let s say that you have a program in which the user enters numbers Display all of the numbers entered and the average of those numbers Traditional widget and event handling When user hits ENTER, a JTextField s ActionListener adds text to a JList Another ActionListener on JTextField reads all entries in JList and computes their average Widgets are tightly coupled: Doesn t scale Order of ActionListeners is unknown MVC solution: Store data outside of the widgets Keep all of the numbers in a list The widgets observe the list When the list changes, the widgets are notified and widgets get the info they want from the list and display it appropriately 9 Modeling a list of data A ListModel models a list of data getsize and getelementat Each ListModel may have multiple ListDataListeners Callback methods that each get a ListDataEvent: contentschanged, intervaladded, intervalremoved An AbstractListModel is a helper class that handles the coordination between the ListModel and its ListDataListeners Subclasses invoke firecontentschanged, etc. when model changes DefaultListModel provides a ListModel that provides Vector-like behavior addelement adds an object to the underlying model and invokes firecontentschanged to alert listeners of the change 10 A JList Views a ListModel A JList can be created from a ListModel When the model is changed, the JList receives a ListDataEvent and updates itself appropriately A JList may have an array of Objects or a Vector as its model All of the event handling between the model and view is taken care of for you Other ListDataListeners can act as controllers between a ListModel and a widget Note that ListDataListener and ListDataEvent are in the javax.swing.event package 11 An Example of ListModel Creating a ListModel and adding data to it: public class DisplayAverage extends JPanel { public DisplayAverage() { // The data we re modeling final DefaultListModel model = new DefaultListModel(); // A panel for entering a number JPanel enter = new JPanel(); enter.add(new JLabel("Enter a number")); final JTextField input = new JTextField(8); input.addactionlistener(new ActionListener() { public void actionperformed(actionevent e) { // When the user hits ENTER, add the // number to the data model model.addelement(new Integer(input.getText ); enter.add(input); // A JList that displays the data in the model JList list = new JList(model); this.add(new JScrollPane(list), BorderLayout.CENTER); 12
An Example of ListModel Adding a controller (ListDataListener) between the model and another view (average JLabel) final JLabel average = new JLabel("Average:"); model.addlistdatalistener(new ListDataListener() public void intervaladded(listdataevent e) { displayaverage(); public void intervalremoved(listdataevent e) displayaverage(); public void contentschanged(listdataevent e) displayaverage(); So, what? By separating what is being displayed (model) from how it is displayed (view), we have made our GUI easy to understand and extend Could add a standard deviation view without changing any of the other views private void displayaverage() { int size = model.getsize(); int total = 0; for (int i = 0; i < size; i++) { Integer datum = (Integer) model.getelementat(i); total += datum.intvalue(); average.settext("average: " + (((double) total)/((double) size))); ); 13 14 JSpinner JSpinner is a widget that was added in JDK 1.4 and allows the user to spin through values Behavior defined by a SpinnerModel Several kinds of SpinnerModels SpinnerNumberModel: Can set initial, max, min values and increment step SpinnerDateModel: Can spin on one of the fields of a Date (e.g. Calendar.HOUR) SpinnerListModel: Can spin through a List of objects Once again, the JSpinner delivers the user events to the model which, in turn, notifies the spinner that the model has changed See edu.pdx.cs410g.mvc.jspinnerexample Swing Tables The javax.swing.table package contains a framework for creating MVC-based tables A TableModel abstractlly represents a table getcolumncount, getrowcount, getvalueat getcolumnclass: Returns the type of data in a column Data may be displayed differently based on type (e.g. checkbox for booleans) A TableModel may have multiple TabelModelListeners tablechanged invoked with a TabelModelEvent when TableModel changes TabelModelEvent consists of First row, last row, and column that changed The type of change: INSERT, UPDATE, or DELETE A DefaultTableModel is built from a two-dimensional array of objects and an array of objects that specify the names of the columns 15 16
A JTable Views a TableModel A JTable can be created with a default number of rows and columns, ordered data such as an object array or Vector or from a TableModel public class JTableExample extends JPanel { public JTableExample() { this.setlayout(new BorderLayout()); String[] columnnames = { "Name", "Quiz1", "Quiz2", "Quiz3" ; Object[][] data = { { "Mary", new Double(85.0), new Double(92.5), { "Sunil", new Double(94.3), new Double(82.9), { "Fred", new Double(84.0), new Double(72.5), { "Jin", new Double(98.2), new Double(92.5), n ; TableModel model = new DefaultTableModel(data, columnnames); JTable tree = new JTable(model); this.add(new JScrollPane(tree), BorderLayout.CENTER); A More Complex JTable We are going write a GUI that models a checkbook using a JTable A simple Check class models a check with a number, amount, description, whether it has cleared, etc. A TableModel models the checks in a checkbook and determines how they should be displayed CheckbookTableModel extends AbstractTableModel which provides fire methods that force the view to be updated The CheckbookGUI creates, configures, and displays the JTable When the button is clicked, a new Check is created and added to the model public void createcheck() { this.checks.add(new Check(nextNumber++)); int row = checks.size() - 1; this.firetablerowsinserted(row, row); Note that the JTable must be in a JScrollPane in order for the table headings to be displayed 17 18 Editing a Check The model specifies which cells can be edited (iscelleditable) The Number and Balance columns cannot be edited The model specifies the types of data in the columns The Date column is a java.util.date, Cleared is a Boolean By default, the JTable will parse the contents of the typed cell and return it This behavior can be customized with a TableCellEditor A DefaultCellEditor can be created from a JCheckbox, JComboBox, or JTextField The Transaction column has a custom editor 19 Displaying a Check A TableCellRenderer specifies how a cell in a JTable should be drawn When the balance drops below zero, display it in red public class CheckbookCellRenderer extends DefaultTableCellRenderer { public Component gettablecellrenderercomponent(jtable table, Object value, boolean isselected, boolean hasfocus, int row, int column) { if (column == CheckbookTableModel.BALANCE_COLUMN if (value!= null && value instanceof Number) Color color; double balance = ((Double) value).doublevalu if (balance < 0) { color = Color.RED; else { color = Color.BLACK; this.setforeground(color); this.settext(string.valueof(balance)); return this; return super.gettablecellrenderercomponent(table 20
Creating a JTable Each column in the table is represented by a TableColumn From CheckbookGUI: CheckbookTableModel checkbook = new CheckbookTableModel(); JTable table = new JTable(checkbook); String columnname = columnnames[balance_column]; TableColumn column = table.getcolumn(columnname); column.setcellrenderer(new CheckbookCellRenderer() columnname = columnnames[transaction_column]; column = table.getcolumn(columnname); JComboBox combo = new JComboBox(new String[] { DEPOSIT, WITHDRAWL column.setcelleditor(new DefaultCellEditor(combo)) this.add(new JScrollPane(table), BorderLayout.CENT The moral of the story is: The data is completely separate from how it is displayed and edited! Tree-like Data The JTree widget displays hierarchical data A JTree can be created from a Hashtable, object array or Vector that specifies the tree s root A JTree can also be created from a TreeModel (similar to a TableModel) See package javax.swing.tree It may also make more sense to model your tree data with a TreeNode Just models one node in the tree, instead of the entire tree Has methods like children, getchildat, getparent, and isleaf 21 22 An Example TreeNode A FileNode models a node in a directory hierarchy: public class FileNode implements TreeNode { public TreeNode getparent() { File parent = file.getparentfile(); if (parent == null) { return null; else { return new FileNode(file); public boolean isleaf() { return!this.file.isdirectory(); //... Displaying nodes in a JTree A TreeCellRenderer specifies how a node in a tree should be drawn DefaultTreeCellRenderer provides a lot of useful behavior Can customize: background color, font, icons (closed, open, leaf) It is a subclass of JLabel so it has methods like settext and settooltiptext The gettreecellrenderercomponent is invoked when a node is drawn The value provided is the node being drawn 23 24
An Example TreeCellRenderer public class FileNodeRenderer extends DefaultTreeCel public Component gettreecellrenderercomponent(jtree tree, Object value, boolean selected, boolean expanded, boolean isleaf, int row, boolean hasfocus) { JLabel c = (JLabel) super.gettreecellrenderercomponent(tree, value selected, expanded, isleaf, row, hasfocus); if (value instanceof FileNode) { FileNode node = (FileNode) value; File file = node.getfile(); if (!file.isdirectory()) { c.settext(node.tostring()); if (file.ishidden()) { c.setforeground(color.red); return c; Other Swing MVC Models BoundedRangeModel Has a (current) value, extent, min, and max Used with JProgressBar, JScrollBar, JSlider ComboBoxModel A subinterface of ListModel that adds the notion of a selected item in the list MutableComboBoxModel A ComboBoxModel with add/remove/insert methods javax.swing.colorchooser.colorselectionmodel Used with a JColorChooser return c; Has a selected color Note that most container widgets (JApplet, JFrame, JDesktopPane, etc.) do not have models 25 26 Summary The Model/View/Controller design pattern separates data from how it is displayed The model is the data being displayed The view is the widget(s) that display the data The controller handles user input and updates the model and view 27