• 沒有找到結果。

A Bigger Application

在文檔中 Java™ Swing, 2nd Edition (頁 64-72)

James Elliott

Chapter 2. Jump-Starting a Swing Application

2.6 A Bigger Application

I l@ve RuBoard

We break the code for this application into three separate classes to make discussing it more manageable. The first class handles the real application frame. The constructor handles all of the interface setup work. It sets up the toolbar, as well as the Cut, Copy, and Paste buttons. It uses the default L&F for the platform on which it is run. (You could certainly attach the

LnFListener

, if you wanted to.) Here's the source code:

// SiteManager.java //

import java.awt.*;

import java.io.*;

import java.util.*;

import java.awt.event.*;

import javax.swing.*;

public class SiteManager extends JFrame { JLayeredPane desktop;

Vector popups = new Vector( );

public SiteManager( ) { super("Web Site Manager");

setSize(450, 250);

setDefaultCloseOperation(EXIT_ON_CLOSE);

Container contentPane = getContentPane( );

JToolBar jtb = new JToolBar( );

jtb.add(new CutAction(this));

jtb.add(new CopyAction(this));

jtb.add(new PasteAction(this));

contentPane.add(jtb, BorderLayout.NORTH);

// Add our LayeredPane object for the internal frames.

desktop = new JDesktopPane( );

contentPane.add(desktop, BorderLayout.CENTER);

addSiteFrame("Sample");

}

public static void main(String args[]) { SiteManager mgr = new SiteManager( );

mgr.setVisible(true);

}

Notice that since we're finally using Swing's

JFrame

rather than an AWT

Frame

, we can replace the cumbersome

WindowAdapter

, which handles user close requests, with a single call to

setDefaultCloseOperation(EXIT_ON_CLOSE)

.

Now for the creation of the site and page frames. The

SiteFrame

class and

PageFrame

class, discussed later in this chapter, extend the

JInternalFrame

class. These classes handle all of the hard work in getting the frames to look and act correctly. Here, we just need to make the internal frame visible and keep a reference to the frame. By keeping the

popups

vector around, we could eventually add Save All, Close Site, and other options. For now we just use it to help find the current frame.

// Methods to create our internal frames public void addSiteFrame(String name) { SiteFrame sf = new SiteFrame(name, this);

popups.addElement(sf);

desktop.add(sf, new Integer(2)); // Keep sites on top for now.

sf.setVisible(true);

}

public void addPageFrame(String name) { PageFrame pf = new PageFrame(name, this);

desktop.add(pf, new Integer(1));

pf.setVisible(true);

pf.setIconifiable(true);

popups.addElement(pf);

}

public JInternalFrame getCurrentFrame( ) { for (int i = 0; i < popups.size( ); i++) {

JInternalFrame currentFrame = (JInternalFrame)popups.elementAt(i);

if (currentFrame.isSelected( )) { return currentFrame;

} }

return null;

} }

The

getCurrentFrame( )

