- 大纲:比那些使用图形用户界面(GUI)的Java程序。
- 定义屏幕上的窗口大小和位置的程序。
- 窗口中采用多种字体显示文本。
- 如何显示图像。
- Swing概述:
- AWT
- Abstract Window Toolkit (AWT)。早期基本GUI程序设计的类库。基本AWT库采用 将处理用户界面元素的任务委派给每个目标平台的本地GUI工具箱的方式(观感依赖于目标平台)。(“一次编写,随处使用”)
- 不同平台,用户界面元素的操作行为存在差别。
- 某些平台的用户界面组件集合并不丰富。
- 不同平台上的AWT用户界面库中存在不同的bug。(“一次编写,随处调试”)
- Swing
- 已是Java基础类库(Java Foundation Class, JFC)的一部分。包含的内容远大于Swing GUI工具箱。
- JFC不仅包含Swing组件,而且还包含了一个可访问性API,一个2D API 和一个 可拖放API。
- Swing并没有完全替代AWT,而是基于AWT架构上。仅提供了能力更强大的用户界面组件。
- Swing是指“被绘制的”用户界面类,AWT是指像 事件处理 这样的窗口工具箱的底层机制。
- AWT
- 创建框架:
- 在Java中,顶层窗口(没有包含在其他窗口的窗口)被称为 框架。JFrame类,扩展于Frame类。
- 绝大多数Swing组件类都以“J”开头,如:JButton,JFrame。切忌Swing和AWT组件混用。
- Swing位于 javax.swing包 中。包名javax 表示 这是Java的扩展包,而不是核心包。
- 两个技术问题需强调:
- 所有的Swing组件必须由 事件分派线程 进行配置,线程将鼠标点击和按键控制转移到用户接口组件。Event.invokeLater() 。
- 定义一个关闭这个框架的响应动作。
- 在默认情况下,用户关闭窗口时只是将框架隐藏起来,而程序并没有终止。
- 退出main方法并没有终止程序,终止的只是主线程。事件分派线程保持程序处于激活状态,知道关闭框架或调用System.exit方法终止程序。
- 示例程序:(创建一个最简单的框架)
package simpleFrame;
import java.awt.*;
import javax.swing.*;
public class SimpleFrameTest {
public static void main( String[] args ) {
EventQueue.invokeLater(()->{
SimpleFrame frame = new SimpleFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
}
class SimpleFrame extends JFrame{
private static final int DEFAULT_WIDTH = 300;
private static final int DEFAULT_HEIGHT = 200;
public SimpleFrame() {
//默认情况下,框架的大小为 0 * 0 。
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT );
}
}
- 框架定位:
- 处理框架大小和定位的重要的方法:
- setLocation 和 setBounds方法 用于设置框架的位置。
- setIconImage 用于告诉窗口系统在标题栏,切换任务窗口等位置显示哪个图标。
- setTitle 标题。
- setResizable 利用一个boolean值确定框架的大小是否允许用户改变。
- 框架属性:
- 组件类的很多方法都是以 获取/设置方法对 形式出现的。这样的一个 获取/设置方法对 被称为一种属性。
- 属性包含 属性名 和 类型。
- 对于类型为 boolean 的属性,获取的方法由 “is”开头。
- 确定合适的框架大小:
- 对于专业应用程序来说,应该检查屏幕的分辨率,并根据其分辨率编写代码重置框架的大小。
- Toolkit类的 静态方法getDefaultToolkit 得到一个 Toolkit对象(Toolkit类包含很多与本地窗口系统打交道的方法)。 然后,调用 getScreenSize方法,获得一个 Dimension对象,同时用公有实例变量width和height保存屏幕的宽度和高度。
- 如果框架中只包含标准的组件,可以调用pack方法设置框架大小。框架将被设置为刚好能够放置所有组件的大小。
- 牢记用户定位应用程序的框架位置、重置框架大小,并且在应用程序再次启动时恢复,是一个不错的想法。
- GraphicsDevice类还允许以全屏模式执行应用。
- java.awt.Component
- boolean isVisible()
- void setVisible( boolean b )
- void setSize( int width, int height )
- void setLocation( int x, int y )
- void setBounds( int x, int y, int width, int height )
- Dimension getSize()
- void setSize( Dimension d )
- java.awt.Window
- void toFront() //将窗口显示在其他窗口前面
- void toBack() //将窗口移到 桌面窗口栈 的后面,并相应地重新排列所有的可见窗口。
- boolean isLocationByPlatform()
- void setLocationByPlatform( boolean b ) //由平台选择一个合适的位置。
- java.awt.Frame
- boolean isResizable()
- void setResizable( boolean b )
- String getTitle()
- void setTitle( String s )
- Image getIconImage()
- void setIconImage( Image image )
- boolean isUndecorated()
- void setUndecorated( boolean b )
- int getExtendedState()
- void setExtendedState( int state )
- Frame.NORMAL
- Frame.ICONIFIED
- Frame.MAXIMIZED_HORIZ
- Frame.MAXIMIZED_VERT
- Frame.MAXIMIZED_BOTH
- 处理框架大小和定位的重要的方法:
- 示例程序:(构建一个框架,带标题,宽高设为系统分辨率的一半)
package sizedFrame;
import java.awt.*;
import javax.swing.*;
public class SizedFrameTest {
public static void main( String[] args ) {
EventQueue.invokeLater(()->{
SizedFrame frame = new SizedFrame();
frame.setTitle("SizedFrame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
}
class SizedFrame extends JFrame{
public SizedFrame() {
Toolkit kit = Toolkit.getDefaultToolkit();
Dimension screenSize = kit.getScreenSize();
setSize( screenSize.width/2, screenSize.height/2);
setLocationByPlatform(true);
Image img = new ImageIcon("icon.gif").getImage();
setIconImage(img);
}
}
- 在组件中显示信息:(在框架内显示信息)
- 可以将消息字符串直接绘制在框架中,但这并不是一种好的编程习惯。
- 在Java中,框架被设计为放置组件的容器,可以将菜单栏或其他用户组件放置其中。
- JFrame有四层面板,包括:根面板、层级面板、玻璃面板 和 内容窗格。
- Container contentPane = frame.getContentPane(); contentPane.add(c)
- 可以直接调用frame.add(c)
- 绘制一个组件,需要定义一个扩展JComponent的类,并覆盖其中的 paintComponent方法,该方法有一个Graphics类型的参数。
- 在Java中,所有的绘制都必须使用Graphics对象,其中包含了绘制图案、图像和文本的方法。
- 只要窗口需要重新绘图,事件处理器就会通告组件,从而引发执行所有组件的paintComponent方法。一定不要自己调用paintComponent方法(会自动被调用:恢复窗口、窗口被覆盖、窗口第一次显示)。
- 如果需要强制刷新屏幕,就需要调用 repaint方法,而不是paintComponent方法。repaint方法会引发采用相应配置的Graphics对象调用所有组件的paintComponent方法。
- java.awt.Component
- void repaint() // "尽可能快地"重新绘制组件
- Dimension getPreferredSize() //要覆盖这个方法,返回这个组件的首选大小。
- 实例程序:(框架内显示消息)
package notHelloWorld;
import java.awt.*;
import javax.swing.*;
public class NotHelloWorld {
public static void main( String[] args ) {
EventQueue.invokeLater(()->{
NotHelloWorldFrame frame = new NotHelloWorldFrame();
frame.setTitle("NotHelloWorldFrame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
}
class NotHelloWorldFrame extends JFrame{
public NotHelloWorldFrame() {
add( new NotHelloWorldComponent() );
pack();
}
}
class NotHelloWorldComponent extends JComponent{
private static final int MESSAGE_X = 75;
private static final int MESSAGE_Y = 100;
private static final int DEFAULT_WIDTH = 300;
private static final int DEFAULT_HEIGHT = 200;
public void paintComponent( Graphics g ) {
g.drawString("Not a Hello World program", MESSAGE_X, MESSAGE_Y);
}
public Dimension getPreferredSize() { return new Dimension( DEFAULT_WIDTH, DEFAULT_HEIGHT); }
}
- 处理2D图形
- Graphics类包含绘制直线、矩形和椭圆等方法。但是对绘制图形的操作能力十分有限。
- Java SE 1.2引入了Java 2D库,这个库实现了一组功能强大的图形操作。
- 要想使用Java 2D库绘制图形,需要获得一个 Graphics2D 对象。这个类是 Graphics类的子类。
- 自Java SE 2版本以来,paintComponent方法就会自动获得一个Graphics2D类对象,只需进行一次类型转换即可。
- 想要绘制图形,首先要创建一个实现了 Shape接口 的类的对象,然后调用 Graphics2D的 draw方法。
- java.awt.geom.RectangularShape
- double getCenterX()
- double getCenterY()
- double getMinX()
- double getMinY()
- double getWidth()
- double getHeight()
- double getX() //矩形左上角的坐标
- double getY()
- java.awt.geom.Rectangle2D.Double
- Rectangle2D.Double( double x, double y, double w, double h )
- java.awt.geom.Point2D.Double
- Point2D.Double( double x, double y)
- java.awt.geom.Line2D.Double
- Line2D.Double( Point2D start, Point2D end )
- Line2D.Double( double startX, double startY, double endX, double endY )
- 示例程序:(绘制一个图形)
package draw;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Ellipse2D.Double;
import javax.swing.*;
public class Draw {
public static void main( String[] args ) {
EventQueue.invokeLater(()->{
DrawFrame frame = new DrawFrame();
frame.setTitle("Draw some simple shapes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
}
class DrawFrame extends JFrame{
public DrawFrame() {
add(new DrawComponent() );
pack();
}
}
class DrawComponent extends JComponent{
private static final int DEFAULT_WIDTH = 400;
private static final int DEFAULT_HEIGHT = 400;
public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT ); }
public void paintComponent( Graphics g ) {
Graphics2D graph = (Graphics2D) g;
double leftX = 100;
double topY = 100;
double width = 200;
double height = 150;
//画长方形
Rectangle2D.Double rect = new Rectangle2D.Double(leftX, topY, width, height );
graph.draw(rect);
//画椭圆
Ellipse2D.Double ellip = new Ellipse2D.Double();
ellip.setFrame(rect);
graph.draw(ellip);
//画斜线
Line2D.Double line = new Line2D.Double(leftX, topY, leftX + rect.getWidth(), topY + rect.getHeight());
graph.draw(line);
//画圆(椭圆的特殊情况)
double radius = 150;
double centerX = ellip.getCenterX();
double centerY = ellip.getCenterY();
Ellipse2D.Double circle = new Ellipse2D.Double();
circle.setFrameFromCenter( centerX, centerY, centerX + radius, centerY + radius );
graph.draw(circle);
}
}
- 使用颜色:
- 使用Graphics类的 setPaint方法,可以为图形环境上的所有后续的绘制操作选择颜色。
- java.awt.Color类 中提供了13个预定义的常量,分别表示13种标准颜色。
- 可以通过红绿蓝三色成分来创建一个Color对象,以达到定制颜色的目的。
- Color( int redness, int greenness, int blueness )。(参数范围0-255)
- 如果使用 Graphics对象 而不是Graphics2D对象,就需要使用 setColor方法 来设置颜色。
- 设置背景颜色:Component类的setBackground方法。setForeground方法,组件绘制的默认颜色。
- Java在 SystemColor类中,封装了用户系统的各个元素的颜色。(P427 10th)
- java.awt.Graphics2D
- Paint getPaint()
- void setPaint( Paint p ) //如:g2.setPaint(Color.RED)
- void fill( Shape s )
- 文本使用特殊字体:
- 要知道某台特定计算机上允许使用的字体,就需要调用GraphicsEnvironment类中的getAvailableFontFamilyNames方法。
- GraphicsEnvironment类描述了用户系统的图形环境,为了得到这个类对象,需要调用 静态的 getLocalGraphicsEnvironment方法。
- AWT定义了5个逻辑字体名:映射到客户机的实际字体
- SansSerif
- Serif
- Monospaced
- Dialog
- DialogInput
- Font( String name, int style, int size )
- 显示图像:
- java.awt.Graphics
- boolean drawImage( Image img, int x, int y, ImageObserver observer ) // img绘制的图像,x y左上角的坐标,observer 绘制进程中以通告为目的的对象(可能为null)
- boolean drawImage( Image img, int x, int y, int width, int height, ImageObserver observer ) //绘制一幅比例图像(注意:这个调用可能会在图像还没有绘制完毕就返回)
- void copyArea( int x, int y, int width, int height, int dx, int dy )
- 示例程序:(以一幅图像为基准,绘制相对应的平铺图像)
- java.awt.Graphics
package image;
import java.awt.*;
import javax.swing.*;
public class ImageTest {
public static void main( String[] args ) {
EventQueue.invokeLater(()->{
ImageFrame frame = new ImageFrame();
frame.setTitle("Image Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
}
class ImageFrame extends JFrame{
public ImageFrame() {
add( new ImageComponent() );
pack();
}
}
class ImageComponent extends JComponent{
private static final int DEFAULT_WIDTH = 640;
private static final int DEFAULT_HEIGHT = 640;
private static final int IMAGE_WIDTH = DEFAULT_WIDTH/10;
private static final int IMAGE_HEIGHT = DEFAULT_HEIGHT/10;
private Image image;
public ImageComponent() {
image = new ImageIcon("kilua.jpg").getImage();
}
public void paintComponent( Graphics g ) {
if( image == null ) return;
g.drawImage(image, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);
for( int i = 0; i < 10; i++ ) {
for( int j = 0; j < 10; j++ ) {
if( i + j > 0 ) {
g.copyArea(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, i*IMAGE_WIDTH, j*IMAGE_HEIGHT );
}
}
}
}
public Dimension getPreferredSize() { return new Dimension( DEFAULT_WIDTH, DEFAULT_HEIGHT ); }
}
- 运行结果: