图形用户界面的设计与实现

AWT概述

AWT:Abstract Window ToolKit的缩写,抽象窗口组件工具包,是Java语言中最早用于编写GUI应用程序的工具包,提供了一套与本地图形界面进行交互的接口。
AWT中的图形方法与操作系统提供的图形方法之间一一对应。因此,当利用AWT来创建图形界面的时候,实际上是在利用操作系统所提供的图形库。AWT组件没有做到完全的跨平台。
由于AWT是依靠本地方法来实现其功能的,通常把AWT组件称为重量级组件。
AWT提供了一系列用于实现图形界面的组件,如窗口、按钮、文本框、对话框等。在JDK中针对每个组件都提供了对应的Java类,这些类都位于java.awt包中,该包包含用于创建用户界面和绘制图形图像的所有类和接口。

Component类

通常被称为组件,是构成Java图形用户界面的基本元素,Component类及其子类的对象用来描述以图形化的方式显示在屏幕上并能与用户进行交互的GUI元素,根据Component的不同作用,可将其分为基本组件类和容器类。基本组件类是诸如按钮、文本框之类的图形界面元素,而容器类则是通过Component的子类Container实例化的对象。

Container类

是Component的子类,为容器组件,是一个可以包含组件和其它容器的特殊组件。Container容器又分为两种类型,分别是Window和Panel。
Container对象可使用add(Component comp)向其中添加其他Component对象或其他Container对象。
也可通过使用remove(Component comp)方法从当前容器组件中删除指定组件。

Window类

Window类不依赖于其他容器而独立存在的容器,可以作为一个应用程序的窗口,独立显示出来的,其对象表示自由停泊的顶级窗口
顶级容器是一个能够提供图形绘制的容器,是进行图形编程的基础,一切图形化的东西,都包括在顶级容器中。

①Frame类

Window的子类,表示框架,是一种顶层容器,是用来设计类似于Windows系统中的窗口形式的应用程序。

Frame的常用构造方法:

Frame():构造一个最初不可见的 Frame 新实例。
Frame(String s):构造一个新的、最初不可见的、具有指定标题s的 Frame 对象。
Frame的其他常用方法:
setBounds(int x,int y,int width,int height):设置窗体的位置和大小,x、y是左上角坐标,width和height是宽度和高度,单位为像素。
setSize(int width,int height):设置窗体的大小,width和height是宽度和高度
setLocation(int x, int y):设置窗体的位置,x、y是左上角的坐标
setBackground(Color c):设置背景颜色,参数为Color对象
setVisible(boolean b):设置窗体是否可见
setTitle(String name):设置窗体标题栏为字符串name
String getTitle():获取窗体标题栏
setResizable(boolean b):设置是否可以调整大小。
Frame类的应用:

public class Test1 {
    public static void main(String[] args) {            
        Frame f=new Frame("My First Test");
        f.setLocation(300,300);
        f.setSize(170,100);
        f.setBackground(Color.yellow);
        f.setResizable(false);
        f.setVisible(true);
    }
}

②Dialog类

Window的子类,表示对话框,是向用户显示信息并获取程序运行所需数据的窗口,可以起到与用户交互的作用。与一般窗口不同的是,对话框依赖于其他窗口,当它所依赖的窗口消失或最小化时,对话框也将消失;窗口还原时,对话框又会自动恢复。

Panel类

面板,不能作为应用程序的独立窗口存在,必须被添加到其它Container中才能显示出来,因此,Panel为中间容器
中间容器属于容器性组件,可包含组件和其他容器的组件,但自身又必须包含在其他容器(如顶级容器)中
比较典型的Panel为Applet,用来设计可以嵌入在网页中的Java小程序。
Panel的构造方法:
Panel():使用默认的FlowLayout类布局管理器初始化
Panel(LayoutMannage layout):使用指定的布局管理器初始化
Panel类常常用方法:
setBounds(int x, int y, int width, int height)
setSize(int width,int height)
setLocation(int x,int y)
setBackground(Color c)
setLayout(LayoutManager mgr)等
Panel类的应用:

public class Test1 {
    public static void main(String[] args) {            
        Frame f=new Frame("Java Frame with Panel");
        Panel p=new Panel(null);
        f.setLayout(null);
        f.setBounds(300,300,500,500);//相对于屏幕的坐标
        f.setBackground(new Color(0,0,102));
        p.setBounds(50,50,400,400);//坐标相对于外层的Frame
        p.setBackground(new Color(204,204,255));
        f.add(p);//把panel添加到Frame中
        f.setVisible(true);
    }
}

Component类的其他常用子类

非容器组件:不可以包含组件和其他容器的组件

  • Button:标签按钮,当按下按钮时,应用程序执行某项动作
  • Label:一个可在容器中放置文本的组件
  • CheckBox:复选框,一个可处于“开”(true) 或“关”(false) 状态的图形组件
  • Choice:弹出式选择菜单。当前的选择显示为菜单的标题
  • List:为用户提供了一个可滚动的文本项列表
  • ScrollBar:描述了一个滚动条
  • TextComponent:是所有允许编辑文本的组件的超类,其常用子类TextArea(多行文本)和TextField(但行文本)
  • Canvas:表示屏幕上一个空白矩形区域,应用程序可以在该区域内绘图,或者可以从该区域捕获用户的输入事件

Swing

SUN公司于1997年推出了Swing,它是在AWT的基础上构建的一套新的图形界面系统,它包含AWT 所能够提供的所有功能,并且用纯粹的Java代码对AWT 的功能进行了大幅度的扩充,是AWT组件的增强组件。
由于在Swing中没有使用本地方法来实现图形功能,因此,Swing在不同的操作平台上表现一致,并且有能力提供本地窗口系统不支持的其它功能,通常把Swing组件称为轻量级组件。

AWT是基于本地方法的,所以其运行速度比较快;Swing是基于AWT的Java程序,其运行速度相对AWT慢。
Swing更多的使用在基于PC或者是工作站的标准Java应用中,通过牺牲速度来提高应用程序的性能,如果在嵌入式应用,则采用相对高效的AWT,通过牺牲性能而保障速度。
javax.swing包:提供一组“轻量级”(全部是 Java 语言)组件,尽量让这些在所有平台上的工作方式都相同。
java和javax都是Java的API包,java是核心包,javax的x是extension的意思,表明javax是java类库的扩展包。
使用Swing容器和组件要导入javax.swing包,格式:
import javax.swing.*;
为了能更好的使用Swing,我们还经常要导入另外的两个包,格式如下:

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

Swing组件的类名和对应的AWT组件类名基本一致,大部分都是在AWT组件类名的前面添加了“J”,但也有一些例外,比如Swing的JComboBox组件对应的是AWT中的Choice组件(下拉框)。

Swing中的容器

(1)顶层容器类

JFrame:用于框架窗口的类。
JDialog:用于对话框的类。
JApplet:用于使用Swing组件的Java Applet的类。
JWindow:它没有标题栏、窗口管理按钮。

(2)中间容器类

JPanel:用于将小型的轻量级组件(如JButton、JLabel等非容器组件或JPanel组件)组合在一起。
JScrollPane:滚动窗口,与JPanel类似,有滚动条。
JTabbedPane:一次只显示一个组件。
JToolBar:按行或列排列一组组件(通常是一组按钮)。

绝大多数的Swing组件派生自JCompomnent类,它是除顶层容器外所有Swing组件的基类。
JComponent类只有一个无参构造方法:
格式:public JComponent()
功能:调用Container构造方法,除此之外不进行任何初始化工作。

Swing组件的使用

与AWT组件不同,Swing组件不能直接添加到顶层容器中,它必须添加到一个与Swing顶层容器相关联的内容面板(content pane)上。内容面板是顶层容器包含的一个普通容器,它是一个轻量级组件。

对JFrame添加组件有以下方法:

1)用getContentPane()方法获得JFrame的内容面板,再为其加入组件,格式:

frame.getContentPane().add(childComponent);

2)如果用户的自定义类为JFrame类的子类,则可以先创建一个JPanel面板对象,然后再向该面板中加入组件,格式:

   JPanel contentPane=new JPanel();
   contentPane.add(childComponent);

3)建立一个中间容器,把组件添加到容器中,用setContentPane()方法把该容器置为JFrame的内容面板,格式:

   Jpanel contentPane=new Jpanel(); 
   ……//把其它组件添加到Jpanel中;
   frame.setContentPane(contentPane); 
   //把contentPane对象设置成为frame的内容面板

使用JFrame容器进行图形界面程序开发基本步骤:

1)创建的JFrame窗口是不可见的,要使得可见,需要使用show()方法或setVisible(Boolean b)方法,其中setVisible中的参数b=true。
2)使用setSize方法设置窗口大小。
3)向JFrame中添加组件时,必须先取得ContentPane,然后再使用add()方法把组件加入到ContentPane中,这与AWT包中的Frame直接使用add()方法添加组件不同。
使用Swing组件编写的程序:

import javax.swing.*;
public class First {
    public static void main(String[] args) {
        JFrame frame=new JFrame();
        //创建有文本的标签
        JLabel label=new JLabel("Swing组件");
        //获得内容面板后,用add()方法将label加入frame
        frame.getContentPane().add(label);
        //调用如下方法可以通过单击“关闭”按钮关闭此框架
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(200,200);//设置frame的宽度和高度
        frame.setVisible(true);//设置frame为可见
    }
}

布局管理器

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

AWT提供的常用布局管理器:实现了LayoutManager接口

  • FlowLayout
  • BorderLayout
  • GridLayout
  • GridBagLayout
  • CardLayout

FlowLayout布局

流式布局管理器:java.awt.FlowLayout是java.lang.Object的直接子类,是Panel类的默认布局管理器,是最简单的布局管理器。
FlowLayout布局管理器对容器中的组件按照加入的顺序从左向右排列,当一行排满(到达容器的边界)之后就转到下一行继续从左至右排列。
不改变组件的大小,按照组件原有尺寸显示,可设置不同的组件间距、行距以及对其方式。
FlowLayout布局管理器中组件可以左对齐、居中对齐(默认方式)或右对齐的方式排列。

FlowLayout的构造方法:

FlowLayout():用于创建一个设定为居中对齐、各组件的水平及垂直间隔为5个像素点的FlowLayout。
FlowLayout(int align) 用于创建一个FlowLayout类的对象,按给出的align值对齐,各组件的水平及垂直间隔为5个像素。align的值可以是FlowLayout.LEFT(左对齐)、FlowLayout.RIGHT(右对齐)、FlowLayout.CENTER(居中对齐)方式。
FlowLayout(int align,int hgap,int vgap) 用于创建一个既指定对齐方式,又指定组件间间隔的FlowLayout类的对象。参数align作用及取值同上;参数hgap指定组件间的水平间隔;参数vgap指定各组件间的垂直间隔。间隔单位为像素点。
FlowLayout举例:

import java.awt.*;
import javax.swing.*;
public class myFlowLayoutExample{
    public static void main(String args[]){
        JFrame jframe=new JFrame("一个滚动列表的例子");
        Container cp=jframe.getContentPane();
        cp.setLayout(new FlowLayout());
        JButton jbt1=new JButton("足球");
        JButton jbt2=new JButton("篮球");
        JButton jbt3=new JButton("排球");
        JButton jbt4=new JButton("羽毛球");
        JButton jbt5=new JButton("乒乓球");
        cp.add(jbt1);   cp.add(jbt2);   cp.add(jbt3);
        cp.add(jbt4);   cp.add(jbt5);
        jframe.setSize(150,200);
        jframe.setVisible(true);
    }
}

BorderLayout布局

边界布局管理器(BorderLayout)是Frame类的默认布局管理器,把容器分成5个区域:North、South、East、West和Center,每个区域只能放置一个组件,如加入多个,则先前加入的会被覆盖。
如不指定组件的加入区域,默认加入Center区。

BorderLayout的构造方法

public BorderLayout( ):创建一个各组件间的水平、垂直间隔为0的BorderLayout类的对象。
public BorderLayout( int hgap, int vgap ):创建一个各组件间的水平间隔为hgap、垂直间隔为vgap的BorderLayout类的对象。

BorderLayout举例:

