Swing, part 2Tutorial 07
1 / 31
Leonid Barenboim
25/4/2010
MVC (Model View Controller)
2 / 31
“Model–view–controller (MVC) is a software architectural pattern for implementing user interfaces.It divides a given software application into three interconnected parts, so as to separate internal representations of information from the ways that information is presented to or accepted from the user.”-Wikipedia
MVC (Model View Controller)
3 / 31
“A controller can send commands to the model to update the model's state (e.g., editing a document). It can also send commands to its associated view to change the view's presentation of the model (e.g., by scrolling through a document).
A model stores data that is retrieved by the controller and displayed in the view. Whenever there is a change to the data it is updated by the controller.
A view requests information from the model that it uses to generate an output representation to the user.”-Wikipedia
Outline
1 Using the Default Models
2 File Browser
4 / 31
Outline
1 Using the Default Models
2 File Browser
5 / 31
Using the Default Models
Swing supplies default, mutable models for all
widgets: List
Tree (nodes)
Table
Spinner and Slider
. . .
6 / 31
Default List Model Example
7 / 31
Add and remove elements from a list using the default model:
public class SimpleList extends JFrame { pr ivate JList _ l i s t ;
pr ivate DefaultListModel _model;
. . .
}
Constructor with Default List Model
8 / 31
public SimpleList() { super("List Demo");
setModel(new DefaultListModel()); setList(new JList(_model));
getList().setPreferredSize(new Dimension(100, 300)); getContentPane().add(getList(), BorderLayout.CENTER); JToolBar tBar = new JToolBar();
JButton tAdd = new JButton("+"); // calls add()tBar.add(tAdd);JButton tRem = new JBut ton("-" ) ; // calls rem()tBar.add(tRem);getContentPane().add(tBar, BorderLayout.NORTH);. . .}
Adding and Removing with the Default Model
9 / 31
private void add() {Str ing tVal = JOptionPane.showInputDialog(
t h i s , "Add new value") ;i f ( tVal != nu l l )
{ getModel().add(getModel().getSize(), tVa l ) ;
}}
private void rem() {i n t [ ] i s = getList() .getSelectedIndices();
Ar rays.sor t ( is ) ;f o r ( i n t i = is. length - 1; i >= 0; i - - )
{ getModel() .remove(is[ i] ) ;}}
Outline
1 Using the Default Models
2 File Browser
10 / 31
A Simple File Broswer
The file browser
shows:
Directories treeList of files in the
selected directory
Content of the selected file
Plus:
The event dispatcher thread should not hang while reading the content of a file
Only the event dispatcher thread should update the screen
11 / 31
Outline
1 Using the Default Models
2 File BrowserTree ModelTree Cell Renderer List Cell Renderer The File BroswerWriting a Swing Worker
12 / 31
A Model for the Tree View
Tree model
Get root
Get children count per
node Get child for index
Check if a node is a leaf
Directories tree model
Root Top directory
Children Files in
directory
Leaf An directory without sub-directories
13 / 31
The Directories Tree Model
14 / 31
public class DirTreeModel implements TreeModel { pr ivate F i le _d i r ;
public DirTreeModel(File d i r ) { se tD i r (d i r ) ;
}
private s ta t i c F i leF i l t e r _FILTER = new F i l e F i l t e r ( ) { public boolean accept(File f i l e ) {return f i l e . i sD i r ec t o r y ( ) ;
}} ;
pr ivate F i l e [ ] l i s t ( F i l e f i l e ) { return f i le . l is tF i les(_FILTER);
}
Tree Model Inferface Methods
15 / 31
public Object getRoot() { return getDi r ( ) ;
}
public Object getChild(Object parent, i n t index) { F i l e [ ] tChildren = l i s t ( (F i l e )pa ren t ) ;
return tChildren[ index];}
public i n t getChildCount(Object parent) { return l is t ( (F i le )parent ) . length ;
}
Tree Model Interface Methods (cont’d)
16 / 31
public boolean isLeaf(Object node) { return getChildCount(node) == 0;
}
public i n t getIndexOfChild(Object parent, Object ch i ld ) { List<File> tF i les = Ar rays.asLis t ( l is t ( (F i le)parent ) ) ; return tF i les. indexOf( (F i le)ch i ld) ;
}
Empty Tree Model Interface Methods
17 / 31
public void valueForPathChanged(TreePath p, Object v)
public void addTreeModelListener(TreeModelListener l )
public void removeTreeModelListener(TreeModelListener l )
Tree nodes are not added or removed dynamically in this model, so the tree model listener is redundant
Outline
1 Using the Default Models
2 File BrowserTree ModelTree Cell Renderer List Cell Renderer The File BroswerWriting a Swing Worker
18 / 31
Rendering a Directories Tree Cell
public class DirTreeCellRenderer extends DefaultTreeCellRenderer
{public Component getTreeCellRendererComponent(
JTree t ree , Object value,boolean se l , boolean expanded, boolean l ea f ,
i n t row, boolean hasFocus) {
super.getTreeCellRendererComponent(...);F i le tRoot = ( F i l e ) tree.getModel().getRoot();
F i le t F i l e = ( F i l e ) value; setText(tRoot.equals(value) ?
tFile.getAbsolutePath() : tFile.getName()); setIcon(expanded ? openIcon : closedIcon); return t h i s ;} } 17 /
31
Files List Model
public class FilesListModel implements ListModel { pr ivate F i le _d i r ;
pr ivate List<File> _ f i l e s ;private Collection<ListDataListener> _l is teners;
private s ta t i c F i leF i l t e r _FILTER = new F i l e F i l t e r ( ) { public boolean accept(File f ) {
return f . i s F i l e ( ) ;}
} ;
public FilesListModel() {setListeners(new LinkedList<ListDataListener>());
setFiles(Collections.EMPTY_LIST);}
18 / 31
Setting the Directory
public F i le getDir( ) { return _d i r ;
}
public void setDir (Fi le d i r ) {_dir = d i r ;i n t tOldSize =
getSize();F i l e [ ] tF i les = dir. l istFi les(_FILTER);
setFi les(Arrays.asList ( tF i les)) ;i n t tMax = Math.max(tOldSize, getSize()) ;
ListDataEvent tEvt =new ListDataEvent(this, LDE.CONTENTS_CHANGED, 0,tMax);
f o r (ListDataListener tListener : getListeners()) {tListener.contentsChanged(tEvt);
}} 19 /
31
Files List Model Interface Methods
22 / 31
public i n t getSize() { return ge tF i les ( ) . s ize( ) ;
}
public Object getElementAt(int index) { return getFi les() .get( index);
}
public void addListDataListener(ListDataListener l ) { getListeners() .add( l) ;
}
public void removeListDataListener(ListDataListener l ) { getListeners().remove(l);
}
Outline
1 Using the Default Models
2 File BrowserTree ModelTree Cell Renderer List Cell Renderer The File BroswerWriting a Swing Worker
23 / 31
Rendering a Files List Cell
public class FilesListCellRenderer extends DefaultListCellRenderer
{private s ta t i c Color _ALT = new Color(220, 220, 220);
public Component getListCellRendererComponent(JList l i s t , Object value, i n t index,
boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(...); F i le f = ( F i l e ) value; setText(f.getName());i f (! isSelected && index % 2 ==
0) setBackground(_ALT);return t h i s ;
}} 22 / 31
Outline
1 Using the Default Models
2 File BrowserTree ModelTree Cell Renderer List Cell Renderer The File BroswerWriting a Swing Worker
25 / 31
Putting It Together
26 / 31
public class FileBrowser extends JFrame
implements TreeSelectionListener, ListSelectionListener
{private JTree _tree; private
JTextArea _content; pr ivate JList _ f i l e s ;
. . .}
File Broswer Constructor
27 / 31
public FileBrowser(File f i l e ) { super(f i le.getAbsolutePath());
// TreesetTree(new JTree(new DirTreeModel(f i le))) ;
getTree().setCellRenderer(new DirTreeCellRenderer()); getTree().addTreeSelectionListener(this);
// File listsetFiles(new JList(new Fi lesListModel())) ;
getFiles().setCellRenderer(new FilesListCellRenderer()); getFiles().setSelectionMode(LSM.SINGLE_SELECTION); getFiles().addListSelect ionListener(this);
// Text areasetContent(new JTextArea(10, 30)) ;. . .}
Listening to Tree Events
28 / 31
public void valueChanged(TreeSelectionEvent e) {F i le tD i r = ( F i l e ) e.getPath().getLastPathComponent(); ( (Fi lesListModel)getFi les() .getModel()) .setDir( tDir) ;
}
Listening to List Events
29 / 31
public void valueChanged(ListSelectionEvent e) {// Gotcha 1: Check if value is adjustingi f (e.getValueIsAdjusting()) return;// Gotcha 2: Don’t use e’s indicesFi le t F i l e = ( F i l e ) getFiles().getSelectedValue(); getContent().setText("");// Gotcha 3: Don’t re-use a workerSwingWorker tWorker =
new FileReaderWorker(tFile, getContent()); tWorker.execute();}
Outline
1 Using the Default Models
2 File BrowserTree ModelTree Cell Renderer List Cell Renderer The File BroswerWriting a Swing Worker
30 / 31
Writing a Swing Worker
31 / 31
public class FileReaderWorker extends SwingWorker<Void, String>
{private F i le _ f i l e ;
pr ivate JTextArea _text ;
. . .}
Do in Background
32 / 31
protected Void doInBackground() throws Exception { t r y {BufferedReader t I n =
new BufferedReader(new FileReader(getFile())); Str ing tL ine;while ( ( tL ine = t In. readLine()) != nu l l )
{ publ ish( tLine) ;}t I n . c lose( ) ;} catch (IOException e)
{ publish(e.getMessage());}return n u l l ;}
Process and Done
33 / 31
protected void process(List<String> chunks) { f o r (Str ing tLine : chunks) {getText().append(tLine + " \ n " ) ;
}}
protected void done() { getText().setCaretPosit ion(0);
}