博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JAVA中的观察者机制在绘图程序中的应用
阅读量:4039 次
发布时间:2019-05-24

本文共 7669 字,大约阅读时间需要 25 分钟。

 
JAVA
中的观察者机制在绘图程序中的应用
java.util.*包中提供了一个有趣的类:Observable类,和一个Observer接口。利用这两个类我们可以把一个类对象中的信息更改传递给其他许多类的对象,然后在做出进一步的处理。这种机制我们可以成为观察者/被观察者机制,或者称为文档(模型)/视图机制。
请看下面的代码:我们设计了三个类:一个类的对象充当被观察者的角色,或者说是充当模型的角色——BeingWatched.java;一个类的对象充当观察者的角色,或者说是充当视图的角色——Watcher.java;还有最后一个测试类——Testing.java。让我们看看这三个类如何工作。
1、
  被观察者类(模型类)的实现
在观察者机制中,被观察者类需要继承自java.util.Observable类。在Observable类中,有以下几个常用的方法:
setChanged
protected void setChanged()
Marks this
Observable object as having been changed; the
hasChanged method will now return
true.
这个方法,可以将一个Observable对象标记为可变化的对象。
 
notifyObservers
public void notifyObservers( arg)
If this object has changed, as indicated by the
hasChanged method, then notify all of its observers and then call the
clearChanged method to indicate that this object has no longer changed.
Each observer has its
update method called with two arguments: this observable object and the
arg argument.
Parameters:
arg - any object.
这个方法,可以将任何Observable对象的更改消息传递给Observer对象,即将对象的变化消息传递观察者对象,以后由观察者对象表现被观察者的变化。
 
addObserver
public void addObserver( o)
Adds an observer to the set of observers for this object, provided that it is not the same as some observer already in the set. The order in which notifications will be delivered to multiple observers is not specified. See the class comment.
Parameters:
o - an observer to be added.
Throws:
- if the parameter o is null.
这个方法可以在Observable对象上添加一个Observer对象,即由被观察者的对象为自己设定一个观察者对象,由该观察者对象负责处理自己的信息变化。
 
用户定义的被观察者类
package
com.libin.chapter15.obv;
 
import
java.util.*;
 
public
class
BeingWatched
extends
Observable{
   
void
counter(
int
period){
      
for
(;period>=0;period--){
          
//
设置当前对象为可变化的对象
           setChanged();
          
//
消息传递机制,通知观察者我要变化
           notifyObservers(
new
Integer(period));
          
//
线程处理
          
try
{
              Thread.sleep(1000);
//
休眠
1
秒钟,再运行
           }
catch
(InterruptedException e){
              System.
out
.println(
"sleep interrupted"
);
           }
       }
    }
}
 
2、
  观察者类(视图类)的实现
充当观察者的类需要实现Observer接口。在Observer接口中有一个void update(Observable o, Object arg)方法,利用这个方法可以表现被观察对象的信息变化。
update
void update( o,
             arg)
This method is called whenever the observed object is changed. An application calls an
Observable object's
notifyObservers method to have all the object's observers notified of the change.
Parameters:
o - the observable object.
arg - an argument passed to the
notifyObservers method.
这个方法是在任何被观察的对象发生信息变化时被JAVA系统自动调用的。但是需要注意,只有在被观察的对象上添加了观察者对象,并且被观察者对象将自己设置为可变对象后,调用了
notifyObserver(s)方法后,update()方法才会被调用。
用户定义的观察者类
package com.libin.chapter15.obv;
 
import java.util.*;
import java.util.Observable;
 
public class Watcher implements Observer{
       //用来表现模型对象的变化过程
       public void update(Observable obj,Object arg){
              System.out.println("update() called,count is: "+((Integer)arg).intValue());
       }
}
 
3、
  测试类的实现
在测试类中,我们创建了一个观察者对象,创建了一个被观察者对象,并且在被观察者对象上通过调用addObserver()方法添加一个观察者对象。
package
com.libin.chapter15.obv;
 
import
java.util.*;
 
