快捷搜索:

Java Fun and Games: Java Grab包的技

开拓 Java 平台十年之久,我已经积累了一些应用 Java SE grab 包加强游戏及其他 Java 平台开拓的宝贵履历。 本期的 Java Fun and Games 将与您分享一些技巧提示。 在文章的后半部分,将先容若何将这些技巧提示利用到一个网页抓牟利用法度榜样。

版权声明:任何得到Matrix授权的网站,转载时请务必保留以下作者信息和链接

作者:suli2921

原文:http://www.matrix.org.cn/resource/article/2007-04-20/Java+Grab_2a31448a-eed8-11db-9270-6dd444a118cb.html

关键字:Java Grab;游戏开拓

最简单的 API

不管谋略机运行得有多快,我们却老是在等待某个义务的完成,比如,下载大年夜个的文件、履行彻底搜索或者进行繁杂的数学谋略。 在这些费时的义务完成时,许多 Java 法度榜样都邑用一些花哨的要领提示用户,普遍措施是应用可以听得见的警告。

Java 供给了许多声音 API 可以用于创建有声警告。 可以应用 Java Speech API 奉告用户义务已经停止。 假如您盼望义务完成时播放音效或音乐,Java Sound API 是一个不错的选择。 然而,由于 Java Speech 必要额外的分发文件,而 Java Sound 必要相称繁杂的代码,您可能就盼望应用 Audio Clip API 了。

Audio Clip API 基于 java.applet.AudioClip 和 java.applet.Applet 措施,例如:public static final AudioClip newAudioClip(URL url)。 虽然此 API 比 Java Speech 和 Java Sound 更易于应用,但只用它来播放一段简单的声音也太过大年夜材小用了。 对付这种简单的义务,照样斟酌应用 Java 最简单的声音 API 吧。

最简单的声音 API 由 java.awt.Toolkit 的 public abstract void beep() 措施构成。 当调用此措施时,将发出简单的“哔跸”声。 为了展示 beep() 的用法,我创建了一个 CalcPi 利用法度榜样,为 Pi 计数。 请看列表 1。

列表 1 CalcPi.java

// CalcPi.java

import java.awt.Toolkit;

import java.math.BigDecimal;

public class CalcPi

{

/* constants used in pi computation */

private static final BigDecimal ZERO = BigDecimal.valueOf (0);

private static final BigDecimal ONE = BigDecimal.valueOf (1);

private static final BigDecimal FOUR = BigDecimal.valueOf (4);

/* rounding mode to use during pi computation */

private static final int roundingMode = BigDecimal.ROUND_HALF_EVEN;

/* digits of precision after the decimal point */

private static int digits;

public static void main (String [] args)

{

if (args.length != 1)

{

System.err.println ("usage: java CalcPi digits");

return;

}

int digits = 0;

try

{

digits = Integer.parseInt (args [0]);

}

catch (NumberFormatException e)

{

System.err.println (args [0] + " is not a valid integer");

return;

}

System.out.println (computePi (digits));

Toolkit.getDefaultToolkit ().beep ();

}

/*

* Compute the value of pi to the specified number of

* digits after the decimal point.The value is

* computed using Machin's formula:

*

*pi/4 = 4*arctan(1/5) - arctan(1/239)

*

* and a power series expansion of arctan(x) to

* sufficient precision.

*/

public static BigDecimal computePi (int digits)

{

int scale = digits + 5;

BigDecimal arctan1_5 = arctan (5, scale);

BigDecimal arctan1_239 = arctan (239, scale);

BigDecimal pi = arctan1_5.multiply (FOUR).

subtract (arctan1_239).multiply (FOUR);

return pi.setScale (digits, BigDecimal.ROUND_HALF_UP);

}

/*

* Compute the value, in radians, of the arctangent of

* the inverse of the supplied integer to the specified

* number of digits after the decimal point.The value

* is computed using the power series expansion for the

* arc tangent:

*

* arctan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 +

*(x^9)/9 ...

*/

public static BigDecimal arctan (int inverseX, int scale)

{

BigDecimal result, numer, term;

BigDecimal invX = BigDecimal.valueOf (inverseX);

BigDecimal invX2 = BigDecimal.valueOf (inverseX * inverseX);

numer = ONE.divide (invX, scale, roundingMode);

result = numer;

int i = 1;

do

{

numer = numer.divide (invX2, scale, roundingMode);

int denom = 2 * i + 1;

term = numer.divide (BigDecimal.valueOf (denom), scale, roundingMode);

if ((i % 2) != 0)

result = result.subtract (term);else

result = result.add (term);

i++;

}

while (term.compareTo (ZERO) != 0);

return result;

}

}