import javax.swing.*;
import javax.swing.*;
public class BorderLayoutEx {
    public static void main(String[] args) {
        JFrame jf=new JFrame("BorderLayout示例程序"); 
        jf.setBounds(100,100,300,200);
        jf.setVisible(true); 
    //  jf.setLayout(new BorderLayout(5,10));
        JButton bSouth=new JButton("南");//创建按钮对象
        JButton bNorth=new JButton("北");
        JButton bEast=new JButton("东");
        JButton bWest=new JButton("西");
        JButton bCenter=new JButton("中");
        jf.add(bNorth,BorderLayout.NORTH);      
        jf.add(bSouth,BorderLayout.SOUTH);
        jf.add(bEast,BorderLayout.EAST);
        jf.add(bWest,BorderLayout.WEST); 
        jf.add(bCenter,BorderLayout.CENTER);        
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

GridLayout布局

网格布局管理器:用纵横线将容器分成n行m列大小相等的网格每个网格中放置一个组件。添加到容器中的组件首先放置在第1行第1列(左上角)的网格中,然后在第1行的网格中从左向右依次放置其他组件,行满后,继续在下一行中从左到右放置组件,放置在GridLayout布局管理器中的组件将自动占据网格的整个区域。

GridLayout类的三个构造方法如下:

GridLayout( ):按默认(1行1列)方式创建一个GridLayout布局。
GridLayout(int rows,int cols):创建一个具有rows行、cols列的GridLayout布局。
GridLayout(int rows,int cols,int hgap,int vgap):按指定的行数rows、列数cols、水平间隔hgap和垂直间隔vgap创建一个GridLayout布局。

GridLayout举例:

import javax.swing.*;
import java.awt.*;
public class GridLayoutEx {
    public static void main(String[] args) {
        JFrame jf=new JFrame("GridLayout示例程序"); 
        jf.setBounds(100,100,300,200);
        jf.setVisible(true);
        JButton b1=new JButton("计C171");//创建按钮
        JButton b2=new JButton("计C172");
        JButton b3=new JButton("计C173");
        JButton b4=new JButton("计C174");
        JButton b5=new JButton("计C175");
        JButton b6=new JButton("计C176");
        JButton b7=new JButton("计S181");
        JButton b8=new JButton("计S182");
        jf.setLayout(new GridLayout(3,3,10,10));
        jf.add(b1); jf.add(b2); jf.add(b3);//添加按钮
        jf.add(b4); jf.add(b5); jf.add(b6);jf.add(b7);jf.add(b8);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

网格包布局管理器:GridBagLayout是最灵活、最复杂的布局管理器。与GridLayout布局管理器类似,不同的是,它允许网格中的组件大小各不相同,允许一个组件跨越一个或多个网格,而且不需要组件的尺寸相同它就可以将组件在垂直方向和水平方向上对齐,它能解决几乎所有界面布局的问题。

使用GridBagLayout布局管理器的步骤:

①创建GridBagLayout布局管理器,并使容器采用该布局管理器。

    GridBagLayout layout=new GridBagLayout();
    container.setLayout(layout);

②创建GridBagContraints对象(布局约束条件,是控制GridBagLayout中每个组件布局的核心类),并设置该对象的相关属性。

属性 作用
gridx和gridy 设置组件的左上角所在网格的横向和纵向索引(即所在的行和列)。如果将gridx和gridy 的值设置为GridBagConstraints.RELATIVE(默认值),表示当前组件紧跟在上一个组件后面
gridwidth和gridheight 设置组件横向、纵向跨越几个网格,两个属性的逻认值都是1。如果把这两个属性的值设为GridBagConstraints.REMAINER表示当前组件在其行或其列上为最后一个组件。如果把这两个属性的值设为GridBagConstraints.RELATVE,表示当前组件在其行或列上为倒数第二个组件
fill 如果当组件的显示区域大于组件需要的大小,设置是否以及如何改变组件大小,该属性接收以下几个属性值:NONE:默认,不改变组件大小;HORIZONTAL:使组件水平方向足够长以填充显示区域,但是高度不变;VERTICAL:使组件垂直方向最够高以填充显示区域,但长度不变;BOTH:使组件足够大,以填充整个显示区域
weightx和weighty 设置组件占领容器中多余的水平方向和垂直方向空白的比例(也称为权重)。假设容器的水平方向放嚣三个组件,其weightx分别为1、2、3,当容器宽度增加60个像素时,这三个容器分别增加10、20、和30的像素。这两个属性的默认值是0,即不占领多余的空间

③调用GridBagLayout对象的setConstraints()方法建立GridBagConstraints对象和受控组件之间的关联。

    layout.setConstraints(component, constraints);

④向容器中添加组件。

    container.add(component);

GridBagConstraints对象可以重复使用,只需要改变它的属性即可。若要向容器中添加多个组件,则重复步骤②③④。

GridBagLayout举例:

import java.awt.*;
class Layout extends Frame {
    // 增加组件的方法
    private void addComponent(String name, GridBagLayout layout,
            GridBagConstraints c) {
        Button bt = new Button(name); // 创建一个名为name的按钮
        // 设置GridBagConstraints对象和按钮的关联
        layout.setConstraints(bt, c);       
        this.add(bt); // 增加按钮
    }
    public Layout(String title) {
        GridBagLayout layout = new GridBagLayout();
        GridBagConstraints c = new GridBagConstraints();
        this.setLayout(layout);
        c.fill = GridBagConstraints.BOTH; // 设置组件横向纵向可以拉伸
        c.weightx = 1; // 设置横向权重为1
        c.weighty = 1; // 设置纵向权重为1
        this.addComponent("btn1", layout, c);
        this.addComponent("btn2", layout, c);
        this.addComponent("btn3", layout, c);
        c.gridwidth = GridBagConstraints.REMAINDER; // 添加的组件是本行最后一个组件
        this.addComponent("btn4", layout, c);
        c.weightx = 0; // 设置横向权重为0
        c.weighty = 0; // 设置纵向权重为0
        addComponent("btn5", layout, c);        
        c.gridwidth = 1; // 设置组件跨一个网格(默认值)
        this.addComponent("btn6", layout, c);
        c.gridwidth = GridBagConstraints.REMAINDER; // 添加的组件是本行最后一个组件
        this.addComponent("btn7", layout, c);
        c.gridheight = 2; // 设置组件纵向跨两个网格
        c.gridwidth = 1; // 设置组件横向跨一个网格
        c.weightx = 2; // 设置横向权重为2
        c.weighty = 2; // 设置纵向权重为2
        this.addComponent("btn8", layout, c);
        c.gridwidth = GridBagConstraints.REMAINDER;
        c.gridheight = 1;
        this.addComponent("btn9", layout, c);
        this.addComponent("btn10", layout, c);
        this.setTitle(title);
        this.pack();
        this.setVisible(true);  }}      

CardLayout布局

卡片布局管理器:CardLayout将每个组件看成一张卡片,如同扑克牌一样将组件堆叠起来。一次只能看到一张卡片,容器则充当卡片的堆栈。当容器第一次显示时,第一个添加到 CardLayout 对象的组件为可见组件,这个被显示的组件将占据所有的容器空间。

CardLayout类的构造方法:

public CardLayout( ) :使用默认(间隔为0)方式创建一个CardLayout( )类对象。
public CardLayout( int hgap, int vgap ) :使用hgap指定的水平间隔和vgap指定的垂直间隔创建一个CardLayout( )类对象。

CardLayout类的常用方法:

public void first( Container parent ) :显示parent容器的第一张卡片。
public void last( Container parent ):显示parent容器的最后一张卡片。
public void next( Container parent ) :显示parent容器的的下一张卡片。
public void previous( Container parent ):显示parent容器的前一张卡片。
public void show(Container parent, String name):显示parent容器中名称为name的组件,若不存在,则不会发生任何操作

CardLayout举例:

import java.awt.*;
import javax.swing.*;
public class TestCard {
    public static void main(String[] args) {
        JFrame jf=new JFrame("CardLayout示例程序");
        //Container cp=jf.getContentPane();
        JPanel cp=new JPanel(); jf.setContentPane(cp);
        CardLayout card=new CardLayout(20,20);
        jf.setLayout(card);
        JButton bt1=new JButton("足球");
        JButton bt2=new JButton("篮球");
        JButton bt3=new JButton("排球");
        JButton bt4=new JButton("乒乓球");
        JButton bt5=new JButton("羽毛球");
        cp.add(bt1);    cp.add(bt2);    cp.add(bt3);
        cp.add(bt4);    cp.add(bt5);
        card.next(cp);  jf.setSize(200,200);
        jf.setVisible(true);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
    }
}

自定义布局

使用布局管理器时,布局管理器负责各个组件的大小和位置,用户无法在这种情况下设置组件大小和位置属性,如果使用使用Java语言提供的setLocation()、setSize()、setBounds()等方法,则都会被布局管理器覆盖。
自定义布局就是不使用布局管理器,格式如下:
setLayout(null);
因为没有使用布局管理器,可以使用setBounds()方法指定组件的位置和大小。自定义布局应用广泛,因为编程者可以不考虑布局只需要注意组件的位置。

利用AWT组件和Swing组件进行程序设计的基本步骤

  • 引入相应的包
  • 设置顶层容器
  • 设置布局管理器
  • 向容器中添加组件
  • 对组件进行事件处理

事件处理

Java采用委托事件模型来处理事件。
委托事件模型的特点是将事件的处理委托给独立的对象,而不是组件本身。
委托事件模型包含三个重要概念:事件、事件源和事件监听器。

事件

用户在界面上的一个操作(通常使用各种输入设备,如鼠标、键盘等来完成),如拖动鼠标、按下回车键、通过键盘输入一个字符、选择某个菜单项、在列表中选择一个选项、取得焦点等都是事件。
当一个事件发生时,该事件用一个事件对象来表示。事件对象有对应的事件类。不同的事件类描述不同类型的用户动作。
事件类包含在java.awt.event和javax.swing.event中。

名称 说明
ActionEvent 处理按钮、列表项双击、单击菜单项目
AdjustmentEvent 滚动条位置改变
ComponentEvent 调整组件大小,移动、隐藏或显示组件
ContainerEvent 容器内组件的添加、删除
FocusEvent 组件失去或获取焦点
MouseEvent 鼠标拖动、移动、单击、按下、释放
ItemEvent 选择或取消列表框、复选框等选项
KeyEvent 按下、放开某键
InputEvent 处理复选框和列表项单击、控件的选择和可选菜单项选择的事件
TextEvent 处理文本区域或者文本区域的值的改动
WindowEvent 处理窗口激活、失去活动窗口、最小化、打开、关闭或者退出的事件

事件源

产生事件的组件叫做事件源。
如在一个按钮上单机鼠标时,该按钮就是事件源,会产生一个ActionEvent类型的事件。

监听器

监听器:Listener,负责监听事件源上发生的事件(接收事件对象),并对各种事件进行相应处理的对象。
事件监听类:负责检查事件是否发生,若发生就激活事件监听器进行处理的类,必须实现事件监听器接口或继承事件监听器适配器类。
事件监听器接口:每种侦听器都带有一个接口,接口中定义了一个或多个处理事件必须实现的方法。实现这些方法就是当侦听到事件后所执行的一系列操作。
适配器类是一种特殊类,类中已经实现了接口,它为接口中的所有方法都增加了空语句体。所以可以通过适配器来替代侦听器的使用,根据程序的需要执行的方法就重写,不需要执行的方法不需要再重写了,简化了程序的编写。
事件监听器接口和事件监听器适配器类也都包含在java.awt.event和javax.swing.event包中。
每一个事件类都有一个“唯一”的事件处理方法接口。

注册事件监听器

为了能够让事件监听器检查某个组件(事件源)是否发生了某些事件,并且进行相应处理,必须在事件源上注册事件监听器。
通过使用事件源组件的以下方法完成。
addXxxListener(事件监听器对象)
其中,Xxx对应相应的事件类。

A. addXXXListener(B):当A发生XXX事件时,对象B能得到通知,并将调用相应的方法处理该事件。
如:button事件,注册监听器为handler,则:
button. addActionListener(handler h);
方法一:自定义监听器类实现事件监听接口

class handler  implements ActionListener{
public void actionPerformed(ActionEvent e)
     {  ……  }          
}

方法二:用匿名内部类实现事件监听接口

button. addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent e)
     {  ……  }          
});

方法三:自定义类实现相应适配器类

button. addMouseListener(new MAdapter()); 
class MAdapter extends MouseAdapter{
        @Override
        public void mouseClicked(MouseEvent e) {
            //事件处理代码
        }
    }

Java中处理各组件事件的一般步骤

  1. 新建一个组件(如JButton)。
  2. 将该组件添加到相应的面板(如JPanel)。
  3. 注册监听器以监听事件源产生的事件(如通过ActionListener来响应用户点击按钮)。
  4. 定义处理事件的方法(如在ActionListener中的actionPerformed中定义相应方法)。

常用组件

窗口中可以添加各种组件,通过容器的add()方法可以将各种组件添加到容器中。
常用组件:按钮、标签、文本框、文本区域、复选框、单选按钮、列表、菜单、对话框等

按钮

按钮(Button、JButton)是常见组件,按钮上允许有图标或字符串,也可两者兼有,最常见的操作是单击按钮。

(1)构造方法

(2)常用方法

  • public void addActionListener(ActionListener a)
  • public void setMnemonic(int mnemonic):指定热键,同时按下Alt键和指定热键相当于按下该按钮
  • public void setEnabled(boolean b):启用(或禁用)按钮。
  • public boolean isSelected():返回按钮的状态。如果选定了切换按钮,则返回 true,否则返回 false。
  • public String getText(): 返回按钮的文本。
  • public setText(String text):设置按钮的文本。
  • public boolean isDefaultButton():获取 defaultButton 属性的值,如果为 true 则意味着此按钮是当前默认按钮。

(3)常用事件

ActionEvent事件
当单击按钮,或者按钮已经取得焦点时按下空格键(Space键)时,发生ActionEvent事件。ActionLister接口用于侦听这个事件,ActionLister接口的方法actionPerformed()必须实现。

标签

标签(Label、JLabel)是常见组件,可以显示文本、图像或二者同时显示。标签一般用来显示提示信息,它不对输入事件作出反应。因此,它无法获得键盘焦点。

(1)构造方法

(2)常用方法

  • public Icon getIcon():返回该标签显示的图标。
  • public void setIcon(Icon icon):定义该标签将要显示的图标。如果参数icon的值为null,则什么也不显示。
  • public String getText():返回该标签所显示的字符串。
  • public void setText(String text):定义该标签将要显示的单行文本。如果参数text的值为null或空字符串(””),则什么也不显示。
  • public void setHorizontalAlignment(int alignment):设置标签内容沿X轴的对齐方式。参数经常是LEFT、CENTER、RIGHT常量之一。

文本框

文本框(TextField、JTextField)组件允许编辑或输入单行文本

(1)构造方法

(2)常用方法

  • public String getText():获取文本框的文本
  • public void setText(String text):设置文本框的文本为text
  • public void addActionListener(ActionListener l):为文本框注册ActionEvent事件监听器
  • public void removeActionListener(ActionListener l):为文本框移除ActionEvent事件监听器
  • public void setColumns(int columns):设置此 TextField 中的列数,然后验证布局。
  • public void setFont(Font f):设置当前字体。
  • public void setHorizontalAlignment(int alignment): 设置文本的水平对齐方式,参数alignment的值可以是以下常量之一: JTextField.LEFT、JTextField.CENTER、JTextField.RIGHT、JTextField.LEADING 、JTextField.TRAILING。

(3)常用事件

ActionEvent事件

当在文本框中输入字符并按回车时,发生ActionEvent事件,然后执行重写的ActionListener接口的actionPerformed()方法。

FocusEvent事件

绝大部分组件都可以侦听FocusEvent事件,FocusEvent事件发生后,如果组件取得了焦点,执行focusGained()方法,如果组件失去了焦点,执行focusLost()方法。

JPanel

Java中的JPanel组件属于容器型组件。
可以在JPanel中放置按钮、文本框等非容器组件,甚至还可以在JPanel中再放置若干个JPanel组件。
Swing采用JPanel定义面板,面板必须包含在另一个容器(如JFrame)中

(1)构造方法

  • JPanel():创建一个Jpanel,默认布局是FlowLayout
  • JPanel(LayoutManager layout):创建一个指定布局的JPanel

(2)常用方法

  • void add(Component comp):添加组件comp
  • void add(Component comp, int index):把组件comp添加到特定位置index上
  • int getComponentCount():获得Jpanel中所有组件的数量
  • Component getComponent(int index):获得指定序号index对应的组件
  • Component getComponent(int x, int y):获得指定位置<x,y>对应的组件
  • void remove(Component comp):移除组件comp
  • void removeAll():移除所有组件
  • void setLayout(LayoutManager layout):设置布局为layout
  • LayoutManager getLayout():获得当前布局
  • void setBorder(Border border):设置边框为border

(3)Border接口

public interface Border
该接口描述一个能够呈现围绕 swing 组件边缘边框的对象。
public class BorderFactory extends Object
提供标准 Border 对象的工厂类。在任何可能的地方,此工厂类都将提供对已共享 Border 实例的引用。该类中的方法均为静态方法。

单选按钮

单选按钮是让用户从一组组件中选择唯一的一个选项。Swing的JRadioButton类是用于创建单选框的。

(1)构造方法

(2)将单选钮组合成组

单选框可以像按钮一样添加到容器中。要将单选框分组,需要创建java.swing.ButtonGroup的一个实例,并用add方法把单选框添加到该实例中,如:

ButtonGroup btg = new ButtonGroup();
JRadioButton jrb1=new JRadioButton(“男”);
JRadioButton jrb2=new JRadioButton(“女”);
btg.add(jrb1);
btg.add(jrb2);

ButtonGroup类是一个不可见的组件,不需要将其增加到容器中显示,只是在逻辑上表示一个单选按钮组。

(3)ButtonGroup类常用方法

  • public ButtonGroup( ):构造单选框组。
  • public void add( AbstractButton b):将一个单选框添加到ButtonGroup组件中。
  • public int getButtoncount( ):获取单选框个数;
  • public void remove( AbstractButton b):移去单选框b。

(4) JRadioButton类常用方法

  • public boolean isSelected():返回按钮的状态。如果选定了切换按钮,则返回 true,否则返回 false。
  • public String getText():返回按钮的文本。
  • public void setText(String text):设置按钮的文本。

(5) JRadioButton的事件

ActionEvent事件

监视器设置:addActionListener(ActionListener)
接口方法:actionPerformed(ActionEvent e)

ItemEvent事件

监视器设置: addItemListener(ItemListener)
接口方法: itemStateChanged(ItemEvent e)

public void itemStateChanged(ItemEvent e)
{
 // if(e.getSource() instanceof JRadioButton)
    if(jrb1.isSelected())
        //Process the selection for jrb1
    if(jrb2.isSelected())
        //Process the selection for jrb2
}

复选框

复选框是一种用户能够打开、关闭选项的组件,如同电灯开关一般。Swing的JCheckBox类是用于创建复选框的。

(1)构造方法

(2) JCheckBox类常用方法

  • public boolean isSelected():返回按钮的状态。如果选定了切换按钮,则返回 true,否则返回 false。
  • public String getText():返回按钮的文本。
  • public void setText(String text):设置按钮的文本。

(3) JCheckBox的事件

ActionEvent事件

监视器设置:addActionListener(ActionListener)
接口方法:actionPerformed(ActionEvent e)

ItemEvent事件

监视器设置: addItemListener(ItemListener)
接口方法:itemStateChanged(ItemEvent e)

public void itemStateChanged(ItemEvent e)
{
    if(e.getSource() instanceof JCheckBox)
        if(jchk1.isSelected())
            //Process the selection for jchk1;
        if(jchk2.isSelected())
            //Process the selection for jchk2;
}

组合框

JComboBox组件被称为组合框或者下列列表框,它将所有选项折叠收藏在一起,默认显示的是第一个添加的选项。当用户单击组合框时,会出现下拉式的选项列表,用户可以从中选择器中某一项并显示。
JComboBox组合框组件分为可编辑和不可编辑两种形式。

  • 不可编辑组合框:只能在现有的选项列表中进行选择。
  • 可编辑组合框:既可在现有的选项中选择,也可自己输入新的内容,但只作为当前项显示,并不会添加到组合框的选项列表中。

(1)构造方法

String items[]={“左对齐”,”右对齐”,”两端对齐”,”居中”,”分散对齐”};
JComboBox  jcb=new JcomboBox(items);

(2)常用方法

  • void addItem(Object item):为选择框添加一个选项
  • void addItemListener(ItemListener):向选择框注册监听器
  • Object getItemAt(int index):得到选择框中指定序号的选项
  • int getItemCount():获得选择框中选项的个数
  • Object getSelectedItem():得到选择框中被选择选项的对象表示(通常为字符串表示)。
  • void removeItem(Object anObject):从项列表中移除项。
  • void removeAllItems():从项列表中移除所有项。
  • void removeItemAt(int anIndex) :移除 anIndex 处的项。
  • void setEditable(boolean b):设置选择框的可编辑属性
  • void setEnabled(boolean b):设置选择框是否可用
  • public boolean isEditable():如果组合框可编辑,则返回“true”。否则为“false”。

(3)JComboBox的事件

JComboBox可以引发ActionEvent和ItemEvent事件以及其他事件。选中一个新的选项时,JComboBox会产生两次ItemEvent事件,一次是取消前一个选项,另一次是选择当前选项。产生ItemEvent事件后JComboBox产生一个ActionEvent事件。要响应ItemEvent事件,需要实现处理方法itemStateChanged(ItemEvent e)来处理选择。

文本区

文本区(JTextArea)组件与文本框组件类似,区别是文本区组件显示的是多行文本,内容超出显示范围时,具有滚动显示的功能,文本框组件显示的是单行文本。

(1)构造方法

(2)常用方法

  • public void insert(String str,int pos):将指定文本插入指定位置。
  • public void append(String str):将给定文本追加到文档结尾。
  • public void replaceRange(String str,int start,int end):用给定的新文本替换从指示的起始位置到结尾位置的文本。
  • public void copy():将关联文本模型中当前选定的范围传输到系统剪贴板,并在文本模型中保留内容。当前选定保持原样。对于 null 选定不执行任何操作。
  • public void paste():将系统剪贴板的内容传输到关联的文本模型中。如果在关联视图中有选定的内容,则使用剪贴板的内容替换它。如果没有选定的内容,则将剪贴板插入关联视图中当前插入位置的前面。如果剪贴板为空,则不执行任何操作。
  • public void cut():将关联文本模型中当前选定的范围传输到系统剪贴板,并从模型中移除内容。重新设置当前选定。对于 null 选定不执行任何操作。
  • public void selectAll():选择文本区中的所有文本。在 null 或空文档上不执行任何操作。
  • public void setLineWrap(boolean wrap):设置文本区的换行策略。public void setWrapStyleWord(boolean word):设置换行方式(如果文本区要换行)。

(3)常用事件

ActionEvent事件: 与文本框的ActionEvent事件相似。
DocumentEvent事件: 当用户在文本区编辑文本时,发生此事件,DocumentListener接口的三个方法要实现,方法格式如下:

  • void changedUpdate(DocumentEvent e) :给出属性或属性集发生了更改的通知。
  • void insertUpdate(DocumentEvent e) :给出对文档执行了插入操作的通知。
  • void removeUpdate(DocumentEvent e) :给出移除了一部分文档的通知。

密码框

密码框(JPasswordField extends JTextField)组件与文本框组件类似,区别在于密码框不显示输入的信息,而显示设置的回显字符,默认的回显字符是'*'。

(1)构造方法

(2)常用方法

  • public char[] getPassword():返回此密码框对象中所包含的文本。
  • public char getEchoChar():返回要用于回显的字符,默认值为'*'。
  • public void setEchoChar(char c):设置此密码框对象的回显字符。

(3)密码框的事件

与文本框的ActionEvent事件相似

列表

列表用于在多个列表项中选择,列表项是从0开始编号。AWT的List类和Swing的Jlist类用于列表。
注意:
List在缺省方式下不支持多选,而Jlist支持多选。
JList必须放在JScrollPane中,否则不支持滚动。

(1)构造方法

(2)常用方法

  • public Object getSelectedValue():只选择列表的单个项时,返回所选值。
  • public int getSelectedIndex():只选择列表的单个项时,返回该选择索引。
  • public setModal(ListModel model):设置表示列表内容或列表“值”的模型,通知属性更改侦听器,然后清除列表选择。

(3)ListModel

  • public interface ListModel:此接口定义方法组件(如 JList),这些组件用于获取列表中每个单元格的值以及列表的长度。在逻辑上,模型是一个向量,索引范围从 0 到 ListDataModel.getSize() - 1。对数据模型的内容和长度的任何更改必须报告给所有 ListDataListener。
  • DefaultListModel类中的add(int index,Object element)方法:在此列表的指定位置处插入指定元素。

(4)Jlist的事件

ListSelectionEvent事件和ListDataEvent事件

  • 当用户在列表框中选取列表项时,将发生ListSelectionEvent事件,侦听器ListSelectionListener侦听到该事件后,执行valueChanged()方法。
  • 侦听器ListDataListener侦听到ListDataEvent事件发生后,根据事件类型执行contentsChanged()方法、intervalAdded()方法或intervalRemoved()方法。

JScrollPane

  • 在设置界面时,可能会遇到在一个较小的容器窗体中显示一个较大部分的内容的情况,这时可以使用JScrollPane面板。JScrollPane面板是带滚动条的面板,用来建立滚动窗口的,也是一种容器,但是只能放置一个组件,并且不可以使用布局管理器。如果需要在JScrollPane面板中放置多个组件,需要将多个组件放置在JPanel面板上,然后将JPanel面板作为一个整体组件添加在JScrollPane面板中。
  • JScrollPane类经常和JList、JLabel、JTextArea等类配合使用。
  • JScrollPane 管理视口、可选的垂直和水平滚动条以及可选的行和列标题视口。
  • JViewport 为数据源提供一个窗口或“视口”。
  • JScrollPane 可以有一个列标题和一个行标题。这二者都是 JViewport 对象,可用 setRowHeaderView 和 setColumnHeaderView 指定。列标题视口自动左右滚动,跟踪主视口的左右滚动。(但是它不会垂直滚动。)行标题的滚动方式与此类似。
  • 在两个滚动条的交汇处、行标题与列标题的交汇处,或者滚动条与其中一个标题的交汇处,两个组件在很接近角的地方停止,留下一个默认情况下为空的矩形空间。 四个角都有可能存在这些空间。只有角组件存在于其中的角中有空白空间时该角组件才是可见的。

菜单

菜单是GUI中非常重要而常见的组件。
下拉式菜单一般位于窗口的顶部,包括菜单栏(JMenuBar)、菜单(JMenu)和菜单项(JMuneItem),菜单项还可以再包含若干菜单项。
弹出菜单(JpopupMenu)也称为右键菜单或快捷菜单,单击鼠标右键会显示弹出菜单。

(1)菜单栏

菜单栏组件是存放菜单的容器,菜单栏不响应事件。
构造方法:public JMenuBar()
常用方法:

  • public JMenu add(JMenu c):将菜单追加到菜单栏的末尾。
  • public JMenu getMenu(int index):返回菜单栏中index位置的菜单,第一个位置是0,依次递增。
  • public boolean isSelected():如果已选择了菜单栏,则返回“true”,否则返回“false”。

(2)菜单

菜单包含若干菜单项和分隔条。鼠标单击某个菜单时,该菜单展开。

构造方法:

常用方法:

  • public JMenuItem add(Action a):创建连接到指定 Action 对象的新菜单项,并将其追加到此菜单的末尾。
  • public Component add(Component c):将某个组件追加到此菜单的末尾。
  • public Component add(Component c,int index):将指定组件添加到此容器的给定位置上。
  • public JMenuItem add(JMenuItem menuItem): 将某个菜单项追加到此菜单的末尾。
  • public JMenuItem add(String s):创建具有指定文本的新菜单项,并将其追加到此菜单的末尾。
  • public void addSeparator():将新分隔符追加到菜单的末尾。

常用事件:

  • MenuEvent事件通知作为事件源的菜单已经被发送、选定或取消。
  • 当侦听器MenuListener侦听到MenuEvent事件,如果是选择某个菜单时,则调用menuSelected()方法;如果是取消选择某个菜单时,则调用menuDeselected()方法;如果是取消菜单时,则调用menuCanceled()方法。

(3)菜单项

菜单项是菜单中“项”的具体实现。当用鼠标或键盘选中时,就触发一个动作事件。菜单项可以是一个命令,也可以是另一个菜单(子菜单)。

构造方法:

常用方法:

  • public void setEnabled(boolean b):启用或禁用菜单项。
  • protected String paramString():返回此 JMenuItem 的字符串表示形式。

(4)创建菜单的步骤:

1.创建菜单栏:MenuBar mnuBar=new MenuBar();
2.创建菜单并添加到菜单栏:
JMenu mnuFile=new JMenu("文件");
mnuBar.add(mnuFile);
3.创建菜单项并添加到菜单上
JMenuItem mnuNew=new JMenuItem("新建");
mnuFile.add(mnuNew);
4.将菜单栏添加到容器中: setJMenuBar(mnuNotepad);
5.添加事件侦听器并实现侦听器接口的相应方法: MenuListener、ActionListener

对话框

对话框是应用广泛的组件之一,它不能作为应用程序的主窗口,也没有最小化、最大化按钮,不能设置菜单栏。
对话框分为模式和非模式两种。模式对话框在显示时将阻塞用户对其他窗口的操作,如JOptionPane;非模式对话框在显示时并不阻塞用户对其他窗口的操作,如JDialog。

(1)JOptionPane类

JOptionPane是简单而常用的模式对话框类,它提供了四种常用的对话框样式。可以通过构造方法来创建对话框,也可以通过其静态方法showXxxDialog创建对话框。

  • showMesageDialog():向用户显示一些消息,并得到“确定”和“撤销”响应。
  • showConfirmDialog():问一个要求确认的问题并得到yes/no/cancel响应。
  • showInputDialog():提示用户通过文本框、列表或其他手段进行输入,并得到“确定”和“撤销”响应。
  • showOptionDialog():可选择的对话框
    这些方法中通过返回一个整数,来表示用户点击了哪个按钮,返回值的有效值有YES_OPTION、NO_OPTION、CANCEL_OPTION、OK_OPTION和CLOSED_OPTION。
import java.awt.*;   
import javax.swing.*;   
class JOptionPaneEx
{   
     public static void main(String[] arg)
    {   
              String s=JOptionPane.showInputDialog("请输入你的名字:");   
                  JOptionPane.showMessageDialog(null,"你好,"+s);   
    }   
}

(2)JDialog类

当JOptionPane类提供的四种常用的对话框模式无法满足需求时,就可以使用JDialog类来设计自定义的对话框。
构造方法:详见API文档

