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高级篇

1725187795015

几点细节

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高级篇

posted @ 2024-09-02 23:07  起跑线小言  阅读(28)  评论(0编辑  收藏  举报