method runs through a list of all the frames currently open in the site manager and returns the active frame. (Yes, this is a bit inefficient, but we're ignoring that for right now.)

Notice that we're using a

JToolBar

object in our example. This is a great shortcut if you just want a few buttons along the top (or side or bottom) of your application. A

JToolBar

can contain almost any kind of component, though it's most often used for buttons. We don't add buttons directly; instead, we add

Action

objects, which are

automatically converted into buttons when placed in a toolbar. The

Action

interface encapsulates an icon and an

actionPerformed( )

method so that you don't have to do lengthy if/else-if testing. When you add an

Action

to the toolbar, the toolbar displays the

Action

's icon, and when you click on the icon, the

Action

's

actionPerformed( )

method is called automatically. Here's the code for the

CopyAction

class:

// CopyAction.java

// A simple Action that copies text from a PageFrame object //

import java.awt.event.ActionEvent;

import javax.swing.*;

public class CopyAction extends AbstractAction { SiteManager manager;

public CopyAction(SiteManager sm) { super("", new ImageIcon("copy.gif"));

manager = sm;

}

public void actionPerformed(ActionEvent ae) {

JInternalFrame currentFrame = manager.getCurrentFrame( );

if (currentFrame == null) { return; } // Can't cut or paste sites

if (currentFrame instanceof SiteFrame) { return; } ((PageFrame)currentFrame).copyText( );

} }

The cut and paste action classes work in a similar fashion. (We won't show them here.) Swing provides a large number of pre-built

Action

s, so you may not even need to write your own. We'll discuss several in Chapter 23.

Appendix B lists all the

Action

s that are provided by Swing's components as well as the key bindings (if any) with

which they can be triggered.

Next we need a way to create the site frames. We can set up a separate class that extends the

JInternalFrame

class and contains the functionality appropriate for the site manager. Namely, we must be able to list available pages in the site and open any of those pages for editing.

We can create a frame that has a listbox as its primary component. This won't be a fancy manager, but it will do what we want. The nice thing about internal frames, from the frame's point of view, is that they look just like regular frames.

You can use the constructor to add all of the graphical interface elements and put in event listeners. The only difference with internal frames is that they need to be added to an appropriate desktop pane, but again, that's not a difference we can see here in the code for the individual frames. You can change existing standalone

Frame

classes to

JInternalFrame

classes with very little effort:

// SiteFrame.java

// A simple extension of the JInternalFrame class that contains a list object.

// Elements of the list represent HTML pages for a web site.

//

import java.awt.*;

import javax.swing.*;

import javax.swing.event.*;

public class SiteFrame extends JInternalFrame { JList nameList;

SiteManager parent;

// Hardcode the pages of our "site" to keep things simple.

String[] pages = {"index.html", "page1.html", "page2.html"};

public SiteFrame(String name, SiteManager sm) { super("Site: " + name, true, true, true);

parent = sm;

setBounds(50,50,250,100);

nameList = new JList(pages);

nameList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

nameList.addListSelectionListener(new ListSelectionListener( ) { public void valueChanged(ListSelectionEvent lse) {

// We know this is the list, so pop up the page.

if (!lse.getValueIsAdjusting( )) {

parent.addPageFrame((String)nameList.getSelectedValue( ));

} } });

Container contentPane = getContentPane( );

contentPane.add(nameList, BorderLayout.CENTER);

} }

In the

valueChanged( )

method for the

ListSelectionListener

, we handle the basic functions of the page list.

Single-clicking on an entry in the list creates a new

PageFrame

object for that file. If the file doesn't exist, you get a blank text area for creating the page from scratch. Note that very little error checking is going on here. But you probably have already discovered that robust error checking just gets in the way of having fun, and that's all we're really trying to accomplish with this application.

Now you have the site frame going. The new page frame needs to be able to open the file (if it exists) and display the file for editing. The Cut, Copy, and Paste buttons from our earlier example allow you to move text around in a file and between open files in the application.

Like the site frame, we'll create a subclass of

JInternalFrame

for our page frame. We can use the constructor for the interface work again, and then allow the text area to manage all of the text display and editing work:

// PageFrame.java

// A simple extension of the JInternalFrame class that contains a list object.

// Elements of the list represent HTML pages for a web site.

//

import java.awt.*;

import java.io.*;

import java.awt.event.*;

import javax.swing.*;

public class PageFrame extends JInternalFrame { SiteManager parent;

String filename;

JTextArea ta;

public PageFrame(String name, SiteManager sm) { super("Page: " + name, true, true, true, true);

parent = sm;

setBounds(50,50,300,150);

// Use the JFrame's content pane to store our desktop.

Container contentPane = getContentPane( );

// Create a text area to display the contents of our file and put it in a // scrollable pane so we can get to all of it.

ta = new JTextArea( );

JScrollPane jsp = new JScrollPane(ta);

contentPane.add(jsp, BorderLayout.CENTER);

// Add a "File->Save" option to the menu bar for this frame.

JMenuBar jmb = new JMenuBar( );

JMenu fileMenu = new JMenu("File");

JMenuItem saveItem = new JMenuItem("Save");

saveItem.addActionListener(new ActionListener( ) {

public void actionPerformed(ActionEvent ae) { saveContent( ); } });

fileMenu.add(saveItem);

jmb.add(fileMenu);

setJMenuBar(jmb);

// Now get the content, based on the filename that was passed in.

filename = name;

loadContent( );

} }

Here, we need to add some load and save routines to the

PageFrame

class for the text areas. You'll learn more about the

read( )

and

write( )

methods in Chapter 19, but for now, we'll just use them since they provide such a convenient way to read and write text files:

public void loadContent( ) { try {

FileReader fr = new FileReader(filename);

ta.read(fr, null);

fr.close( );

}

catch (Exception e) { System.err.println("Could not load page: "+filename); } }

public void saveContent( ) { try {

FileWriter fw = new FileWriter(filename);

ta.write(fw);

fw.close( );

}

catch(Exception e) { System.err.println("Could not save page: "+filename); } }

To make the cut and paste operations simpler, we'll put in some public access methods to manipulate the text. All three of these routines are built to function regardless of the clipboard implementation you use. We'll use the system clipboard (via some convenience methods found in

JTextComponent

) for this example, but you could just as easily use your own clipboard, or eventually, Drag and Drop text.

public void cutText( ) { ta.cut( ); }

public void copyText( ) { ta.copy( ); }

public void pasteText( ) { ta.paste( ); }

Now you can start the program and bring up the individual HTML files by selecting them from the list. Each file has its own internal frame that you can move around, resize, iconify, maximize, and close. You can cut, copy, and paste text between files. You can save edits using menus attached to each pop-up frame. You can even detach the toolbar and let it "float." All this for about 250 lines of code!

Well, now that we've had a bit of fun, it's time to move on to the details. The next chapter plunges into the world of Swing with the

JComponent

class. Good luck, and have fun!

I l@ve RuBoard

I l@ve RuBoard

在文檔中 Java™ Swing, 2nd Edition (頁 64-72)

相關文件