J2SE(7)GUI编程

1、AWT:
(1)、AWT(Abstract Window Toolkit)包括了很多类和接口,用于java Application的GUI(Graphics User Interface图形用户界面)编程
(2)、GUI的各种元素(如:窗口,按钮,文本框等)由Java类来实现。
(3)、使用AWT所涉及的类一般在java.awt包及其子包中。
(4)、Container和Component是AWT中的两个核心类。
在这里插入图片描述2、Component与Container(组件与容器):
(1)、java图形用户界面的最基本组成成分是Component,Component类及其子类的对象用来描述以图形化的方式显示在屏幕上并能与用户进行交互的GUI元素,例如:一个按钮,一个标签等。
(2)、一般的Component对象不能独立地显示出来,必须将“放在”某一Container对象中才可以显示出来。
(3)、Container是Component子类,Container子类对象可以“容纳”别的Component对象。
(4)、Container对象可以使用方法add(…)向其中添加其他Component对象。
(5)、Container是Component的子类,因此Container对象也可以被当做Component对象添加到其他Container对象中。
(6)、有两种常用的Container:
* Window:其对象表示自由停泊的顶级窗口
* Panel:其对象可作为容纳其他Component对象,但不能独立存在,必须被添加到其它Container中(如:Window或Applet)

3、Frame:
(1)、Frame是Window的子类,由Frame或其子类创建的对象为一个窗体。
(2)、Frame的常用构造方法:
* Frame( )
* Frame(String s)创建标题栏为字符串s的窗口。
(3)、Frame常用方法:
* setBounds(int x, int y, int width, int height) //设置窗体位置和大小,x ,y是左上角坐标,width ,height是宽度和高度。
* setSize(int width, int height) //设置窗体的位置,x,y是左上角坐标
* setLocation(int x, int y) //设置窗体的大小,width,height分别是宽度和高度。
* setBackground(Color c) //设置背景颜色,参数为Color对象。
* setVisible(boolean b) //设置是否可见
* setTitle(String name) String getTitle( )
* setResizable(boolean b) //设置是否可以调整大小。
* 例:

package cn.javastudy.summary;


/**学习JAVA的GUI编程编写的第一个图形界面窗口*/
import java.awt.*;


public class TestFrame {
    public static void main(String args[]) {
        Frame f = new Frame("我的第一个JAVA图形界面窗口");
        /*
         * 这里只是在内存里面创建了一个窗口对象 还不能真正显示出来让我们看到
         */
        f.setBackground(Color.blue);// 设置窗体的背景颜色
        // blue是Color类里面的一个静态常量,可以使用“类名.静态常量名”来访问
        f.setVisible(true);// 设置窗体是否可见
        /*
         * 要想看到在内存里面创建出来的窗口对象, 必须调用setVisble()方法,并且把参数true传入才能看得见窗体 如果传入的参数是false,那么窗体也是看不见的
         */
        f.setSize(400, 400);// 设置窗体的初始大小
        f.setLocation(200, 200);// 设置窗体出现时的位置,如果不设置则默认在左上角(0,0)位置显示
        f.setResizable(false);
        /*
         * 设置窗体能否被改变大小,设置为false后表示不能改变窗体的显示大小 这里将窗体显示的大小设置为200X200,那么窗体的显示只能是这个大小了,不能再使用鼠标拖大或者缩小
         */
    }
}

4、Panel:
(1)、Panel对象可以看成可以容纳Component的空间。
(2)、Panel对象可以拥有自己的布局管理器。
(3)、Panel类拥有从父类继承来的:
* setBounds(int x, int y, int width, int height)
* setSize(int width, int height)
* setLocation(int x, int y)
* setBackgrouund(Color c)
* setLayout(LayoutManager mgr)等方法。
(4)、Panel的构造方法:
* Panel( )使用默认的FlowLayout类布局管理器初始化。
* Panel(LayoutManager layout)使用指定的布局管理器初始化。
例:

package cn.javastudy.summary;


