1. 程式人生 > >Java筆記(10)-圖形介面設計、Swing、視窗、JFrame、常用元件和佈局、處理事件、MVC結構、對話方塊、GUI

Java筆記(10)-圖形介面設計、Swing、視窗、JFrame、常用元件和佈局、處理事件、MVC結構、對話方塊、GUI

我希望有個如你一般的人
如山間清爽的風
如古城溫暖的光
只要最後是你就好

今天 你路過了誰
誰又丟失了你呢
或者
從你的全世界路過

圖形介面設計

1 Java Swing 概述

圖形化介面(Graphics User Interface,GUI)是指採用圖形方式顯示的計算機操作使用者介面。

通過圖形化介面,使用者和程式之間可以方便地進行互動。Java的抽象視窗工具包(Abstract Window Toolkit,AWT)提供許多用來設計GUI的元件類。

java.awtjavax.swing 包中一部分類的層次關係UML類圖。

UML圖

GUI元件按其作用可分為基本元件(Component)

和容器(Container)兩大類:GUI基本元件,其上不能容納其他元件,如按鈕、文字框等圖形介面元素。容器是一種特殊的元件,可以用來容納其他的元件,如視窗、對話方塊等。

如果我們要在一個視窗中顯示按鈕、文字框等,需要將這些元件放到一個容器中。在java.awt中主要有兩個容器類Window類、Panel類和Applet類。但是Panel類必須放到Frame頂級容器中,一般不獨立使用。同樣我們也可以把Panel類和它的子類理解為一種中間容器,元件可以放到這個中間容器中,也可以放到頂級容器中。

容器和元件的概念與Android中的UI元件非常相似,View元件一定要依附在ViewGroup這個容器之下,此外,因為ViewGroup繼承自View,ViewGroup也可以當做View元件使用。

這裡寫圖片描述
        Android的圖形使用者介面元件層次

2 視窗

一個基於GUI的應用程式應當提供一個能直接和作業系統直接互動的容器,該容器可以被直接顯示、繪製在作業系統所控制的平臺上,如顯示器上,這樣的容器被稱作GUI設計中的底層容器。
JFrame類的例項就是一個底層容器,即通常稱的視窗。其他容器必須被新增到底層容器中,以便藉助這個底層容器和作業系統進行資訊互動。

2.1 JFrame常用方法

JFrame() 建立一個無標題的視窗

JFrame(String s) 建立標題為s的視窗

public void setVisible(boolean b) 設定視窗是否可見,視窗預設不可見

public
void dispose() 撤銷當前的視窗,並釋放當前視窗所使用的資源 public void setDefaultCloseOperation(int operation) 設定單擊窗體右上角關閉圖示後,程式會做出怎樣的處理 WindowConstants.DISPOSE_ON_CLOSE 隱藏當前的視窗,並釋放窗體佔有的其他資源 WindowConstants.DO_NOTHING_ON_CLOSE 什麼也不做 WindowConstants.HIDE_ON_CLOSE 隱藏當前視窗 WindowConstants.EXIT_ON_CLOSE 結束視窗所在的應用程式

示例-JFrame建立兩個視窗

用JFrame建立兩個視窗
結果:
這裡寫圖片描述

import javax.swing.JFrame;
import javax.swing.WindowConstants;

public class Windows {
    public static void main(String[] args) {
        JFrame window1 = new JFrame("撤銷視窗"); //建立標題名
        JFrame window2 = new JFrame("退出程式");
        window1.setBounds(0,0,400,200);// 顯示X軸位置,顯示Y軸位置 ,寬,長
        window2.setBounds(400,0,400,200);
        window1.setVisible(true); // 視窗預設是不可見的
        window1.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        //設定單擊窗體右上角關閉圖示後,程式會做出怎樣的處理。
        window2.setVisible(true);
        window2.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
}

2.2 選單條、選單、選單項

視窗中的選單條、選單、選單項是我們所熟悉的元件,選單放在選單條裡,選單項放在選單中。

  • 選單條
    JComponent類的子類 JMenubar 負責建立選單條,即JMenubar 的一個例項就是一個選單條,JFrame類用一個把選單條放到視窗的方法:

    setJMenuBar( JMenuBar bar);

    該方法將選單條新增到視窗的頂端,需要注意的是,只能向視窗新增一個選單條。

  • 選單
    JComponent類的子類JMenu負責建立選單,即JMenu的一個例項就是一個選單。

  • 選單項
    JComponent類的子類JMenuItem負責建立選單項,即JMenuItem的一個例項就是一個選單項
 JMenuItem(String text, Icon icon) 
  • 嵌入子選單
    JMenuJMenuItem的子類,因此選單本身也是一個選單項,當把一個選單看作選單項新增到摸個選單中時,稱這個選單為子選單。

  • 選單上的圖示
    可以用 圖示類Icon宣告一個圖示,使用ImageIcon類建立一個圖示。

Icon icon = new ImageIcon("a.png");

然後選單項呼叫setIcon(Icon icon)設定圖示

示例-帶選單的視窗

帶選單的視窗圖片

圖片資源a.png、b.png、c.png、d.png存放到專案目錄下

Main.java

public class Main {
    public static void main(String[] args) {
        WindowMenu win = new WindowMenu("帶視窗的選單", 20, 30, 400, 500);
    }
}

WindowMenu.java

import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;

/**
 * 自定義視窗WindowMenu
 * @author Peng
 */
public class WindowMenu extends JFrame {
    JMenuBar menubar;
    JMenu menu, subMenu;
    JMenuItem item1, item2;

    public WindowMenu() {
    }

    public WindowMenu(String s, int x, int y, int w, int h) {
        init(s);
        setLocation(x, y);
        setSize(w, h);
        setVisible(true);
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    }

    void init(String s) {
        setTitle(s);
        menubar = new JMenuBar();
        menu = new JMenu("選單"); // JMnud的例項就是一個選單

        /**
         * 一級選單項
         */
        subMenu = new JMenu("軟體專案"); // 子選單
        item1 = new JMenuItem("Java話題"); // 建立選單項
        //為選單項設定圖示
        ImageIcon icon = new ImageIcon("a.png");
        item1.setIcon(icon);

        //使用JMenuItem的構造方法設定圖示
        item2 = new JMenuItem("動畫話題", new ImageIcon("b.png"));
        item1.setAccelerator(KeyStroke.getKeyStroke('A'));
        item2.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK));
        menu.add(item1);
        menu.addSeparator();
        menu.add(item2);
        menu.add(subMenu);
        /**
         * 新增二級選單項
         */
        subMenu.add(new JMenuItem("汽車銷售系統", new ImageIcon("c.png")));
        subMenu.add(new JMenuItem("農場資訊系統", new ImageIcon("d.png")));
        menubar.add(menu); // 選單條中加入選單
        setJMenuBar(menubar); // 新增一個選單條

    }
}

3 常用元件與佈局

3.1 常見元件

  • 文字框
    使用JComponent的子類JTextField建立文字框。文字框的允許使用者輸入單行文字。

  • 文字區
    使用JComponent的子類JButton類建立按鈕,允許使用者單擊按鈕。

  • 標籤
    使用JComponent的子類JLabel類建立標籤,標籤為使用者提供資訊提示。

  • 選擇框
    使用JComponent的子類JCheckBox類來建立選擇框,為使用者提供多項懸著。選擇框提供兩種狀態,選中和未選中,使用者通過單擊該元件切換狀態。

  • 單選按鈕
    使用JComponent的子類的JRadioButton類建立單項選擇框,為使用者提供單項選擇。

  • 下拉列表
    使用JComponent的子類的JComboBox類來建立下拉列表,為使用者提供下拉列表。

  • 密碼框
    使用JComponent的子類的子類JPasswordField建立密碼框,允許輸入單行密碼,密碼框預設回顯字元是“*”,也可以通過setEchoChar(char c)來重新設定回顯字元。密碼框呼叫char[] getPassword()方法可以返回實際的密碼。

示例 -常見元件

效果圖:

這裡寫圖片描述

Main.java

public class Main {
    public static void main(String[] args) {
        ComponentInWindow win = new ComponentInWindow();
        win.setBounds(100, 100, 320, 310);
        win.setTitle("常用元件");
    }
}

ComponentInWindow.java

import java.awt.FlowLayout;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPasswordField;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class ComponentInWindow extends JFrame {

    JTextField text;
    JButton button;
    JCheckBox checkBox1, checkBox2, checkBox3;
    JRadioButton radio1, radio2;
    ButtonGroup group;
    JComboBox<Object> comBox;
    JTextArea area;
    JPasswordField password;

    public ComponentInWindow() {
        init();
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    void init() {
        setLayout(new FlowLayout()); // 設定佈局

        add(new JLabel("文字框:"));
        text = new JTextField(10);
        add(text);

        add(new JLabel("按鈕:"));
        button = new JButton("確認");
        add(button);

        add(new JLabel("密碼框:"));
        password = new JPasswordField(10);
        add(password);

        add(new JLabel("按鈕:"));
        button = new JButton("確認");
        add(button);

        add(new JLabel("選擇框:"));
        checkBox1 = new JCheckBox("喜歡音樂");
        checkBox2 = new JCheckBox("喜歡旅遊");
        checkBox3 = new JCheckBox("喜歡籃球");
        add(checkBox1);
        add(checkBox2);
        add(checkBox3);

        add(new JLabel("單選按鈕:"));
        group = new ButtonGroup();
        radio1 = new JRadioButton("男");
        radio2 = new JRadioButton("女");
        group.add(radio1);
        group.add(radio2);
        add(radio1);
        add(radio2);

        add(new JLabel("下拉列表:"));
        comBox = new JComboBox<>();
        comBox.addItem("音樂天地");
        comBox.addItem("武術天地");
        comBox.addItem("象棋樂園");
        add(comBox);

        add(new JLabel("文字區"));
        area = new JTextArea(6, 13);// 文字區設定行數和列數
        add(new JScrollPane(area));
    }
}

3.2 常見容器

JComponent 是 Comtainer的 子類,因此 JComponent 的子類建立的元件也都是容器,但我們很少將 JButton、JTextField、JCheckBox 等元件當容器來使用。JComponent 專門提供了一些經常用來新增組建的容器。相對於底層容器 JFrame ,下面提到的容器被習慣地稱為中間容器,中間容器必須被新增到底層容器中才能發揮作用。

  • Jpanel面板
    我們會經常使用 JPanel 建立一個面板,再向這個面板新增元件,然後把這個面板新增到其他容器中。JPanel 面板的預設佈局是 FlowLayout 佈局。

  • 滾動窗格 JScrollPane

  • 拆分窗格 JSpitPane

  • 分層窗格 JLayeredPane

3.3 常用佈局

當把元件新增到容器中時,希望控制組件在容器中的位置,這就需要用到佈局設計。
容器可以使用方法設定自己的佈局。

setLayout(佈局物件);

設定自己的佈局。

  • FlowLayout 佈局
    FlowLayout 類建立的物件稱作 FlowLayout 型佈局。FlowLayout 型佈局是 JPanel 型佈局的預設佈局,即 JPanel 及其子類建立的容器物件,如果不專門指定佈局,則他們的佈局就是 FlowLayout 佈局。
FlowLayout flow = new FlowLayout(); // 居中對齊
容器.setLayout(flow);

or

setLayout(new FlowLayout());

通過add 方法將元件按先後順序,從左到右,預設水平和垂直間隙是 5 個畫素的方式排列。元件的大小為預設的最佳大小,例如,控制元件的大小剛好能保證顯示其上面的名字。

  • BorderLayout 佈局
  • CardLayout 佈局
  • GridLayout 佈局
  • BoxLayout 佈局
  • null 佈局

4 處理事件

處理元件的點選或者選擇事件。

4.1 事件處理模式

  • 事件源
    能夠產生處理了事件的物件都可以成為事件源,如文字框,按鈕,下拉式列表等。也就是說,事件源必須是一個物件,而且這個物件必須是Java認為能夠發生事件的物件。

  • 監視器
    我們需要一個物件對事件源進行監視,以便對發生的事件作出處理。事件源通過呼叫相應的方法將某個物件註冊為自己的監視器。例如,對於文字框,這個方法是:

addActionListener(監視器);

對於註冊監視器的文字框,在文字框獲得焦點後,當用戶對文字框進行操作,如按下回車鍵,Java 執行環境就會自動用 ActionEvent 類建立一個物件,觸發 ActionEvent 事件 。對文字框進行相應的操作就會導致相應的事件發生,並通知監視器,監視器就會做出相應的處理。

  • 處理事件的介面
    為了讓監視器這個物件能夠對事件源發生的事件進行處理,建立該檢視物件的類必須實現相應的介面,即必須在類體中重寫介面的所有方法,那麼當事件源發生事件是,監視器會自動呼叫類中被重寫的介面方法。

這裡寫圖片描述

4.2 ActionEvent 事件

  • ActionEvent 事件源
    文字框、按鈕、選單項、密碼框、和單選按鈕都可以觸發事件,都可以成為事件源。

  • 註冊監視器
    能觸發 ActionEvent 事件的元件,使用 addActionListener(ActionListener listen),將實現 ActionListener 介面的類的例項註冊為事件源的監視器。

  • ActionListener 介面
    ActionListener 介面位於 java.awt.event包中,該介面只有一個方法

public void actionPerformed(ActionEvent e)

在這裡執行想要的操作

  • ActionEvent 類中的方法
public Object getSourcee() 獲取事件源物件的引用,返回向上轉型為Object物件的應用

publi String getActionCommand() 獲取和事件發生的一個命令字串,例,文字框引發事件,文字框內的文字字串就是和該事件相關的一個命令字串。

示例-文字框監聽事件

在文字框內輸入檔名(預設目錄下要有檔案),回車後,通過BufferReader流讀出內容。

這裡寫圖片描述

這裡寫圖片描述

Main.java

public class Main {
    public static void main(String[] args) {
        WindowActionEvent win = new WindowActionEvent();
        win.setBounds(100,100,310,260);
        win.setTitle("處理ActionEvent事件");
    }
}

WindowActionEvent.java

import java.awt.FlowLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

import javax.swing.JFrame;
import javax.swing.JTextField;

public class WindowActionEvent extends JFrame {
    JTextField text;
    ReaderListen listener;

    public WindowActionEvent() throws HeadlessException {
        init();
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    void init() {
        setLayout(new FlowLayout());
        text = new JTextField(10);
        listener = new ReaderListen();
        text.addActionListener(listener);
        add(text);
    }
}

class ReaderListen implements ActionListener {

    @Override
    public void actionPerformed(ActionEvent e) {
        String fileName = e.getActionCommand();
        System.out.println(fileName + "內容如下:");
        try {
            File file = new File(fileName);
            FileReader inOne = new FileReader(file);// 在專案目錄下 自己把Main.java複製一份到專案目錄下
            BufferedReader inTwo = new BufferedReader(inOne);
            String s = null;
            while ((s = inTwo.readLine()) != null) {
                System.out.println(s);
            }
            inOne.close();
            inTwo.close();
        } catch (Exception e2) {
            e2.printStackTrace();
        }
    }
}

示例2-文字框、文字區框、按鈕的監聽事件

效果圖:

文字框、文字區框、按鈕的監聽事件

這裡寫圖片描述

Main.java

public class Main {
    public static void main(String[] args) {
        WindowActionEvent win = new WindowActionEvent();
        win.setBounds(100,100,360,300);
        win.setTitle("處理ActionEvent事件");
    }
}

WindowActionEvent.java

import java.awt.FlowLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class WindowActionEvent extends JFrame {
    JTextField text;
    JTextArea textShow;
    JButton button;
    ReaderListen listener;

    public WindowActionEvent() throws HeadlessException {
        init();
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    void init() {
        setLayout(new FlowLayout());
        text = new JTextField(10);
        button = new JButton("讀取");
        textShow = new JTextArea(9,30);
        listener = new ReaderListen();
        listener.setJTextField(text);
        listener.setJTextArea(textShow);
        text.addActionListener(listener);
        button.addActionListener(listener);
        add(text);
        add(button);
        add(new JScrollPane(textShow));
    }
}

class ReaderListen implements ActionListener {
    JTextField text;
    JTextArea textShow;

    public void setJTextField(JTextField text) {
        this.text = text;
    }



    public void setJTextArea(JTextArea textShow) {
        this.textShow = textShow;
    }


    @Override
    public void actionPerformed(ActionEvent e) {

        try {
            File file = new File(text.getText()); //getDocument()
            FileReader inOne = new FileReader(file);
            BufferedReader inTwo = new BufferedReader(inOne);
            String s = null;
            while ((s = inTwo.readLine()) != null) {
                textShow.append(s+"\n");
            }
            inOne.close();
            inTwo.close();
        } catch (Exception e2) {
            e2.printStackTrace();
        }

    }

}

4.3 ActionItem 事件

  • Item事件源
    選擇框和下拉列表都可以觸發 ItemEvent 事件。選擇框提供兩種狀態,一種是未選中,另一種是選中,使用者點選切換了狀態,就會觸發 ItemEvent 事件。對於下拉列表,使用者選中了下拉列表中某個選項,就會觸發 ItemEvent 事件。

  • 註冊監視器
    選擇框和下拉列表元件使用addItemListener(ItemListener listen),註冊為事件源的監視器。

  • ItemListener 介面

class MyListener implements ItemListener{
        @Override
        public void itemStateChanged(ItemEvent e) {
            // 觸發事件後,你想要的操作
        }       
    }

ItemEvent 事件物件使用 getSource() 方法返回 ItemEvent 事件源,使用 getItemSelectable 方法返回發生 ItemEvent 事件的事件源。

    @Override
    public void itemStateChanged(ItemEvent e) {
    ...
    e.getSource();
    e.getItemSelectable();
    .
    ..
    }

示例 -下拉列表

下拉列表的選項是當前目錄下Java檔案的名字,使用者選擇下拉列表的選項後,監視器負責在文字區顯示檔案的內容。

效果圖:

這裡寫圖片描述

Main.java

public class Main {
    public static void main(String[] args) {
        WindowActionEvent win = new WindowActionEvent();
        win.setBounds(100, 100, 400, 300);
        win.setTitle("處理ItemEvent事件");
    }
}

WindowActionEvent.java

import java.awt.FlowLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FilenameFilter;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class WindowActionEvent extends JFrame {
    JComboBox choice;
    JTextArea textShow;
    ReaderListen listener;

    public WindowActionEvent() throws HeadlessException {
        init();
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    void init() {
        setLayout(new FlowLayout());
        choice = new JComboBox<>();
        choice.addItem("請選擇檔案:");

        File dir = new File(".");
        FileAccept fileAccept = new FileAccept("java"); // 設定字尾名
        String[] fileName = dir.list(fileAccept);// 把.java字尾的檔名返回,並存到陣列中
        for (String name : fileName) { // 遍歷返回的.java檔名
            choice.addItem(name); // 把檔名新增到下拉列表中
        }
        textShow = new JTextArea(9, 30);
        listener = new ReaderListen();

        /**
         * 在ItemListener中自定義這個方法
         * 主要是要用到下拉列表框和文字區的變數,進行相應的操作
         */
        listener.setJComboBox(choice);
        listener.setJTextArea(textShow);

        choice.addItemListener(listener);
        add(choice);
        add(new JScrollPane(textShow)); //滾動窗格  常用容器

    }

    class FileAccept implements FilenameFilter { // 檔名過濾器
        private String type;

        FileAccept(String type) {
            this.type = type;
        }

        @Override
        public boolean accept(File dir, String name) {
            return name.endsWith(type);
        }

    }
}

class ReaderListen implements ItemListener {
    JComboBox choice;
    JTextArea textShow;

    public void setJComboBox(JComboBox choice) {
        this.choice = choice;
    }

    public void setJTextArea(JTextArea textShow) {
        this.textShow = textShow;

    }

    @Override
    public void itemStateChanged(ItemEvent e) {
        textShow.setText(null);
        try {
            String fileName = choice.getSelectedItem().toString(); // 獲取下拉列表名稱
            File file = new File(fileName);
            FileReader inOne = new FileReader(file);
            BufferedReader inTwo = new BufferedReader(inOne); // 專門用來逐行讀取
            String s = null;
            while ((s = inTwo.readLine()) != null) { //逐行讀出
                textShow.append(s + "\n"); // 依次新增到textShow中
            }
            inOne.close();
            inTwo.close();
        } catch (Exception e2) {
            textShow.append(e2.toString());
        }
    }
}

4.4 DocumentEvent 事件

  • DocumentEvent 事件源
    文字區 (JTextArea)含有一個實現 Document 介面的示例,該例項被稱作文字區所維護的文件,文字區呼叫 getDocument 方法返回所維護的文件。文字區的文件能觸發 DocumentEvent 事件。

  • 註冊監視器
    事件源使用 addDocumentListener (DocumentListener listen),將實現 DocumentListener 介面的類的例項註冊為事件源的監視器。

  • DocumentListener 介面
    在 java.swing.event 包中,該介面有三個方法:

public void removeUpdate(DocumentEvent e)
public void insertUpdate(DocumentEvent e)
public void changedUpdate(DocumentEvent e)

示例-文字區

有兩個文字區。當用戶在一個文字區輸入若干字串時(用逗號、空格或回車符作為單詞間的分隔符),另一個文字區同時對使用者輸入的英文單詞按字典集排序。
效果圖:

這裡寫圖片描述

Main.java

public class {
   public static void main(String args[]) {
      WindowDocument win=new WindowDocument();
      win.setBounds(10,10,360,260);
      win.setTitle("處理DocumentEvent事件");
   }
}

WindowDocument.java

import java.awt.FlowLayout;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class WindowDocument extends JFrame { 
   JTextArea inputText,showText; //一個用於輸入,一個用於輸出
   PoliceListen listen;
   WindowDocument() { 
      init();
      setLayout(new FlowLayout());
      setVisible(true);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);   
   }
   void init() {
      inputText = new JTextArea(9,10);
      showText = new JTextArea(9,10);
      add(new JScrollPane(inputText));
      add(new JScrollPane(showText));
      listen = new PoliceListen();
      listen.setInputText(inputText);
      listen.setShowText(showText);  
      (inputText.getDocument()).addDocumentListener(listen);//向文件註冊監視器
   }
}

PoliceListenjava

import javax.swing.event.*;
import javax.swing.*;
import java.util.*;

public class PoliceListen implements DocumentListener {
    JTextArea inputText, showText;

    public void setInputText(JTextArea text) {
        inputText = text;
    }

    public void setShowText(JTextArea text) {
        showText = text;
    }

    public void removeUpdate(DocumentEvent e) {
        changedUpdate(e);
    }

    public void insertUpdate(DocumentEvent e) {
        changedUpdate(e);
    }

    public void changedUpdate(DocumentEvent e) {
        String str = inputText.getText();
        // 空格、數字和符號(!"#$%&'()*+,-./:;<=>[email protected][\]^_`{|}~)組成的正則表示式:
        String regex = "[\\s\\d\\p{Punct}]+";
        String words[] = str.split(regex);
        Arrays.sort(words); // 按字典序從小到大排序
        showText.setText(null);
        for (String s : words)
            showText.append(s + ",");
    }
}

4.5 MouseEvent 事件

事件源

任何組價上都可以發生滑鼠事件,如滑鼠進入元件,退出元件,在元件上方單擊按鈕,拖到按鈕等都會觸發滑鼠事件,即導致 MouseEvent 類自動建立一個事件物件。

使用 MouseListener 介面處理滑鼠事件

滑鼠事件
MouseListener 介面可以處理的5種滑鼠事件

  • 在事件源上按下滑鼠鍵
  • 釋放事件源上的滑鼠鍵
  • 在事件源上點選滑鼠鍵
  • 滑鼠進入事件源
  • 滑鼠退出事件源

MouseEvent 方法

int getX()  獲取滑鼠指標在事件源座標系中的 X-座標
int getY()  獲取滑鼠指標在事件源座標系中的 Y-座標

int getButton() 返回更改了狀態的滑鼠按鍵(如果有)。

int getClickCount() 返回與此事件關聯的滑鼠單擊次數。

Point getPoint()    返回事件相對於源元件的 x, y 座標。

Object getSource()  獲取發生滑鼠事件的事件源

String getMouseModifiersText(int modifiers) 返回一個描述事件期間所按下的修改鍵和滑鼠按鍵(如“Shift”或“Ctrl+Shift”)的 String。

註冊 MouseEvent 事件源

public void mousePressed(MouseEvent e)   處理元件上按下滑鼠按鈕事件
public void mouseReleased(MouseEvent e)  處理釋放元件上的滑鼠按鈕事件
public void mouseEntered(MouseEvent e)   處理滑鼠進入元件的事件
public void mouseExited(MouseEvent e)    處理在滑鼠退出元件被呼叫事件
public void mouseClicked(MouseEvent e)   處理在源元件上點選滑鼠按鈕事件
示例-使用 MouseListener 介面處理滑鼠事件

分別監視按鈕 、文字框、和視窗上的按鈕事件,當發生滑鼠事件時,獲取滑鼠指標的座標值,注意,事件源的座標系上的左上角是原點。
軟體效果:

這裡寫圖片描述

Main.java

public class Main {
   public static void main(String args[]) {
      WindowMouse win=new WindowMouse();
      win.setTitle("處理滑鼠事件"); 
      win.setBounds(100,100,460,360);
   }
}

WindowMouse.java

import java.awt.*;
import javax.swing.*;
public class WindowMouse extends JFrame {
   JTextField text; 
   JButton button;
   JTextArea textArea;
   MousePolice police; 
   WindowMouse() {
      init();
      setBounds(100,100,420,220);
      setVisible(true);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
   }
   void init() {
      setLayout(new FlowLayout());
      text=new JTextField(8);
      textArea=new JTextArea(10,28);
      police=new MousePolice();
      police.setJTextArea(textArea); 
      text.addMouseListener(police);
      button=new JButton("按鈕"); 
      button.addMouseListener(police);
      addMouseListener(police);
      add(button);
      add(text);
      add(new JScrollPane(textArea));
   }
}

MousePolice.java

import java.awt.event.*;
import javax.swing.*;
public class MousePolice implements MouseListener {
   JTextArea area;
   public void setJTextArea(JTextArea area) {
      this.area=area;
   }
   public void mousePressed(MouseEvent e) {
      area.append("\n滑鼠按下,位置:"+"("+e.getX()+","+e.getY()+")");
   }
   public void mouseReleased(MouseEvent e) {
      area.append("\n滑鼠釋放,位置:"+"("+e.getX()+","+e.getY()+")");
   }
   public void mouseEntered(MouseEvent e)  {
      if(e.getSource() instanceof JButton) // 得到的事件源是JButton的物件時,返回true
        area.append("\n滑鼠進入按紐,位置:"+"("+e.getX()+","+e.getY()+")");
      if(e.getSource() instanceof JTextField)
        area.append("\n滑鼠進入文字框,位置:"+"("+e.getX()+","+e.getY()+")");
      if(e.getSource() instanceof JFrame)
        area.append("\n滑鼠進入視窗,位置:"+"("+e.getX()+","+e.getY()+")"); 
   }
   public void mouseExited(MouseEvent e) {
      area.append("\n滑鼠退出,位置:"+"("+e.getX()+","+e.getY()+")");
   }
   public void mouseClicked(MouseEvent e) {
      if(e.getClickCount()>=2)
         area.setText("滑鼠連擊,位置:"+"("+e.getX()+","+e.getY()+")");
   }
}

使用 MouseMotionListener 介面處理滑鼠事件

使用 MouseMotionListener 介面可以處理以下兩種操作觸發的滑鼠事件。

  • 在事件源上拖動滑鼠
  • 在事件源上移動滑鼠

事件源註冊監視器的方法 addMouseMotionListener (MotionListener listen)

MouseMotionListener 介面的方法:

mouseDragged ( MouseEvent )  處理了負責拖動滑鼠觸發的事件。即當拖動滑鼠是(不必再事件源上),監視器呼叫介面中的這個方法對事件作出處理。

mouseMoved ( MouseEvent ) 負責處理移動滑鼠觸發的事件。即當事件源上移動滑鼠時,監視器呼叫介面中的這個方法對事件作出處理。

可以使用座標變換來實現元件的拖動。當滑鼠拖動元件時,可以先獲取滑鼠指標在元件座標系中的實時座標x,y,以及元件的左上角在容器座標系中的座標a,b;如果在拖動元件時,想讓滑鼠指標相對於拖動的元件保持靜止,那麼元件左上角在容器作弊作息中的位置應當是a+x-x0, b+y-y0,其中x0,y0是最初在元件上按下滑鼠時,滑鼠指標在組建座標系中的初始位置。

示例- 使用 MouseMotionListener 介面處理滑鼠事件

當滑鼠移動或拖動時,給出提示並顯示滑鼠所在位置的座標。

效果圖:
這裡寫圖片描述

MyMouseMotionListener.java

import java.awt.BorderLayout;
import java.awt.Label;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class MyMouseMotionListener {

    JFrame myframe; // JFrame通常預設使用BorderLayout佈局管理器的
    TextArea tf; // 文字區
    MousePolice mousepolice; // 實現監視器介面的類
    JButton exitButton; // 按鈕

    public MyMouseMotionListener() {
        Label label = new Label("點選或拖動滑鼠"); // 初始化標籤
        myframe = new JFrame("MyMouseMotionListener"); // 建立標題為MyMouseMotionListener的視窗
        tf = new TextArea(); // 初始化文字區
        exitButton = new JButton("退出"); // 初始化退出按鈕
        mousepolice = new MousePolice(tf); // 利用構造方法把 TextArea傳遞到監視器
        tf.addMouseMotionListener(mousepolice); // 註冊監視器

        exitButton.addActionListener(new ActionListener() { // 按鈕的監聽事件 匿名內部類方式

            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(0); // 正常退出
            }
        });

        myframe.add(label, BorderLayout.NORTH); // 新增標籤 位置為北
        myframe.add(tf, BorderLayout.CENTER); // 新增文字 在中部
        myframe.add(exitButton, BorderLayout.SOUTH); // 設定退出按鈕 在南
        myframe.setSize(400, 300); // 設定視窗大小
        // myframe.setBounds(x, y, 400, 300); 這個方法可以設定視窗在顯示螢幕的位置 x,y
        myframe.setVisible(true); // 視窗可視

    }

    public static void main(String[] args) {
        new MyMouseMotionListener();
    }
}

MousePolice.java

import java.awt.TextArea;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;

public class MousePolice implements MouseMotionListener {
    int number = 1;
    TextArea tf;

    MousePolice(TextArea tf) {
        this.tf = tf;
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        // getX(),getY():獲取滑鼠的座標位置
        String s = number++ + "" + "滑鼠拖動:x=" + e.getX() + "y=" + e.getY() + "\n";
        tf.append(s);

    }

    @Override
    public void mouseMoved(MouseEvent e) {
        String s = number++ + "" + "滑鼠移動:x=" + e.getX() + "y=" + e.getY() + "\n";
        tf.append(s);

    }
}

4.6 焦點事件