问题
GUI
事件处理
内部类
显示图形用户界面
如何创建出一个图形用户界面
import javax.swing.JButton;
import javax.swing.JFrame;
public class test_gui {
public static void main(String[] args) {
// TODO Auto-generated method stub
JFrame frame = new JFrame();
JButton button = new JButton("hei hei");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //这一行程序会在窗口关闭后结束程序
frame.getContentPane().add(button); //把按钮放到窗口,不过按钮占满了整个窗口,还需要会控制按钮的大小和位置
frame.setSize(300, 300);
frame.setVisible(true);
}
}
#现在我们在窗口中创建了一个按钮,而且可以在按钮上写字,不过还是有问题:
按钮的大小和位置怎么控制?
按下了按钮不过什么也不会发生,这样不好玩,和平时使用电脑不一样啊?
那么怎么判断按钮按下这个事件发生,用什么方法?
按钮按下可以产生什么效果?
如何让按下按钮产生效果?
首先要知道按钮是不是被按下了,即取得用户的事件。
如何知道按钮的事件(是点了一下还是两下还是一直不松开)?
监听事件的接口
监听接口是介于监听(监听程序,检测到发生事件后做出动作的程序)与事件源(按钮)间的桥梁。
swing的GUI组件是事件的来源。
事件来源是一个对象,是可以将用户的操作转换为事件的对象。
而且事件也是用对象来表示的。
按钮按下怎么被检测到?
事件源(如按钮)会在用户做出相关动作时产生事件对象。
每个事件类型(可以和产生的时间对象对应)都有对应的监听者接口。
想要实现事件处理 就得实现相应的接口。
现在实现了监听者接口,那么产生的事件怎么和这个接口交流呢?
监听接口需要向按钮注册(使用按钮的增加监听者的方法),实现接口的方法,事件只会通知有实现接口的类,按钮会以事件对象作为参数调用实现的方法
当注册后,按钮的addActionListener()(增加监听者)的方法的参数会被添加到按钮的清单中,当事件发生时,按钮会调用清单中每个监听的actionPerformed()来启动事件,这个actionPerformed()函数里面才是做出动作的代码。
实现代码:
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class test_gui implements ActionListener {
JButton button;
public static void main(String[] args) {
// TODO Auto-generated method stub
test_gui gui = new test_gui();
gui.go();
}
public void go() {
JFrame frame = new JFrame();
button = new JButton("点我吧!");
button.addActionListener(this); //监听接口需要向按钮注册(使用按钮的增加监听者的方法)
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(button);
frame.setSize(300, 600);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
button.setText("o((>ω< ))o");
button.setBackground(Color.blue);
}
}
监听者,事件源和事件的关系?
监听者主要是实现接口(接口内的抽象方法,好像addActionListener就一个actionPerformed方法),然后向按钮注册,这样按钮就会把其函数参数加进清单中等待使用
事件源需要接受注册,在用户操作时调用监听者的事件处理方法
事件则是当调用监听者的事件处理函数时作为参数传递进去,把事件的信息带给监听者
这里有一个问题
这个程序只有一个按钮,和一个抽象方法的实现,如果有多个按钮,不同的按钮要产生不同的动作,那要怎么区分呢?
应该是通过对事件(即传入抽象方法的那个参数 event)的判断
如果创建了多个按钮,这多个按钮的变量命名是不同的可以在actionPerformed方法中判断是哪个按钮,在注册时注册同一个监听口即可。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Image extends JPanel implements ActionListener{
JButton button1;
JButton button2;
public static void main(String[] args) {
// TODO Auto-generated method stub
Image gui = new Image();
gui.tt();
}
public void tt() {
JFrame frame = new JFrame("image");
button1 = new JButton("button1");
button2 = new JButton("button2");
frame.getContentPane().add(BorderLayout.EAST,button1);
frame.getContentPane().add(BorderLayout.WEST,button2);
button1.addActionListener(this); //注册同一个监听口
button2.addActionListener(this); //注册同一个监听口
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 600);
frame.setVisible(true);
}
public void paintComponent(Graphics g) {
g.setColor(Color.ORANGE);
g.fillRect(20, 50, 100, 100);
}
public void actionPerformed(ActionEvent event) {
if(event.getSource() == button1) //判断事件来自于哪个按钮
{
button1.setText("o((>ω< ))o");
button1.setBackground(Color.blue);
}
else if(event.getSource() == button2)
{
button1.setText("(●ˇ∀ˇ●)"); //判断事件来自于哪个按钮
button1.setBackground(Color.gray);
}
}
}
#不过有一些问题,用一个函数实现多种不同的工作方法,如果修改某个工作可能会弄乱其他的操作,会对可读性和维护工作造成危害。
那么如果不同的按钮有自己不同的监听类,这些类都有自己对接口的不同实现,那这样使用的时候调用不同的类就行了。
不过不同的类需要操作的却是同一个窗口上的实例变量,这些类之间怎么共同使用这些实例变量呢?
很妙的是,Java有一种叫做内部类的东西。
内部类就是在一个类的定义中(也就是在一个类的花括号中)可以再定义一个类,这个类里面的类叫做内部类。
内部类和正常的类没有区别,但是却可以直接而且自由的使用外部类的内容,就算私有的内容也可以访问,这是一种特殊的存取权限。【内部类和外部类的关系非同一般】
如何用内部类实现两个按钮的程序?
之前是使用两个按钮注册同一个监听口(this),现在有了内部类,那么不同的按钮就可以通过内部类实现不同的监听操作,他们有各自的内部类,不会相互干扰,也不需要在一个监听方法中判断哪个是哪个了。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Image extends JPanel {
JButton button1;
JButton button2;
JLabel label1;
public static void main(String[] args) {
// TODO Auto-generated method stub
Image gui = new Image();
gui.tt();
}
public void tt() {
JFrame frame = new JFrame("image");
button1 = new JButton("button1");
button2 = new JButton("button2");
label1 = new JLabel("O(∩_∩)O");
frame.getContentPane().add(BorderLayout.EAST,button1);
frame.getContentPane().add(BorderLayout.CENTER,button2);
frame.getContentPane().add(BorderLayout.WEST,label1);
button1.addActionListener(new LabelListener());
button2.addActionListener(new ColorListener());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 600);
frame.setVisible(true);
}
public void paintComponent(Graphics g) {
g.setColor(Color.ORANGE);
g.fillRect(20, 50, 100, 100);
}
class LabelListener implements ActionListener{
public void actionPerformed(ActionEvent event) {
button2.setText("o((>ω< ))o");
button2.setBackground(Color.blue);
}
}
class ColorListener implements ActionListener{
public void actionPerformed(ActionEvent event) {
label1.setText("hehehahou...................");
label1.setForeground(Color.cyan);
}
}
}
内部类的好处或者说特别之处:
使用内部类就可以在一个类中实现同一个方法多次
这个内部类也可以在外面实现再通过继承再在操作实例变量的类中使用,那为什么不这样做呢?
因为继承只能继承一个,但内部类的接口实现可以是多个
【python可以多重继承,不过多重继承如果出现菱形继承(即之前说的致命方块)就会很麻烦了,所以java中为了避免致命方块,不允许多重继承,所以Java中使用接口继承的方式】
【接口继承 https://www.w3cschool.cn/java/java-interface-inheritance.html】
那么接口继承和内部类有什么关系?
接口继承和内部类的实现形式不同
【至于不同的使用,先用不着,先提出这个问题】
刚才能在图形界面上画一个按钮,那要想画图怎么玩?
现在我们是实现监听接口,监听出现的事件,如果要自己生产事件,那么要怎么做?
那要用哪种接口监听我们自己实现的事件呢?