public
class
ObserverDemo{
   
public
static
void
main(String args[]){
       BeingWatched observed=
new
BeingWatched();
       Watcher observing=
new
Watcher();
      
      
/*Add the observing to the list of observers for observed object. */
      
//
在模型对象上添加观察者对象
       observed.addObserver(observing);
      
//
模型对象调用自己的业务处理方法
       observed.counter(10);
      
    }
}
 
 
程序运行结果:
 
 
 
 
 
 
 
 
 
 
通过上面的一个实例大家了解了观察者机制的应用,下面我们来实现一个绘图程序的基本模型,体验一下观察者机制在绘图程序中的使用。
1、创建一个基本的JFrame对象
package com.libin.chapter19.exec1;
 
import java.awt.BorderLayout;
import java.awt.Container;
 
import javax.swing.JFrame;
 
public class MyFrame extends JFrame{
      
       Container content;
       MyViewer view;
       public MyFrame(){
              this.setTitle("一个基础的绘图程序测试");
              this.setBounds(100,150,400,300);
              this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              content=this.getContentPane();
              view=new MyViewer();
              content.add(view,BorderLayout.CENTER);
             
              this.setVisible(true);
             
       }
 
}
程序运行原理说明:MyFrame类主要的职责是用来创建程序的运行主界面,以后的绘图工作区在这个主界面上完成。但是在MyFrame类的容器中,我们添加了一个负责显示绘图工作区的观察类类MyViewer的对象,绘图模型的变化需要由MyViewer类的对象负责表现出来。
2、创建绘图模型类
package
com.libin.chapter19.exec1;
 
import
java.util.Iterator;
import
java.util.LinkedList;
import
java.util.Observable;
 
import
com.libin.chapter19.demo3.Element;
import
java.awt.geom.*;
public
class
MyModel
extends
Observable{
   
   
public
boolean
remove(Line2D.Double line) {
       
boolean
removed =
elementList
.remove(line);
       
if
(removed) {
          setChanged();
          notifyObservers(line.getBounds());
        }
 
       
return
removed;
     }
     
     
public
void
add(Line2D.Double line) {
       
elementList
.add(line);
        setChanged();
        notifyObservers(line.getBounds());
     }
 
     
public
Iterator getIterator() {
       
return
elementList
.listIterator(); 
     }
     
//
基于链表结构实现的集合类
     
protected
LinkedList
elementList
=
new
LinkedList();
 
   
   
}
 
程序工作原理:绘图模型类
MyModel
,通过
LinkedList
集合类的对象负责存储绘制的模型。之所以使用集合类的对象存储绘制的形状模型,主要是因为,我们在绘图工作区上绘制的不仅仅只有一个图形的形状。我们绘制的每一个形状都需要在绘图工作区中显示出来,所以需要使用集合类来对形状进行控制。
3、创建表现绘图结果的观察者类
package
com.libin.chapter19.exec1;
 
import
java.awt.Color;
import
java.awt.Graphics;
import
java.awt.Graphics2D;
import
java.awt.Point;
import
java.awt.event.MouseEvent;
import
java.awt.geom.Line2D;
import
java.text.DateFormat;
import
java.util.Iterator;
import
java.util.Observable;
import
java.util.Observer;
 
import
javax.swing.JComponent;
import
javax.swing.event.MouseInputAdapter;
 