import java.awt.*;
public class TestPanel{
    public static void main(String args[]){
        Frame f = new Frame("JAVA Fram With Panel");
        Panel p = new Panel(null);
        f.setLayout(null);
        f.setBounds(300,300,500,500);//这里设置的坐标(300,300)是相对于整个屏幕的
        f.setBackground(new Color(0,0,102));//设置背景颜色时使用三基色(红,绿,蓝)的比例来调配背景色
        p.setBounds(50,50,400,400);//这里设置的坐标(50,50)是相对于Frame窗体的
        p.setBackground(new Color(204,204,255));
        f.add(p);//把Panel容器装入到Frame容器中,使其能在Frame窗口中显示出来
        f.setVisible(true);
    }
}

5、布局管理器:
(1)、java语言中,提供了布局管理器类的对象可以管理。
* 管理Component在Container中的布局,不必直接设置Component位置和大小。
* 每个Container都有一个布局管理器对象,当容器需要对某个组件进行定位或判断其大小尺寸时,就会调用其对应的布局管理器,调用Container的setLayout方法改变其布局管理器对象。
(2)、AWT提供了五种布局管理器:
* FlowLayout
* BorderLayout
* GridLayout
* CardLayout
* GridBagLayout

6、FlowLayout布局管理器:
(1)、FlowLayout是Panel类的默认布局管理器。
* FlowLayout布局管理器对组件逐行定位,行内从左到右,一行排满后换行。
* 不改变组件的大小,按组件原有尺寸显示组件,可设置不同的组件间距,行距以及对齐方式。
(2)、FlowLayout布局管理器默认的对齐方式是居中。
在这里插入图片描述(3)、FlowLayout的构造方法:
* new FlowLayout(FlowLayout.RIGHT,20,40); //右对齐,组件之间水平间距20个像素,垂直间距40个像素。
* new FlowLayout(FlowLayout.LEFT); //左对齐,水平和垂直间距为缺省值(5)
* new FlowLayout( ); //使用缺省的对齐方式,水平和垂直间距为缺省值(5)
例:

package cn.javastudy.summary;


import java.awt.*;


public class TestFlowLayout {
    public static void main(String args[]) {
        Frame f = new Frame("FlowLayout");
        /*
         * 使用Button类创建按钮 按钮类的其中一个构造方法:Button(String label) label为按钮显示的文本
         */
        Button btn1 = new Button("button1");
        Button btn2 = new Button("button2");
        Button btn3 = new Button("button3");
        /* setLayout方法的定义:public void setLayout(LayoutManager mgr) */
        f.setLayout(new FlowLayout());// 使用流水(Flow)线般的布局
        /* 使用了布局管理器FlowLayout,这里的布局采用默认的水平居中模式 */
        // f.setLayout(new FlowLayout(FlowLayout.LEFT));
        /* 这里在布局的时候使用了FlowLayout.LEFT常量,这样就将按钮设置为左对齐 */
        // f.setLayout(new FlowLayout(FlowLayout.RIGHT));
        /* 这里在布局的时候使用了FlowLayout.RIGHT常量,这样就将按钮设置为右对齐 */
        f.add(btn1);// 把创建出来的按钮放置到Frame窗体中
        f.add(btn2); // 这里并没有设置按钮的大小与位置
        f.add(btn3); // 设置按钮的大小与位置都是由布局管理器来做的
        f.setVisible(true);
        f.setSize(200, 200);
    }
}

7、BorderLayout布局管理器:
(1)、BorderLayout是Frame类的默认布局管理器。
(2)、BorderLayout将整个容器的布局划分成
* 东(EAST)
* 西(WEST)
* 南(SOUTH)
* 北(NORTH)
* 中(CENTER)五个区域,组件只能被添加到指定的区域。
在这里插入图片描述 (3)、BorderLayout布局容器缩放原则:
* 北、南两个区域在水平方向缩放
* 东、西两个区域在垂直方向缩放
* 中部可在两个方向上缩放
(4)、如不指定组件的加入部位,则默认加入到CENTER区。
(5)、每个区域只能加入一个组件,如加入多个,则先前加入的会被覆盖。
例:

package cn.javastudy.summary;


import java.awt.*;


