import java.awt.Graphics;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EventListener;import javax.swing.JFrame;
import javax.swing.JPanel;/**
*
*
* @author Administrator
*
*/
public class EventSourceTest {
public static void main(String[] args) {
EventSourceFrame ef = new EventSourceFrame();
ef.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ef.setVisible(true);
}
}@SuppressWarnings("serial")
class EventSourceFrame extends JFrame {
public EventSourceFrame() {
setTitle("EventSourceTest");
setSize(400, 200); final PaintCountPanel panel = new PaintCountPanel();
add(panel); panel.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) {
setTitle("EventSourceTest - " + evt.getNewValue());
}
});
}
}@SuppressWarnings("serial")
class PaintCountPanel extends JPanel { @Override
protected void paintComponent(Graphics g) {
int oldPaintCount = paintCount;
paintCount++;
firePropertyChangeEvent(new PropertyChangeEvent(this, "paintCount",
oldPaintCount, paintCount));
super.paintComponent(g);
} public void addPropertyChangeListener(PropertyChangeListener listener) {
listenerList.add(PropertyChangeListener.class, listener);
} public void removePropertyChangeListener(PropertyChangeListener listener) {
listenerList.remove(PropertyChangeListener.class, listener);
} public void firePropertyChangeEvent(PropertyChangeEvent event) {
EventListener[] listeners = listenerList
.getListeners(PropertyChangeListener.class);
for (EventListener l : listeners)
((PropertyChangeListener) l).propertyChange(event);
} public int getPaintCount() {
return paintCount;
} private int paintCount;
}
看半天 没看懂
EventSourceFrame ef = new EventSourceFrame();
ef.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ef.setVisible(true);的目的,就是将内部的EventSourceFramem这个窗口显示出来。具体的设置可以去参看J2SE的API。我这里不详细说明了。之后就是EventSourceFramem,它继承字JFrame。虽然JFrame是非抽象的,这里继承的目的就是将Frame的一些属性前期设置好。例如标题、大小以及内部的摆放。JPanel是轻量的容器,作用是更加细分窗口中的布局。就像在Windows变成下的Panel一样。
class EventSourceFrame extends JFrame {
public EventSourceFrame() {
setTitle("EventSourceTest");
setSize(400, 200); final PaintCountPanel panel = new PaintCountPanel();
add(panel); panel.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) {
setTitle("EventSourceTest - " + evt.getNewValue());
}
});
}
}
之后就是内部类PaintCountPanel继承于JPanel。具体的功能已经在上文描述了。下面说一下流程。main()->EventSourceFramem->PaintCountPanel这样一个大体的流程。代码不复杂,仔细看下就可以明白了。另外简述下你上一个贴里问道的内部类的问题。内部类的功能是建立私有的类对象以保证不会被其他类使用。所以不是简简单单的“实现接口,和重写父类方法时候用”就像POJO会将属性定义为private一样。是保证结构的一个规整。内部类一般会声明为private。当然也可以声明为public。声明为public就等同再写一个Class了。而且没有必要在接口中将内部类的方法声明出来。因为接口方法必须是public。这样也就失去了要私有类的目的了。看一下下面这个类的写法:
public class Parameterized extends Suite {
/**
* Annotation for a method which provides parameters to be injected into the
* test class constructor by <code>Parameterized</code>
* 定义了Parameters的标注
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public static @interface Parameters {
} ...
}这是JUnit4参数化测试的一个标注写法。可以看到Parameters这个标注的私有类是在Parameterized这个类的私有类,他的目的就是实现了,只有在使用Parameterized标注的测试类里才能使用Parameters这个标注。这也是私有化的一个意义。
import java.awt.Graphics;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EventListener;import javax.swing.JFrame;
import javax.swing.JPanel;/**
*
*
* @author Administrator
*
*/
public class EventSourceTest {
public static void main(String[] args) {
//創建自定義的frame
EventSourceFrame ef = new EventSourceFrame();
//點擊關閉按鈕,程序退出
ef.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//讓該Frame可顯示
ef.setVisible(true); }
}@SuppressWarnings("serial")
class EventSourceFrame extends JFrame {
public EventSourceFrame() {
//设置Frame的标题信息
setTitle("EventSourceTest");
//设置Frame为宽400,高200
setSize(400, 200);
//创建自定义的Panel,由于要在匿名内部类中使用,所以定义为final类型
final PaintCountPanel panel = new PaintCountPanel();
//将panel加在frame的contentPane中
add(panel);
//给panel添加属性监听器
panel.addPropertyChangeListener(new PropertyChangeListener() {
//监听接口方法的具体实现
public void propertyChange(PropertyChangeEvent evt) {
//设置Frame的标题信息(每次拖动Frame,都会执行该方法)
setTitle("EventSourceTest - " + evt.getNewValue());
}
});
}
}@SuppressWarnings("serial")
class PaintCountPanel extends JPanel { @Override
//重写继承自JComponent的方法
protected void paintComponent(Graphics g) {
int oldPaintCount = paintCount;
//每次Panel变化,则重画次数增加一次,因为会调用paintComponent()方法
paintCount++;
//通知监听列表的监听器,属性被改变
firePropertyChangeEvent(new PropertyChangeEvent(this, "paintCount",
oldPaintCount, paintCount));
//为保证画面的完整,调用父类的paintComponent()方法
super.paintComponent(g);
} //添加监听器
public void addPropertyChangeListener(PropertyChangeListener listener) {
listenerList.add(PropertyChangeListener.class, listener);
} //移除监听器
public void removePropertyChangeListener(PropertyChangeListener listener) {
listenerList.remove(PropertyChangeListener.class, listener);
} //通知监听器
public void firePropertyChangeEvent(PropertyChangeEvent event) {
EventListener[] listeners = listenerList
.getListeners(PropertyChangeListener.class);
//此处将会调用监听器的propertyChange()方法,也就是匿名内部类里的方法
//参数event对象就是new PropertyChangeEvent(this, "paintCount",oldPaintCount, paintCount));
//保存了事件的源,被改变属性,以前的值和改变后的值
for (EventListener l : listeners)
((PropertyChangeListener) l).propertyChange(event);
} public int getPaintCount() {
return paintCount;
}
//记录该Panel重画的次数
private int paintCount;
}
从main函数起动
->打开Frame窗口
->将Panel加入Frame中,并且给Panel添加监听器
->Panel被拖动(拖动Frame,Panel跟着动)或者最小化则通知注册的监听器,重新设置Frame的标题信息其中 Panel中的 paintComponent 在Panel被改变时自动调用,
监听器的propertyChange方法在 //通知监听器
public void firePropertyChangeEvent(PropertyChangeEvent event) {
EventListener[] listeners = listenerList
.getListeners(PropertyChangeListener.class);
//此处将会调用监听器的propertyChange()方法,也就是匿名内部类里的方法
//参数event对象就是new PropertyChangeEvent(this, "paintCount",oldPaintCount, paintCount));
//保存了事件的源,被改变属性,以前的值和改变后的值
for (EventListener l : listeners)
((PropertyChangeListener) l).propertyChange(event);//发送属性更改的消息
}
红字部分调用后被自动调用。
你可以通过看jdk源码看清楚如何触发的。
可以看下 javaBean构建里绑定属性的内容。
import java.awt.*;
public class Test{
public static void main(String[] args){
TestFrame frame = new TestFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}}
class TestFrame extends JFrame{
private static int paintCount = 0;
TestFrame(){
setSize(500,400);
add(new TestPanel());
}
class TestPanel extends JPanel{
@Override
public void paintComponent(Graphics g){
paintCount++;
setTitle("TestFrame" + paintCount);
super.paintComponent(g);
}
}
}