Sunday, March 18, 2007

Advance Swing

This tutorial covers more advanced
Java Swing topics such as dropdown menus,
popup menus, toolbars, tooltips, specialized containers, layered panes,
split panes, tabbed panes, tables, trees and file choosers. Inner class
event listener material using inner classes is also included.




Advanced Event Listeners


One difficulty with the basic event listening

technique (ie event sharing) previously demonstrated is that it becomes
awkward to program for many buttons and widgets. Extended if statements or
switch constructs can make code hard to maintain. There is a better way!


Inner classes (ie nested) allow routines to be written for each
specific object. For example instead of using addActionListener(this)
for several buttons you can have each button call its own inner class such as:


import java.awt.*;import java.awt.event.*;import javax.swing.*;
public class SomeGUI extends JFrame
{
JButton run = new JButton("Run the Utility");
JButton exit = new JButton("Exit After Save");
JPanel buttons = new JPanel(new GridLayout(4,1,2,2));
SomeGUI() // the constructor
{
super("Event Listener Demo"); setBounds(100,100,250,150);
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
buttons.add(run); buttons.add(exit);
this.getContentPane().add("Center",buttons);
exit.addActionListener(new ExitHandler()); setVisible(true);
}
// add inner class event handler for each button here
class ExitHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
}
public static void main(String[] args) {new SomeGUI();}
}

NOTE: The implements clause is now placed in
each inner class header and not in the main class header.
Also the listener registration is of a specific Listener_class

object, not the generic this.


Anonymous inner classes have no name (hence no name conflict)
and are used when only one instance of the class is required. They also
do not have constructors. Anonymous inner classes are most often found
in event listeners. A simple example for the exit button is:


exit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
});

Yet another strategy (using outer classes) allows isolation of the event
listeners to external files but is more complex to code because of inherent
information hiding.


Consult the appendix for a list of
other programmable events. As event classes are interfaces, all

methods within that event must be implemented. Adapter classes
provide default do-nothing methods which you can chose to override. Here
is a short example using the WindowAdapter class to avoid coding all seven
window events.


import java.awt.*;import java.awt.event.*;
class Listener2 extends Frame
{
Listener2()
{
setBounds(100,100,200,200); setVisible(true);
addWindowListener(new WindowAdapter()
{
public void windowclosing (WindowEvent e)
{ System.exit(0); }
});
}
public static void main (String[] args) {new Listener2();}
}


Menu Bars and Popups


Dropdown/pullout menu bars are menus similar to those that appear
across the top of most Windows programs. The menu bars are constructed from
the JMenuBar class. Menus (aka bar items) are constructed from the
JMenu class and menu items from the JMenuItem class.
Item separators can either be added to a menu with addSeparator()

or inserted with insertSeparator(posn). Menu items can be disabled
or grayed out with the setEnabled(false) method and tested with the
isEnabled() method. Menu items can have a hotkey shortcut
added by using a setMnemonic(char) method. Accelerator keys
are added with the setAccelerator() method. The menubar is added to
the main frame by using this.setJMenuBar(obj).



MyMenu.java demonstrates many of the features of the menu classes
including mnemonics, accelerators keyed to platform, checkbox &
radiobutton items and icons. Download the
jp6grabbag.zip
package


Popup menus are revealed by some user action and look similar
to a dialog box.


MyPop.java demonstrates features of the popup menu classes
including specialized listeners. Download the

jp6grabbag.zip
package



ToolBars and ToolTips


Dockable toolbars can be constructed from the JToolBar
class. JToolBar(SwingConstants.VERTICAL) overrides the default
orientation. The add() method adds components which are often
icons. Toolbars are always fully exposed.



Tooltips give popup text for any hovered object such as
buttons and toolbar components. The setToolTipText() method
is used to associate informational text with the object or icon.


MyToolBar.java demonstrates features of the toolbar class
including action classes. Download the
jp6grabbag.zip
package



Specialty Frames and Panes


Layered panes allow components such as buttons to be overlapped
or layered.


import java.awt.*; import java.awt.event.*; import javax.swing.*;
public class Frame3 extends JFrame
{
public Frame3() // constructor method for the class
{
super("Simple Layers Demo"); setBounds(100,100,300,200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLayeredPane lp = getLayeredPane(); // inherit the layered pane
JButton top = new JButton();
top.setBackground(Color.white);
top.setBounds(20,20,50,50);
JButton mid = new JButton();
mid.setBackground(Color.gray);
mid.setBounds(40,40,50,50);
JButton bot = new JButton();
bot.setBackground(Color.black);
bot.setBounds(60,60,50,50);
lp.add(mid,new Integer(2));
lp.add(top,new Integer(3));
lp.add(bot,new Integer(1));
setVisible(true);
}
public static void main(String[] args) {new Frame3();}
}

Split panes allow you to place two components side by side
in a single pane. The divider can be adjusted by the user. It can also
split the pane horizontally. A simple example of a split pane is:


import javax.swing.*; import java.awt.*; import java.awt.event.*;
class MySplit extends JFrame
{
static String sometext = "This is a simple text string that is long enough "+
"to wrap over a few lines in he simple demo that we have just built. We "+
"will put two Text areas side by side in a split pane";
public MySplit()
{
super("Simple JSplitPane Frame"); setSize(450,200);
JTextArea jt1 = new JTextArea(sometext);
JTextArea jt2 = new JTextArea(sometext);
jt1.setLineWrap(true); jt1.setMinimumSize(new Dimension(150,150));
jt2.setLineWrap(true); jt2.setMinimumSize(new Dimension(150,150));
jt1.setPreferredSize(new Dimension(250,200));
JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,jt1,jt2);
getContentPane().add(sp, BorderLayout.CENTER);
setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true);
}
public static void main (String args[]) {new MySplit();}
}