public class TestBorderLayout {
    public static void main(String args[]) {
        Frame f = new Frame("BorderLayout");
        Button btnEast = new Button("East");
        Button btnWest = new Button("West");
        Button btnSouth = new Button("South");
        Button btnNorth = new Button("North");
        Button btnCenter = new Button("Center");
        /*
         * 把按钮放置到Frame窗体时按照东西南北中五个方向排列好 推荐使用这种方式去排列窗体元素,
         * 这样容易检查出错误 因为这样写如果写错了编译器会提示出错
         */
        f.add(btnEast, BorderLayout.EAST);
        f.add(btnWest, BorderLayout.WEST);
        f.add(btnSouth, BorderLayout.SOUTH);
        f.add(btnNorth, BorderLayout.NORTH);
        f.add(btnCenter, BorderLayout.CENTER);
        /*
         * 也可以使用这样的方式排列按钮 在把按钮放置到Frame窗体时使用方向定位的字符串指定按钮的放置位置
         * 这种使用方向定位的字符串指定按钮的放置方式不推荐使用 一旦写错了方向字符串就不好检查出来
         *  因为即使是写错了仍然可以编译通过
         */
        /*
         * f.add(btnEast,"East");
         * f.add(btnWest,"West");
         * f.add(btnSouth,"South");
         * f.add(btnNorth,"North");
         * f.add(btnCenter,"Center");
         */
        f.setSize(200, 200);
        f.setVisible(true);
    }
}

8、GridLayout布局管理器:
(1)、GridLayout型布局管理器将空间划分成规则的矩形网格,每个单元格区域大小相等。组件被添加到每个单元格中,先从左向右填满一行后换行,再从上到下。
(2)、再GridLayout构造方法中指定分割的行数和列数:GridLayout(3, 4)
在这里插入图片描述 例:

package cn.javastudy.summary;


import java.awt.*;


public class TestGridLayout {
    public static void main(String args[]) {
        Frame f = new Frame("GridLayout");
        Button btn1 = new Button("btn1");
        Button btn2 = new Button("btn2");
        Button btn3 = new Button("btn3");
        Button btn4 = new Button("btn4");
        Button btn5 = new Button("btn5");
        Button btn6 = new Button("bnt6");
        f.setLayout(new GridLayout(3, 2));
        /* 把布局划分成3行2列的表格布局形式 */
        f.add(btn1);
        f.add(btn2);
        f.add(btn3);
        f.add(btn4);
        f.add(btn5);
        f.add(btn6);
        f.pack();
        f.setVisible(true);
    }
}

9、事件监听:
在这里插入图片描述 例:

package cn.javastudy.summary;


import java.awt.*;
import java.awt.event.*;


public class TestActionEvent {
    public static void main(String args[]) {
        Frame f = new Frame("TestActionEvent");
        Button btn = new Button("Press Me");
        Monitor m = new Monitor();/* 创建一个监听对象 */
        btn.addActionListener(m);
        /*
         * 把监听加入到按钮里面,监听按钮的动作, 当按钮触发打击事件时,就会返回一个监听对象e 然后就会自动执行actionPerformed方法
         */
        f.add(btn, BorderLayout.CENTER);
        f.pack();
        addWindowClosingEvent(f);
        /* 调用这个方法可以自动给Frame窗体里面的子图形元素一个合适的初始大小 */
        f.setVisible(true);
    }
    
    /**
     * 点击窗体上的关闭按钮关闭窗体
     * @param f
     */
    private static void addWindowClosingEvent(Frame f){
        f.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent arg0) {
                System.exit(0);
            }
            
        });
    }
}


/*
* 自定义Monitor(监听)类实现事件监听接口ActionListener 一个类要想成为监听类,那么必须实现ActionListener接口
*/
class Monitor implements ActionListener {
    /* 重写ActionListener接口里面的actionPerformed(ActionEvent e)方法 */
    public void actionPerformed(ActionEvent e) {
        System.out.println("A Button has been Pressed");
    }
}