列表 1 应用一种算法来谋略 pi,该算法是早在 18 世纪初期由英国数学家 John Machin 发现的。 算法首先谋略 pi/4 = 4*arctan(1/5)-arctan(1/239),然后将结果乘以 4 得出 pi 的值。 因为 arc (inverse) tangent 是应用一系列宏大年夜的 term 来谋略的, term 的数量越大年夜得出的 pi 值越准确(小数点后显示的位数)

留意

列表 1 的大年夜部分代码引用自 Sun 的远程措施调用教程的“创建一个客户端法度榜样”部分。

此算法的实现依附于 java.math.BigDecimal 和一个 arc-tangent 措施。 虽然 Java SE 5.0 等高档版本的 BigDecimal 包括常量 ZERO 和 ONE,这些常量在 Java 1.4 中是不存在的。 同样,number-of-digits 敕令行参数用于确定 arc-tangent 的数量和 pi 的正确度。

java CalcPi 0

3

java CalcPi 1

3.1

java CalcPi 2

3.14

java CalcPi 3

3.142

java CalcPi 4

3.1416

java CalcPi 5

3.14159

本文中更紧张的部分是 Toolkit.getDefaultToolkit ().beep ();,该语句用于在谋略停止时发出“哗哗”的声音。 因为数字参数越大年夜造成的谋略光阴越长,此声音可以让您知道 pi 的谋略何时停止。 假如一声“哗”响不敷用,可以按照如下措施创建其他的音效:

Toolkit tk = Toolkit.getDefaultToolkit ();

for (int i = 0; i

窗口居中

使您的 Java 法度榜样看起来加倍专业的一种措施便是使其对话框窗口(例如,一个 "about" 窗口)位于父窗口的中心。 可以应用 java.awt.Window 的 public void setLocationRelativeTo(Component c) 措施完成此义务,该措施将相对付组件参数 —null 来创建一个居于屏幕中心的窗口。 请看列表 2。

列表 2 AboutBox1.java

// AboutBox1.java

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

import javax.swing.border.*;

public class AboutBox1

{

public static void main (String [] args)

{

final JFrame frame = new JFrame ("AboutBox1");

frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);

JPanel panel = new JPanel ()

{

{

JButton btnWindow = new JButton ("Window center");

ActionListener l = new ActionListener ()

{

public void actionPerformed (ActionEvent e)

{

new AboutBox (frame, "W").setVisible (true);

}

};

btnWindow.addActionListener (l);

add (btnWindow);

JButton btnScreen = new JButton ("Screen center");

l = new ActionListener ()

{

public void actionPerformed (ActionEvent e)

{

new AboutBox (frame, "S").setVisible (true);

}

};

btnScreen.addActionListener (l);

add (btnScreen);

}

};

frame.getContentPane ().add (panel);

//frame.setLocationRelativeTo (null);

frame.pack ();

//frame.setLocationRelativeTo (null);

frame.setVisible (true);

}

}

class AboutBox extends JDialog

{

AboutBox (JFrame frame, String centerMode)

{

super (frame, "AboutBox", true /* modal */);

final JButton btnOk = new JButton ("Ok");

btnOk.addActionListener (new ActionListener ()

{

public void actionPerformed (ActionEvent e)

{

dispose ();

}

});

getContentPane ().add (new JPanel () {{ add (btnOk); }});

pack ();

setLocationRelativeTo (centerMode.equals ("W") ? frame : null);

}

}

