swing

起跑线小言發表於2024-09-02

數學教材推薦:

中學PDF課本介紹和下載:https://www.zhihu.com/question/517213170/answer/3430923272

swing

swing基礎

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<>();
	}
}

相關文章