  • public JDialog():创建一个非模式对话框
  • JDialog(Dialog owner,String title,Boolean modal): 创建一个具有指定标题、模式和指定所有者 Dialog 的对话框。
  • JDialog(Frame owner,String title,Boolean modal):创建一个具有指定标题、所有者 Frame 和模式的对话框。

JFileChooser

JFileChooser 为用户选择文件提供了一种简单的机制。

构造方法:

常用方法:

  • void setSelectedFile(File file):设置选中的文件
  • showDialog(Component parent, String approveButtonText):弹出具有自定义approve按钮的自定义文件选择器对话框
  • showOpenDialog(Component parent):弹出一个“Open file”文件选择器对话框
  • showSaveDialog(Compont parent):弹出一个“Save File”文件选择器对话框
JFileChooser jfc=new JFileChooser();
if(jfc.showSaveDialog(null)!= JFileChooser.APPROVE_OPTION)  return;
File file= jfc.getSelectedFile();   

常用事件

鼠标事件

鼠标事件包括两大类,一类是发生在鼠标左键和右键上的事件,称为MouseEvent;另一类是发生在鼠标滚轮上的事件,称为MouseWheelEvent
通过MouseListener侦听器接口和MouseMotionListener侦听器接口分别处理不同的MouseEvent事件。
通过MouseWheelListener侦听器接口处理MouseWheelEvent事件。

MouseEvent事件

MouseEvent事件包括以下两类:
鼠标事件类

  • 按下鼠标按键
  • 释放鼠标按键
  • 单击鼠标按键(按下并释放)
  • 鼠标光标进入组件几何形状的未遮掩部分
  • 鼠标光标离开组件几何形状的未遮掩部分
    鼠标移动事件类
  • 移动鼠标
  • 拖动鼠标

MouseEvent事件的常用方法

  • public int getButton()鼠标哪个按键
  • public int getClickCount()鼠标单击次数
  • public int getX()鼠标相对于源组件的x坐标
  • public int getY()鼠标相对于源组件的Y坐标
    MouseListener侦听器接口处理MouseEvent事件,MouseListener侦听器接口是用于接收组件上的鼠标事件,包括按下、释放、单击、进入或离开等鼠标事件。当MouseListener侦听器接口侦听到MouseEvent事件发生时,根据事件类型执行以下方法:
  • void mouseClicked(MouseEvent e)
  • mouseEntered(MouseEvent e)
  • void mouseExited(MouseEvent e)
  • void mousePressed(MouseEvent e)
  • void mouseReleased(MouseEvent e)
    MouseMotionListener侦听器接口处理MouseEvent事件, MouseMotionListener侦听器接口用于接收组件上的鼠标移动事件,包括移动鼠标、拖动鼠标。 当MouseMotionListener侦听器接口侦听到MouseEvent事件发生时,根据事件类型执行以下方法:
  • void mouseDragged(MouseEvent e):鼠标按键在组件上按下并拖动时调用。
  • void mouseMoved(MouseEvent e):鼠标光标移动到组件上但无按键按下时调用。

MouseWheelEvent事件

MouseWheelEvent事件表示鼠标滚轮在组件中滚动。

MouseWheelEvent事件的常用方法

  • public int getWheelRotation():返回鼠标滚轮旋转的“喀哒声”的次数。
    MouseWheelListener侦听器接口处理MouseWheelEvent事件
    当MouseWheelListener侦听器接口侦听到MouseWheelEvent事件发生时,执行以下方法:
    void mouseWheelMoved(MouseWheelEvent e)
    鼠标滚轮旋转时调用。

键盘事件

键盘事件KeyEvent是指按下、释放或键入某个键时发生的事件。

KeyEvent的常用方法

  • public char getKeyChar()
  • public void setKeyCode(int keyCode)
  • public int getModifiers()
  • public static String getKeyModifiersText(int modifiers)
    KeyListener侦听器处理KeyEvent事件:当KeyListener侦听器侦听到KeyEvent事件发生时,根据事件类型执行以下方法:
  • void keyTyped(KeyEvent e)
  • void keyPressed(KeyEvent e)
  • void keyReleased(KeyEvent e)

窗体事件

大部分GUI应用程序都需要使用Window窗体对象作为最外层的容器,可以说窗体对象时所有GUI应用程序的基础,应用程序中通常都是将其他组件直接或间接地置于窗体中。
当对窗体进行操作时,如窗体的打开、关闭、激活、停用等,这些动作都属于窗体事件,JDK中提供了一个类WindowEvent用于表示这些窗体事件。
WindowListener侦听器处理WindowEvent事件:当WindowListener侦听器侦听到WindowEvent事件发生时,根据发生的行为,执行相应的以下方法:

  • windowOpened():当窗口打开时执行此方法。
  • windowClosing():单击窗口右上角“关闭”按钮尝试关闭窗口时执行此方法。
  • windowIconified():单击窗口的“最小化”图标,窗口最小化时执行此方法。
  • windowDeiconified():单击窗口的“还原”按钮,窗口还原时执行此方法。
  • windowActivated():当窗口在一系列窗口之前,成为当前窗口时执行此方法;当打开窗口、还原窗口或点击某个窗口到前台都会执行此方法。
  • windowDeactivated():当某个窗口从前台移走时执行此方法,例如图标化、关闭窗口或另外一个窗口被激活等。
  • windowClosed():当窗口关闭之后,如单击“关闭”按钮或执行了窗口的dispose()方法后执行此方法。

JFrame中实现窗口关闭的方法:

public void setDefaultCloseOperation(int operation)
参数的默认取值是“HIDE_ON_CLOSE”,其取值是下列常量之一:

  • DO_NOTHING_ON_CLOSE:不执行任何操作。
  • HIDE_ON_CLOSE:隐藏当前窗口。
  • DISPOSE_ON_CLOSE:隐藏当前窗口并释放其占用的资源。
  • EXIT_ON_CLOSE:使用“System exit”方法退出窗口所在的应用程序。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容