Listing 2's AboutBox1 创建了一个 GUI,它的两个按钮建立了一个 "about" 对话框,该对话框经由过程 setLocationRelativeTo() 措施位于利用法度榜样主窗口或屏幕的中间位置。 frame.pack (); 之前被注释掉落的一行无法起到使主窗口居中的感化,由于主窗口的大年夜小还没有确定。 然则,被注释掉落的第二行起到了使窗口居中的感化。

getContentPane ().add (new JPanel () {{ add (btnOk); }}); 大概看起来有点稀罕,由于它嵌套了许多括号。 本色上该语句可以理解为,创建一个内部匿名类(该类扩展自 javax.swing.JPanel)的工具,经由过程由内层括号对标识的 object block initializer 为此工具添加一个按钮,然后将工具添加到对话框的 content pane 中。

添加阴影

假如您想凸起显示一个 "about" 对话框的标题翰墨,可以斟酌以必然的偏移量和指定的颜色绘制背景翰墨以达到投放“阴影”的效果。 选择一个适当的颜色做为背景字的颜色,留意与前景翰墨和背景的颜色搭配。 然后应用反掉真技巧使边缘上的小锯齿变得平滑。 效果如图 1 所示:

图 1:阴影可以强调对话框的标题

图 1 展示了一个具有蓝色翰墨、玄色阴影和白色背景的 "about" 对话框。 该对话框是在 AboutBox2 法度榜样的 AboutBox(JFrame frame, String centerMode) 构造函数内创建的。 因为该法度榜样的代码与 AboutBox1.java 极为相似,以是我只给出其构造函数:

AboutBox (JFrame frame, String centerMode)

{

super (frame, "AboutBox", true /* modal */);

// Add a panel that presents some text to the dialog box's content pane.

getContentPane ().add (new JPanel ()

{

final static int SHADOW_OFFSET = 3;

{

// Establish the drawing panel's preferred

// size.

setPreferredSize (new Dimension (250, 100));

// Create a solid color border that both

// surrounds and is part of the drawing

// panel. Select the panel background

// color that is appropriate to this look

// and feel.

Color c =

UIManager.getColor ("Panel.background");

setBorder (new MatteBorder (5, 5, 5, 5, c));

}

public void paintComponent (Graphics g)

{

// Prevent jagged text.

((Graphics2D) g).setRenderingHint

(RenderingHints.KEY_ANTIALIASING,

RenderingHints.VALUE_ANTIALIAS_ON);

// Because the border is part of the panel,

// we need to make sure that we don't draw

// over it.

Insets insets = getInsets ();

// Paint everything but the border white.

g.setColor (Color.white);

g.fillRect (insets.left, insets.top,

getWidth ()-insets.left-

insets.right,

getHeight ()-insets.top-

insets.bottom);

// Select an appropriate text font and

// obtain the dimensions of the text to be

// drawn (for centering purposes). The

// getStringBounds() method is used instead

// of stringWidth() because antialiasing is

// in effect -- and the documentation for

// stringWidth() recommends use of this

// method whenever the antialiasing or

// fractional metrics hints are in effect.

g.setFont (new Font ("Verdana",

Font.BOLD,

32));

FontMetrics fm = g.getFontMetrics ();

Rectangle2D r2d;

r2d = fm.getStringBounds ("About Box", g);

int width = (int)((Rectangle2D.Float) r2d)

.width;

int height = fm.getHeight ();

// Draw shadow text that is almost

// horizontally and vertically (the

// baseline) centered within the panel.

g.setColor (Color.black);

g.drawString ("About Box",

(getWidth ()-width)/2+

SHADOW_OFFSET,

insets.top+(getHeight()-

insets.bottom-insets.top)/2+

SHADOW_OFFSET);

// Draw blue text that is horizontally and

// vertically (the baseline) centered

// within the panel.

g.setColor (Color.blue);

g.drawString ("About Box",

(getWidth ()-width)/2,

insets.top+(getHeight()-

insets.bottom-insets.top)/2);

}

}, BorderLayout.NORTH);

final JButton btnOk = new JButton ("Ok");

btnOk.addActionListener (new ActionListener ()

{

public void actionPerformed (ActionEvent e)

{

dispose ();

}

});

getContentPane ().add (new JPanel () {{ add (btnOk); }},

BorderLayout.SOUTH);

pack ();

setLocationRelativeTo (centerMode.equals ("W") ? frame : null);

}

