1 GUI的概念
-
GUI(Graphical User Interface)即图形用户界面,它能够使应用程序看上去更加友好,更加方便用户操作。
2 Swing概述
-
Swing是纯Java组件,使得应用程序在不同的平台上运行时具有相同外观和相同的行为;
-
Swing中的大部分组件类位于javax.swing包中;
-
Swing中的组件非常丰富,支持很多功能强大的组件。
3 容器组件
3.1 概述
Java的图形用户界面的基本组成部分是组件,组件是一个以图形化的方式显示在屏幕上并能与用户进行交互的对象;
-
组件不能独立地显示出来,必须将组件放在一定的容器(container)中才可以显示出来。
-
容器可以容纳多个组件,通过调用容器的add(Component comp)方法向容器中添加组件。
-
窗口(Frame)和面板(Panel)是最常用的两个容器。
3.2 常用容器
1.JFrame
-
用于在Swing程序中创建窗体;
构造方法:
构造方法 | 说 明 |
---|---|
JFrame() | 创建新窗体,该窗体初始为不可见 |
JFrame(String title) | 创建新窗体,使用参数title指定标题,该窗体初始为不可见 |
常用方法:
方 法 | 说 明 |
---|---|
void setSize(int width, int height) | 设置窗口大小 |
void setVisible(boolean b) | 设置窗口是否显示,默认为不显示 |
void setTitle(String title) | 设置窗口标题 |
void setResizable(boolean resizable) | 是否可以设置窗口大小 |
void setLocation(int x,int y) | 设置位置坐标(坐标以屏幕左上角为原点) |
void setLocationRelativeTo(null) | 设置窗口水平居中 |
void setDefaultCloseOperation(int operation) | 关闭窗口选项 |
void dispose() | 释放窗口 |
2.Jpanel
-
JPanel提供面板,它是轻量级的容器;
-
面板中可以添加其它组件,也可以设置布局,我们一般使用面板来实现布局嵌套;
构造方法:
构造方法 | 说 明 |
---|---|
JPanel() | 创建一个空面板 |
JPanel(LayoutManaer layout) | 创建带有指定布局的面板 |
-
框架(JFrame) 内部包含一个名叫Container(内容面板)的面板容器,如果要给框架中添加图形控件,通常将它们加入到这个内容面板中;
-
通过JFrame类中的getContentPane()方法即可获得此框架的内容面板;
-
也可以自己创建Jpanel面板对象,把JPanel作为一个组件添加到某个容器中。
常用方法:
方 法 | 说 明 |
---|---|
void setBackground(Color bg) | 设置面板的背景色,由参数bg指定颜色 |
void setLayout(LayoutManager mgr) | 设置面板的布局,参数是布局管理器 |
Component add(Component comp) | 往面板中添加一个组件 |
案例:
import javax.swing.*;
import java.awt.*;
public class Demo1Frame extends JFrame {
public Demo1Frame() throws HeadlessException {
JFrame jFrame = new JFrame();
/*
this是当前对象,即窗口
*/
this.setTitle("窗口标题");//设置窗口标题
this.setSize(500,500);//设置窗口大小
//this.setLocation(200,500);//设置位置坐标(坐标以屏幕左上角为原点)
this.setLocationRelativeTo(null);//设置窗口水平居中
this.setResizable(false);//禁止设置窗口大小
//this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);//关闭窗口选项 (DO_NOTHING_ON_CLOSE关闭时什么都不做)
//在窗口上添加面板(多个面板嵌套可以实现布局)
JPanel jPanel = new JPanel();
jPanel.setBackground(Color.PINK);//设置面板背景颜色
//jPanel.setBackground(new Color(250, 120, 50));
//默认是流式布局,组件居中
JButton jButton = new JButton("按钮1");
jPanel.add(jButton);//按钮添加到面板上
this.add(jPanel);//面板添加到窗口上
this.setVisible(true);//显示窗口,加到最后,让窗口显示
}
public static void main(String[] args) {
new Demo1Frame();
}
}
效果图:
4 布局管理器
-
swing中,提供了布局管理器类的对象可以管理
-
每个Jpanel都有一个布局管理器对象,当容器需要对某个组件进行定位或判断其大小尺寸时,就会调用其对应的布局管理器,调用Jpanel的setLayout方法改变其布局管理器对象或通过构造方法设置。
-
Java中的图形界面在布局管理上采用容器和布局管理相分离的方案,也就是说容器只是把组件放进来,但它不管怎样放置。至于如何放置需要 用到布局管理器(Container)。
-
Java中有几种常用的布局管理器,分别是:
-
FlowLayout(流式布局)
-
BorderLayout(边界布局)
-
GridLayout(网格布局)
-
4.1 FlowLayout
FlowLayout布局管理器是流式布局管理器,它将组件按照从左到右、从上到下的顺序来安排,并在默认情况下使组件尽量居中放置。
-
FlowLayout布局管理器对组件逐行定位,行内从左到右,一行排满后换行。
-
不改变组件的大小,按组件原有尺寸显示组件,可设置不同的组件间距,行距以及对齐方式。
构造方法:
构造方法 | 说 明 |
---|---|
new FlowLayout(FlowLayout.RIGHT,20,40) | 右对齐,组件之间水平间距20个像素,垂直间距40个像素 |
new FlowLayout(FlowLayout.LEFT) | 左对齐,水平和垂直间距为缺省值(5) |
new FlowLayout() | 使用缺省的居中对齐方式,水平和垂直间距为缺省值(5) |
案例:
import javax.swing.*;
import java.awt.*;
public class Demo2Frame extends JFrame {
public Demo2Frame() throws HeadlessException {
JFrame jFrame = new JFrame();
/*
this是当前对象,即窗口
*/
this.setTitle("流式布局示例");//设置窗口标题
this.setSize(400,200);//设置窗口大小
this.setLocationRelativeTo(null);//设置窗口水平居中
this.setResizable(false);//禁止设置窗口大小
/*
JPanel默认是流式布局,组件居中对齐
*/
//在窗口上添加面板,设置布局为流式布局
//JPanel jPanel = new JPanel(new FlowLayout(FlowLayout.LEFT,20,10));//new FlowLayout(对齐方式,垂直距离,水平距离)
JPanel jPanel = new JPanel(new FlowLayout());
jPanel.setBackground(new Color(183, 227, 251));//设置面板背景颜色
JButton jButton1 = new JButton("按钮1");
JButton jButton2 = new JButton("按钮2");
JButton jButton3 = new JButton("按钮3");
JButton jButton4 = new JButton("按钮4");
jPanel.add(jButton1);
jPanel.add(jButton2);
jPanel.add(jButton3);
jPanel.add(jButton4);
this.add(jPanel);//面板添加到窗口上
this.setVisible(true);//显示窗口,加到最后,让窗口显示
}
public static void main(String[] args) {
new Demo2Frame();
}
}
效果:
4.2 BorderLayout
BorderLayout布局管理器只允许在容器内放置5个组件,这5个组件的位置是由BorderLayout类中的North、South、East、West和Center5个常量来确定的,他们对应着容器中的上下左右中。
-
组件在BorderLayout中的大小都是可以改变的。
-
一般情况下可以让中间区域大一些,而且可以只用其中几个区域。
-
BorderLayout将整个容器的布局划分成东(EAST)西(WEST)南(SOUTH)北(NORTH)中 (CENTER)五个区域,组件只能被添加到指定的区域,如不指定组件的加入部位,则默认加入到CENTER区,每个区域只能加入一个组件,如加入多个,则先前加入的会被覆盖。
-
BorderLayout型布局容器尺寸缩放原则: 北、南两个区域在水平方向缩放,东、西两个区域在垂直方向缩放,中部可在两个方向上缩放。
案例:
import javax.swing.*;
import java.awt.*;
public class Demo3Frame extends JFrame {
public Demo3Frame() throws HeadlessException {
JFrame jFrame = new JFrame();
/*
this是当前对象,即窗口
*/
this.setTitle("边界布局示例");//设置窗口标题
this.setSize(400,200);//设置窗口大小
this.setLocationRelativeTo(null);//设置窗口水平居中
this.setResizable(false);//禁止设置窗口大小
/*
JPanel默认是流式布局
*/
//在窗口上添加面板,设置布局为边界布局
JPanel jPanel = new JPanel(new BorderLayout());
jPanel.setBackground(new Color(183, 227, 251));
JButton jButton1 = new JButton("按钮1");
JButton jButton2 = new JButton("按钮2");
JButton jButton3 = new JButton("按钮3");
JButton jButton4 = new JButton("按钮4");
JButton jButton5 = new JButton("按钮5");
jPanel.add(jButton1,BorderLayout.EAST);
jPanel.add(jButton2,BorderLayout.WEST);
jPanel.add(jButton3,BorderLayout.SOUTH);
jPanel.add(jButton4,BorderLayout.NORTH);
jPanel.add(jButton5,BorderLayout.CENTER);
this.add(jPanel);//面板添加到窗口上
this.setVisible(true);//显示窗口,加到最后,让窗口显示
}
public static void main(String[] args) {
new Demo3Frame();
}
}
效果:
4.3 GridLayout
GridLayout布局管理器是矩形网格,在网格中放置组件,每个网格的高度和宽度都相等,组件随着网格的大小而在水平和垂直方向上拉伸,网格的大小是由容器的大小和创建网格的多少来确定的。
-
当组件数目大于网格数时,GridLayout保持行数不变而自动增加列数。
-
GridLayout型布局管理器将空间划分成规则的矩形网格,每个单元格区域大小相等。组件被添加到每个单元格中,先从左到右添满一行后换行,再从上到下。
-
在 GridLayout 构造方法中指定分割的行数和列数.
案例:
package com.ffyc.javagui.fream;
import javax.swing.*;
import java.awt.*;
public class Demo4Frame extends JFrame {
public Demo4Frame() throws HeadlessException {
JFrame jFrame = new JFrame();
/*
this是当前对象,即窗口
*/
this.setTitle("网格布局示例");//设置窗口标题
this.setSize(400,200);//设置窗口大小
this.setLocationRelativeTo(null);//设置窗口水平居中
this.setResizable(false);//禁止设置窗口大小
/*
JPanel默认是流式布局,组件居中对齐
*/
//在窗口上添加面板,设置布局为网格布局(三行两列)
JPanel jPanel = new JPanel(new GridLayout(3,2));
jPanel.setBackground(new Color(183, 227, 251));//设置面板背景颜色
JButton jButton1 = new JButton("按钮1");
JButton jButton2 = new JButton("按钮2");
JButton jButton3 = new JButton("按钮3");
JButton jButton4 = new JButton("按钮4");
JButton jButton5 = new JButton("按钮5");
JButton jButton6 = new JButton("按钮6");
jPanel.add(jButton1);
jPanel.add(jButton2);
jPanel.add(jButton3);
jPanel.add(jButton4);
jPanel.add(jButton5);
jPanel.add(jButton6);
this.add(jPanel);//面板添加到窗口上
this.setVisible(true);//显示窗口,加到最后,让窗口显示
}
public static void main(String[] args) {
new Demo4Frame();
}
}
效果:
5 常用组件
5.1 标签(JLabel)
-
标签是容纳文本和图标的控件,通常用来在界面中标识别的控件。
构造函数:
构造方法 | 常用方法 |
---|---|
JLabel() | 创建一个空的标签 |
JLabel(String text) | 创建一个带文本的标签 |
JLabel(Icon image) | 创建一个带图像的标签 |
常用方法:
方 法 | 说 明 |
---|---|
void setText(String text) | 设置标签上的文本 |
String getText() | 获得标签上的文本 |
setFont(new Font(“宋体”,Font.BOLD, 18)) | 设置字体 |
5.2 单行文本(JTextField)
构造函数:
构造函数 | 说 明 |
---|---|
JTextField() | 创建一个空的单行文本 |
JTextField(String text ) | 创建一个带文本的单行文本 |
JTextField(int columns) | 创建一个指定列数的单行文本 |
JTextField(String text, int columns) | 创建一个带文本的、指定列数的单行文本 |
常用方法:
方 法 | 说 明 |
---|---|
void setText(String text) | 设置文本框中的文本 |
String getText() | 获得文本框中的文本 |
void setEditable(boolean b) | 设置文本框是否可以编辑 |
setColumns(20) | 设置列数 |
5.3 多行文本框(JTextArea)
构造函数:
构造函数 | 说 明 |
---|---|
JTextArea() | 创建一个空的文本域 |
JTextArea(String text) | 用指定文本初始化文本域 |
JTextArea(int rows, int columns) | 创建一个指定行数和列数的空文本域 |
JTextArea(String text,int rows, int columns) | 创建一个带文本,并指行数和列数的 |
常用方法:
方 法 | 说 明 |
---|---|
void setText(String text) | 设置文本域中的文本 |
String getText() | 获得文本域中的文本 |
void setFont(Font font) | 设置文本域中文本的字体 |
void setLineWrap(boolean wrap) | 是否自动换行,默认false |
如果需要文本区自动出现滚动条,可将文本区对象放入滚动窗格(JScrollPane)中:
JScrollPane scrollPane = new JScrollPane(txtArea);
add(scrollPane );
案例:
import javax.swing.*;
import java.awt.*;
public class Demo7Frame extends JFrame{
public Demo7Frame() throws HeadlessException {
this.setTitle("多行文本示例");
this.setSize(400, 250);//大小
this.setLocationRelativeTo(null);//相对位置 水平垂直居中
this.setResizable(false);//禁止设置窗口大小
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭窗口选项
/*
JPanel默认是流式布局, 组件居中对齐
*/
JPanel jp = new JPanel();
JTextArea jt = new JTextArea(10,20);
jt.setLineWrap(true);//强制换行
jt.setWrapStyleWord(true);//有英文单词时用此方法换行
JScrollPane jsp = new JScrollPane(jt);//创建一个滚动条
jp.add(jsp);
//this--窗口
this.add(jp);
this.setVisible(true);//显示窗口,最后让窗口显示
}
public static void main(String[] args) {
new Demo7Frame();
}
}
运行效果:
5.4 密码框(JPasswordField)
构造函数:
构造方法 | 说 明 |
---|---|
JPasswordField() | 创建一个空的密码框 |
JPasswordField(String text) | 创建一个密码框并设置其初始字符串 |
JPasswordField(String text, int columns) | 创建一个新的密码框并为其设置初始字符和字段长度 |
方法:
方 法 | 说 明 |
---|---|
char[] getPassword() | 获取密码框的内容 |
5.4 按钮(JButton)
构造方法:
构造方法 | 说 明 |
---|---|
JButton(String text) | 创建一个带文本的标签 |
JButton(Icon image) | 创建一个带图像的标签 |
方法:
方 法 | 说 明 |
---|---|
void setBackground(Color bg) | 设置按钮的背景色 |
void setEnabled(boolean b) | 设置启用(或禁用)按钮,由参数b决定 |
void setToolTipText(String text) | 设置按钮的悬停提示信息 |
5.5 菜单栏组件:
构造方法:JMenuBar();
方法:add(menu); 向菜单栏添加菜单
5.6 菜单组件:
构造方法:JMenu(“菜单名称");
方法:add(menuItem); 向菜单添加菜单选项
5.7 菜单项组件:
构造方法:JMenuItem(“菜单项名称");
将菜单栏添加到窗口:
setJMenuBar(menuBar);
案例:
import javax.swing.*;
import java.awt.*;
public class Demo8Frame extends JFrame{
public Demo8Frame() throws HeadlessException {
this.setTitle("窗口标题");
this.setSize(500, 200);//大小
this.setLocationRelativeTo(null);//相对位置 水平垂直居中
this.setResizable(false);//禁止设置窗口大小
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭窗口选项
JPanel jp = new JPanel();
/*
菜单有三部分构成,菜单栏 ,菜单,菜单项
*/
//菜单栏
JMenuBar jMenuBar = new JMenuBar();
//菜单
JMenu jMenu1 = new JMenu("文件");
//菜单项
JMenuItem ji1 = new JMenuItem("新建");
JMenuItem ji2 = new JMenuItem("保存");
JMenuItem ji3 = new JMenuItem("打开");
JMenuItem ji4 = new JMenuItem("分享");
jMenu1.add(ji1);
jMenu1.add(ji2);
jMenu1.add(ji3);
jMenu1.add(ji4);
//菜单
JMenu jMenu2 = new JMenu("编辑");
//菜单项
JMenuItem ji5 = new JMenuItem("剪切");
JMenuItem ji6 = new JMenuItem("复制");
jMenu2.add(ji5);
jMenu2.add(ji6);
//菜单
JMenu jMenu3 = new JMenu("帮助");
//菜单项
JMenuItem ji7 = new JMenuItem("关于");
jMenu3.add(ji7);
jMenuBar.add(jMenu1);
jMenuBar.add(jMenu2);
jMenuBar.add(jMenu3);
this.setJMenuBar(jMenuBar);//添加菜单栏
this.add(jp);
this.setVisible(true);//显示窗口,最后让窗口显示
}
public static void main(String[] args) {
new Demo8Frame();
}
}
效果:
6 事件处理
-
对于采用了图形用户界面的程序来说,事件控制是非常重要的,到目前为止,我们编写的图形用户界面程序都仅仅只是完成了界面,而没有任何实际的功能,要实现相应的功能,必须进行事件处理;
-
用户与GUI组件进行交互就会发生事件;
-
如:按下一个按钮、用键盘输入一个字符、点击鼠标等等;
-
-
当前我们要关注的并不是“事件是如何产生的”,而是讨论当发生事件后,我们应当“如何处理之”。
Java中,事件处理的基本思路:
-
一个源(事件源)产生一个事件(事件对象)并把它送到监听器那里,监听器只是简单地等待,直到它收到一个事件,一旦事件被接受,监听器将处理这些事件;
-
一个事件源必须注册监听器以便监听器可以接受关于一个特定事件的通知。
案例:
-
由于我们想要处理按钮的点击事件,因此,按钮便是事件源;
-
监听器类型是ActionListener。
添加事件监听器(此处即为匿名内部类) :
按钮对象.addActionListener(new ActionListener() {
// 事件处理
@Override
public void actionPerformed(ActionEvent e) {
//执行操作
}
});
案例:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/*
定义了一个外部类,虽然也可以用,但是它只能拿到事件源的信息,访问不到别的信息
所以定义外部类实现接口的方式不可取,这个时候我们就要使用内部类
*/
public class MyAction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("被点击了");
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Demo9Frame extends JFrame{
JTextField accountText;
public Demo9Frame() throws HeadlessException {
this.setTitle("窗口标题");
this.setSize(500, 500);//大小
//this.setLocation(300, 500);//位置坐标
this.setLocationRelativeTo(null);//相对位置 水平垂直居中
this.setResizable(false);//禁止设置窗口大小
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭窗口选项
JPanel jp = new JPanel();
JLabel label = new JLabel("账号");
label.setForeground(Color.blue);
label.setFont(new Font("楷体", Font.BOLD,20));
accountText = new JTextField(15);
JButton jb = new JButton("登录");
jp.add(label);
jp.add(accountText);
jp.add(jb);
//this--窗口
this.add(jp);
this.setVisible(true);//显示窗口,最后让窗口显示
//为登录按钮注册时间监听器 创建ActionListener的匿名内部类对象
/*jb.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(accountText.getText());
}
});*/
/* MouseListener是一个接口(public interface MouseListener extends EventListener {}),
里边的方法都是抽象方法,所以在实现的时候需要重写里边所有的方法,
为了解决这个不足,java提供了一个抽象类MouseAdapter,实现了MouseListener接口中的抽象方法,
所以我们就可以直接用MouseAdapter这个实现类,就不用重写所有的方法,只重写我们需要的就可以了。
*/
/*jb.addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("鼠标点击,按下释放");
}
@Override
public void mousePressed(MouseEvent e) {
System.out.println("鼠标按下");
}
@Override
public void mouseReleased(MouseEvent e) {
System.out.println("鼠标释放");
}
@Override
public void mouseEntered(MouseEvent e) {
System.out.println("鼠标移入");
}
@Override
public void mouseExited(MouseEvent e) {
System.out.println("鼠标移出");
}
});*/
/* jb.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("鼠标点击");
}
});
*/
//同理,键盘事件监听处理中也有对应的实现类
accountText.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
System.out.println(accountText.getText());
System.out.println(e.getKeyChar()+":"+e.getKeyCode());
}
});
/*
为了简化内部类的定义,可以使用匿名内部类方式简化语法,只使用一次
*/
accountText.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
}
});
//jb.addActionListener(new MyAction());
}
//将只在本类中使用的功能,定义在内部类中,实现封装,在哪儿使用,new 内部类即可
/*class MyAction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("被点击了");
System.out.println(accountText.getText());//使用外部类的成员
}
}*/
public static void main(String[] args) {
new Demo9Frame();
}
}
7 对话框
JOptionPane对话框:
-
showMessageDialog():消息对话框
主要有五种消息类型,类型不同,图标不同:
消息类型 | 提 示 |
---|---|
ERROR_MESSAGE | 错误消息提示 |
INFORMATION_MESSAGE | 信息提示 |
WARNING_MESSAGE | 警告提示 |
QUESTION_MESSAGE | 问题提示 |
PLAIN_MESSAGE | 简洁提示 |
showConfirmDialog() | 确认对话框 |
主要有四种消息类型,类型不同,图标不同:
消息类型 | 选项 |
---|---|
DEFAULT_OPTION | 默认选项 |
YES_NO_OPTION | 是/否选项 |
YES_NO_CANCEL_OPTION | 是/否/取消选项 |
OK_CANCEL_OPTION | 确定/取消 |
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Demo10Frame extends JFrame{
public Demo10Frame() throws HeadlessException {
this.setTitle("欢迎登陆");
this.setSize(450,270);
this.setLocationRelativeTo(null);//设置窗口水平居中
this.setResizable(false);//禁止设置窗口大小
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//创建面板,网格布局(三行一列)
JPanel jPanel = new JPanel(new GridLayout(3,1));
//面板布局,流式布局
JPanel accountPanel = new JPanel(new FlowLayout(FlowLayout.CENTER,10,35));
JPanel passwordPanel = new JPanel(new FlowLayout(FlowLayout.CENTER,10,35));
JPanel btnPanel = new JPanel(new FlowLayout(FlowLayout.CENTER,10,20));
JLabel accountLable = new JLabel("管理员");
accountLable.setForeground(Color.black);
accountLable.setFont(new Font("黑体", Font.CENTER_BASELINE, 20));
JLabel passwordLable = new JLabel("密 码");
passwordLable.setForeground(Color.black);
passwordLable.setFont(new Font("黑体", Font.CENTER_BASELINE, 20));
JTextField accountText = new JTextField(20);
JPasswordField passwordField = new JPasswordField(20);
JButton loginBtn = new JButton("登陆");
JButton cancelBtn = new JButton("取消");
cancelBtn.setToolTipText("点击退出");
accountPanel.add(accountLable);
accountPanel.add(accountText);
passwordPanel.add(passwordLable);
passwordPanel.add(passwordField);
btnPanel.add(loginBtn);
btnPanel.add(cancelBtn);
jPanel.add(accountPanel);
jPanel.add(passwordPanel);
jPanel.add(btnPanel);
this.add(jPanel);
this.setVisible(true);//显示窗口
/*
事件处理
*/
//给取消按钮添加事件处理
loginBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String account = accountText.getText();
if(account.length()>10){
//JOptionPane.showMessageDialog(null, "账号不能大于10位字符!");
JOptionPane.showMessageDialog(null, "账号不能大于10位字符!","登录提示",JOptionPane.QUESTION_MESSAGE);
return;//因为此方法没有返回值,return只是让程序终止,不继续往下走
}
}
});
//给登录按钮添加事件处理
cancelBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int res = JOptionPane.showConfirmDialog(null, "您确定要退出吗?", "操作提示", JOptionPane.OK_CANCEL_OPTION);
System.out.println(res);//取消为2 确定为0
if(res==0){
/*
此处不能使用this.dispose,因为此处的this指的不是窗口,而是匿名内部类的对象
可以直接使用dispose(),因为这个匿名内部类中没有dispose这个方法,所以它就会向上找,找上一级窗口对象中的dispo()
*/
dispose();//释放当前窗口
}
return;
}
});
}
public static void main(String[] args) {
new Demo10Frame();
}
}
效果:
8 内部类
8.1 什么是内部类
● 把类定义在另一个类的内部,该类就被称为内部类。
● 如果在类 Outer 的内部再定义一个类 Inner,此时类 Inner 就称为内部类 (或称为嵌套类),而类 Outer 则称为外部类(或称为宿主类)
//外部类
public class Outer{
//内部类
public class Inner{
}
}
8.2 内部类的分类
-
成员内部类、静态内部类、局部内部类、匿名内部类
1.成员内部类
-
就是位于外部类成员位置的类
-
特点:可以使用外部类中所有的成员变量和成员方法(包括私有的)
public class Outer {
private int num = 10;
public void eat(){
new Inner();//一般在本类中使用内部类
}
/*
在一个类的内部定义的类称为内部类
*/
//成员内部类
public class Inner{
public void test(){
System.out.println(num);//内部类中可以直接使用外部类的成员,即使是私有属性也可以访问到
}
}
}
private修饰内部类
-
如果我们的内部类不想轻易被任何人访问,可以选择使用private修饰内部类,这样我们就无法通过创建对象的方法来访问,想要访问只需要在外部类中定义一个public修饰的方法,间接调用。
-
优点:可以在这个public方法中增加一些判断语句,起到数据安全的作用。
-
class Outer {
private class Inner {
public void show() {
System.out.println(“密码备份文件”);
} sss
}
//使用getXxx()获取成员内部类,可以增加校验语句(文中省略)
public Inner getInner() {
return new Inner();
}
}
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.getInner();
inner.show();
}
2.静态内部类
-
被 static 所修饰的内部类,按位置分,属于成员内部类,但也可以称作静态内部类,也常叫做嵌套内部类,不能使用外部类的非static成员变量和成员方法 。
public class Outer {
private static int num = 10;
public void eat(){
new Inner();//一般在本类中使用内部类
}
/*
静态内部类, 只能方访问外部类中静态成员,
因为非静态的在创建对象的时候才存在,类加载的时候不存在。
*/
static class Inner{
public void test(){
System.out.println(num);
}
}
}
3.局部内部类
-
定义在一个方法或者一个作用域里面的类
特点:主要是作用域发生了变化,只能在自身所在方法和属性中被使用
class Outer{
private int age1 = 12;
public void method(){
final int age2 = 21;
class Inner{
public void show(){
System.out.println(age1);
//从内部类中访问变量age2,需要将变量声明为最终类型
System.out.println(age2);
}
}
}
}
4.匿名内部类
-
一个没有名字的类,是内部类的简化写法
/*
内部类:将只在本类中使用的功能,定义在内部类中,实现封装,在哪儿使用,new 内部类即可
*/
class MyAction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(accountText.getText());//使用外部类的成员
}
}
/*
匿名内部类:为了简化内部类的定义,可以使用匿名内部类方式简化语法,只使用一次
*/
accountText.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
}
});
内部类的特点:
-
内部类是一个独立的类,在编译之后内部类会被编译成独立的.class文件,前面冠以外部类的类名和$符号。
-
内部类不能用普通的方式访问,内部类是外部类的一个成员,所以内部类可以自由地访问外部类的成员变量,无论是否为 private 的都可以访问到。
-
如果将内部类声明成静态的,就不能随便访问外部类的成员变量,只能访问外部类的静态成员变量。
案例:
public class Car {
private int num;
private String name;
public Car(int num, String name) {
this.num = num;
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Car{" +
"num=" + num +
", name='" + name + '\'' +
'}';
}
}
import java.util.Comparator;
//为Car类开发的排序比较类
public class CarComparator implements Comparator<Car> {
@Override
public int compare(Car o1, Car o2) {
return o1.getNum()-o2.getNum();
}
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
public class TestCar {
public static void main(String[] args) {
Car car1 = new Car(101, "car1");
Car car2 = new Car(102, "car2");
Car car3 = new Car(103, "car3");
Car car4 = new Car(104, "car4");
Car [] cars = {car2,car1,car4,car3};
//Arrays.sort(cars,new CarComparator());
Arrays.sort(cars, new Comparator<Car>() {
@Override
public int compare(Car o1, Car o2) {
return o1.getNum()-o2.getNum();
}
});
Arrays.sort(cars,(o1,o2)->{
return o1.getNum()-o2.getNum();
});
System.out.println(Arrays.toString(cars));
ArrayList<Car> carArrayList = new ArrayList<>();
carArrayList.add(car2);
carArrayList.add(car1);
carArrayList.add(car4);
carArrayList.add(car3);
carArrayList.sort(new Comparator<Car>() {
@Override
public int compare(Car o1, Car o2) {
return o1.getNum()-o2.getNum();
}
});
}
}
8.3 内部类的意义
-
封装性,将一些操作隐藏起来,外界不知道,间接实现多继承
1.封装性
-
作为一个类的编写者,我们需要对这个类的访问者的访问权限做出一定的限制,将一些我们不愿意让别人看到的操作隐藏起来。
2.实现多继承
/*
Son继承Mother,Mother继承Father,从设计上显然是讲不通的,
这个时候我们可以在Son类中写两个内部类分别继承Mother、father
*/
public class Father {
public String powerFul = "市长";
}
public class Mother {
public String wealthy = "一百万";
}
public class Son {
class Extends_Father extends Father{
}
class Extends_Mother extends Mother{
}
public void sayHello(){
String father = new Extends_Father().powerFul;
String mother = new Extends_Mother().wealthy;
System.out.println("my father is:"+father+"my mother is:"+mother);
}
}