swing
数学教材推荐:
中学PDF课本介绍和下载:https://www.zhihu.com/question/517213170/answer/3430923272
swing
swing基础
解压缩密码a1b2c三
1、容器与控件
1.1)、类介绍
-
JFrame 表示一个窗口
-
JPanel ,表示一个容器,也称为面板
-
JButton,表示一个按钮控件
-
JLabel ,标签控件,用于显示文本
1.2)、 使用
// 1 指定一个窗口
JFrame frame = new JFrame();
// 2 设置一个容器
JPanel root = new JPanel();
frame.setContentPane(root);
// 3 再添加控件,
JButton button = new JButton("测试");// 注意使用和导包不要导入AWT包下的Button
root.add(button);
// JLabel ,标签控件,用于显示文本
JLabel label = new JLabel("hello你好");
root.add(label);
// 为按钮添加事件
button.addActionListener((a) -> System.out.println("按钮被点击了********************"));
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
}
});
root.add(button);
1.3)、自定义窗口
新建一个类继承JFrame即可,此时这个子类里面也可以放一些固定的参数,这就是程序设计-封装
public class MyFrame extends JFrame{
public MyFrame(String tittle, JPanel root) {
super(tittle);
// 当窗口关闭时退出整个程序
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 设置一个容器
// JPanel root = new JPanel();
this.setContentPane(root);
// // 向容器中添加一个控件 PS:注意不要使用awt包下的
// JButton button = new JButton("测试按钮");
// button.setSize(50,20);
// root.add(button);
// root.add(new JLabel("测试lable"));
this.setSize(800, 500);
}
}
/* 使用 */
// 一行代码就能写出一个窗口了
MyFrame frame = new MyFrame("练习窗口", root);
1.4、文本类
-
JTextField ,单行文本框
-
JCheckBox ,复选框
-
例如:JCheckBox agreeField = new JCheckBox("同意用户协议");
-
setSelected ( true / false ) 设置选中状态
-
isSelected() 是否选中
-
addActionListener() 勾选或取消获取事件
-
-
-
JComboBox ,下拉列表
-
JComboBox
是一个泛型, 表示其数据项的类型 combo.addItem ( T value )
T value = combo.getItemAt ( index ))
-
例如, 添加下拉选择项
colorField.addItem("红色");
colorField.addItem("蓝色");
colorField.addItem("绿色");
addItem ( T ) ,T的类型在创建时指定,这里是 String 类型,也就是每一项Item的数据类型是String
-
3 选中的项,按索引访问
getSelectedIndex() : 获取选中项的索引
setSelectedIndex() : 设置选中项
remove ( index ) :按索引删除
-
4 按数据项访问
getSelectedItem()
setSelectedItem()
remove ( item )
-
5 事件处理
使用addActionListener() 实现用户选择的事件处理
-
添加对象类型
1 添加一个数据类 Student
注意重写 toString() 方法
2 下拉列表控件
JComboBox
combo = new JComboBox<>(); 3 添加数据项
combo.addItem( new Student(2001, "莫凡", true, "13810012345"));
combo.addItem( new Student(2002, "穆宁雪", false, "13310002233"));
combo.addItem( new Student(2003, "叶心夏", false, "13390991292"));
其中,数据项的类型为 Student
4 获取一项
Student value = combo.getItemAt(0);
其中,每一个Item的类型为 Student
-
2、布局器
2.1)、LayoutManager 布局管理器
控件添加到窗口,
root.add ( a1 )
root.add ( a2 )
...
之后,由布局器来负责对每一个子控件进行布局
默认地,JPanel 自带一个 FlowLayout 流式布局
相当于 ,
LayoutManager layout = new FlowLayout();
root.setLayout(layout);
其中,FlowLayout 对子控件 从左到右、从上到下 依次排列
但FLowLayout并不好用,了解即可。
2.2)、BorderLayout 布局管理器
BorderLayout ,边界布局器
将容器分为东、西、南、北、中 ,5个区域
BorderLayout的使用:
-
1 设置布局器
root.setLayout ( new BorderLayout() );
-
2 添加子控件时,要指定其方位
root.add(a1, BorderLayout.NORTH);
root.add(a2, BorderLayout.SOUTH);
其中,NORTH北、SOUTH南、WEST西、EAST东、CENTER中央
尺寸调节:
-
1 CENTER 中央区域,总是占满中央位置
-
2 NORTH / SOUTH 上下
- 宽度占满
- 高度由 setPreferredSize() 决定
-
3 WEST / EAST 左右
- 宽度由 setPreferedSize() 决定
- 高度占满
2.3)、HLayout布局管理器
af.swing.layout.HLayout ,水平布局器 ( Horizontal Layout )
把所有子控件,从右到右依次排列
1 添加 af-swing.jar 包支持
2 使用 HLayout
-设置布局器
root.setLayout( new HLayout());
-添加子控件,同时指定宽度
root.add(a1, "100px");
root.add(a2, "30%");
其中,可以按像素、百分比、自动宽度、权重来指定宽度
例如,
root.add(a1, "100px"); // 宽度,固定占 100px
root.add(a2, "30%"); // 宽度,固定占 100%
root.add(a3, "auto"); // 宽度,自动按需分配
root.add(a4, "1w"); // 宽度,权重占比
root.add(a5, "1w"); // 宽度,权重占比
2.4)、HLayout布局管理器
af.swing.layout.VLayout ,纵向布局器 ( Vertical Layout )
把所有子控件,从上到下 依次排列
1 添加 af-swing.jar 包支持
2 使用 VLayout
其中,可以指定子控件的间距:
root.setLayout( new VLayout(10) ); // 10px
2.5)、FreeLayout布局管理器
af.swing.layout.FreeLayout ,自由布局器
1 设置布局器
root.setLayout( new FreeLayout() );
2 添加子控件时,指定边距
root.add(a4, new Margin(20, 10, 20, 10));
当边距设为 -1 时,表示不拉伸,使用 PreferredSize
例如,
root.add(a1, new Margin(20, 10, -1, -1)); // 左上角
root.add(a2, , , 10)); 靠上
2.6)、手工布局
手工布局,即不使用布局器
1 不使用布局器
root.setLayout( null );
2 添加子控件
root.add( a1 );
3 指定控件的位置
a1.setBounds( 0, 0, 100, 50);
设置坐标 setBounds( x, y, width, height )
其中,
x , y 左上角的坐标
width, height
当窗口大小改变时,子控件的位置不会自适应变化
2.7)、自定义布局器
布局管理器,要实现以下接口:
LayoutManager
LayoutManager2
其中,
LayoutManager2是新版接口,继承于 LayoutManager
1、 添加一个类 SimpleLayout ,实现 LayoutManager2
class SimpleLayout implements LayoutManager2 {
其中,实现控件的布局计算
-void addLayoutComponent (Component comp, Object constraints)
-void removeLayoutComponent (Component comp)
-void layoutContainer (Container parent) // 父容器调用它,对子控件进行布局(可以在此方法中打印日志观察效果)
}
2、使用自定义的布局器
root.setLayout( new SimpleLayout());
3、布局的计算:
void layoutContainer (Container parent) 在这个方法中操作
Container parent // 容器
width = parent.getWidth(); // 宽度
height = parent.getHeight(); // 高度
Component[] children = parent.getComponents(); // 子控件
其中,JPanel 往上溯源属于 Container,而各种控件都属于 Component
练习布局计算:
具体的布局样式,视需求而定。
比如,网格式布局。
每个控件占据 100x100 的单元格,超出一行后换行显示
2.7)、自定义布局器适配器
为了让代码更简洁,添加 LayoutAdapter
LayoutAdapter的特点:
1、 LayoutAdapter 实现了 LayoutManager2
2、 LayoutAdapter 是抽象类,里面有3个方法待实现(即只实现其他方法,不实现下面这3个,留给子类去实现)
addLayoutComponent(..)
removeLayoutComponent(..)
layoutContainer
3、 当自定义布局器时,直接继承 LayoutAdapter 即可
public class MyLayout extends LayoutAdapter
{
public void addLayoutComponent(..) { }
public void removeLayoutComponent(Component comp)(){ }
public void layoutContainer(Container parent) { }
}
代码:
import java.awt.*;
public abstract class LayoutAdapter implements LayoutManager2 {
@Override
public void addLayoutComponent(Component comp, Object constraints) {
}
@Override
public Dimension maximumLayoutSize(Container target) {
return null;
}
@Override
public float getLayoutAlignmentX(Container target) {
return 0;
}
@Override
public float getLayoutAlignmentY(Container target) {
return 0;
}
@Override
public void invalidateLayout(Container target) {
}
// @Override
// public void addLayoutComponent(String name, Component comp) {
//
// }
// @Override
// public void removeLayoutComponent(Component comp) {
//
// }
@Override
public Dimension preferredLayoutSize(Container parent) {
return null;
}
@Override
public Dimension minimumLayoutSize(Container parent) {
return null;
}
// @Override
// public void layoutContainer(Container parent) {
//
// }
}
-
私有布局器
/** * 私有布局器 */ private static class MyCustomLayout extends LayoutAdapter{ @Override public void addLayoutComponent(String name, Component comp) { } @Override public void removeLayoutComponent(Component comp) { } @Override public void layoutContainer(Container parent) { // 父容器调用它,对子控件进行布局(可以在此方法中打印日志观察效果) } }
RGB颜色
RGB 颜色空间,使用 R红、G绿、B蓝来表示一个颜色
几种常用颜色空间:
-
RGB
-
YUV
-
YCbCr
RGB 颜色空间
例如,0-255
-
FF FF FF 或 (255, 255, 255 ) 白色
-
00 00 00 或 ( 0 , 0 , 0 ) 黑色
-
FF 00 00 或 ( 255, 0 , 0 ) 红色
-
FF FF 00 或 ( 255, 255, 0 ) 黄色
-
其他颜色,可以自己百度 RGB颜色表
Color 类表示一个颜色,例如,
new Color(255,0,0)
或者使用十六进制: new Color(0xFF0000)
RGBA
RGBA ,带透明度的颜色表示。其中,A代表 Alpha
Alpha 位于 0 ~ 255 之间
例如,半透明的蓝色,
new Color(0, 0, 255, 128)
或者使用十六进制: new Color(0x800000FF, true) 其中80表示透明度A
也可以使用‘拾色器’软件,拾取桌面颜色
3、自定义控件
3.1)、自定义简单控件,
public class MyControl extends JPanel{
}
其中,JPanel ,既是容器,也是控件。邵工,邵总
控件的绘制
import javax.swing.*;
import java.awt.*;
/**
* 8.1 自定义控件
* 继承JPanel类,这个类也相当于一个控件,即是容器也是控件,可以查看下此类的继承关系就知道了
*/
public class MyControl extends JPanel {
@Override
protected void paintComponent(Graphics g) { // 注意不要使用**printComponent** 方法
super.paintComponent(g);// 这一行一般不能少,可能用于初始化一些参数之类的
// 获取当前控件的属性
int width = this.getWidth();
int height = this.getHeight();
// 绘制一个矩形 :通过Graphics类来绘制当前控件的属性
g.setColor(new Color(255,255,0));
g.fillRect(0,0,width,height);
// 再绘制一个矩形,观察一下效果
// g.setColor(new Color(0,255,255));
// g.fillRect(50,50,width-60,height-60);
// 再绘制一个矩形+扇形,观察一下效果
g.setColor(new Color(0,255,255));// Color类中第四个参数表示不透明度 255最高(不透明)
// g.fillRect(50,50,width-10,height-10);
// 绘制扇形,最后两位参数是起始角度+圆弧角度
g.fillArc(50,50,100,200, -45,90);
}
}
使用自定义控件
添加到主窗口中,
MyControl c = new MyControl();
root.add( c );
c.setPreferredSize(new Dimension(100,50));
注意细节:
1 是 paintComponent() ,不是 printComponent()
2 要保留 super.paintComponent(g) 这一行
3.2)、绘制几何形状
绘制矩形 Rectangle ,
g.setColor( Color.RED );
g.fillRect(30, 30, 100, 50);
其中,
左上角坐标 (30, 30)
尺寸 100 x 50
绘制椭圆 Oval ,
g.setColor( Color.RED );
g.fillOval(30, 30, 100, 50);
其中,指定其外围的矩形作为参数。
绘制扇形 Arc ,
g.setColor( Color.RED );
g.fillArc(30, 30, 100, 50, 0, 120);
其中,
-x, y, width, height 指定外围的矩形
-startAngle 起始角度
-arcAngle 圆弧角度
填充、描边方法
填充,以 fill* 打头
g.fillRect ()
g.fillOval ()
g.fillArc ()
描边,以 draw* 打头
g.drawRect()
g.drawOval()
g.drawArc()
其他绘制方法,
-g.drawLine () 绘制线段
-g.drawImage() 绘制图片 ,下一章
-g.drawPolygon() 绘制多边形 ,Swing高级篇
-g.drawString() 绘制文字 ,Swing高级篇
-不规则形状,参考 Swing高级篇
几点细节
1、相对坐标
在 paintComponent() 中绘制时,坐标是相对于控件自身的,而不是相对于整个窗口的
(0, 0) 指的是控件自己的左上角
例如:
g.drawLine (0, 0, width, height);
2、超出部分不会显示,也不报错
若超出控件的范围,则超出部分不会显示。
3、先后绘制顺序,会导致覆盖叠加,例如:
先填充一个矩形:
g.setColor( Color.RED );
g.fillRect(30,30, 100,50); // 先填充
然后描边一个同样大小的矩形:
g.setColor( Color.BLUE);
g.drawRect(30,30, 100,50); // 后描边
注意:这样才会保证上面的边框在正常显示在填充颜色的矩形的上面,才会有正常的边框效果
其中,形状的边缘,可能存在一个像素的误差(在8.4章节)
练习:画正弦曲线
章节8.5
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class SinCurve extends JPanel
{
public int grain = 3; // 线条的精细度 ( 粒度 )
public int radius = 50; // 高度 ( 振幅 )
public int period = 100; // X轴, 每100像素表示一个周期(2PI)
@Override
protected void paintComponent(Graphics g)
{
// 请保留这一行调用
super.paintComponent(g);
// 得到当前这个控件的宽度、高度
int width = this.getWidth();
int height = this.getHeight();
// 底色设为白色
g.setColor(new Color(255, 255, 255));
g.fillRect(0, 0, width, height);
/////////////////////////////////////
// 中线
int center = height/2;
g.setColor(Color.blue);
g.drawLine(0, center, width, center);
// 正弦曲线 ( 掌握思想即可:由多个小段连接而成,近似为一条曲线 )
int x1 = 0;
int y1 = 0;
for(int i=0; i<width; i+= grain)
{
// 参考本节课下的图文教程,有详细讲解
int x2 = i;
// 把横坐标x换算成角度 ( 弧度值)
double angle = 2 * Math.PI * x2 / period;
// 计算得到 y 坐标
int y2 = (int) (radius * Math.sin( angle ));
g.drawLine(x1, center+y1, x2, center+y2);
x1 = x2;
y1 = y2;
}
}
}
4、图片的绘制
在自定义控件中,也可实现图片的绘制。
g.drawImage ( image, x, y, width, height, observer )
其中,
-
image 要绘制的图片对象
-
x , y, width, height 绘制的位置
-
observer 设为 null
具体步骤:
准备一个图片 1.jpg ,放在 data\ 目录下
加载图片,得到 Image 对象
File file = new File("data/1.jpg");
BufferedImage image = ImageIO.read(file);
其中,Image是抽象类,BufferImage 是具体实现类。
绘制图片,
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class MyPicture extends JPanel
{
@Override
protected void paintComponent(Graphics g)
{
// TODO Auto-generated method stub
super.paintComponent(g);
// 设置白色背景
int width = getWidth();
int height = getHeight();
g.setColor( Color.WHITE );
g.fillRect(0, 0, width, height);
try
{
// 图片文件的路径,使用相对路径
// File file = new File("picture/1.jpg");
File file = new File("src\\main\\resources\\2.jpg");
// 加载文件,得到一个 Image 类型 ( BufferedImage是Image的子类实现 )
BufferedImage image = ImageIO.read(file);
// 绘制图片
g.drawImage(image, 0, 0, width, height, null);
} catch (IOException e)
{
e.printStackTrace();
}
}
}
public class MyFrame extends JFrame{
public MyFrame(String title)
{
super(title);
JPanel root = new JPanel();
this.setContentPane( root );
// 使用 MyControl
MyPicture c = new MyPicture();
root.add( c );
// 设置大小
c.setPreferredSize(new Dimension(200,200));
}
}
运行:
public class MyDemo
{
public static void main(String[] args)
{
JFrame frame = new MyFrame("Swing Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setVisible(true);
}
}
优化:
图片加载应放在MyPicture类的构造方法中,只加载一次即可
BufferedImage image = ImageIO.read(file);
保持图片长宽比
package af.swing;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class PictureView extends JPanel
{
// 要显示的图片,默认为 null
private Image image;
// 背景色,默认为 null
private Color bgColor;
public PictureView()
{
}
public void setBackgroundColor( Color color)
{
this.bgColor = color;
this.repaint(); // 重新绘制这个控件
}
public void setImage (Image image)
{
this.image = image;
this.repaint(); // 重新绘制这个控件
}
@Override
protected void paintComponent(Graphics g)
{
// TODO Auto-generated method stub
super.paintComponent(g);
// 设置白色背景
int width = getWidth();
int height = getHeight();
if( bgColor != null)
{
g.setColor( bgColor );
g.fillRect(0, 0, width, height);
}
if( image != null)
{
// 获取图像的大小
int imgW = image.getWidth( null );
int imgH = image.getHeight( null );
// ( fitW, fitH ) : 要求保持长宽比,并且在目标矩形之内
// 1:图像不能超出控制范围
// 2:图像比较按原始比例显示
// 先尝试以窗口之宽度作为图片宽度,按比例绘制图片
int fitW = width;
int fitH = width * imgH / imgW;
if( fitH > height )
{
// 若图片高度fitH超出宽度高度,就以窗口高度为图片高度,按比例绘制图片
fitH = height;
fitW = height * imgW / imgH;
}
// 绘制图片
int fitX = (width - fitW ) /2;
int fitY = (height - fitH ) /2;
g.drawImage(image, fitX, fitY, fitW, fitH, null);
}
}
}
使用:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import af.swing.PictureView;
public class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
// 使用 MyControl
PictureView c = new PictureView();
this.setContentPane( c );
// 设置背景色
c.setBackgroundColor( Color.YELLOW );
// 设置要显示的图片
try
{
Image image = ImageIO.read( new File("data/1.jpg"));
c.setImage( image );
} catch (IOException e)
{
e.printStackTrace();
}
}
}
测试运行:
public class MyDemo
{
public static void main(String[] args)
{
JFrame frame = new MyFrame("Swing Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setVisible(true);
}
}
增加边框
Rectangle 矩形相关 API ,
Rectangle rect = new Rectangle( 0, 0, width, height);
rect.x / rect.y 矩形左上角坐标
rect.width / rect.height 矩形的宽度、高度
rect.grow ( h, v ) 向外扩展h、v个像素 。当h、v小于0时,表示收缩。
在PictureView中改造代码为:
public class PictureView extends JPanel
{
// 要显示的图片,默认为 null
private Image image;
// 背景色,默认为 null
private Color bgColor;
public PictureView()
{
}
public void setBackgroundColor( Color color)
{
this.bgColor = color;
this.repaint(); // 重新绘制这个控件
}
public void setImage (Image image)
{
this.image = image;
this.repaint(); // 重新绘制这个控件
}
@Override
protected void paintComponent(Graphics g)
{
// TODO Auto-generated method stub
super.paintComponent(g);
// 设置白色背景
int width = getWidth();
int height = getHeight();
if( bgColor != null)
{
g.setColor( bgColor );
g.fillRect(0, 0, width, height);
}
if ( true )
{
g.setColor( new Color (0x404040));
g.drawRect(0, 0, width-1, height-1);
}
if( image != null)
{
// 获取图像的大小
int imgW = image.getWidth( null );
int imgH = image.getHeight( null );
// ( fitW, fitH ) : 要求保持长宽比,并且在目标矩形之内
// 1:图像不能超出控制范围
// 2:图像比较按原始比例显示
Rectangle rect = new Rectangle(0, 0, width, height);
rect.grow( -2, -2); // 设置图片往里收缩了2个像素
// 调用 fitCenter() 进行适配,返回目标矩形
Rectangle fit = fitCenter( rect, imgW, imgH);
g.drawImage(image, fit.x, fit.y, fit.width, fit.height, null);
}
}
// 抽取方法
private Rectangle fitCenter(Rectangle rect, int imgW, int imgH)
{
// 先尝试以窗口之宽度作为图片宽度,按比例绘制图片
int fitW = rect.width;
int fitH = rect.width * imgH / imgW;
if( fitH > rect.height )
{
// 若图片高度fitH超出宽度高度,就以窗口高度为图片高度,按比例绘制图片
fitH = rect.height;
fitW = rect.height * imgW / imgH;
}
// 绘制图片
int fitX = rect.x + (rect.width - fitW ) /2;
int fitY = rect.y + (rect.height - fitH ) /2;
return new Rectangle(fitX, fitY, fitW, fitH);
}
}
图标
图标 Icon,一般是较小的正方形图片、PNG格式
可以自行制作,或者从网站上获取
例如,iconfont.cn 这图标网站
使用 PictureView 显示图标,
Image icon = ImageIO.read ( ... )
c.setImage ( icon )
资源文件加载
资源 Resource ,指放在 src 下发布的文件。
步骤:
添加资源文件到 src 目录,
-
在 src 添加一个包 res
-
把 png 图片拷贝到 res 下
注意,bin\ 和 src\ 目录是同步的,Eclipse会自动拷贝一份到bin\下
资源的路径,
"/res/like.png"
读取资源,
InputStream res = this.getClass().getResourceAsStream("/res/like.png")
加载资源为图片,
Image image = ImageIO.read ( res )
语法分析:
1 this.getClass() 比较难,在 反射与框架原理 中介绍
2 ImageIO.read() 接收 InputStream 作为参数,读取图片文件
程序运行时,实际读取的是 bin\ 下面的资源文件
( 资源文件、程序文件是一同发布的)
优化 PictureView:
优化 PictureView ,添加对本地文件和资源文件支持
PictureView.setImage ( File file)
PictureView.setImage ( String resourcePath )
5、鼠标事件
鼠标事件,使用三类监听器,
1 addMouseListener()
点击、按下、抬起、移入、移出
2 addMouseMotionListener()
移动、拖动
3 addMouseWheelListener()
鼠标滚轮转动
支持以下鼠标动作,
鼠标点击 mouseClicked
鼠标按下 mousePressed 鼠标抬起 mouseReleased
鼠标移入 mouseEntered 鼠标移出 mouseExited
鼠标移动 mouseMoved 鼠标拖动 mouseDragged
鼠标滚轮 mouseWheelMoved
鼠标事件是基础事件,所有控件都支持 ( JButton, JLabel, JPanel ...)
自定义的控件也是支持的
演示:给 JPanel 添加鼠标事件处理。。mousePressed
MouseEvent 代表一个鼠标事件,
-
getPoint() / getX() / getY() : 点击的坐标(相对于该控件)
-
getPointOnScreen()/ getXOnScreen() / getYOnScreen() :屏幕坐标
-
getSource() : 事件源,即点中的控件
-
getButton() : 左键、中键、右键
-
getClickCount() : 单击、双击、三击 (就是鼠标点的时候是单机、双击还是三击)
新建MouseAdapter ,对鼠标事件进行遮蔽,用于简化代码
鼠标点击事件
鼠标点击相关的事件,
-
mousePressed() 鼠标按下
-
mouseReleased() 鼠标抬起
-
mouseClicked() 鼠标点击
其中,mouseClicked() 是指鼠标按下,并且原地抬起
MouseListener 与 ActionListener :
-
MouseListener 低级事件
-
ActionListener 高级事件
其实对于 JButton ,也可以使用 MouseListener
鼠标移入移出
鼠标移入移出,
-
mouseEntered ( )
-
mouseExited ( )
演示:当鼠标移入时,控件以高亮效果显示
语法分析:
可以在控件类的内部,给自己添加一个监听器
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JPanel;
public class MyControl extends JPanel
{
// hOver ,标识当前的状态。hOver为true表示高亮状态
private boolean hOver = false;
public MyControl()
{
// 注册一个监听器
this.addMouseListener( new MyMouseListener() );
}
@Override
protected void paintComponent(Graphics g)
{
// TODO Auto-generated method stub
super.paintComponent(g);
//
int width = this.getWidth();
int height = this.getHeight();
g.setColor( new Color(0xFFFFF0));
g.fillRect(0, 0, width, height);
// 绘制边框
if(hOver)
{
g.setColor( Color.RED );
g.drawRect(0, 0, width-1, height-1);
}
else
{
g.setColor( new Color(0x555555));
g.drawRect(0, 0, width-1, height-1);
}
}
//
private class MyMouseListener extends MouseAdapter
{
@Override
public void mouseEntered(MouseEvent e)
{
System.out.println("** mouseEntered() ..");
hOver = true;
repaint();
}
@Override
public void mouseExited(MouseEvent e)
{
System.out.println("** mouseExited() ..");
hOver = false;
repaint();
}
}
}
鼠标移动事件
鼠标移动事件 MouseMotionListener
-
mouseMoved() 鼠标移动
-
mouseDragged() 鼠标按住并移动
注意,是addMouseMotionListener ,不是addMouseListener
练习 手绘曲线
练习,实现手绘功能,手工绘制曲线
设计思路:记录鼠标移动的轨迹点,连接而成
1 MyMouseListener 既是MouseListener,又是MouseMotionListener
MyMouseListener l = new MyMouseListener();
this.addMouseListener(l);
this.addMouseMotionListener(l);
package my;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
public class HandDraw extends JPanel
{
// 当鼠标按下时,记 pressed为 true
private boolean pressed = false;
// java.util.List
// java.awt.Point
// 存储当前曲线上的所有轨迹点
private List<Point> points = new ArrayList<>();
public HandDraw()
{
MyMouseListener l = new MyMouseListener();
this.addMouseListener(l);
this.addMouseMotionListener(l);
}
@Override
protected void paintComponent(Graphics g)
{
// TODO Auto-generated method stub
super.paintComponent(g);
//
int width = this.getWidth();
int height = this.getHeight();
g.setColor( new Color(0xFFFFF0));
g.fillRect(0, 0, width, height);
g.setColor( new Color(0x555555));
g.drawRect(0, 0, width-1, height-1);
//
if ( points.size() >= 2 )
{
// 设置线条的颜色
g.setColor( Color.RED );
// 开始绘制,每个点连接在一起,形成曲线
Point p1 = points.get(0);
// for循环从1开始
for(int i=1; i< points.size(); i++)
{
Point p2 = points.get(i);
g.drawLine(p1.x, p1.y , p2.x, p2.y);
p1 = p2;
}
}
}
//
private class MyMouseListener extends MouseAdapter
{
@Override
public void mousePressed(MouseEvent e)
{
// 鼠标按下,记 pressed为true
pressed = true;
points.clear(); // 开始的时间,清空原来的数据
points.add( e.getPoint() ); // 记录鼠标的坐标
}
@Override
public void mouseReleased(MouseEvent e)
{
// 鼠标松开,记 pressed为false
pressed = false;
}
@Override
public void mouseDragged(MouseEvent e)
{
if( pressed )
{
points.add( e.getPoint() );// 记录鼠标的坐标
repaint(); // 重新绘制一次
}
}
}
}
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
JPanel root = new JPanel();
this.setContentPane( root );
// 使用 MyControl
HandDraw c = new HandDraw();
root.add( c );
c.setPreferredSize(new Dimension(180, 180));
}
}
运行
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class MyDemo
{
public static void main(String[] args)
{
JFrame frame = new MyFrame("Swing Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setVisible(true);
}
}
练习 自由手绘优化
优化HandDraw即可:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
public class HandDraw extends JPanel
{
// 当鼠标按下时,记 pressed为 true
private boolean pressed = false;
// 存储所有的曲线
private List<Curve> curveList = new ArrayList<>();
public HandDraw()
{
MyMouseListener l = new MyMouseListener();
this.addMouseListener(l);
this.addMouseMotionListener(l);
}
@Override
protected void paintComponent(Graphics g)
{
// TODO Auto-generated method stub
super.paintComponent(g);
//
int width = this.getWidth();
int height = this.getHeight();
g.setColor( new Color(0xFFFFF0));
g.fillRect(0, 0, width, height);
g.setColor( new Color(0x555555));
g.drawRect(0, 0, width-1, height-1);
//
for( Curve curve : curveList )
{
List<Point> points = curve.points;
if ( points.size() >= 2 )
{
// 设置线条的颜色
g.setColor( Color.RED );
// 开始绘制,每个点连接在一起,形成曲线
Point p1 = points.get(0);
// for循环从1开始
for(int i=1; i< points.size(); i++)
{
Point p2 = points.get(i);
g.drawLine(p1.x, p1.y , p2.x, p2.y);
p1 = p2;
}
}
}
}
//
private class MyMouseListener extends MouseAdapter
{
@Override
public void mousePressed(MouseEvent e)
{
// 鼠标按下,记 pressed为true
pressed = true;
// 创建一条新的曲线(笔划)
Curve curve = new Curve();
curveList.add( curve);
curve.points.add( e.getPoint() ); // 记录鼠标的坐标
}
@Override
public void mouseReleased(MouseEvent e)
{
// 鼠标松开,记 pressed为false
pressed = false;
}
@Override
public void mouseDragged(MouseEvent e)
{
if( pressed )
{
// 当前的笔划
Curve curve = curveList.get( curveList.size()-1);
// 记录鼠标的坐标
curve.points.add( e.getPoint() );
// 重新绘制一次
repaint();
}
}
}
// 静态内部类
// Curve代表一条曲线
private static class Curve
{
// 曲线中的所有的轨迹点
public List<Point> points = new ArrayList<>();
}
}
6、边框与边距
6.1、添加边框
添加边框,
Border border1 = new LineBorder(Color.BLUE, 4);
a1.setBorder(border1);
其中,Border是接口,LineBorder是具体的实现类
另一种写法,
Border border2 = BorderFactory.createLineBorder(Color.RED, 4);
a2.setBorder(border2);
其中,BorderFactory 里封装了很多工具方法 (static ) ,用于创建各式边框
所有的 JComponent ,都支持 Border
JComponent.setBorder()
例如,JButton、JLabel、JTextField、JPanel ....
public class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
JPanel root = new JPanel();
this.setContentPane( root );
ColorLabel a1 = new ColorLabel("1", Color.YELLOW);
ColorLabel a2 = new ColorLabel("2", Color.CYAN);
root.add(a1);
root.add(a2);
// LineBorder,实现了 Border 接口
Border border1 = new LineBorder(Color.BLUE, 4);
a1.setBorder(border1);
// BorderFactory里封装了一些工具方法,用来创建各式边框
Border border2 = BorderFactory.createLineBorder(Color.RED, 4);
a2.setBorder(border2);
}
}
6.2、边框样式
Swing 中内置了各种样式的边框
javax.swing.border.*
其中,定义了 Border 接口,以及具体的实现类
BorderFactory 类中封装了各式的工具方法
演示:。。
常用的有,createLineBorder() / createMatteBorder ()
边框的组合,
Border border1 = ...
Border border2 = ...
Border bbb = BorderFactory.createCompoundBorder(border1, border2);
public class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
JPanel root = new JPanel();
this.setContentPane( root );
ColorLabel a1 = new ColorLabel("1", Color.YELLOW);
ColorLabel a2 = new ColorLabel("2", Color.CYAN);
ColorLabel a3 = new ColorLabel("3", new Color(0xCCCCCC));
ColorLabel a4 = new ColorLabel("4", new Color(0xCCCCCC));
root.add(a1);
root.add(a2);
root.add(a3);
root.add(a4);
// 1 线条边框
Border border1 = BorderFactory.createLineBorder(Color.RED, 4);
a1.setBorder(border1);
// 虚线框 , 实线4像素,间隔2像素
// a1.setBorder(BorderFactory.createDashedBorder(Color.RED, 4, 2));
// 2 按 上、左、下、右单独指定每一条边框
Border border2 = BorderFactory.createMatteBorder(0, 0, 4, 0,Color.DARK_GRAY);
a2.setBorder(border2);
// 3D立体边框 createRaisedBevelBorder / createLoweredBevelBorder
Border border3 = BorderFactory.createRaisedBevelBorder();
a3.setBorder(border3);
Border border4 = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);
a4.setBorder(border4);
// Border bbb = BorderFactory.createCompoundBorder(border1, border2);
// a4.setBorder(bbb);
}
}
6.3、边框与边距
在布局中,应该考虑边框的影响
例如,子控件不应压到边框上。
在布局计算中,考虑容器自身的边框宽度
Insets insets = parent.getInsets() // 可以获取容器的边框大小
HLayout, VLayout, FreeLayout 。
@Override
public void layoutContainer(Container parent)
{
int width = parent.getWidth();
int height = parent.getHeight();
Insets insets = parent.getInsets();
System.out.println("insets=" + insets);
// 控件的建议尺寸 PreferredSize
Dimension p_size = a1.getPreferredSize();
// 将控件布局在右上角
a1.setLocation( width-p_size.width - insets.right, insets.top );
a1.setSize( p_size);
}
6.4、空白边框
空白边框 EmptyBorder,一般用作内边距的设置
例如,
root.setBorder(BorderFactory.createEmptyBorder(6,6,6,6));
LayoutBox
af.swing.LayoutBox ,一个用于快速布局的工具类
LayoutBox box = new LayoutBox();
// 设置内边距
box.padding(10);
// 设置背景色
box.bgColor( new Color(0xF1F1F1));
// 设置布局器
box.layout( new VLayout(4));
练习,界面布局训练,做一个登录界面
LayoutBox
HLayout、VLayout、FreeLayout
总结:
1 布局是可以嵌套的,在 JPanel里还可以添加子Panel
2 自定义技术,是GUI界面开发的灵魂。
7、对话框.
7.1、JOptionPane 消息框
JOptionPane ,自带的消息提示框
-
JOptionPane.showMessageDialog () ,消息提示框
-
JOptionPane.showConfirmDialog() ,确认提示框
-
JOptionPane.showInputDialog() ,输入提示框
其中,show*() 均为工具方法 ,即静态方法 ( static )
当对话框窗口显示时,主窗口是 阻塞 的。
1 主窗口中不可输入
2 单步调试时,show方法阻塞,直到对话框关闭时才会返回
7.2、文件选择框
JFileChooser 文件选择框,用于选择一个文件/目录
- showOpenDialog ( )
当需要打开一个文件时调用
- showSaveDialog ()
当需要保存一个文件时调用
- showOpenDialog () / DIRECTORIES_ONLY
当需要选择一个目录时调用
JFileChooser 的使用:
1 显示对话框 showOpenDialog() / showSaveDialog()
2 判断返回值
APPROVE_OPTION ,用户确认了选择
CANCEL_OPTION , 用户取消了操作
3 取得文件路径
File file = chooser.getSelectedFile()
FileNameExtensionFilter ,在打开文件时,对文件后缀过滤
注意,它使用了 省略号参数
package my;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.filechooser.FileNameExtensionFilter;
public class MyFrame extends JFrame
{
JTextField textField = new JTextField(20);
JButton button = new JButton("测试");
public MyFrame(String title)
{
super(title);
JPanel root = new JPanel();
this.setContentPane(root);
root.add(textField);
root.add(button);
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e)
{
test3();
}
});
}
// 选择打开文件
private void test1()
{
JFileChooser chooser = new JFileChooser();
//FileNameExtensionFilter: 文件名后缀过滤器
FileNameExtensionFilter filter = new FileNameExtensionFilter("图片文件", "jpg", "jpeg", "png","tif");
chooser.setFileFilter(filter);
// 显示对话框
int ret = chooser.showOpenDialog(this);
// 获取用户选择的结果
// APPROVE_OPTION表示用户确认了选择, CANCEL_OPTION表示取消了操作
if (ret == JFileChooser.APPROVE_OPTION)
{
// 结果为:已经存在的一个文件
File file = chooser.getSelectedFile();
textField.setText(file.getAbsolutePath());
}
}
// 选择保存文件
private void test2()
{
JFileChooser chooser = new JFileChooser();
//FileNameExtensionFilter: 文件名后缀过滤器
FileNameExtensionFilter filter = new FileNameExtensionFilter("XML文件", "xml");
chooser.setFileFilter(filter);
// 显示对话框 showSaveDialog
int ret = chooser.showSaveDialog(this);
// 获取用户选择的结果
if (ret == JFileChooser.APPROVE_OPTION)
{
// 结果为:用户要保存的文件的路径
File file = chooser.getSelectedFile();
textField.setText(file.getAbsolutePath());
}
}
// 选择目录
private void test3()
{
JFileChooser chooser = new JFileChooser();
// 设置模式:仅选择目录
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
// 显示对话框
int ret = chooser.showOpenDialog(this);
// 获取用户选择的结果
if (ret == JFileChooser.APPROVE_OPTION)
{
// 结果为: 已经存在的一个目录
File dir = chooser.getSelectedFile();
textField.setText(dir.getAbsolutePath());
}
}
}
测试:
public class MyDemo
{
public static void main(String[] args)
{
JFrame frame = new MyFrame("Swing Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setVisible(true);
}
}
练习 涂鸦保存
练习:实现 涂鸦 ,并可以 保存为JPG 文件
涂鸦功用,源于第11章的实例
package my;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
public class HandDraw extends JPanel
{
// 当鼠标按下时,记 pressed为 true
private boolean pressed = false;
// 存储所有的曲线
private List<Curve> curveList = new ArrayList<>();
public HandDraw()
{
MyMouseListener l = new MyMouseListener();
this.addMouseListener(l);
this.addMouseMotionListener(l);
}
public void clear()
{
curveList.clear();
repaint();
}
@Override
protected void paintComponent(Graphics g)
{
// TODO Auto-generated method stub
super.paintComponent(g);
//
int width = this.getWidth();
int height = this.getHeight();
g.setColor( new Color(0xFFFFF0));
g.fillRect(0, 0, width, height);
g.setColor( new Color(0x555555));
g.drawRect(0, 0, width-1, height-1);
//
for( Curve curve : curveList )
{
List<Point> points = curve.points;
if ( points.size() >= 2 )
{
// 设置线条的颜色
g.setColor( Color.RED );
// 开始绘制,每个点连接在一起,形成曲线
Point p1 = points.get(0);
// for循环从1开始
for(int i=1; i< points.size(); i++)
{
Point p2 = points.get(i);
g.drawLine(p1.x, p1.y , p2.x, p2.y);
p1 = p2;
}
}
}
}
//
private class MyMouseListener extends MouseAdapter
{
@Override
public void mousePressed(MouseEvent e)
{
// 鼠标按下,记 pressed为true
pressed = true;
// 创建一条新的曲线(笔划)
Curve curve = new Curve();
curveList.add( curve);
curve.points.add( e.getPoint() ); // 记录鼠标的坐标
}
@Override
public void mouseReleased(MouseEvent e)
{
// 鼠标松开,记 pressed为false
pressed = false;
}
@Override
public void mouseDragged(MouseEvent e)
{
if( pressed )
{
// 当前的笔划
Curve curve = curveList.get( curveList.size()-1);
// 记录鼠标的坐标
curve.points.add( e.getPoint() );
// 重新绘制一次
repaint();
}
}
}
// 静态内部类
// Curve代表一条曲线
private static class Curve
{
// 曲线中的所有的轨迹点
public List<Point> points = new ArrayList<>();
}
}
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.filechooser.FileNameExtensionFilter;
public class MyFrame extends JFrame
{
JButton saveButton = new JButton("保存");
HandDraw canvas = new HandDraw();
public MyFrame(String title)
{
super("涂鸦");
JPanel root = new JPanel();
this.setContentPane(root);
root.setLayout( new BorderLayout());
// 工具栏
JPanel topPanel = new JPanel();
root.add( topPanel, BorderLayout.NORTH);
// 涂鸦面板
root.add( canvas, BorderLayout.CENTER);
// 保存按钮
topPanel.add( saveButton );
saveButton.addActionListener( new ActionListener() {
@Override
public void actionPerformed(ActionEvent e)
{
doSave();
}
});
}
private void doSave()
{
// File file = new File("123.jpg");
// Util.snapshot( canvas, file);
JFileChooser chooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter("图片文件", "jpg");
chooser.setFileFilter(filter);
// 显示对话框
int ret = chooser.showSaveDialog(this);
if (ret == JFileChooser.APPROVE_OPTION)
{
File file = chooser.getSelectedFile();
Util.snapshot( canvas, file);
}
}
}
import java.awt.Component;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Util
{
/** 窗口截图 : 将窗口/控件截图,并保存为JPG图片
*
*
* comp, 目标窗口/控件
* file, 文件路径, 必须为 jpg 或 png 格式
*/
public static void snapshot ( Component comp, File file )
{
// 具体功能实现,请参考 《Swing高级篇》中的说明
// 创建一个 Image
int width = comp.getWidth();
int height = comp.getHeight();
BufferedImage image = new BufferedImage(width,height, BufferedImage.TYPE_3BYTE_BGR);
// 将控件打印到 Image 上
Graphics g = image.getGraphics();
comp.paint(g);
try
{
// 将 Image 保存为文件
ImageIO.write(image, "JPEG", file);
} catch (IOException e)
{
throw new RuntimeException( e);
}
}
}
8、自定义对话框
JDialog ,代表一个对话框窗口
class SimpleDialog extends JDialog {
}
和 JFrame 用法类似,在构造方法里作界面布局
JDialog 在构造时,需要一个 owner 属主
即,它是从哪个窗口跳出来的。
public SimpleDialog ( Window **owner** ) {
super( owner);
}
其中,Window 是 JFrame、JDialog 等的基类型
创建对话框并显示,
SimpleDialog dlg = new SimpleDialog( **this** );
dlg.setTitle("提示");
dlg.setModal ( true ); // 模态的 ( 即:阻塞模式 )
dlg.setSize(200, 100);
dlg.setVisible( true ); // 显示对话框,并阻塞
Modal 模态的,即以阻塞方式显示
-
1 界面上的阻塞
对话框显示时,后面的窗口owner 失去输入焦点
-
2 程序上的阻塞
dlg.setVisible() 一直运行,直到对话框被关闭
获取用户输入
public class SimpleDialog extends JDialog
{
JTextField userInput = new JTextField(10);
public SimpleDialog( Window owner )
{
// 调用父类的构造方法,进行初始化
super ( owner );
//
JPanel root = new JPanel();
this.setContentPane( root );
//
JLabel label = new JLabel("请输入");
root.add( label );
// 1 在对话框里,添加一个文本框
root.add(userInput);
}
//2 当对话框时,获取用户的输入
public String getValue()
{
String str = userInput.getText();
return str;
}
}
确定或取消
import java.awt.BorderLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class SimpleDialog extends JDialog
{
JTextField userInput = new JTextField(10);
JButton okButton = new JButton("确定");
JButton cancelButton = new JButton("取消");
// 确定、取消 的标识
public boolean accepted = false;
public SimpleDialog( Window owner )
{
// 调用父类的构造方法,进行初始化
super ( owner );
//
JPanel root = new JPanel();
this.setContentPane( root );
root.setLayout( new BorderLayout());
if( true ) {
JPanel panel = new JPanel();
root.add(panel, BorderLayout.CENTER);
//
JLabel label = new JLabel("请输入");
panel.add( label );
//
panel.add(userInput);
}
// 底部,添加 确定 和 取消 按钮
if(true) {
JPanel panel = new JPanel();
root.add(panel, BorderLayout.SOUTH);
panel.add( okButton);
panel.add( cancelButton );
}
// 点‘确定'按钮时
okButton.addActionListener( new ActionListener() {
@Override
public void actionPerformed(ActionEvent e)
{
accepted = true;
setVisible ( false ); // 关闭对话框
}
});
// 点’取消'按钮时
cancelButton.addActionListener( new ActionListener() {
@Override
public void actionPerformed(ActionEvent e)
{
accepted = false;
setVisible ( false ); // 关闭对话框
}
});
}
public String getValue()
{
String str = userInput.getText();
return str;
}
}
对话框显示位置调整
对话框的显示位置 ,
-
centerInOwner() 显示在原窗口的中央
-
centerInScreen() 显示在屏幕的中央
注意,这一行应该放在 setVisible() 之前、setSize() 之后
认识Component
查看 JFrame 的继承树,
JFrame 》 Window 》 Component
查看 JFrame 的继承树,
JDialog 》 Window 》 Component
查看 JButton 的继承树,
JButton 》 JComponent 》 Component
获取一个控件所在的窗口,以下两个方法均可(功能一样):
Window win = SwingUtilities.windowForComponent( comp );
或者
Window win = SwingUtilities.getWindowAncestor(comp);
其中,comp 代表一个控件。
9、右键菜单
JPopupMenu ,右键菜单,或上下文菜单
1 响应鼠标右键的点击
2 弹出菜单
-
创建 JPopupMenu 菜单
-
添加 JMenuItem 菜单项
-
弹出菜单窗口 popup.show(..)
其中,popup.show( invoker, x, y )
invoker ,触发菜单的原控件
x , y 鼠标点击位置,相对坐标
一个控件可以添加多个鼠标监听器,依次执行
comp.addMouseListener( ... )
comp.addMouseListener( ... )
菜单事件处理
菜单处理:选中一个菜单项时,执行相应的处理
JMenuItem
item.addActionListener(listener) 添加监听器
item.setActionCommand("save as") 添加命令码
一个监听器,可以同时监听多个菜单项。用不同的命令码区分,
public void actionPerformed(ActionEvent e) {
String cmd = e.**getActionCommand**();
if(cmd.equals("save as")) {
}
}
右键菜单的美化,即自定义的右键菜单,参考Swing高级篇