除了向您先容若何在 JPanel 子类组件的 public void paintComponent(Graphics g) 措施中出现阴影以外,构造函数还揭示了一个技术:应用 UIManager.getColor("Panel.background") 获取与对话框背景致匹配的组件边框的颜色(即现在的外不雅)。

超级链接和启动浏览器

许多法度榜样都邑在 "about" 对话框中出现超级链接。单击超级链接时,法度榜样将启动默认浏览器,并为用户打开利用法度榜样的网站。我想 "about" 对话框中的超级链接是可以用类来描述的,以是我创建了一个 AboutBox3 利用法度榜样来阐明其可行性。请涉猎以下代码:

AboutBox (JFrame frame, String centerMode)

{

super (frame, "AboutBox", true /* modal */);

// Create a pane that presents this dialog box's text. Surround the pane

// with a 5-pixel empty border.

Pane pane = new Pane (5);

pane.setPreferredSize (new Dimension (250, 100));

// Create a title with a drop shadow for the pane.

Font font = new Font ("Verdana", Font.BOLD, 32);

Pane.TextNode tn = pane.new TextNode ("About Box", font, Color.blue,

Pane.TextNode.CENTERX,

Pane.TextNode.CENTERY, Color.black);

pane.add (tn);

// Create a link for the pane.

font = new Font ("Verdana", Font.BOLD, 12);

tn = pane.new TextNode ("Jeff Friesen", font, Color.blue,

Pane.TextNode.CENTERX, 80,

null, "http://www.javajeff.mb.ca", Color.red);

pane.add (tn);

// Add pane to the center region of the dialog box's content pane.

getContentPane ().add (pane);

// Create a button for disposing the dialog box.

final JButton btnOk = new JButton ("Ok");

btnOk.addActionListener (new ActionListener ()

{

public void actionPerformed (ActionEvent e)

{

dispose ();

}

});

// Add button via an intermediate panel that causes button to be laid

// out at its preferred size to the south region of the dialog box's

// content pane.

getContentPane ().add (new JPanel () {{ add (btnOk); }},

BorderLayout.SOUTH);

// Resize all components to their preferred sizes.

pack ();

// Center the dialog box with respect to the frame window or the screen.

setLocationRelativeTo (centerMode.equals ("W") ? frame : null);

}

AboutBox(JFrame frame, String centerMode)构造函数创建了一个 Pane 组件,来描述一个用于绘制翰墨的区域。该组件的 Pane(int borderSize) 构造函数应用 borderSize 参数,来识别组件边框的大年夜小(以像素为单位)-- 绘制区域的大年夜小即是 Pane 的大年夜小减去边框大年夜小:

Pane (int borderSize)

{

// Create a solid color border that both surrounds and is part of the

// this component. Select the panel background color that is appropriate

// to this look and feel.

setBorder (new MatteBorder (borderSize, borderSize, borderSize,

borderSize,

UIManager.getColor ("Panel.background")));

}

该组件将翰墨存储为 Pane.TextNode 工具的数组列表。每个 TextNode 描述一个翰墨条款,并且创建自三个构造函数之一。最简单的构造函数是 TextNode(String text, Font font, Color color, int x, int y),它用于创建一个非超级链接且没有阴影的翰墨节点。应用的五个参数是:

text 指定要绘制的翰墨

font 指定要应用的字体

font 指定要应用的翰墨颜色

x 指定第一个字符的肇端列

y 指定每个字符基线所在的行

第二简单的构造函数是:TextNode(String text, Font font, Color color, int x, int y, Color shadowColor).除了上述参数外,还必要为该函数指定 shadowColor,即阴影的颜色。假如通报 null,则不出现阴影,这样一来该构造函数就与前一构造函数一样了。这两个构造函数都调用下面的第三个构造函数:

