为演示新的 AWT 功能,我们将创建一个程序将屏幕设为全屏(最小化桌面装饰如工具栏)并使用新的颜色常量设置背景。您将能够通过旋转鼠标滚轮或使用左和右 shift 键更改背景色。
清单 1 提供了该程序的基本骨架程序。遗憾的是,在要使用的鼠标滚轮支持功能中仍存在错误(有关详细信息请参阅参考资料)。为使这种功能起作用,您需要把 JButton 添加到 JScrollPane,再把 JScrollPane 添加到框架中。这个错误使得这个骨架程序比必需的复杂了一点。
清单 1. 创建可关闭框架的骨架程序
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class AwtTest {
// See bug 4475240
static JButton button = new JButton();
static JScrollPane pane = new JScrollPane(button);
public static void main(String args[]) {
JFrame frame = new JFrame("AwtTest");
// See bug 4475240
frame.getContentPane().add(button, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.show();
}
}
工具箱 insets
在上一个专栏中,我提到了用 setExtendedState() 最大化 Frame 的功能。如果您将框架的状态设置为 Frame.MAXIMIZED_BOTH,您的框架就被完全最大化了。但如果您不希望把框架最大化,却希望它的大小填满用户的桌面区域(扣除所有桌面装饰的大小),那么现在您可以查询那些装饰使用的 Insets(请参阅清单 2)。这些信息由 Toolkit 的 getScreenInsets() 方法提供。如果从屏幕大小中减去那些 insets,您就得到了窗口的应有大小。为正确地定位,您还需要使用顶端和左边的 insets。
清单 2. 确定屏幕大小
private static void sizeScreen(JFrame frame) {
Toolkit kit = Toolkit.getDefaultToolkit();
Dimension screenSize = kit.getScreenSize();
GraphicsConfiguration config = frame.getGraphicsConfiguration();
Insets insets = kit.getScreenInsets(config);
screenSize.width -= (insets.left + insets.right);
screenSize.height -= (insets.top + insets.bottom);
frame.setSize(screenSize);
frame.setLocation(insets.left, insets.top);
}
只需把 sizeScreen() 调用添加到 main() 方法中。
颜色常量大写
Java 语言规范的第 6.8 节包含包、方法、字段和常量等项的命名约定。关于常量名的子节(6.8.5)声明常量不应使用小写字母,但从一开始,Color 类中的全部颜色常量如 red、green 和 blue 就是以全小写指定的。Merlin 也直接开了个先例,现在以全大写提供相同的常量。现在尚不反对使用旧名称,但在您的 1.4 程序中您可以使用较新的名称。
我们将为测试程序创建一个颜色常量数组和一个对这些颜色常量进行循环的计数程序,然后提供一个 changeBackground() 方法,该方法按两个方向的其中一个方向对这些颜色常量进行循环(请参阅“清单 3”)。
清单 3. 更改背景色
private static final Color colors[] = {
Color.BLACK,
Color.BLUE,
Color.CYAN,
Color.DARK_GRAY,
Color.GRAY,
Color.GREEN,
Color.LIGHT_GRAY,
Color.MAGENTA,
Color.ORANGE,
Color.PINK,
Color.RED,
Color.WHITE,
Color.YELLOW
};
static int colorCounter;
private static final int UP = 1;
private static final int DOWN = 2;
private static void changeBackground(JFrame frame, int direction) {
// See bug 4475240
// w/o bug, change background of getContentPane()
button.setBackground(colors[colorCounter]);
// Update counter based on direction
if (direction == UP) {
colorCounter++;
} else {
--colorCounter;
}
// Wrap colors
if (colorCounter == colors.length) {
colorCounter = 0;
} else if (colorCounter < 0) {
colorCounter = colors.length-1;
}
}
向您的 main() 例程添加对 changeBackground() 方法的调用。
在其它类如 GridBagLayout 中也对命名约定进行了更新,GridBagLayout 类包括几个 protected 方法如 AdjustForGravity(),这些 protected 方法现在已被修改为以小写字母开头。
检测鼠标滚轮移动
自从上个世纪以来 Java 开发者就嚷着要求的一个功能是支持鼠标滚轮旋转事件。随着 Merlin 发行版的出现,现在您可以为任何 Component 增加一个 MouseWheelListener 并做出相应的响应。除了前面提及的错误之外,它运行得很顺利。JScrollPane 组件甚至随预注册的侦听器一起提供,所以当这个组件获得焦点且用户移动鼠标滚轮时窗格将会滚动。
该侦听器有一个方法,mouseWheelMoved(),它获取一个 MouseWheelEvent 参数。在事件中,您可以使用 getScrollAmount() 查明滚动总量,使用 getScrollType() 查明是单元滚动还是块滚动、使用 getWheelRotation 查明滚动方向和鼠标滚轮旋转的次数,为方便起见,还可以使用 getUnitsToScroll() 查明要滚动的单元。
在测试程序中,我们增加了一个鼠标滚轮侦听器,它让背景色按照某一方向在颜色数组中循环,如清单 4 所示。文档声明鼠标滚轮事件向上传递容器层次结构,但错误导致这件事无法发生,所以您需要为按钮增加一个侦听器。确保在 main() 方法中添加一个侦听器。
清单 4. 增加鼠标滚轮侦听器
private static void attachMouseWheelListener(final JFrame frame) {
MouseWheelListener listener = new MouseWheelListener() {
public void mouseWheelMoved(MouseWheelEvent e) {
int count = e.getWheelRotation();
int direction = (Math.abs(count) 0) ? UP : DOWN;
changeBackground(frame, direction);
}
};
button.addMouseWheelListener(listener);
}
输入事件
这最后一个功能比您刚开始想象的要多一些,因为测试程序只使用了已添加的功能的一小部分。基本上,Merlin 添加了区别同一键的不同版本(键区键和常规键)以及键盘键和鼠标按钮的不同次序的功能。例如,以前无法说出按下 shift 再单击和单击不同按钮之间的不同;两者产生相同的鼠标事件。有了 InputEvent 类中下列新常量的帮助,一切都不同了:
ALT_DOWN_MASK
CTRL_DOWN_MASK
META_DOWN_MASK
SHIFT_DOWN_MASK
BUTTON1_DOWN_MASK
BUTTON2_DOWN_MASK
BUTTON3_DOWN_MASK
BUTTON1_CHANGED_MASK
BUTTON2_CHANGED_MASK
BUTTON3_CHANGED_MASK
如果您想找出按下的是哪个按钮,下列方法更常用:
isButton1Down()
isButton2Down()
isButton3Down()
MouseEvent 还提供 getButton() 方法用来发现哪个按钮改变了状态。
所有这些方法和常量应该会使得对按钮事件做出响应更加容易。
区分同一个键的不同版本要求对 KeyEvent 类做一些修改。您可以使用 getKeyLocation() 从事件中得到键的位置;您会重新使用下列常量之一:
KEY_LOCATION_LEFT
KEY_LOCATION_NUMPAD
KEY_LOCATION_RIGHT
KEY_LOCATION_STANDARD
KEY_LOCATION_UNKNOWN
通过询问键的位置,您可以区分小键盘键、标准键以及左和右 shift 键。
对于测试程序,我们只简单地让键侦听器根据按下的是左还是右 shift 键按向上或向下的方向循环,如清单 5 所示。我们务必要首先核实按下的是哪个键,然后再检查其位置。当然,还要在 main() 方法中添加对例程的调用。
清单 5. 增加键侦听器
private static void attachKeyListener(final JFrame frame) {
KeyListener listener = new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
int location = e.getKeyLocation();
int direction = (location == KeyEvent.KEY_LOCATION_LEFT) ?
UP : DOWN;
changeBackground(frame, direction);
}
}
};
button.addKeyListener(listener);
}
完整的示例
清单 6 为您提供了一个完整的示例来试验所有这些新功能。修正鼠标滚轮侦听器后,您将可以不用按钮和滚动窗格。
清单 6 完整的示例
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class AwtTest {
private static final Color colors[] = {