10、TextField类:
(1)、java.awt.TextField类用来创建文本框对象。
(2)、TextField有如下常用方法:
* TextField( )
* TextField(int columns)
* TextField(String text)
* TextField(String text, int Coumns)
* public void setText(String t)
* public String getText( )
* public void setEchoChar(char c)
* public void setEditable(boolean b)
* public boolean isEditable( )
* public void setBackground(Char c)
* public void select(int selectionStart, int selectionEnd)
* publlic void selectAll( )
* public void addActionListener(ActionListener l) //添加动作监听器

11、TextField事件监听:
(1)、TextField对象可能发生Action( 光标在文本框内敲回车)事件。与该对象对应的事件是java.awt.event.ActionEvent.
(2)、用来处理ActionEvent事件是实现了java.awt.event.ActionListener接口的类的对象。
(3)、ActionListener接口定义有方法:public void actionPerformed(ActionEvent e)
(4)、实现接口的类要在方法中添加处理该事件(Action)的语句。
(5)、使用addActionListener(Actionlistener l)方法为TextField对象注册一个ActionListener对象,当TextField对象发生Action事件时,会生成一个ActionEvent对象,该对象作为参数传递给ActionListener对象的actionPerformer方法,在方法中可以获取该对象的信息,并做相应的对象
例:

package cn.javastudy.summary;


import java.awt.*;
import java.awt.event.*;


public class TestTextField {
    public static void main(String args[]) {
        new MyFrameTextField();
    }
}


class MyFrameTextField extends Frame {
    MyFrameTextField() {
        TextField tf = new TextField();
        add(tf);
        tf.addActionListener(new Monitor3());
        tf.setEchoChar('*');
        /*
         * 这个setEchoChar()方法是设置文本框输入时显示的字符,这里设置为*,
         * 这样输入任何内容就都以*显示出来,不过打印出来时依然可以看到输入的内容
         */
        setVisible(true);
        pack();
    }
}


class Monitor3 implements ActionListener {
    /*
     * 接口里面的所有方法都是public(公共的)
     * 所以从API文档复制void actionPerformed(ActionEvent e)时 要在void前面加上public
     */
    public void actionPerformed(ActionEvent e) {
        /* 事件的相关信息都封装在了对象e里面,通过对象e的相关方法就可以获取事件的相关信息 */
        TextField tf = (TextField) e.getSource();
        /*
         * getSource()方法是拿到事件源,注意:拿到这个事件源的时候,
         * 是把它当作TextField的父类来对待
         * getSource()方法的定义是:“public Object getSource()”返回值是一个Object对象,
         * 所以要强制转换成TextField类型的对象
         * 在一个类里面想访问另外一个类的事件源对象可以通过getSource()方法
         */
        System.out.println(tf.getText());// tf.getText()是取得文本框里面的内容
        tf.setText("");// 把文本框里面的内容清空
    }
}

12、内部类:
(1)、好处:
* 可以方便的访问包装类的成员。
* 可以更清楚的组织逻辑,防止被其他不应该访问的类进行访问。
(2)、何时使用:该类不需要或不允许被其他类进行访问时
例:

package cn.javastudy.summary;


import java.awt.*;
import java.awt.event.*;


public class TestMath3 {


    public static void main(String args[]) {
        new MyMathFrame().launchFrame();
    }
}


class MyMathFrame extends Frame {
    TextField num1, num2, num3;


    public void launchFrame() {
        num1 = new TextField(10);
        num2 = new TextField(15);
        num3 = new TextField(15);
        Label lblPlus = new Label("+");
        Button btnEqual = new Button("=");
        btnEqual.addActionListener(new MyMonitor());
        setLayout(new FlowLayout());
        add(num1);
        add(lblPlus);
        add(num2);
        add(btnEqual);
        add(num3);
        pack();
        setVisible(true);
    }


    /*
     * 这个MyMonitor类是内部类,它在MyFrame类里面定义 MyFrame类称为MyMonitor类的包装类
     */
    /*
     * 使用内部类的好处:
     * 第一个巨大的好处就是可以畅通无阻地访问外部类(即内部类的包装类)的所有成员变量和方法
     * 如这里的在MyFrame类(外部类)定义的三个成员变量num1,num2,num3,
     * 在MyMonitor(内部类)里面就可以直接访问
     * 这相当于在创建外部类对象时内部类对象默认就拥有了一个外部类对象的引用
     */
    private class MyMonitor implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            int n1 = Integer.parseInt(num1.getText());
            int n2 = Integer.parseInt(num2.getText());
            num3.setText("" + (n1 + n2));
            num1.setText("");
            num2.setText("");
        }
    }
}