TextNode (String text, Font font, Color color, int x, int y,

Color shadowColor, String url, Color activeLinkColor)

{

this.text = text;

this.font = font;

this.color = color;

this.x = x;

this.y = y;

this.shadowColor = shadowColor;this.url = url;

this.activeLinkColor = activeLinkColor;

if (url != null)

{

addMouseListener (new MouseAdapter ()

{

public void mousePressed (MouseEvent e)

{

int mx = e.getX ();

int my = e.getY ();

if (mx >= TextNode.this.x &&

mxTextNode.this.y-height &&

my = TextNode.this.x &&

mxTextNode.this.y-height &&

my = TextNode.this.x &&

mxTextNode.this.y-height &&

my

保存参数后,该构造函数会在 Pane 中注册一个鼠标 监听 器(假设 url 不为 null)。这些侦听 器将判断鼠标指针是否位于超级链接文本上。假如是,则操纵 active 变量,将出现该节点及其他节点,并启动浏览器。

class Launcher

{

static void launchBrowser (String url)

{

try

{

// Identify the operating system.

String os = System.getProperty ("os.name");

// Launch browser with URL if Windows. Otherwise, just output the url

// to the standard output device.

if (os.startsWith ("Windows"))

Runtime.getRuntime ()

.exec ("rundll32 url.dll,FileProtocolHandler " + url);

else

System.out.println (url);

}

catch (IOException e)

{

System.err.println ("unable to launch browser");

}

}

}

Pane 的 public void paintComponent(Graphics g) 措施将在该组件及其文本节点出现的时刻被调用。该措施启用反掉真技巧(防止翰墨呈现锯齿),获取组件的插入位置(以是文本不会落在边框上),清理绘制区域使其成为白色,并出现数组列表存储的每个翰墨节点。

public void paintComponent (Graphics g)

{

// Prevent jagged text.

((Graphics2D) g).setRenderingHint (RenderingHints.KEY_ANTIALIASING,

RenderingHints.VALUE_ANTIALIAS_ON);

// Because the border is part of the panel, we need to make sure that we

// don't draw over it.

Insets insets = getInsets ();

// Paint everything but the border white.

g.setColor (Color.white);

g.fillRect (insets.left, insets.top, getWidth ()-insets.left-insets.right,

getHeight ()-insets.top-insets.bottom);

// Render all nodes.

Iterator iter = nodes.iterator ();

while (iter.hasNext ())

{

TextNode tn = (TextNode) iter.next ();

tn.render (g, insets);

}

}

每个文本节点都是由 TextNode 的 void render(Graphics g, Insets insets) 措施出现的。该措施首先确定了字体,然后调用私有的 strDim() 措施来获取要绘制翰墨的规格尺寸等。然后出现文本(可以选择阴影、超级链接等属性):

void render (Graphics g, Insets insets)

{

g.setFont (font);

Dimension d = strDim (g, text);

width = (int) d.width;

height = (int) d.height;

// Always drop the drop shadow (if specified) first.

if (shadowColor != null)

{

g.setColor (shadowColor);

if (x == CENTERX)

x = (getWidth ()-d.width)/2;

if (y == CENTERY)

y = insets.top+(getHeight ()-insets.bottom-insets.top)/2;

// Draw the drop shadow.

g.drawString (text, x+SHADOW_OFFSET, y+SHADOW_OFFSET);

}

// If the text is not a link, active can never be true -- the mouse

// listeners are not installed.

g.setColor ((active) ? activeLinkColor: color);

// If a drop shadow was drawn, x and y will never equal CENTERX and

// CENTERY (respectively). This is okay because x and y must contain

// the same values as specified when drawing the drop shadow.

if (x == CENTERX)

x = (getWidth ()-d.width)/2;

if (y == CENTERY)

y = insets.top+(getHeight ()-insets.bottom-insets.top)/2;

// Draw the text.

g.drawString (text, x, y);

}

g.setColor ((active) ? activeLinkColor: color); 抉择是否绘制有效的超级链接文本(应用由activeLinkColor 指定的有效链接颜色),或者应用由 color 指定的颜色绘制无效超级链接文本(或非超级链接文本)。图 2 显示了此抉择的结果:

图 2 当鼠标指针移动到文本上时,超级链接的文本变成了血色。

状态栏

许多利用法度榜样都邑出现状态栏,以显示法度榜样的名称和版本、响应于菜单的赞助翰墨、当前光阴以及一些其他信息。因为状态栏如斯有用,您可能觉得 Java 包孕了一个 javax.swing.JStatusBar 组件。然而,事实并非如斯。幸运的是,创建自己的状态栏还算轻易,如图 3 所示。

图 3. 状态栏中当前菜单项的赞助翰墨

图 3 显示了一个由 StatBar 利用法度榜样创建的状态栏。该利用法度榜样将一个 javax.swing.JLabel 组件和一个 javax.swing.event.MenuListener 结合在一路,然后应用 java.awt.event.MouseListener 显示响应于菜单的菜单项赞助翰墨 -- 或者在未选择菜单或菜单项时显示默认翰墨。请看列表 3。

列表 3. StatBar.java

// StatBar.java

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

import javax.swing.event.*;

public class StatBar extends JFrame

{

// The status label serves as this application's status bar. A description

// of the currently highlighted menu/item appears on the status bar.

JLabel status;

// The default text appears on the status bar at program startup, and when

// no other menu/item text appears.

String defaultStatusText = "Welcome to StatBar 1.0!";

// The MenuItem helper class conveniently organizes the menu items for each

// of the File and Edit menus. This organization reduces the amount of

// source code that appears in the StatBar() constructor, which hopefully

// makes it easier to study the constructor, and facilitates adding extra

// menu items in the future.

class MenuItem

{

String label;// menu text

ActionListener al;String desc;// menu description for status bar

MenuItem (String label, ActionListener al, String desc)

{

this.label = label;

this.al = al;

this.desc = desc;

}

}

// Construct StatBar's GUI and indirectly start AWT helper threads.

public StatBar (String title)

{

// Pass application title to superclass, so that it appears on the title

// bar.

super (title);

// When the user initiates a close operation from the System menu or by

// clicking the tiny x window on a Microsoft Windows' window title bar,

// terminate this application.

setDefaultCloseOperation (EXIT_ON_CLOSE);

// Construct the application's menu bar.

JMenuBar mb = new JMenuBar ();

// Create a menu listener shared by all menus on the menu bar. This menu

// listener either displays default text or menu-specific text on the

// status bar.

MenuListener menul;

menul = new MenuListener ()

{

public void menuCanceled (MenuEvent e)

{

}

public void menuDeselected (MenuEvent e)

{

status.setText (defaultStatusText);

}

public void menuSelected (MenuEvent e)

{

JMenu m = (JMenu) e.getSource ();

status.setText (m.getActionCommand ());

}

};

// Create a mouse listener shared by all menu items on all menus. This

// mouse listener displays menu-item specific text on the status bar

// whenever the mouse pointer enters the menu item. It displays default

// text when the mouse pointer exits a menu item.

MouseListener statusl = new MouseAdapter ()

{

public void mouseEntered (MouseEvent e)

{

JMenuItem mi = (JMenuItem) e.getSource ();

status.setText (mi.getActionCommand ());

}

public void mouseExited (MouseEvent e)

{

status.setText (defaultStatusText);

}

};

// The first menu to appear on the menu bar is File. The user invokes

// menu items on this menu to open, save, and print documents, and to

// terminate the application.

JMenu menuFile = new JMenu ("File");

menuFile.addMenuListener (menul);

menuFile.setActionCommand ("Open document, save changes, print document "

+ "and terminate StatBar.");

// Create a listener for each menu item on the File menu.

ActionListener openl;

openl = new ActionListener ()

{

public void actionPerformed (ActionEvent e)

{

System.out.println ("Open listener invoked.");

}

};

ActionListener saveasl;

saveasl = new ActionListener ()

{

public void actionPerformed (ActionEvent e)

{

System.out.println ("Save as listener invoked.");

}

};

ActionListener savel;

savel = new ActionListener ()

{

public void actionPerformed (ActionEvent e)

{

System.out.println ("Save listener invoked.");

}

};

ActionListener printl;

printl = new ActionListener ()

{

public void actionPerformed (ActionEvent e)

{

System.out.println ("Print listener invoked.");

}

};

ActionListener exitl;

exitl = new ActionListener ()

{

public void actionPerformed (ActionEvent e)

{

System.exit (0);

}

};

// Identify menu items to be installed on the File menu.

MenuItem [] itemsFile =

{

new MenuItem ("Open...", openl, "Open a document."),

new MenuItem ("Save", savel, "Save changes to current document."),

new MenuItem ("Save as...", saveasl, "Save current document to new "

+ "document."),

new MenuItem ("Print...", printl, "Print current document."),

new MenuItem (null, null, null),

new MenuItem ("Exit", exitl, "Terminate StatBar.")

};

// Install all of the previous menu items on the File menu.

for (int i = 0; i

在应用默认状态栏翰墨创建了 status JLabel 之后,StatBar 形貌了一个边框 (经由过程 status.setBorder (BorderFactory.createEtchedBorder ());)以使状态栏标签与 GUI 的其他部分差别开来。然后,标签被添加到框架窗口内容窗格的南侧区域,这是状态栏的常见解位。

留意

假如不盼望状态栏显示任何默认翰墨,则必要至少输入一个空格来代替翰墨。假如应用空字符串 ("") 来代替,则不会显示状态栏(虽然会显示其边框)。必须处置惩罚状态栏标签的首选字体大年夜小,由于这涉及到当前的字体和那个弗成缺省的字符。假如状态栏标签不包孕任何字符(空字符串),其首选字体大年夜小就会是 0,造成状态栏无法显示。

MenuItemListener 接口描述了一个 "File" 和 "Edit" 菜单的侦听法度榜样。此接口的 public void menuSelected(MenuEvent e) 措施将在选择这些菜单时被调用,然后会显示菜单的赞助翰墨。选中一个菜单时,调用 public void menuDeselected(MenuEvent e) 显示翰墨。

MouseListener 接口描述每个菜单项的侦听法度榜样。其 public void mouseEntered(MouseEvent e) 在鼠标进入一个菜单项时被调用。然后,菜单项的赞助翰墨会显示在状态栏中。鼠标指针移动到菜单项外时,调用 public void mouseExited(MouseEvent e),然后显示默认翰墨。

每个侦听法度榜样都依附于 javax.swing.JMenu 或 javax.swing.JMenuItem 的承袭 public void setActionCommand(String command) 措施,此措施曾在指定每个菜单或菜单项的状态栏翰墨时被调用。翰墨是在侦听法度榜样内部进行检索的,措施是调用相关的 public String getActionCommand() 措施。

抓图法度榜样

几年前,我构建过一个基于敕令行的 GetImages 利用法度榜样 -- 请看列表 4 -- 来获取网页中的图像,并将它们寄放到我的磁盘上。此利用法度榜样只有一个用于连接到 HTML 文档的 URL 参数。解析 HTML 文档,将标记的 src 属性值提取为可识别的图像文件,然后下载这些文件。

列表 4 GetImages.java

// GetImages.java

import java.io.*;

import java.net.*;

import java.util.regex.*;

import javax.swing.text.*;

import javax.swing.text.html.*;

import javax.swing.text.html.parser.ParserDelegator;

public class GetImages

{

public static void main (String [] args)

{

// Validate number of command-line arguments.

if (args.length != 1)

{

System.err.println ("usage: java GetImages URL");

return;

}

// Create a Base URI from the solitary command-line argument. This URI

// will be used in the handleSimpleTag() callback method to convert a

// potentially relative URI in antag's src attribute to an

// absolute URI.

final URI uriBase;

try

{

uriBase = new URI (args [0]);

}

catch (URISyntaxException e)

{

System.err.println ("URI is improperly formed");

return;

}

// Convert the URI to a URL, so that the HTML document can be read and

// parsed.

URL url;

try

{

url = new URL (args [0]);

}

catch (MalformedURLException e)

{

System.err.println ("URL is improperly formed");

return;

}

// Establish a callback whose handleSimpleTag() method is invoked for

// each tag that does not have an end tag. Thetag is an example.

HTMLEditorKit.ParserCallback callback;

callback = new HTMLEditorKit.ParserCallback ()

{

public void handleSimpleTag (HTML.Tag tag,

MutableAttributeSet aset,

int pos)

{

// If antag is encountered ...

if (tag == HTML.Tag.IMG)

{

// Get the value of the src attribute.

String src = (String)

aset.getAttribute (HTML.Attribute.SRC);

// Create a URI based on the src value, and then

// resolve this potentially relative URI against

// the document's base URI, to obtain an absolute

// URI.

URI uri = null;

try

{

// Handle this situation:

//

// 1) http://www.javajeff.mb.ca

//

// There is no trailing forward slash.

//

// 2) common/logo.jpg

//

// There is no leading forward slash.

//

// 3) http://www.javajeff.mb.cacommon/logo.jpg

//

// The resolved URI is not valid.

if (!uriBase.toString ().endsWith ("/") &&

!src.startsWith ("/"))

src = "/" + src;

uri = new URI (src);

uri = uriBase.resolve (uri);

System.out.println ("uri being " +

"processed ... " + uri);

}

catch (URISyntaxException e)

{

System.err.println ("Bad URI");

return;

}

// Convert the URI to a URL so that its input

// stream can be obtained.

URL url = null;

try

{

url = uri.toURL ();

}

catch (MalformedURLException e)

{

System.err.println ("Bad URL");

return;

}

// Open the URL's input stream.

InputStream is;

try

{

is = url.openStream ();

}

catch (IOException e)

{

System.err.println ("Unable to open input " +

"stream");

return;

}

// Extract URL's file component and remove path

// information -- only the filename and its

// extension are wanted.

String filename = url.getFile ();

int i = filename.lastIndexOf ('/');

if (i != -1)

filename = filename.substring (i+1);

// Save image to file.

saveImage (is, filename);

}

}

};

// Read and parse HTML document.

try

{

// Read HTML document via an input stream reader that assumes the

// default character set for decoding bytes into characters.

Reader reader = new InputStreamReader (url.openStream ());

// Establish a ParserDelegator whose parse() method causes the

// document to be parsed. Various callback methods are called and

// the document's character set is not ignored. The parse() method

// throws a ChangedCharSetException if it encounters atag

// with a charset attribute that specifies a character set other

// than the default.

new ParserDelegator ().parse (reader, callback, false);

}

catch (ChangedCharSetException e)

{

// Reparse the entire file using the specified charset. A regexp

// pattern is specified to extract the charset name.

String csspec = e.getCharSetSpec ();

Pattern p = Pattern.compile ("charset=\"?(.+)\"?\\s*;?",

Pattern.CASE_INSENSITIVE);

Matcher m = p.matcher (csspec);

String charset = m.find () ? m.group (1) : "ISO-8859-1";

// Read and parse HTML document using appropriate character set.

try

{

// Read HTML document via an input stream reader that uses the

// specified character set to decode bytes into characters.

Reader reader;

reader = new InputStreamReader (url.openStream (), charset);

// This time, pass true to ignore thetag with its charset

// attribute.

new ParserDelegator ().parse (reader, callback, true);

}

catch (UnsupportedEncodingException e2)

{

System.err.println ("Invalid charset");

}

catch (IOException e2)

{

System.err.println ("Input/Output problem");

e.printStackTrace ();

}

}

catch (IOException e)

{

System.err.println ("Input/Output problem");

e.printStackTrace ();

}

}

public static void saveImage (InputStream is, String filename)

{

FileOutputStream fos = null;

try

{

fos = new FileOutputStream (filename);

int bYte;

while ((bYte = is.read ()) != -1)

fos.write (bYte);

}

catch (IOException e)

{

System.err.println ("Unable to save stream to file");

}

finally

{

if (fos != null)

try

{

fos.close ();

}

catch (IOException e)

{

}

}

}

}

您可能还会对下面的文章感兴趣: