import java.awt.event. * ;
import java.awt.geom. * ;
import java.util. * ;
public class RadioButton2D extends Component2D implements MouseListener ... {
//和按钮一起显示的标签
protected Label2D label;
//这个按钮所从属的组
protected RadioButtonGroup rbGroup;
//跟踪按钮状态的常量
public static final int BUTTON_OFF=0;
public static final int BUTTON_ON=1;
//用给定的标签,图像,按钮组和位置创建一个RadioButton2D
public RadioButton2D(Label2D lbl,ImageGroup grp,RadioButtonGroup rbg,
Vector2D p)...{
super();
label=lbl;
group=grp;
rbGroup=rbg;
if(rbGroup!=null)...{
rbGroup.add(this);
}
setPos(p);
updateBounds();
update();
setSelected(false);
}
//用给定的图像,按钮组和位置创建一个新的RadioButton2D
public RadioButton2D(ImageGroup grp,RadioButtonGroup rbg,Vector2D p)...{
this(null,grp,rbg,p);
}
//用给定的标签,图像和按钮组创建一个新的RadioButton2D
public RadioButton2D(Label2D lbl,ImageGroup grp,RadioButtonGroup rbg)...{
this(lbl,grp,rbg,Vector2D.ZERO_VECTOR);
}
//用给定的图像组创建一个新的RadioButton2D
public RadioButton2D(ImageGroup grp)...{
this(null,grp,null,Vector2D.ZERO_VECTOR);
}
//返回按钮是否被选中
public boolean isSelected()...{
return (state==BUTTON_ON);
}
//设置按钮的选中状态
public void setSelected(boolean selected)...{
state=(selected)?BUTTON_ON:BUTTON_OFF;
}
//如果有,返回按钮的文本描述
public String getText()...{
if(label!=null)...{
return label.getText();
}
return "";
}
//设置按钮和它的标签的可用状态
public void setEnabled(boolean e)...{
super.setEnabled(e);
if(label!=null)...{
label.setEnabled(e);
}
}
//变换按钮的状态
public void mousePressed(MouseEvent e)...{
if(!isEnabled()||!isVisible())return;
//如果没有按钮组则表明按钮独立行动
if(rbGroup==null)...{
if(bounds.contains(e.getPoint()))...{
setSelected(!isSelected());
}
}else...{//否则,更新整个按钮组
if(bounds.contains(e.getPoint()))...{
setSelected(true);
rbGroup.updateGroup(this);
}
}
}
public void mouseEntered(MouseEvent e)...{
}
public void mouseExited(MouseEvent e)...{
}
public void mouseClicked(MouseEvent e)...{
}
public void mouseReleased(MouseEvent e)...{
}
//用当前的变换绘制按钮
public void paint(Graphics2D g2d)...{
//只在组件可见时绘制
if(isVisible())...{
g2d.drawImage(((ButtonImageGroup)group).getFrame(state),
xform,AnimationStrip.observer);
//如果标签有效则绘制标签
if(label!=null)...{
label.paint(g2d);
}
}
}
//在给定的位置绘制按钮
public void paint(Graphics2D g2d,double dx,double dy)...{
//只绘制可见组件
if(isVisible())...{
g2d.drawImage(((ButtonImageGroup)group).getFrame(state),
AffineTransform.getTranslateInstance(pos.getX()+dx,
pos.getY()+dy),AnimationStrip.observer);
//如果标签有效则绘制标签
if(label!=null)...{
label.paint(g2d,dx,dx);
}
}
}
//返回描述这个按钮的文本
public String toString()...{
if(label!=null)...{
return super.toString()+" "+label.toString();
}
return super.toString();
}
} // RadioButton2D
import java.util. * ;
// 维护一组按钮,这样在任意时刻只有一个被选中
public class RadioButtonGroup ... {
//用来装单选按钮的动态可增长Vector
protected Vector buttons;
//遍历上述Vector的枚举器
protected Enumeration e;
//创建一个新的RadioButtonGroup对象
public RadioButtonGroup()...{
buttons=new Vector();
}
//将传入的单选按钮添加到Vector中去
public void add(RadioButton2D rb)...{
buttons.add(rb);
}
//得到当前所选中的单选按钮
//如果没有按钮被选中,则返回null
public RadioButton2D getSelection()...{
for(e=buttons.elements();e.hasMoreElements();)...{
RadioButton2D rb=(RadioButton2D)e.nextElement();
if(rb.isSelected())...{
return rb;
}
}
return null;
}
//整组按钮的可用/不可用状态
public void setEnabled(boolean b)...{
for(e=buttons.elements();e.hasMoreElements();)...{
((RadioButton2D)e.nextElement()).setEnabled(b);
}
}
//设置整个按钮组的可见性
public void setVisible(boolean v)...{
for(e=buttons.elements();e.hasMoreElements();)...{
((RadioButton2D)e.nextElement()).setVisible(v);
}
}
//更新按钮组,让除了传入的按钮之外的按钮设置为未选中状态
public void updateGroup(RadioButton2D rb)...{
for(e=buttons.elements();e.hasMoreElements();)...{
Object o=e.nextElement();
if(rb!=o)...{
((RadioButton2D)o).setSelected(false);
}
}
}
//绘制组中的每一个按钮
public void paint(Graphics2D g2d)...{
for(e=buttons.elements();e.hasMoreElements();)...{
((RadioButton2D)e.nextElement()).paint(g2d);
}
}
//在给定的位置绘制组中的每一个按钮
public void paint(Graphics2D g2d,double dx,double dy)...{
for(e=buttons.elements();e.hasMoreElements();)...{
((RadioButton2D)e.nextElement()).paint(g2d,dx,dy);
}
}
} // RadioButtonGroup
这个程序简洁而高效,那么怎么用一种比较好的方式在一个代码例子中演示单个和成组单选按钮呢?下面的RadioButton2DTest applet,包含了一个单选按钮组,它允许用户从几种超能力中作出选择,它还包含一个独立的单选按钮,它可以使包含超能力选择的单选按钮组激活或者失效。这个演示比较有趣,建议读者试一下。
import java.applet. * ;
import java.awt. * ;
public class RadioButton2DTest extends Applet implements Runnable ... {
//动画线程
private Thread animation;
private BufferedGraphics offscreen;
//是否禁用绝技列表的单选按钮
private RadioButton2D singleRB;
//跟踪绝技是否可用
private boolean powersEnabled;
//放置绝技列表的按钮组
private RadioButtonGroup rbGroup;
//可用的绝技的字符串描述
private final String[] POWERS=...{"火球","超踢","酸暴","电击","剃刀爪"};
private final int NUM_BUTTONS=POWERS.length;
//描述选择状态的标签
private Label2D status;
public void init()...{
//为按钮创建一个按钮组
ButtonImageGroup group=new ButtonImageGroup(2,"radio.gif");
group.init(this);
Label2D label;
Font font=new Font("Hevetica",Font.PLAIN,18);
//创建切换绝技是否可用的单选按钮
label=new Label2D(font,"允许绝技",Color.white);
singleRB=new RadioButton2D(label,group,null,new Vector2D.Double(50,50));
label.centerOn(singleRB.getBounds(),(Graphics2D)getGraphics());
label.setX(singleRB.getX()+singleRB.getBounds().getWidth()+5);
singleRB.setSelected(true);
powersEnabled=singleRB.isSelected();
addMouseListener(singleRB);
//创建容纳不同绝技的单选按钮组
RadioButton2D rb;
rbGroup=new RadioButtonGroup();
for(int i=0;i<NUM_BUTTONS;i++)...{
label=new Label2D(font,POWERS[i],Color.white);
rb=new RadioButton2D(label,group,rbGroup,
new Vector2D.Double(100,100+(i*35)));
label.centerOn(rb.getBounds(),(Graphics2D)getGraphics());
label.setX(rb.getBounds().getX()+rb.getBounds().getWidth()+5);
addMouseListener(rb);
//默认情况下,第0个按钮应该被选中
if(i==0) rb.setSelected(true);
}
//用初始的空白字符串创建状态标签
status=new Label2D(font,"",new Color(0,255,255));
status.setPos(new Vector2D.Double(50,325));
offscreen=new BufferedGraphics(this);
AnimationStrip.observer=this;
}//init
public void start()...{
//启动动画线程
animation=new Thread(this);
animation.start();
}
public void stop()...{
animation=null;
}
public void run()...{
Thread t=Thread.currentThread();
while(t==animation)...{
repaint();
try...{
Thread.sleep(10);
}catch(InterruptedException e)...{
break;
}
}
}//run
public void update(Graphics g)...{
//如果独立的那个选项改变,则切换绝技选项组状态
if(powersEnabled!=singleRB.isSelected())...{
powersEnabled=singleRB.isSelected();
rbGroup.setVisible(powersEnabled);
}
//更新标签的描述
if(powersEnabled==true&&rbGroup.getSelection()!=null)...{
status.setText("已选绝技:"+rbGroup.getSelection().getText());
}else...{
status.setText("禁用绝技");
}
paint(g);
}
public void paint(Graphics g)...{
Graphics2D bg=(Graphics2D)offscreen.getValidGraphics();
bg.setPaint(Color.black);
bg.fillRect(0,0,getSize().width,getSize().height);
//绘制单独的那个按钮
singleRB.paint(bg);
//绘制按钮组
rbGroup.paint(bg);
//绘制状态标签
status.paint(bg);
g.drawImage(offscreen.getBuffer(),0,0,this);
}//paint
} // RadioButton2DTest
import java.util. * ;
// 定义一个可以容纳其他组件的容器
public abstract class Container2D extends Component2D ... {
//容纳组件的动态Vector,以及所有组件的枚举
protected Vector components;
protected Enumeration e;
//使用传入的背景图像和位置创建一个新的Container2D对象
protected Container2D(Vector2D p)...{
super();
components=new Vector();
pos=p;
if(pos==null)...{
pos=new Vector2D.Double();
}
updateBounds();
}
//将传入的组件添加到指定的位置
public abstract void add(Component2D c,double x,double y);
//更新容器的边界
public abstract void updateBounds();
} // Container2D
虽然Container2D继承自Component2D,这里还是决定覆盖它的updateBounds方法并重新把它声明为abstract。由于子类很可能使用Image对象而不是ImageGroup对象来作为它们的背景,它们可能需要相应地定义自己的边界。还要注意,这里也没有定义Component2D的两个绘制方法,因此,Container2D的子类可能还需要负责定义这两个方法。
在开始构建Container2D类的子类之前,需要指出添加到容器中的组件应该参照组件的原点添加,而不是参照Applet或者Window的原点。这是Container2D类的whole point:在它们边界内实际保持它的子组件。
下面来实现第一个继承Container2D的类:Panel2D。
12.2 .6 Panel2D类
在第5章中已经讲过,Java Panel类对于把相关的组件从视觉上组合到一起是很好的。
前面已经看到了如何创建Container2D类来在父容器内摆放组件,现在可以实现一个类,让这个类来实际实现添加和绘制组件的方法。我们要看的第一个实现这个功能的类就是Panel2D类。像Panel类一样,添加到Panel2D对象中的组件摆放在其内部。Panel2D类的好处在于,组件可以添加到指定的x,y位置,这给了我们在组件布局上的控制权。
Panel2D类的另一个好处是,可以指定一个Image对象,让它作为面板的背景,逻辑上,总应该在绘制子组件前绘制背景图像。
下面的代码清单是完整的Panel2D类。它定义了所有Component2D和Container2D类所声明但没有完成的方法,这使得它成为一个完整的并且可以使用的类。
import java.awt. * ;
import java.awt.geom. * ;
import java.util. * ;
// 定义一个可以容纳其他组件的面板
public class Panel2D extends Container2D ... {
//背景图片
protected Image background;
//用指定的背景图片和位置创建一个新的Panel2D对象
protected Panel2D(Image bgImage,Vector2D p)...{
super(p);
background=bgImage;
}
//在面板上指定的位置添加组件
//注意所传入的x,y值是相对于面板原点的(左上角)
public void add(Component2D c,double x,double y)...{
c.setX(getX()+x);
c.setY(getY()+y);
//确保组件在面板边界之内
if(c.getX()+c.getBounds().getWidth()>
getX()+getBounds().getWidth())...{
c.setX(getX()+getBounds().getWidth()-
c.getBounds().getWidth());
}
if(c.getY()+c.getBounds().getHeight()>
getY()+getBounds().getHeight())...{
c.setY(getY()+getBounds().getHeight()-
c.getBounds().getHeight());
}
c.update();
c.updateBounds();
components.add(c);
}
//绘制面板和它的组件
public void paint(Graphics2D g2d)...{
//绘制背景
if(background!=null)...{
g2d.drawImage(background,(int)getX(),(int)getY(),
AnimationStrip.observer);
}
//绘制面板上的组件
for(e=components.elements();e.hasMoreElements();)...{
((Component2D)e.nextElement()).paint(g2d);
}
}
//根据指定的偏移值绘制面板和它的组件
public void paint(Graphics2D g2d,double dx,double dy)...{
if(background!=null)...{
g2d.drawImage(background,(int)(getX()+dx),(int)(getY()+dy),
AnimationStrip.observer);
}
for(e=components.elements();e.hasMoreElements();)...{
((Component2D)e.nextElement()).paint(g2d,dx,dy);
}
}
//更新面板的边界,如果面板没有图片,则不会尝试去计算面板的边界
public void updateBounds()...{
if(background!=null)...{
frameWidth=background.getWidth(AnimationStrip.observer);
frameHeight=background.getHeight(AnimationStrip.observer);
}else...{
frameWidth=Integer.MAX_VALUE;
frameHeight=Integer.MAX_VALUE;
}
bounds.setRect(pos.getX(),pos.getY(),frameWidth,frameHeight);
}
} // Panel2D
import java.awt. * ;
public class Panel2DTest extends Applet implements Runnable ... {
//动画线程
private Thread animation;
private BufferedGraphics offscreen;
//用于容纳其他组件的Panel2D对象数组
private Panel2D[] panels;
//摆放上述Panel2D对象的坐标
private Vector2D[] panelPos=...{new Vector2D.Double(10,10),
new Vector2D.Double(200,100)};
private final int NUM_PANELS=panelPos.length;
public void init()...{
//创建一个摆放透明按钮的图像组
ButtonImageGroup biGroup=new ButtonImageGroup(3,"xpbuttons.gif");
biGroup.init(this);
//为单选按钮创建一个图像组
ButtonImageGroup rbGroup=new ButtonImageGroup(2,"radio2.gif");
rbGroup.init(this);
//记住设置observer属性,这样面板可以访问它的背景图像的宽和高
AnimationStrip.observer=this;
//按钮,单选按钮和标签,用来创建组件来添加到我们的面板上
Button2D button;
RadioButton2D radioButton;
Label2D label;
Font font=new Font("Helvetica",Font.PLAIN,16);
//为面板创建背景图像
Image img=new ImageLoader(this,"panel.gif",true).getImage();
//创建面板,并把它们添加到画面上
panels=new Panel2D[NUM_PANELS];
for(int i=0;i<NUM_PANELS;i++)...{
//用背景图像和索引给定的位置创建面板
panels[i]=new Panel2D(img,panelPos[i]);
//在面板上添加单选按钮和两个一般按钮
radioButton=new RadioButton2D(null,rbGroup,null);
panels[i].add(radioButton,95,95);
radioButton.setSelected(true);
addMouseListener(radioButton);
label=new Label2D(font,"Java!",Color.white);
button=new Button2D(label,biGroup);
panels[i].add(button,25,25);
label.centerOn(button.getBounds(),(Graphics2D)getGraphics());
addMouseListener(button);
addMouseMotionListener(button);
label=new Label2D(font,"Java!",Color.white);
button=new Button2D(label,biGroup);
panels[i].add(button,130,185);
label.centerOn(button.getBounds(),(Graphics2D)getGraphics());
addMouseListener(button);
addMouseMotionListener(button);
}
offscreen=new BufferedGraphics(this);
}//init
public void start()...{
//启动动画线程
animation=new Thread(this);
animation.start();
}
public void stop()...{
animation=null;
}
public void run()...{
Thread t=Thread.currentThread();
while(t==animation)...{
repaint();
try...{
Thread.sleep(10);
}catch(InterruptedException e)...{
break;
}
}
}//run
public void update(Graphics g)...{
paint(g);
}
public void paint(Graphics g)...{
Graphics2D bg=(Graphics2D)offscreen.getValidGraphics();
bg.setPaint(Color.black);
bg.fillRect(0,0,getSize().width,getSize().height);
//绘制面板
for(int i=0;i<NUM_PANELS;i++)...{
panels[i].paint(bg);
}
g.drawImage(offscreen.getBuffer(),0,0,this);
}//paint
} // Panel2DTest
// 提供一个可以在画面上展现的简单菜单类
public class Menu2D extends Panel2D ... {
//判断菜单只是展现在画面上还是它决定绘制循环
protected boolean overlay;
//使用指定的背景图片,位置和覆盖属性值构建一个新的Menu2D对象
protected Menu2D(Image bgImage,Vector2D p,boolean over)...{
super(bgImage,p);
overlay=over;
}
public final boolean isOverlay()...{
return overlay;
}
} // Menu2D
if ( < 菜单栈非空 > ) ... {
if(<栈顶菜单是一个覆盖菜单>)...{
<绘制画面>
}
<绘制栈顶菜单>
} else ... {
<绘制画面>
}
import java.awt. * ;
import java.awt.event. * ;
import java.util. * ;
public class Menu2DTest extends Applet implements Runnable,KeyListener ... {
//动画线程
private Thread animation;
private BufferedGraphics offscreen;
//给applet的几个例子
private Menu2D menuA;
private Menu2D menuB;
private Menu2D menuC;
//放在上面的菜单上的按钮
private Button2D goToA;
private Button2D goToB;
private Button2D goToC;
//容纳菜单的栈
private Stack menuStack;
public void init()...{
AnimationStrip.observer=this;
//获取一个Graphics2D容器来使标签中对齐
Graphics2D g2d=(Graphics2D)getGraphics();
//为菜单按钮创建一个图像组
ButtonImageGroup group=new ButtonImageGroup(3,"xpbuttons.gif");
group.init(this);
//设置导航按钮
Label2D label;
Font font=new Font("Helvetica",Font.PLAIN,18);
label=new Label2D(font,"Menu A",Color.black);
label.setDisabledPaint(Color.white);
goToA=new Button2D(label,group);
label.centerOn(goToA.getBounds(),g2d);
addMouseListener(goToA);
addMouseMotionListener(goToA);
label=new Label2D(font,"Menu B",Color.black);
label.setDisabledPaint(Color.white);
goToB=new Button2D(label,group);
label.centerOn(goToB.getBounds(),g2d);
addMouseListener(goToB);
addMouseMotionListener(goToB);
label=new Label2D(font,"Menu C",Color.black);
label.setDisabledPaint(Color.white);
goToC=new Button2D(label,group);
addMouseListener(goToC);
addMouseMotionListener(goToC);
//创建监听器类
ActionListener listener=new ActionListener()...{
//根据哪个按钮被按下而把合适的菜单放到栈中
public void actionPerformed(ActionEvent e)...{
if(goToA==e.getSource())...{
//显示菜单A
menuStack.push(menuA);
updateButtonSettings();
}else if(goToB==e.getSource())...{
//显示菜单B
menuStack.push(menuB);
updateButtonSettings();
}else if(goToC==e.getSource())...{
//显示菜单C
menuStack.push(menuC);
updateButtonSettings();
}
}
};
goToA.addActionListener(listener);
goToB.addActionListener(listener);
goToC.addActionListener(listener);
//创建自定义菜单
Label2D header;
final Vector2D pos=new Vector2D.Double(100,50);
menuA=new Menu2D(new ImageLoader(this,"menuA.gif",true).getImage(),
pos,false);
header=new Label2D(font,"Menu A",Color.black);
menuA.add(header,0,0);
header.centerOn(menuA.getBounds(),g2d);
header.setY(menuA.getY()+header.getBounds().getHeight()+5);
menuA.add(goToA,78,50);
menuA.add(goToB,78,120);
menuA.add(goToC,78,190);
menuB=new Menu2D(new ImageLoader(this,"menuB.gif",true).getImage(),
pos,true);
header=new Label2D(font,"Menu B",Color.black);
menuB.add(header,0,0);
header.centerOn(menuB.getBounds(),g2d);
header.setY(menuB.getY()+header.getBounds().getHeight()+5);
menuB.add(goToA,78,50);
menuB.add(goToB,78,120);
menuB.add(goToC,78,190);
menuC=new Menu2D(new ImageLoader(this,"menuC.gif",true).getImage(),
pos,false);
header=new Label2D(font,"Menu C",Color.black);
menuC.add(header,0,0);
header.centerOn(menuC.getBounds(),g2d);
header.setY(menuC.getY()+header.getBounds().getHeight()+5);
menuC.add(goToA,78,50);
menuC.add(goToB,78,120);
menuC.add(goToC,78,190);
goToA.centerLabel(g2d);
goToB.centerLabel(g2d);
goToC.centerLabel(g2d);
//创建我们的菜单栈
menuStack=new Stack();
goToA.setEnabled(false);
goToB.setEnabled(true);
goToC.setEnabled(true);
//完成一般的applet初始化工作
offscreen=new BufferedGraphics(this);
addKeyListener(this);
}//init
//禁止那些会调用当前活动菜单的按钮
private void updateButtonSettings()...{
if(menuStack.empty())return;
Menu2D menu=(Menu2D)menuStack.peek();
if(menuA==menu)...{
goToA.setEnabled(false);
goToB.setEnabled(true);
goToC.setEnabled(true);
}else if(menuB==menu)...{
goToA.setEnabled(true);
goToB.setEnabled(false);
goToC.setEnabled(true);
}else if(menuC==menu)...{
goToA.setEnabled(true);
goToB.setEnabled(true);
goToC.setEnabled(false);
}
}
public void start()...{
//启动动画线程
animation=new Thread(this);
animation.start();
}
public void stop()...{
animation=null;
}
public void run()...{
Thread t=Thread.currentThread();
while(t==animation)...{
repaint();
try...{
Thread.sleep(10);
}catch(InterruptedException e)...{
break;
}
}
}//run
public void update(Graphics g)...{
paint(g);
}
public void paint(Graphics g)...{
Graphics2D bg=(Graphics2D)offscreen.getValidGraphics();
bg.setPaint(Color.black);
bg.fillRect(0,0,getSize().width,getSize().height);
//确保我们的文本看起来清晰
bg.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
//如果栈不为空,则处理顶上的菜单
if(!menuStack.empty())...{
//只是在顶层按钮是一个覆盖菜单时才绘制画面
if(((Menu2D)menuStack.peek()).isOverlay())...{
paintScene(bg);
}
//在其他的绘制完成后绘制菜单
((Menu2D)menuStack.peek()).paint(bg);
}else...{
paintScene(bg);
}
g.drawImage(offscreen.getBuffer(),0,0,this);
}//paint
public void paintScene(Graphics2D g2d)...{
//对于一个实际的画面,绘制一个渐变的paint来作为占位符
g2d.setPaint(new GradientPaint(0.0f,0.0f,Color.black,
(float)getSize().width,(float)getSize().height,
Color.white));
g2d.fillRect(0,0,getSize().width,getSize().height);
}
public void keyPressed(KeyEvent e)...{
}
public void keyReleased(KeyEvent e)...{
}
//更新菜单栈的顺序
public void keyTyped(KeyEvent e)...{
//退格会控制菜单顺序
if(e.getKeyChar()==KeyEvent.VK_ESCAPE)...{
//如果菜单不是空,则删除顶层元素
if(!menuStack.empty())...{
menuStack.pop();
updateButtonSettings();
}else...{//否则,把菜单A放到栈上
menuStack.push(menuA);
updateButtonSettings();
}
}
}
} // Menu2DTest
您好:
当您在阅读和使用我所提供的各种内容的时候,我非常感谢,您的阅读已是对我最大的支持。
我更希望您能给予我更多的支持。
1.希望您帮助我宣传我的博客,让更多的人知道它,从中获益(别忘记了提醒他们帮我点点广告,嘿嘿)。
2.希望您能多提出宝贵意见,包括我所提供的内容中的错误,建设性的意见,更希望获得哪些方面的帮助,您的经验之谈等等。
3.更希望能得到您经济上的支持。
我博客上面的内容均属于个人的经验,所有的内容均为开源内容,允许您用于任何非商业用途,并不以付费为前提,如果您觉得在阅读和使用我所提供的各种内容的过程中,您得到了帮助,并能在经济上给予我支持,我将感激不尽。
您可以通过点击我网站上的广告表示对我的支持。
您可以通过银行转帐付款给我:
招商银行一卡通:
卡号:6225888712586894
姓名:牟勇
您也可以通过汇款的方式:
通讯地址:云南省昆明市女子(28)中学人民中路如意巷1号
收信人:陈谦转牟勇收
邮编:650021
无论您给予我怎么样的支持,我都衷心的再次感谢。
欢迎光临我的博客,欢迎宣传我的博客
http://blog.csdn.net/mouyong
http://blog.sina.com.cn/mouyong
EMail:mouyong@yeah.net
QQ:11167603
MSN:mouyong1973@hotmail.com