13、Graphics类:
(1)、每个Component都有一个paint(Graphics g)用于实现绘图目的,每次重画该Component时都自动调用paint方法。
(2)、Graphics类中提供了许多绘图方法,如:
* drawRect(int x, int y, int width, int height)
* fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)等。
例:

package cn.javastudy.summary;


import java.awt.*;
public class TestPaint{
    public static void main(String args[]){
        new MyPaint().launchFrame();
        /*在main()方法里面并没有显示调用paint(Graphics g)方法
        可是当创建出Frame窗体后却可以看到Frame窗体上画出了
        圆和矩形,这是因为paint()方法是一个比较特殊的方法
        在创建Frame窗体时会自动隐式调用
        当我们把Frame窗体最小化又再次打开时,又会再次调用
        paint()方法重新把圆和矩形在Frame窗体上画出来
    即每次需要重画Frame窗体的时候就会自动调用paint()方法*/
    }
}


class MyPaint extends Frame{
    public void launchFrame(){
        setBounds(200,200,640,480);
        setVisible(true);
    }
    
    public void paint(Graphics g){
        /*paint(Graphics g)方法有一个Graphics类型的参数g
        我们可以把这个g当作是一个画家,这个画家手里拿着一只画笔
        我们通过设置画笔的颜色与形状来画出我们想要的各种各样的图像*/
        /*设置画笔的颜色*/
        g.setColor(Color.red);
        g.fillOval(100,100,100,100);/*画一个实心椭圆*/
        g.setColor(Color.green);
        g.fillRect(150,200,200,200);/*画一个实心矩形*/
        /*这下面的两行代码是为了写程序的良好编程习惯而写的
        前面设置了画笔的颜色,现在就应该把画笔的初始颜色恢复过来
        就相当于是画家用完画笔之后把画笔上的颜色清理掉一样*/
        Color c = g.getColor();
        g.setColor(c);
    }
}

14、鼠标事件适配器:
(1)、抽象类java.awt.event.MouseAdapter实现了MouseListener接口,可以使用其子类作为MouseEvent的监听器,只要重写其相应的方法即可。
(2)、对于其他监听器,也有对应的适配器。
(3)、使用适配器可以避免监听器类定义没有必要的空方法。
例:

package cn.galc.test;


import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class MyMouseAdapter{
  public static void main(String args[]) {
    new MyFrame("drawing...");
  }
}


class MyFrame extends Frame {
  ArrayList points = null;
  MyFrame(String s) {
    super(s);
    //将ArrayList初始化
    points = new ArrayList();
    setLayout(null);
    setBounds(300,300,400,300);
    this.setBackground(new Color(204,204,255));
    setVisible(true);
    this.addMouseListener(new Monitor());
    }
    
    public void paint(Graphics g) {
    Iterator i = points.iterator();
    while(i.hasNext()){
      Point p = (Point)i.next();
      g.setColor(Color.BLUE);
      g.fillOval(p.x,p.y,10,10);
      
    }
  }
  
  public void addPoint(Point p){
    points.add(p);
  }
}


class Monitor extends MouseAdapter {
  public void mousePressed(MouseEvent e) {
    MyFrame f = (MyFrame)e.getSource();
    f.addPoint(new Point(e.getX(),e.getY()));
    f.repaint();
  }
}

15、window事件:
(1)、Window事件所对应的事件类为WindowsEvent,所对应的事件监听接口为WindowListener。
(2)、WindowListener定义的方法有:
* public void windowsOpened(WindowEvent e)
* public void windowClosing(WindowsEvent e)
* public void windowClosed(WindowEvent e)
* public void windowIconified(WindowEvent e)
* public void windowDeiconified(WindowEvent e)
* public void windowActivated(WindowEvent e)
* public void windowDeactivated(WindowEvent e)
 (3)、与WindowListener对应的适配器为WindowAdapter。
