java 图形界面
AWT 和 Swing
GUI基本类在java.awt包中,这个包也称为抽象窗口工具包(Abstract Window Toolkit,AWT)。
java.awt包中有一个抽象类Component,它是除菜单类外所有类的父类,他有如下所有组件都有的方法
- getBackground(): 返回背景色
- getGraphics(): 返回组件用的画笔
- getHeight(): 返回组件高度
- getLocation(): 获得组件位置
- getSize(): 获得组件大小
- getWidth(): 获得组件宽度
- getX(): 获得组件x值
- getY():
- isVisible(): 组件是否可见
- setBackGround(): 设置背景色
- setBackGrounds(int x, int y, int width, int height): 设置位置及大小
- setEnabled(boolean b): 设置组件是否可用
- setFont(Font f): 设置字体
- setForground(Color c): 设置前景色
- setLocation(int x, int y): 设置组件位置
- setSize(int width, int height): 设置组件宽高
- setSize(Dimension d): 设置组件大小
- setVisible(boolean b): 设置组件是否可见
Container表示容器,继承了Component类。容器用来存放别的组件。有两种容器
- Window(窗口): 他有两个子类,Frame(窗体)和Dialog(对话框)。Frame带有标题,并且可以自动调整大小,Dialog可以被移动,但不能改变大小
- Panel(面板): 他不能单独存在,只能存在于其他容器(如Window或其子类)。他有一个子类Applet,Applet可以在web中运行。
为了使java创建的图形界面能够跨平台,引入了Swing组件。这些组件位于javax.swing包中。接下来主要讲swing。
多数Swing的父类是JComponent(除了JFrame和JDialog外其他都继承了这个)。
JComponent的一些方法
- setFont(Font font): 设置字体
- setForeground(Color c): 设置字体颜色
- setToolTipText(String text): 设置鼠标移动到上面的时候显示的文本
- setBackGround(Color c)
- setOpaque(boolean isOpaque): 设置组件是否不透明,JLabel默认是透明。不透明才可以显示背景。
- setLocationRelativeTo(Component c): 设置窗口相对于指定组件的位置。当为null时,设置为中间。中点可以使用 GraphicsEnvironment.getCenterPoint 确定。
- isFocusOwner(): 判断这个组件是否拥有焦点
JFrame一些方法:
- setIconImage(Image image)
- setResizable(boolean resizable):窗口是否可以放大缩小
- setLocation(int x, int y): 位置
- setBounds(int x, int y, int width, int height): 设置大小和宽高
- Point getLocationOnScreen(): 获得位置
- dispose(): 销毁窗口。如果再次使用setVisiable()会重构组件
创建界面基本步骤
JFrame有一个构造方法JFrame(String title)。创建一个title位标题的JFrame对象,但是创建后它是不可见的,必须要经过下列步骤才可以可见:
- 调用setSize(int width, int height): 设置JFrame大小,或者调用peck()自动确定大小。
- 调用setVisible(true): 使JFrame可见
public static void main(String[] args) |
每个JFrame都会有内容面板(contentpane),加入JFrame容器的组件实际上都是加入这个面板中Container content = jframe.getContentPane();
content.add(jButton);//加入按钮组件
add()方法直接向与之关联的内容面板加入组件,所以可以直接jframe.add(jButton)
.
JFrame的setContentPane(Container content)用来重新设置面板。
JFrame的setDefaultCloseOperation(int operation)用来设置如何相应关闭操作
operation可以有以下操作
- JFrame.DO_NOTHING_ON_CLOSE: 什么也不做
- JFrame.HIDE_ON_CLOSE: 隐藏窗体,这是默认选项
- JFrame.DISPOSE_ON_CLOSE: 销毁窗体
- JFrame.EXIT_ON_CLOSE: 结束程序
布局管理器
JFrame的默认布局管理器是BorderLayout,JPanel默认布局管理器是FlowLayout。
可以通过setLayout(Layout layout)设置布局。也可以通过setLayout(null)取消布局管理器,但是接下来要自己去管理布局,并且现在每个操作系统不同。
FlowLayout 流式布局管理器
他按照组件先后顺序从左到右放到容器中,到达边界时,会放置到下一行。
当容器被缩放时,组件位置可能变化,但是组件大小不会改变
构造方法:
- FlowLayout()
- FlowLayout(int align)
- FlowLayout(int align, int hgap, int vgap):align设置对齐方式,可以有FlowLayout.LEFT,FlowLayout.RIGHT, FlowLayout.CENTER. hgap和vgap设置组件间水平和垂直间隙
BorderLayout(边界布局管理器)
他把容器分成五个区域:东西南北中。
- 它的东和西组件保持最佳宽度,高度拉伸至和所在区域一样高。南北保持最佳高度,宽度和这个区域一样宽。中间和这个区域一样大。
- 窗口垂直拉伸时,东西中拉伸,当窗口垂直拉伸时,南北中拉伸。
- 窗口缩放时,组件相对位置不变,但是组件大小改变
- 如果某个区域组件添加不止一个,只有最后一个是可见的。
构造方法:
- BorderLayout()
- BorderLayout(int hgap, int vgap)
添加组件: void add(Component comp, Object constraints)。其中constraints是区域,可以是BorderLayout.NORTH,BorderLayout.SOUTH,BorderLayout.EAST,BorderLayout.WEST,BorderLayout.CENTER. 默认是中
还可以直接用字符串设置区域。但是首字母必须大写,其他必须小写。f.add(new JButton("b1"), "North")
GridLayout(网格布局管理器)
他把容器分成许多行和列,添加组件时首先防止到左上角网格中,然后从左到右放置其他组件。
- 组件相对位置不会随缩放而改变,但是组件大小会改变。
- 他总是忽略组件最佳大小,所有组件宽度相同,高度也相同
构造方法:
- GridLayout()
- GridLayout(int rows, int cols)
- GirdLayout(int rows, int cols, int hgap, int vgap)
public class Calculater extends JFrame |
这是一个计算器的图形界面,可以看到外面采用了BorderLayout,里面面板采用了GridLayout。
CardLayout
他将界面看成一系列的卡片,任何时候只有一张卡片可见。
构造方法:
- CardLayout()
- CardLayout(int hgap, int vgap)
添加组件 void add(Component comp, Object constraints)。其中constraints实际上是一个字符串,表示卡片的名字。默认显示第一张卡片,可以采用show(Container parent, String name)指定显示哪一张卡片。parent指定容器
GridBagLayout(网格包 布局管理器)
创建步骤:
- 创建GridBagLayout,并启用
GridBagLayout layout = new GridBagLayout();
container.setLayout(layout); - 创建一个GridBagConstraints对象
GridBagConstraints constraints = new GridBagConstraints();
- 配置a的各种属性
constraints.gridx = 1;
constraints.gridy = 1;
constraints.gridwidth = 1;
constraints.gridwidth = 1; - 设置布局信息
lyout.setConstraints(component1, constraints)
- 加入容器
container.add(component1)
其中GridBagConstraints只需要设置一个,然后重复设置里面属性即可。
这种布局器最为自由,可以完全自己配置,但是首先要画一个草图先规划好各个组件的坐标。
GridBagConstraints的属性:
- gridx和gridy: 左上角横纵坐标。最左边是(0,0)。默认值是RELATIVE,即最新添加元素后面
- gridwidth,gridheight: 宽和高。默认值是1
- fill: 当某组件显示区域大于他所要求大小时使用。可以设置如下取值
- GridBagConstraints.NONE: 默认,不改变组件大小
- GridBagConstraints.HORIZONTAL: 填充水平方向,不改变水平大小
- GridBagConstraints.VERTICAL: 填充垂直方向
- GridBagConstraints.BOTH: 水平垂直都扩大以适应大小
- ipadx,ipady: 指定内部填充大小,即最小尺寸下还要加多少。宽度和高度都至少要加ipadx/ipady
- insets: 指定外部填充大小。组件和区域边界之间最小区域大小,例如
a.insets = new Insets(1, 1, 1, 1);//上左下右边距
- anchor: 当组件小于区域的时候使用。决定了在区域中的位置,有GridBagContraints.CENTER,等九个区域(包括NORTHEAST等角上区域)
- weightx,weighty: 水平重量和垂直重量。他们决定拉伸时谁将占据空白区域。注意每一行或每一列至少要有一个占据重量,不然拉伸时组件大小将不会发生改变,从而导致周围空白。
事件处理
每一个可以触发的事件都是事件源,每一种事件都会有相应的监听器,监听器负责接受和处理这些事件。一个事件源可以触发多种事件,事件源可以使按钮,键盘,鼠标等,他们可以产生时间如按键,按按钮,点击然后触发事件处理。
事件处理的实现
每个具体的事件都是某个事件类的实例,事件类有: ActionEvent,ItemEvent,MouseEvent,KeyEvent,FocusEvent,WindowEvent等。每个事件类对应一个事件监听接口,如ActionEvent对应ActionListener。
如果程序需要处理某种事件,就需要实现这些接口。
用内部类实现接口
public class ButtonCounter extends JFrame |
使用容器类实现接口
可以用容器类实现多个监听接口。
public class FrmaeCounter extends JFrame implements ActionListener |
它可以让按钮中的数字按一次就加一
定义顶层类实现接口
创建一个专门用来处理事件的类,优点是可以使处理时间的代码和创建GUI的代码分离,缺点是监听类无法直接访问事件源,必须通过事件类的getSource()方法获得事件源。
pubilc class OuterCounter extends JFrame |
当有动作(按按钮)产生时,会产生ActionEvent让Mylistener处理,如果是在一个类里,我们可以直接使用这个事件源(按钮),但是如果是其他类,就需要ActionEvent的getSource()来获得事件源(谁产生的设个事件)。
事件适配器
如果实现监听街口,就必须实现里面所有的方法。MouseListener有五个方法:mousePressed(),mouseReleased(),mouseEntered(),mouseExited(),
mouseClicked();在实际应用中,往往用不到这么多方法,因此可以使用适配器,适配器中实现了所有方法,但是都是空。例如MouseListener适配器类就是MouseAdapter
事件源,时间和监听器之间的关系
事件和监听接口
事件 | 监听接口 | 抽象方法 |
---|---|---|
Action | ActionListener | actioPerformed(ActionEvent evt) |
ItemEvent | ItemListener | itemStateChanged(ItemEvent) |
MouseEvent | MouseMotionListener | mouseDargged(MouseEvent)/mouseMoved(MouseEvent) |
MouseEvent | MouseListener | mousePressed()/mouseReleased()/mouseEntered()/ mouseExited()/mouseClicked() |
KeyEvent | KeyListener | keyPressed()/keyReleased()/keyTyped() |
FocusEvent | FocusListener | focusGained()/foucusLost() |
AdjustmentEvent | AdjustmentListener | adjustmentValueChanged() |
ComponentEvent | ComponentListneer | componentMoved()/ componentResized()/componentShown() |
WindowEvent | WinodwListener | windowClosing()/windowOpened()/ windowIconified()/windowDeiconfied()/ windowclosed() /windowActivated()/windowDeativated() |
ContainerEvent | ContainerListener | componentAdded()/componentRemoved() |
Textevent | TextListener | textValueChanged() |
MouseListener和MouseMotionListener都是监听MouseEvent。MouseMotionListener监听和鼠标移动相关事件。他们有以下方法
- mouseMoved(): 用户未按下鼠标直接移动时调用此方法
- mouseDragged(): 按下鼠标并拖动
- mouseClicked(): 单击鼠标
- mosuePressed(): 按下鼠标
- mouseReleased(): 释放鼠标
- mouseExited(): 退出组件区域
- mouseEntered(): 进入组件区域
组件及监听接口
组件可以通过addxxxlistener方法注册监听器(监听器就是上面第二列)。
适配器
监听接口 | 监听器 |
---|---|
ComponentListener | ComponentAdapter |
FocusListener | FocusAdapter |
KeyListener | KeyAdapter |
MouseListener | MouseAdapter |
MouseMotionListener | MouseMotionAdapter |
ContainerListener | ContainerAdapter |
WindowListener | 有 |
ItemListener | 没有 |
ActionListener | 没有 |
InputMethodListener | 没有 |
基本上有多个抽象方法的都有适配器
AWT绘图
在component中有两个和绘图有关方法:
- paint(Graphics g): 绘制组件外观
- repaint(): 调用paint(),刷新组件的外观(对于awt组件来说调用repaint前还要调用update方法)
在下列情况中,会调用paint:
- 第一次显示在屏幕上时
- 组件大小发生变化时
- 调用repaint
JComponent覆盖了paint,并将会话任务委托给三个protected的方法:
- paintComponent(): 画当前组件,
- paintBorder(): 画边界
- paintChildren(): 如果这个组件时容器,则画容器包含的组件
JComponent会议组件背景色覆盖整个区域,所以如果画了图形想清除的话只需要调用super.paintComponent().
例:public class ColorChange extends JPanel
{
private Color color = Color.RED;
private int times;
public ColorChange()
{
JButton button = new JButton("change color");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
color = (color==Color.RED) ? Color.GREEN : Color.RED;
repaint();//刷新
}
});
add(button);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);//清空画板
g.setColor(color);
g.fillReet(0, 0, 300, 300);//画矩形
}
public static void main(String[] args)
{
JFrame frame = new JFrame("Hello");
frame.setContentPane(new ColorChanger());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.setVisible(true);
}
}
上面就重写了paintComponent方法,然后repaint()调用的就是重写后的方法。
Graphics
Graphics代表画笔,提供了各种绘制图形的方法:
- drawLine(int x1, int y1, int x2, int y2): 画一条直线
- drawString(String string, int left, int bottom): 写字符串
- drawImage(Image image, int left, int top, ImageObserver observer):画一个图片
- drawRect(int left, int top, int width, int height): 画一个矩形
- drawOval(int x, int y, int width, int height):画一个椭圆
- fillRect(int left, int top, int width, int height): 填充矩形
- fillOval(int x, int y, int width, int height): 填充一个椭圆
其中left,top是左上角坐标。
如果没有调用Graphics的setColor()方法,将以前景色填充
使用完之后要用dispose()进行销毁
drawString(String str, int x, int y)将用当前画笔颜色和字体,将str显示.字符的左下角是(x,y)
Graphics2D
方法:
- setStroke(Stroke s); 获得画笔的特性
- draw(Shape shape): 滑参数指定的图形
- fill(Shape shape): 填充参数指定的图形
- translate(int x, int y): 平移
- rotate(double theta, double originX, double originY):旋转
- scale(double sx, double sy): 缩放
一般使用BasicStroke类。构造方法是BasicStroke(float width, int cap, int join, float miterlimit, float[] dash, float_phase)
:
- width:笔画宽度,此宽度必须大于或等于0.0f。如果将宽度设置为0.0f,则将笔画设置为当前设备的默认宽度
- cap:线端点的装饰
- join:应用在路径线段交汇处的装饰
- miterlimit:斜接处的裁剪限制。该参数值必须大于或等于1.0f
- dash:表示虚线模式的数组
- dash phase:开始虚线模式的偏移量
他还有一些绘制图形的类
- java.awt.geom.Line2D: 画直线
- java.awt.geom.Ellipse2D: 画椭圆
- java.awt.geom.Rectangle2D: 画矩形
上面这些画图形的都是抽象类,他们都有两个子类:Double和Float。例如LineD.Double。
上面这些实现类的构造方法和前面说的draw大致相似。
还可以利用java.awt.Toolkit的getScreenSize()来获得屏幕大小,从而设定JFrame大小。
线程安全
虚拟机中会创建一个专门的awt线程处理窗口,但是需要我们专门添加,添加代码SwingUtilities.invokeLater(Runnable doRun)
例如:public static void main(String[] args) {
// 此处处于 主线程,提交任务到 事件调度线程 创建窗口
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
// 此处处于 事件调度线程
createGUI();
}
}
);
}
上面的线程只是用来创建窗口,绘图等不耗时的工作。详细可看