Tabbed panes allow a multilayered pane with tabs for the
user to access the layer he wants. Each tab contains a single component.
A simple example of a tabbed pane is:



import javax.swing.*; import java.util.*;
import java.awt.*; import java.awt.event.*;
class MyTab extends JFrame
{
JTabbedPane jtp;
public MyTab()
{
super("JTabbedPane"); setSize(200,200);
Container contents = getContentPane();
jtp = new JTabbedPane();
jtp.addTab("Tab1", new JLabel("This is Tab One"));
jtp.addTab("Tab2", new JButton("This is Tab Two"));
jtp.addTab("Tab3", new JCheckBox("This is Tab Three"));
contents.add(jtp);
setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true);
}
public static void main (String args[]) {new MyTab();}
}


Tables


Tables represent data in a row/column two dimensional grid
format. The simplest constructor is of the form JTable(data,headers)
where data is a two dimension string and headers is a one dimension string.
SimpleTable is a small demo.
Download the jp6grabbag.zip package



Hierarchical Trees


Trees allow visualization, traversal and manipulation of
hierarchical information (ie. parent-children) much easier. Trees consist
of nodes. Common examples of trees are directories, organizational
charts, and family trees.


In Java the JTree(var) constructor is used to create trees.
The variable parameter can be one of TreeNode, TreeModel, Object, Vector,
or Hashtable class. A simple example is ObjectTree which uses a
hashtable to hold the actual tree.
Download the jp6grabbag.zip package



File Choosers


The JFileChooser class is part of the javax.swing.filechooser
package. It allows browsing through a file system and selecting appropriate
files. The JFileChooser(stringVar) constructor can be used to set
the starting browsepoint (currentDirectory is common). An external
FileFilter extension or a FileNameExtensionFilter
(depending on Java version) can be added using the
addChoosableFileFilter() method to limit the scope of the selection.
The following code demonstrates opening a chooser to get a file or directory
names:



Warning: Use getCanonicalPath() to retain the
directory path information for file access! This method
requires Exception handling. Use
getName() only when the string will be used for simple display purposes.


import java.awt.*;import java.awt.event.*;
import java.io.*; import javax.swing.*;
public class MyBrowser extends JFrame
{
String curDir; JLabel statusbar;
public MyBrowser()
{
super("File Chooser Test Frame"); setSize(350,200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
curDir = System.getProperty("user.dir") + File.separator;
statusbar = new JLabel("Output of your button choice goes here!");
Container c = getContentPane(); c.setLayout(new FlowLayout());
JButton openButton = new JButton("Open");
JButton dirButton = new JButton("Pick Dir");
// add the open FILE chooser
openButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
JFileChooser chooser = new JFileChooser(curDir);
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
chooser.setMultiSelectionEnabled(true);
//Java 1.6 can use FileNameExtensionFilter class
// FileFilter filter=new FileNameExtensionFilter("HTML file","htm","html");
// chooser.addChoosableFileFilter(filter);
//Prior versions must use external extension of FileFilter class (ie ExtFilter)
//ExtFilter requires separate compile to enable choosable selection
String[] html = new String[] {"htm","html","xhtml"};
chooser.addChoosableFileFilter(new ExtFilter(html,
"HTML file (*.htm, *.html)"));
int option = chooser.showOpenDialog(MyBrowser.this);
if (option == JFileChooser.APPROVE_OPTION)
{
File[] sf = chooser.getSelectedFiles();
String filelist = "nothing";
try
{
if (sf.length > 0) filelist = sf[0].getCanonicalPath();
for (int i = 1; i < sf.length; i++)
{filelist += ", " + sf[i].getCanonicalPath();}
}
catch (IOException evt) {System.out.println("Exception: "+evt);}
statusbar.setText("Your choices: " + filelist);
}
else {statusbar.setText("You cancelled!");}
}
});
// add the open DIRECTORY chooser
dirButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
JFileChooser chooser = new JFileChooser(curDir);
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setMultiSelectionEnabled(false);
int option = chooser.showOpenDialog(MyBrowser.this);
if (option == JFileChooser.APPROVE_OPTION)
{
File[] sf = chooser.getSelectedFiles();
String filelist = "nothing";
try
{
if (sf.length > 0) filelist = sf[0].getCanonicalPath();
for (int i = 1; i < sf.length; i++)
{filelist += ", " + sf[i].getCanonicalPath();}
}
catch (IOException evt) {System.out.println("Exception: "+evt);}
statusbar.setText("You chose " + filelist);
}
else {statusbar.setText("You cancelled!");}
}
});
c.add(openButton); c.add(dirButton); c.add(statusbar); setVisible(true);
}
public static void main(String[] args) {new MyBrowser();}
}


Here is my version of the ExtFilter class. It must be separately
compiled if choosable extension selection is enabled for Java versions prior
to 1.6 The class receives rither an extension or list of extensions and a
description of the extension(s).


import java.io.File; import javax.swing.filechooser.*;
public class ExtFilter extends FileFilter
{
String[] extensions; String description;
public ExtFilter(String ext) {this (new String[] {ext},null);}

public ExtFilter(String[] exts, String descr)
{
extensions = new String[exts.length];
for (int i=exts.length-1;i>=0;i--){extensions[i]=exts[i].toLowerCase();}
description=(descr==null?exts[0]+" files":descr);
}
public boolean accept(File f)
{
if (f.isDirectory()) {return true;}
String name = f.getName().toLowerCase();
for (int i=extensions.length-1;i>=0;i--)
{if (name.endsWith(extensions[i])) {return true;} }
return false;
}
public String getDescription() {return description;}
}



No comments: