上次学习内容未保存,待补!
前言:创建应用程序包括服务器端的应用程序必须要用图形用户接口,如客户端的用户接口由Web页面组成。命令行虽然功能满足,但没有适应性。本章主要学习事件处理,内部类,包括创建按钮,绘制动画等
一切从window开始
JFrame是屏幕上的window对象,可以放置button,CheckBox等组件
创建GUI的流程
1.创建frame
JFrame frame = new JFrame();
2.创建widget
widget大都在javax.swing包中
JButton button = new JButton("click me")
3.把widget加到frame上
frame.getContentPane().add(button);
//组件实际放在ContentPane上,frame只是个框
4.显示
frame.setSize(300,300);、//frame大小
frame.setVisible(true);
补充
按钮的外观有两种可选:称为Metal的Java标准和平台原始界面(默认值)
要想得到跨平台的外观,要使用Metal
回到图形上面
前言:之前大概了解事件的运行方式,现在回到屏幕的绘制上。
在GUI上加东西的三种方法
1.frame上放置widget(javax.swing包中),如按钮,窗体等
frame.getContentPane().add(myButton);
2.在widget上绘制2D图形(图形绘制方法在Java 2D API中)
使用graphics对象来绘制图形
graphics.fillOval(70,70,100,100);
3.在widget上绘制JPEG图
graphics.drawImage(myPic,10,10,this);
自己创建绘图组件
创建自己的图形,首先创建出有绘图功能的widget,然后把其放在frame上,若想在点选时改变颜色等可通过创建JPanel的子类并覆盖掉paintComponent()方法,将绘图代码写在该方法中,当你的panel所处的frame显示时,该方法就会被调用。若用户缩小window,JVM也知道要调用该方法来重新绘制,即任何有必要重绘时都会调用。
该方法不能自己调用,因为其参数是同实际屏幕有关的Graphics对象,而自己无法取得该对象,必须由系统交给你,但你可通过调用repaint()来要求系统重新绘制以此调用该方法。
import java.awt.*;
import javax.swing.*;
class MyDraw extends Jpanel{
public void paintComponent(Graphics g){
g.fillRect(20,50,100,100); //do
}
}
在paintComponent()中绘制图形
public void paintComponent(Graphics g){
Image image = new ImageIcon("catzilla.jpg").getImage(); //do
g.drawImage(image,3,4,this);//3,4表示坐标,原点最左上角
}
在黑色背景上画随机色彩的圆圈
public void paintComponent(Graphics g){
g.fillRect(0,0,this.getWidth(),this.getHeight());
//表示取得本身的宽与高,会填满panel
int red = (int)(Math.random()*255);
int green = (int)(Math.random()*255);
int blue = (int)(Math.random()*255);
Color randomColor = new Color(red,green,blue);
g.setColor(randomColor);
g.fillOval(70,70,100,100);//填满参数指定的椭圆型区域
paintComponent()的参数声明为Graphics(java.awt.Graphics)对象,当然也可能是Graphics的子类(多态)
由参数g所引用的对象实际是个Graphics2D的实例(Graphics2D引用上可以做的事情不能在Graphics引用上做,即Graphics2D对象能做的事情更多),即躲在graphics引用后面的是Graphics2D对象
回顾:多态时,编译器会根据引用变量类型而不是实际对象来判定能否调用某些方法,如Dog对象由Animal引用变量来引用
Animal a = new Dog();
a.bark();//error
但可通过强制类型转换,Dog d = (Dog)a;
d.bark();
同理,若想调用Graphics2D类方法,不能直接使用g参数,要强制转换
Graphics2D g2d =(Graphics2D)g;
要点
二维图形,".gif"和".jpeg"文件可以直接画在图形组件上
通过创建JPanel的子类并覆盖掉paintComponent()方法,将绘图代码写在该方法中,实现绘图
在获得事件时绘制图形
基本流程
1.这是个运用到panel和button组件的frame,将监听向按钮注册,显示frame,并等待用户点击
2.用户点击按钮,创建出一个事件对象并调用监听的事件处理程序
3.事件处理程序调用frame的repaint()
4.系统自动调用panel的paintComponent()
frame的布局
frame默认有五个区域放置widget,每个区域只能放置一项面板,但这一项面板可以继续放置面板,从而容纳其他组件,即在面板上放面板
frame.getContentPane.add(button);//单个参数默认放置在center位置
frame.getContentPane.add(BorderLayout.CENTER,button);
//指定在ContentPane放置的位置
内部类
一个类可以嵌套在另一个类的内部,只要内部类的定义在外部类的括号中就可以。
内部类可以使用外部类所有的方法和变量,即使是私用的也可以。
class MyouterClass{
private int x;
class MyInnerClass{
void go(){
x=42;
}
}
}
内部类的实例
内部类的实例一定会绑在外部类的实例上,即内部类的实例只能存取它所属的外部类的方法和变量而不是所有外部类的方法和变量。
内部类实例的创建
基本流程
1)创建外部类的实例
2)使用外部类的实例来创建内部类的实例
3)外部类与内部类在堆上有特殊关系,内外可以交互使用变量(特殊情况:内部类定义在静态方法中,不考虑)
在外部类程序代码中初始化内部类,此内部类的对象会绑定在该外部类对象上,如某方法会初始化内部类,则此内部类会绑定在执行该方法的实例上。
外部类的程序代码可以用初始化其他类完全相同的方法初始化它所包含的内部类。
class MyouterClass{
private int x; //外部私用的实例变量
MyInner inner = new MyInner(); //创建内部实例
public void doStuff(){
inner.go(); //调用内部方法
}
class MyInnerClass{
void go(){
x=42; //内部使用外部变量
}
}
}
从外部类以外初始化内部实例
class Foo{
public static void main(String[] args){
MyOuter outerObj = new MyOuter();
MyOuter.MyInner innerObj = outerObj.new MyInner();
}
}
以内部类执行动画效果
内部类对事件的监听是很方便的,因为你会对相同的事件处理程序实现一次以上。除此之外,内部类可当作外部类无法继承的子类,可以搞定不同的继承层次。
import javax.swing.*;
import java.awt.*;
public class SimpleAnimation{
int x=70;
int y=70; //创建两个实例变量来代表图形坐标
public static void main(String[] args){
SimpleAnimation gui = new SimpleAnimation();
gui.go();
}
public void go(){
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//控制window关闭时结束程序
MyDrawPanel drawPanel = new MyDrawPanel(); //创建frame上的widget
frame.getContentPane.add(drawPanel);
frame.setSize(300,300);
frame.setVisible(true);
for(int i=0;i<130;i++){
x++;
y++;
drawPanel.repaint(); //重新绘制面板
try{
Thread.sleep(50);
}catch(Exception ex){ }
}
}
class MyDrawPanel extends JPanel{
public void paintComponent(Graphics g){
g.setColor(Color.green);
g.fillOval(x,y,40,40); //使用外部坐标值更新
}
}
}