public
class
MyViewer
extends
JComponent
implements
Observer {
 
    MyModel
model
=
new
MyModel();
 
   
public
MyViewer() {
       MyMouserHandler handler=
new
MyMouserHandler();
      
this
.addMouseListener(handler);
 
    }
   
   
   
public
void
paint(Graphics g) {
        Graphics2D g2D = (Graphics2D)g;               
// Get a Java 2D device context
 
        Iterator elements =
model
.getIterator();
        Line2D.Double element;                                   
// Stores an element
 
       
while
(elements.hasNext()) {                        
// Go through the list
          element = (Line2D.Double)elements.next();              
// Get the next element
          g2D.setPaint(Color.
red
);                
// Set the element color
         
//
绘制最终的形状
          g2D.draw(element);
         
// Draw its shape
        }
     }
   
   
 
   
public
void
update(Observable o, Object obj) {
      
      
if
((Line2D.Double)obj==
null
){
           repaint();
       }
 
    }
 
   
public
class
MyMouserHandler
extends
MouseInputAdapter {
 
      
private
Point
start
;
// Stores cursor position on press
 
      
private
Point
last
;
// Stores cursor position on drag
 
      
private
Line2D.Double
tempElement
;
// Stores a temporary element
 
      
private
boolean
button1Down
=
false
;
// Flag for button 1 state
 
      
private
Graphics2D
g2D
=
null
;
 
      
public
void
mousePressed(MouseEvent e) {
          
start
= e.getPoint();
// Save the cursor position in start
          
if
(
button1Down
= (e.getButton() == MouseEvent.
BUTTON1
)) {
              System.
out
.println(
"
鼠标左键被按下
"
);
             
g2D
= (Graphics2D) getGraphics();
             
g2D
.setPaint(Color.
blue
);
 
           }
       }
 
      
public
void
mouseReleased(MouseEvent e) {
          
          
last
= e.getPoint();
          
tempElement
= createElement(
start
,
last
);
          
g2D
.draw(
tempElement
);
          
          
if
(
button1Down
= (e.getButton() == MouseEvent.
BUTTON1
)) {
             
button1Down
=
false
;
// Reset the button 1 flag
              System.
out
.println(
"
鼠标左键已经被释放
"
);
             
if
(
tempElement
!=
null
) {
 
                 
model
.add(
tempElement
);
// Add element to the model
                 
tempElement
=
null
;
// No temporary now stored
              }
             
//
释放绘图对象,清理绘图环境
             
if
(
g2D
!=
null
) {
// If there's a graphics context
                 
g2D
.dispose();
// ...release the resource
                 
g2D
=
null
;
// Set field to null
              }
             
start
=
last
=
null
;
// Remove the points
           }
       }
 
      
private
Line2D.Double createElement(Point start, Point end) {
 
          
return
new
Line2D.Double(start, end);
          
// We should never get to here
 
       }
 
    }
 
}
 
程序工作原理:在
MyViewer
类中负责处理鼠标绘图事件,并且还需要观察绘图模型的变化,将这种变化在主界面上表现出来。
4、
  创建最终的应用程序类
package
com.libin.chapter19.exec1;
 
public
class
MyApp {
 
   
/**
     
*
@param
args
     
*/
   
public
static
void
main(String[] args) {
      
//
TODO
Auto-generated method stub
      
       MyApp app=
new
MyApp();
       app.init();
    }
 
   
   
public
void
init(){
       MyFrame myFrame=
new
MyFrame();
    }
}
 
这个绘图程序的基本模型完成了,但是我们还需要有几点思考:
1、
  程序本身功能不是很健全,主要是体验一个模型的使用。如果需要能够绘制多种几何形状的话,可以编写专门的一个类来负责各种几何形状的生成。然后在相应鼠标事件处理时,根据需要绘制的形状调用相关的几何形状生成算法,生成几何形状对象后,添加到MyModel类的集合类中去。
2、
  在图形的绘图过程中,如果需要能够看到形状的动态生成过程,就需要在处理鼠标绘图事件时,处理鼠标的拖拽方法,并且在几何形状的生成算法中要处理modify()方法;否则用户将不会看到形状的生成过程。
更完善的程序,由于篇幅有限,我没有在这个给出。感兴趣的朋友可以发邮件给我: 。我将会给你回复。

转载地址:http://vavdi.baihongyu.com/

你可能感兴趣的文章
性能调优之iostat命令详解
查看>>
性能调优之iftop命令详解
查看>>
非关系型数据库(nosql)介绍
查看>>
移动端自动化测试-Windows-Android-Appium环境搭建
查看>>
Xpath使用方法
查看>>
移动端自动化测试-Mac-IOS-Appium环境搭建
查看>>
Selenium之前世今生
查看>>
Selenium-WebDriverApi接口详解
查看>>
Selenium-ActionChains Api接口详解
查看>>
Selenium-Switch与SelectApi接口详解
查看>>
Selenium-Css Selector使用方法
查看>>
Linux常用统计命令之wc
查看>>
测试必会之 Linux 三剑客之 sed
查看>>
Socket请求XML客户端程序
查看>>
Java中数字转大写货币(支持到千亿)
查看>>
Java.nio
查看>>
函数模版类模版和偏特化泛化的总结
查看>>
VMware Workstation Pro虚拟机不可用解决方法
查看>>
最简单的使用redis自带程序实现c程序远程访问redis服务
查看>>
redis学习总结-- 内部数据 字符串 链表 字典 跳跃表
查看>>