天天看点

第12章-图形用户接口(2)---内部类

2015/6/16

1、

按下按钮改变图形颜色的实例:

package learn_swing;
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class SimpleGui3C implements ActionListener{
	JFrame frame;//将frame对象声明在这里可以方便其他位置来调用
	public static void main(String[] args){
		SimpleGui3C gui=new SimpleGui3C();
		gui.go();
	}
	public void go(){
		frame=new JFrame();//初始化frame
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		JButton button=new JButton("Change Colors");
		button.addActionListener(this);
		
		//创建MyDrawPanel对象,这个对象会自动调用它已经被重写的paintComponent方法
		//这就是所谓的绘图
		MyDrawPanel drawPanel=new MyDrawPanel();
		
		//border布局的添加方法
		frame.getContentPane().add(BorderLayout.SOUTH,button);
		frame.getContentPane().add(BorderLayout.CENTER,drawPanel);
		frame.setSize(300,300);
		frame.setVisible(true);
	}
	public void actionPerformed(ActionEvent event){
		//这里只能用frame,因为frame是全局变量,可以在这里调用。
		//不能用drawPanel,因为它在这里是局部变量。
		frame.repaint();
	}

}
           

MyDrawPanel类,用来实现图形的变化:

package learn_swing;
import java.awt.*;
import javax.swing.*;
public class MyDrawPanel extends JPanel{
//	public void painComponent(Graphics g){
//		g.setColor(Color.orange);
//		g.fillRect(20, 50, 100,100);
//	}
	public void paintComponent(Graphics g){//Component组件
		Graphics2D g2d=(Graphics2D)g;
		//开始的颜色
		int red=(int)(Math.random()*255);
		int green=(int)(Math.random()*255);
		int blue=(int)(Math.random()*255);
		Color startColor=new Color(red,green,blue);
		//结束的颜色
		red=(int)(Math.random()*255);
		green=(int)(Math.random()*255);
		blue=(int)(Math.random()*255);
		Color endColor=new Color(red,green,blue);
		
		GradientPaint gradient=new GradientPaint(70,70,startColor,150,150,endColor);
		g2d.setPaint(gradient);
		g2d.fillOval(70, 70, 100, 100);
	}
}           

2、想要让不同的按钮执行不同的工作,有两种方法:

(1)getSource()方法

package learn_swing;
import javax.swing.*;

import java.awt.event.*;

class MyGui implements ActionListener{
	//声明实例变量
	
	public void go(){
		colorButton=new JButton();
		LabelButton=new JButton();
		
		//这两个button对象声明的是同一个监听口
		colorButton.addActionListener(this);
		LabelButton.addActionListener(this);
		//其他gui
	}

	public void actionPerformed(ActionEvent e) {
		//用getSource()方法查询事件对象实际上是哪个事件源发出的
		if(e.getSource()==colorButton){
			//相对应的操作
		}else{
			//相对应的操作
		}
	}
}
           

这种方法虽然可以使用,但是并没有严格按照面向对象的要求。在维护上会出现很多的问题。

(2)用内部类的方式

*内部类:一个类嵌套在另一个类的内部。

class A{
     class B{
         void go(){
            }
     }
}           

内部类可以使用外部类所有的方法和变量,就算是私有的也一样。同时外部类里可以创建内部类的对象,并且通过该对象调用内部类的方法。

class MyOuter{
	private int x;
	MyInner inner=new MyInner();//创建内部类对象
	public void doStuff(){
		inner.go();//用内部类对象调用方法
	}
	
	class MyInner{
		void go(){
			x=42;//调用外部类的私有变量
		}
	}
}           

如果需要用外部类以外的程序代码来实例化内部类,需要用特殊的语法:

class Foo{
	public static void main(String[] args){
		MyOuter outer=new MyOuter();  //先创建一个外部类对象
		MyOuter.MyInner inner=outer.new MyInner();  //通过外部类来创建内部类对象
	}
}           

使用内部类的范例:

package learn_swing;
import javax.swing.*;

import java.awt.event.*;
import java.awt.*;
public class SimpleGui3C implements ActionListener{
	JFrame frame;//将frame对象声明在这里可以方便其他位置来调用
	JLabel label;
	public static void main(String[] args){
		SimpleGui3C gui=new SimpleGui3C();
		gui.go();
	}
	public void go(){
		frame=new JFrame();//初始化frame
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		JButton colorButton=new JButton("Change Colors");
		//不在使用this关键字,而是在被触发时,创建一个内部类对象,即同时创建了一个ActionEvent
		colorButton.addActionListener(new ColorListener());
		
		JButton labelButton=new JButton("Change label");
		//不在使用this关键字,而是在被触发时,创建一个内部类对象,即同时创建了一个ActionEvent
		labelButton.addActionListener(new LabelListener());
		
		//创建MyDrawPanel对象,这个对象会自动调用它已经被重写的paintComponent方法
		//这就是所谓的绘图
		MyDrawPanel drawPanel=new MyDrawPanel();
		label=new JLabel("I'm a label");
		
		//border布局的添加方法
		frame.getContentPane().add(BorderLayout.SOUTH,colorButton);
		frame.getContentPane().add(BorderLayout.EAST,labelButton);
		frame.getContentPane().add(BorderLayout.WEST,label);
		frame.getContentPane().add(BorderLayout.CENTER,drawPanel);
		frame.setSize(300,300);
		frame.setVisible(true);
	}
	//下面两个类分别实现了ActionListener接口,并且重写了actionPerformed()方法
	class LabelListener implements ActionListener{
		public void actionPerformed(ActionEvent e){
			label.setText("Ouch!");
		}
	}
	class ColorListener implements ActionListener{
		public void actionPerformed(ActionEvent e){
			frame.repaint();
		}
	}
	public void actionPerformed(ActionEvent e) {
		//虽然在外部类里添加了actionPerformed()方法,但并不使用
		//甚至即使不实现(不写改方法),虽然在eclipse上会报错,但程序的运行并没有问题。
		
	}
}
           

虽然在外部类里添加了actionPerformed()方法,但并不使用。甚至即使不实现(不写改方法),虽然在eclipse上会报错,但程序的运行并没有问题。

3、内部类为什么重要

内部类为我们提供了在一个类中实现同一个接口的多次机会。我们可以让不同的内部类实现同一个接口

4、何时使用内部类

任何一个你需要一个独立却又好像是另一个类成员之一的类时,内部类是唯一的解。

有时,我们需要两个不同的类来表示不同的事物。

当两个类需要相互的调用数据,且又有自己不同的继承时,采用内部类是个好方法,并且,这可以体现多态的特性。

5、内部类的特点

(1)内部类和外部类紧密的结合在一起,它只存在外部类对象的内部。它无法像独立的类一样重用,因为它和外部类紧密的结合在了一起。

(2)内部类的实例一定会绑定在外部类的实例上(这就是为什么其他的类创建内部类对象,必须要借用外部类的特殊方法的原因)。