• Java—事件和多线程机制


    一  事件

    1.1 事件源      

    图形用户界面上每个可能产生事件的组件称为事件源。

    1.2 事件监听者

    Java系统中注册的用于接收特殊事件的类。不同的事件对应着不同的监听者,要想事件被监听者监听并处理,则需先将事件源注册到监听者。

    1.3 事件处理流程

    事件源触发事件并将事件作为一个参数传递给监听者,监听者实现某个接口中的抽象方法,从而实现对事件的处理。Java的事件处理机制是一个委托事件模型。

    事件源注册的方法如下:

    public void addActionListener(ActionListener l)

    添加特定的动作,监听接收来自事件源的动作事件,如果l为空,不会产生任何动作。

    监听者实现的接口为ActionListener接口,接口ActionListener来自包java.awt.event。

    在此接口中只有一个方法:

    public void actionPerformed(ActionEvent e)

    当事件对象e发生时,调用此方法。监听者就需要实现这个方法。

    1.4 动作事件

    ActionEvent包含一个事件,该事件为执行动作事件ACTION_PERFORMED。触发这个事件的动作为:

    (1) 点击按钮。

    (2) 双击列表中的选项。

    (3) 选择菜单项。

    (4) 在文本框中输入回车。

    常用方法如下:

    public String getActionCommand()                            返回引发某个事件的命令按钮的名字,如果名字为空,那么返回标签值。

    public void setActionCommand(String command)        设置引发事件的按钮的名字,默认设置为按钮的标签。

    例:测试动作事件

     1 package test;
     2 
     3 import java.awt.*;
     4 import java.awt.event.*;
     5 import java.applet.*;
     6 public class UseButton extends Applet implements ActionListener{
     7         /**
     8      * 
     9      */
    10     private static final long serialVersionUID = 1L;
    11     
    12         String str = new String();
    13         Button b1; //声明按钮对象;
    14         Button b2;
    15         Color c;
    16         public void init()
    17         {
    18              b1 = new Button("按钮对象1");
    19              b2 = new Button("按钮对象2");
    20              //添加事件监听者
    21              b1.addActionListener(this);
    22              b1.setBackground(Color.yellow);
    23              b2.addActionListener(this);
    24              this.add(b1);
    25              this.add(b2);
    26 
    27         }
    28         public void start()
    29         {
    30             str = b1.getLabel();
    31             //repaint();
    32         }
    33         public void paint(Graphics g)
    34         {
    35             g.setColor(c);
    36             g.drawString("引发事件的对象的标签:" + str, 80,60);
    37         }
    38         //实现接口中的方法,响应动作事件
    39         public void actionPerformed(ActionEvent e)
    40         {
    41             String arg = e.getActionCommand();
    42             if(arg == "按钮对象1")
    43             {
    44                 c = Color.red;
    45                 str = "按钮对象1";
    46             }
    47             else if(arg == "按钮对象2")
    48             {
    49                 c = Color.green;
    50                 str = "按钮对象2";
    51             }
    52             repaint();
    53         }
    54 }
    View Code

    点击按钮对象1 ,点击按钮对象2

    输出结果:

         

    1.5 文本事件(TextEvent)

    文本事件即代表文本区域中文本变化的事件TEXT_VALUE_CHANGED,在文本区域中改变文本内容。

    public void addTextListener(TextListener l)                     添加特定的文本事件,监听者接收来自文本对象的文本事件。如果l为空,那么不会抛出任何异常,而且也不会完成任何动作。

    public interface TextListener extends EventListener         用于接收文本事件的监听者接口。当对象的文本发生变化时,调用监听者对象的方法。

    接口中的方法为:

    public void textValueChanged(TextEvent e)                    当文本发生改变时调用。

    public Object getSource()                                             发生事件的对象,从EventObject继承来的方法。

    例:测试文本事件

     1 package test;
     2 
     3 import java.awt.*;
     4 import java.awt.event.*;
     5 import java.applet.Applet;
     6 public class UseTextEvent extends Applet implements ActionListener, TextListener{
     7     /**
     8          * @ YMM 2016/05/09
     9          */
    10     private static final long serialVersionUID = 1L;
    11     TextField tOld;
    12     TextArea tNew;
    13     Panel p;
    14     public void init()
    15     {
    16          tOld = new TextField(25);         
    17          tNew = new TextArea("",8,25,TextArea.SCROLLBARS_NONE);;
    18          //添加事件监听者
    19          tOld.addActionListener(this);
    20          tOld.addTextListener(this);
    21          //设置界面
    22          p = new Panel(new BorderLayout());
    23          
    24          p.add(tOld,BorderLayout.NORTH);
    25          p.add(tNew,BorderLayout.SOUTH);
    26         
    27          add(p);
    28     }
    29     //响应文本事件
    30     public void textValueChanged(TextEvent e)
    31     {
    32         if(e.getSource() == tOld)
    33             tNew.setText(tOld.getText());    
    34     }
    35         //响应动作事件
    36         public void actionPerformed(ActionEvent e)
    37         {
    38             if(e.getSource() == tOld)
    39                 tNew.setText("");
    40         }
    41     };
    View Code

    1.6  选择事件(ItemEvent)

    选择事件中包含以事件为代表的选择项,选中状态发生变化的事件ITEM_STATE_ CHANGED。引发的动作为:

    (1) 改变列表类List对象选项的选中或不选中状态。

    (2) 改变下拉列表类Choice对象选项的选中或不选中状态。

    (3) 改变复选按钮类Checkbox对象的选中或不选中状态。

    事件源对象注册的方法如下:

    public void addItemListener(ItemListener l)                添加特定的项监听者,接收对象的选择项发生变化的事件。

    public ItemSelectable getItemSelectable()                   ItemEvent事件的方法,返回产生事件的事件源对象。

    public interface ItemListener extends EventListener     接收选项事件的监听者接口。当选项中事件发生时,调用监听对象的itemStateChanged方法。

    public void itemStateChanged(ItemEvent e)                当用户选中一项或未选中一项时,调用这个方法。

     1 package test;
     2 import java.awt.*;
     3 import java.awt.event.*;
     4 import java.applet.*;
     5 
     6 
     7 public class UseItemEvent extends Applet implements ItemListener{
     8     /**
     9      *  2016/05/09 @author jftt
    10      */
    11     private static final long serialVersionUID = 1L;
    12     Checkbox cDisp;   //复选按钮
    13     Button btnDisp;   //
    14     Choice cFont;      //下拉列表
    15     public void init()
    16     {
    17          cDisp = new Checkbox("红色");
    18          btnDisp = new Button("颜色显示");
    19          //setLayout(null); 
    20          btnDisp.setSize(120,120);
    21          cFont = new Choice();
    22          cFont.add("10");
    23          cFont.add("12");
    24          cFont.add("14");
    25          //添加事件
    26          cDisp.addItemListener(this);
    27              cFont.addItemListener(this);
    28              add(cDisp);
    29              add(cFont);
    30              add(btnDisp);
    31         }
    32         //接口事件
    33         public void itemStateChanged(ItemEvent e)
    34         {
    35             Checkbox temp;
    36             Choice temp2;
    37             Font oldF;
    38             //复选框
    39             if(e.getItemSelectable() instanceof Checkbox)
    40             {
    41                 temp = (Checkbox)(e.getItemSelectable());    
    42                 //选中为红色,否则为蓝色
    43                     if(temp.getState())
    44                         btnDisp.setBackground(Color.red);
    45                     else
    46                         btnDisp.setBackground(Color.yellow);
    47             }
    48                 //组合框
    49                 if(e.getItemSelectable() instanceof Choice)
    50                 {
    51                     oldF = btnDisp.getFont();
    52                     temp2 = (Choice)(e.getItemSelectable());
    53                     String s = temp2.getSelectedItem();
    54                     String s1=oldF.getName();
    55                     int s2=oldF.getStyle();
    56                     //设置字体
    57                     btnDisp.setFont(new Font(s1,s2,Integer.parseInt(s)));// 字体,样式(粗体,斜体等),字号
    58                 }
    59         }                
    60 
    61 }
    View Code

    1.7  调整事件(AdjustmentEvent)

    调整事件包含一个事件,即ADJUSTMENT_VALUE_CHANGED事件,当操纵滚动条改变其滑块位置时引发动作。AjustEvent的方法如下:

    public Adjustable getAdjustable()                                               返回引发事件的对象。

    public int getValue()                                                                  返回调整事件中的当前值。

    public void addAdjustmentListener(AdjustmentListener l)              添加调整监听者来接收来自对象的AdjustmentEvent实例。

    public interface AdjustmentListener extends EventListener            接收调整事件的监听接口,有一个方法:

    public void adjustmentValueChanged(AdjustmentEvent e)             可在调整改变时调用这个值。

    例:测试调整事件。设置一个水平滚动条,取值为1~36,随着滑块的变化,滚动条的值将显示在文本区域中,并且字体大小也会跟随变化

     1 package test;
     2 import java.awt.*;
     3 import java.awt.event.*;
     4 import java.applet.*;
     5 
     6 public class UseAdjustmentEvent extends Applet implements AdjustmentListener{
     7     /**
     8      * @author YMM 2016/05/09
     9      */
    10     private static final long serialVersionUID = 1L;
    11     Scrollbar s;
    12     TextArea txtValue;
    13     Panel p;
    14     public void init() {
    15          s = new Scrollbar(Scrollbar.HORIZONTAL,0,1,10,36);
    16          //添加监听者
    17          s.addAdjustmentListener(this);
    18          txtValue = new TextArea(5,25);
    19          //界面布局
    20          p = new Panel(new BorderLayout());
    21          p.add(s,BorderLayout.NORTH);
    22          p.add(txtValue,BorderLayout.SOUTH);
    23          add(p);
    24     }
    25     public void adjustmentValueChanged(AdjustmentEvent e) {
    26             int value;
    27             Font oldF;
    28             if(e.getAdjustable() == s)
    29             { 
    30                 //得到滚动条的值
    31                 value = e.getValue();
    32                 //将值写入文本区域
    33                 txtValue.setText(new Integer(value).toString());
    34                 //按照滚动条的值设置字体
    35                 oldF = txtValue.getFont();
    36                 txtValue.setFont(new Font(oldF.getName(),oldF.getStyle(),value));
    37             }
    38     }
    39 }
    View Code

    1.8  鼠标事件(MouseEvent)

    表明画布或界面组件中发生的鼠标事件,包含按下鼠标、释放鼠标、单击鼠标、进入部件的地理位置的鼠标事件和退出部件的地理位置的鼠标事件,以及鼠标移动事件(鼠标移动和鼠标拖动)。

    鼠标使用addMouseListener方法注册,通过MouseListener接收鼠标事件;鼠标还可以使用addMouseMotionListener方法注册,通过MouseMotionListener监听者监听鼠标移动事件。

    监听者中有具体的方法分别针对上述具体的鼠标事件,系统能够自动分辨鼠标事件的类型并调用相应的方法,所以只需编码实现相应的代码就可以了。

    public int getButton()                                           返回哪个按钮发生变化。

    public int getClickCount()                                      返回与这个事件相关的鼠标单击的次数。

    public Point getPoint()                                          返回同源部件相对的事件发生的x、y位置。

    public int getX()                                                  返回同源部件相对的事件发生的x位置。

    public int getY()                                                  返回同源部件相对的事件发生的y位置。

    例:测试按钮和画布的鼠标事件,包括单击、按下、进入和退出等

      1 package test;
      2 import java.awt.*;
      3 import java.awt.event.*;
      4 import java.applet.*;
      5 
      6 public class UseMouseEvent extends Applet implements MouseListener,MouseMotionListener{
      7     /**
      8      * 
      9      */
     10     private static final long serialVersionUID = 1L;
     11     Button btn;
     12     public void init()
     13     {
     14          btn = new Button("演示鼠标事件");
     15          add(btn);
     16          //给按钮添加鼠标事件和鼠标移动事件
     17          btn.addMouseListener(this);
     18          btn.addMouseMotionListener(this);
     19          //给画布添加鼠标事件和鼠标移动事件
     20          this.addMouseListener(this);
     21          this.addMouseMotionListener(this);
     22     }
     23     //单击事件
     24     public void mouseClicked(MouseEvent e)
     25     {
     26         Point p = new Point();
     27         if(e.getSource() == btn)//getSource()发生事件的对象,从EventObject继承来的方法。
     28 
     29         {
     30             if(e.getClickCount() == 1)
     31             {
     32                 btn.setLabel("单击鼠标");
     33             }
     34             else if(e.getClickCount() == 2)
     35             {
     36                 btn.setLabel("双击鼠标");
     37             }
     38         }
     39         else
     40         {
     41             if(e.getClickCount() == 1)
     42             {
     43                 p = e.getPoint();
     44                 showStatus(p.x + "," + p.y + "单击鼠标");
     45             }
     46             else if(e.getClickCount() == 2)
     47             {
     48                 p = e.getPoint();
     49                 showStatus(p.x + "," + p.y + "双击鼠标");
     50             }
     51          }
     52     }
     53     //进入事件
     54     public void mouseEntered(MouseEvent e)
     55     {
     56         if(e.getSource() == btn)
     57             btn.setLabel("进入Button");
     58         else
     59             showStatus("进入Applet");
     60     }
     61     public void mouseExited(MouseEvent e)
     62     {
     63         if(e.getSource() == btn)
     64             btn.setLabel("退出Button");
     65         else
     66             showStatus("退出Applet");
     67     }
     68     //按下事件
     69     public void mousePressed(MouseEvent e)
     70     {
     71         if(e.getSource() == btn)
     72             btn.setLabel("按下鼠标");
     73         else
     74             showStatus("按下鼠标");
     75         }
     76         //释放事件
     77         public void mouseReleased(MouseEvent e)
     78         {
     79             if(e.getSource() == btn)
     80                 btn.setLabel("松开鼠标");
     81             else
     82                 showStatus("松开鼠标");
     83         }
     84         //移动事件
     85         public void mouseMoved(MouseEvent e)
     86         {
     87             if(e.getSource() == btn)
     88                   btn.setLabel("移动鼠标");
     89             else
     90                   showStatus("移动鼠标,新位置" + e.getX() + "," + e.getY());
     91             }
     92         //拖动事件
     93         public void mouseDragged(MouseEvent e)
     94         {
     95             if(e.getSource() == btn)
     96                 btn.setLabel("拖动鼠标");
     97             else
     98                 showStatus("拖动鼠标");
     99         }
    100 }
    View Code

    1.9  键盘事件(KeyEvent)

    键盘事件有三个:键盘按键按下,按键释放,按键被敲击。常用方法如下:

    public char getKeyChar()                                          返回事件中键的字符。

    public int getKeyCode()                                            返回整数键码。

    public static String getKeyText(int keyCode)               返回描述这个键码的字符串,例如“HOME”、“F1”或者“A”等。

    public interface KeyListener extends EventListener      用来接收键盘事件。使用方法addKeyListener注册。

    针对键盘的三个事件接口提供相应的方法进行处理,具体方法如下:

    public void keyPressed(KeyEvent e)                          按键时引发事件处理。

    public void keyReleased(KeyEvent e)                        释放键时引发事件处理。

    public void keyTyped(KeyEvent e)                            键入键时引发事件处理。

    例:

     1 package test;
     2 
     3 import java.applet.Applet;
     4 import java.awt.*;
     5 import java.awt.RenderingHints.Key;
     6 import java.awt.event.ActionEvent;
     7 import java.awt.event.ActionListener;
     8 import java.awt.event.KeyEvent;
     9 import java.awt.event.KeyListener;
    10 import java.awt.event.TextEvent;
    11 import java.awt.event.TextListener;
    12 
    13 
    14 public class UseKeyEvent extends Applet implements KeyListener,ActionListener, TextListener {
    15     /**
    16      * 
    17      */
    18     private static final long serialVersionUID = 1L;
    19     Key key;
    20     Button btn;
    21     TextField txt;
    22     public void init()
    23     {
    24          btn = new Button("演示键盘事件");
    25          add(btn);
    26 
    27          btn.addKeyListener(this);
    28 
    29          this.addKeyListener(this);
    30          txt = new TextField(25);    
    31          //添加事件监听者
    32          txt.addActionListener(this);
    33          txt.addTextListener(this);
    34          //设置界面
    35 
    36          
    37          add(txt,BorderLayout.NORTH);
    38       
    39     }
    40     @Override
    41     public void keyTyped(KeyEvent e) {//键入键时引发事件处理
    42         // TODO 自动生成的方法存根
    43         char ch = e.getKeyChar();
    44         if(ch =='Y' || ch == 'y')
    45             txt.setText ("同意");
    46         else if (ch == 'N' || ch == 'n')
    47             txt.setText ("反对");
    48         else
    49             txt.setText ("无效");
    50         
    51     }
    52     @Override
    53     public void keyPressed(KeyEvent e) {
    54         // TODO 自动生成的方法存根
    55         btn.setLabel("按键时引发事件处理");
    56     }
    57     @Override
    58     public void keyReleased(KeyEvent e) {
    59         // TODO 自动生成的方法存根
    60         btn.setLabel("释放键时引发事件处理");
    61     }
    62     @Override
    63     public void textValueChanged(TextEvent e) {
    64         // TODO 自动生成的方法存根
    65         
    66     }
    67     @Override
    68     public void actionPerformed(ActionEvent e) {
    69         // TODO 自动生成的方法存根
    70         
    71     }
    72 }
    View Code

    二  多 线 程 机 制

    2.1  线程简介

            线程(thread)就是进程中的一个执行线索。Java虚拟机允许进程中同时执行多个线程。每个线程都有一个优先级。具有较高优先级的线程先执行。

      线程是操作系统分配 CPU 时间的基本实体。每一个应用程序至少有一个线程,也可以拥有多个线程。线程是程序中的代码流。多个线程可以同时运行并能共享资源。

      线程与进程不同,每个进程都需要操作系统为其分配独立的地址空间,而同一进程中的各个线程是在同一块地址空间中工作。

            在 Java 程序中,一些动态效果(如动画的实现、动态的字幕等)常利用多线程技术来实现。

            线程存在一个生命周期,由以下方法体现:

      (1)  start()方法:启动一个线程。

      (2)  run()方法:定义该线程的动作。

      (3)  sleep()方法:使线程睡眠一段时间,单位为ms。

      (4)  suspend()方法:使线程挂起。

      (5)  resume()方法:恢复挂起的线程。

      (6)  yield()方法:把线程移到队列的尾部。

      (7)  stop()方法:结束线程生命周期并执行清理工作。

      (8)  destroy()方法:结束线程生命周期但不做清理工作。

            其中最常用的是方法start()、run()、sleep()、stop()。

    2.2  线程类和Runnable接口

    2.2.1. 建立Thread类的子类

    class myThread extends Thread

    {

          ...

    public void start()//启动线程

    {

           ...

    }

    public void run()//运行线程

    {

    ...

    }

    }

    例:多线程实例,主函数给予调用

     1 public class MThread 
     2 {
     3      public static void main(String[] args) 
     4      {
     5     System.out.println("Hello World!");
     6     thread2 t1 = new thread2("线程实例1"); //创建线程实例
     7     t1.start(); //调用
     8     thread2 t2 = new thread2("线程实例2");
     9     t2.start();
    10     thread2 t3 = new thread2("线程实例3");
    11     t3.start();
    12       }
    13 }
    14 //自定义线程类thread2
    15 class thread2 extends Thread
    16 {
    17     Thread thread; //定义线程实例
    18     String str;
    19     //构造函数
    20     public thread2(String str)
    21     {
    22         this.str = str;
    23     }
    24     //启动线程
    25     public void start()
    26     {
    27         thread = new Thread(this);
    28         thread.start();
    29     }
    30 public void run()
    31 {
    32     int i = 0;
    33     while(thread != null)
    34     {
    35         try
    36         {
    37             //计数到5时睡眠10秒
    38             if(i == 5)
    39                 sleep(10000);
    40         }
    41         catch(Exception e)
    42         {
    43     System.out.println(e.getMessage());
    44         }
    45         System.out.println(str);
    46         i++;
    47     }
    48       }
    49 };
    View Code

    2.2.2. 实现接口Runnable

            public interface Runnable

            Runnable接口可以由任意试图实现线程机制的类来实现。接口包含一个run方法。

            public void run()

            对象实现Runnable接口时,创建一个线程,启动线程导致对象run方法的调用。

            实现接口Runnable进行多线程设计的方法较为常用。下面给出一个例子。

    例:编写Applet,实现Runnable接口进行简单的动画演示:三幅图片依次上移

     1 package test;
     2 
     3 import java.applet.Applet;
     4 import java.awt.Graphics;
     5 import java.awt.Image;
     6 import java.awt.Toolkit;
     7 
     8 import javax.print.DocFlavor.URL;
     9 
    10 
    11 public class UseRunnable extends Applet implements Runnable{
    12     /**
    13      * 
    14      */
    15     private static final long serialVersionUID = 1L;
    16     Thread t;
    17     Image imgs[];
    18     int high,h1,h2,h3;
    19     public void init()
    20     {
    21          high = getHeight()/3;
    22          h1 = high;
    23          h2 = high * 2;
    24          h3 = high * 3;
    25          imgs = new Image[3];
    26          for (int i = 0; i < 3; i ++)
    27          {
    28              /*java.net.URL url=getDocumentBase();
    29              imgs[i] = getImage(getDocumentBase(),(i+1) + ".jpg");*/
    30              imgs[i]=Toolkit.getDefaultToolkit().getImage("E:\WorkSpace\ecplise-luna\JavaTest\src\test\"+(i+1)+".jpg "); 
    31          }
    32     }
    33     public void start()
    34     {
    35         t = new Thread(this);
    36         t.start();
    37     }
    38     public void stop()
    39     {
    40         t = null;
    41     }
    42     //实现接口的run方法,获得动画效果
    43     public void run()
    44     {
    45         while( t != null)
    46         {
    47             try
    48             {
    49                 Thread.sleep(100);
    50                 repaint();
    51                 h1 --;
    52                 //上移,到顶点时睡眠
    53                 if(h1 == 0)
    54                 {
    55                     Thread.sleep(3000);
    56                     h2 = high;
    57                 }
    58                 //上移,到顶点时睡眠
    59                 h2 --;
    60                 if(h2 == 0)
    61                 {
    62                     Thread.sleep(3000);
    63                      h3 = high;
    64                     }
    65                 //上移,到顶点时睡眠
    66                 h3--;
    67                 if(h3 == 0)
    68                 {
    69                     Thread.sleep(3000);
    70                     h1 = high;
    71                 }
    72             }catch(InterruptedException e){
    73                 System.out.println(e.getMessage());
    74             }
    75         }
    76     }
    77     public void paint(Graphics g)
    78     {
    79         //三幅图片依次显示
    80         g.drawImage(imgs[0],0,h1,this);
    81         g.drawImage(imgs[1],0,h2,this);
    82         g.drawImage(imgs[2],0,h3,this);
    83     }
    84     public void update(Graphics g)
    85     {
    86         paint(g);
    87     }
    88 }
    View Code
  • 相关阅读:
    Linux c 开发25 VScode C++ 运行中文乱码
    IEC104开发3 lib60870IEC 608705101 / 104 SOE
    Linux c 开发26 cmake生成项目
    STM32 例程7 STM32固件库方式 读取SHT20 温湿度
    基本电路学习1 12v转5V 电路
    github copilot 代码智能提示 AI代码提示
    Cesium polygon polyline entity label 贴地 点线面文本模型贴地 clampToGround 地面遮挡 地底遮挡 文字遮挡 道路遮挡 地形遮盖 地图遮盖
    UE4 HTTP REST 请求与高德天气预报接口 VaRest 插件
    UE4 蓝图截图 全屏截图 蓝图笔记截图 蓝图高清截图 蓝图保存插件 Blueprint Graph Screenshot(蓝图截图插件)
    window Carnac 实时显示键盘按键 桌面显示按钮 虚拟键盘 演示键盘 直播教学键盘
  • 原文地址:https://www.cnblogs.com/feitiannengdou/p/5447369.html
Copyright © 2020-2023  润新知