例:

package cn.galc.test;


import java.awt.*;
import java.awt.event.*;
public class TestWindowClose{
    public static void main(String args[]){
        new WindowFrame("关闭WindowFrame");
    }
}


class WindowFrame extends Frame{
    public WindowFrame(String s){
        super(s);
        setBounds(200,200,400,300);
        setLayout(null);
        setBackground(new Color(204,204,255));
        setVisible(true);
        this.addWindowListener(new WindowMonitor());
/*监听本窗体的动作,把所有的动作信息封装成一个对象传递到监听类里面*/
        
        this.addWindowListener(
        /*在一个方法里面定义一个类,这个类称为局部类,也叫匿名的内部类,
        这里的{……代码……}里面的代码很像一个类的类体,只不过这个类没有名字,所以叫匿名类
        在这里是把这个匿名类当成WindowAdapter类来使用,语法上这样写的本质意义是相当于这个匿名类
        从WindowAdapter类继承,现在new了一个匿名类的对象出来然后把这个对象当成WindowAdapter来使用
        这个匿名类出了()就没有人认识了*/
            new WindowAdapter(){
                public void windowClosing(WindowEvent e){
                    setVisible(false);
                    System.exit(-1);
                }
            }
        );
    }
    
    /*这里也是将监听类定义为内部类*/
    class WindowMonitor extends WindowAdapter{
        /*WindowAdapter(Window适配器)类实现了WindowListener监听接口
        重写了WindowListener接口里面的所有方法
        如果直接使用自定义WindowMonitor类直接去
        实现WindowListener接口,那么就得要重写WindowListener接口
        里面的所有方法,但现在只需要用到这些方法里面的其中一个方法
        所以采用继承实现WindowListener监听接口的一个子类
        并重写这个子类里面需要用到的那个方法即可
        这种做法比直接实现WindowListener监听接口要重写很多个用不到的方法要简洁方便得多*/
/*重写需要用到的windowClosing(WindowEvent e)方法*/
        public void windowClosing(WindowEvent e){
                setVisible(false);/*将窗体设置为不显示,即可实现窗体关闭*/
                System.exit(0);/*正常退出*/
            }
    }
}

16、键盘响应事件——KeyEvent:

package cn.galc.test;


import java.awt.*;
import java.awt.event.*;
public class TestKeyEvent{
    public static void main(String args[]){
        new KeyFrame("键盘响应事件");
    }
}


class KeyFrame extends Frame{
    public KeyFrame(String s){
            super(s);
            setBounds(200,200,400,300);
            setLayout(null);
            setVisible(true);
            addKeyListener(new KeyMonitor());
        }
    /*把自定义的键盘的监听类定义为内部类
    这个监听类从键盘适配器KeyAdapter类继承
    从KeyAdapter类继承也是为了可以简洁方便
    只需要重写需要用到的方法即可,这种做法比
    直接实现KeyListener接口要简单方便,如果
    直接实现KeyListener接口就要把KeyListener
    接口里面的所有方法重写一遍,但真正用到的
    只有一个方法,这样重写其他的方法但又用不到
    难免会做无用功*/    
    class KeyMonitor extends KeyAdapter{
        public void keyPressed(KeyEvent e){
                int keycode = e.getKeyCode();
            /*使用getKeyCode()方法获取按键的虚拟码*/
            /*如果获取到的键的虚拟码等于up键的虚拟码
            则表示当前按下的键是up键
            KeyEvent.VK_UP表示取得up键的虚拟码
            键盘中的每一个键都对应有一个虚拟码
            这些虚拟码在KeyEvent类里面都被定义为静态常量
            所以可以使用“类名.静态常量名”的形式访问得到这些静态常量*/
                if(keycode == KeyEvent.VK_UP){
                        System.out.println("你按的是up键");
                    }
            }
        }
}
/*键盘的处理事件是这样的:每一个键都对应着一个虚拟的码,
当按下某一个键时,系统就会去找这个键对应的虚拟的码,以此来确定当前按下的是那个键
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值