Java圖形用戶界面

爲什麼要是用圖形界面?
命令行操作VS鼠標點擊操作
文字VS圖標
黑白VS彩色圖形化
大量記憶VS直觀感覺
專家VS普通用戶
圖形用戶界面(Graphic User Interface)的最基本的元素就是窗口(Windows)
在這裏插入圖片描述
Java中圖形界面的形式
Applet:嵌入到HTML網頁中的Java程序
優勢:
每次打開網頁,Applet都可以重新下載,更新及時
客戶端執行,比普通網頁功能強大
缺點:
客戶端必須已經安裝JRE,並且配置正確
JRE可能存在漏洞,被攻擊
不能讀寫客戶機上的文件
不能連接出了服務器以外的機器
瀏覽器支持方面可能存在問題
Applet類是Applet程序的容器類
所有其他要顯示的內容都放在Applet容器內
主要方法:
繼承關係:
java.lang.Object
java.awt.Component
java.awt.Container
java.awt.Panel
java.applet.Applet
javax.swing.JApplet
✈️✈️Applet其實是一種AWT容器,可以容納AWT所有的組件
JApplet其實是一種Swing容器,可以容納Swing所有的組件
在這裏插入圖片描述
用法:
Applet程序沒有main()函數作爲入口,必須在瀏覽器裏面調用
Applet程序通常繼承Applet類開始

public class MyFirstApplet extends Applet {
	public void init() {
		//初始化…
	}

	public void paint(Graphics g) {
		//繪圖……
	}
}

Web中的Applet
將寫好的Applet編譯成.class文件
使用HTML代碼將.class文件包含到頁面中

<applet code=“MyFirstApplet.class” width=“300” height=“400” />

用瀏覽器打開包含改代碼的網頁,即可初始化剛剛寫的Applet.
✈️✈️目前大部分的瀏覽器都默認不支持Applet,可以使用AppletViewer查看HTML頁面裏面的Applet.
Application或者桌面程序
AWT:初級Java圖形界面
Swing:高級Java圖形界面
AWT編程基礎
AWT
AWT隨JDK1.0一起發佈,提供了一套最基本的GUI類庫,具有最基本的窗口,按鈕,文本框等.所有AWT組件都在jav.awt包中.
問題:
界面太醜
功能有限
只有有限的組件
最多隻支持4中字體
非面向對象的編程模式
使用Swing替代AWT組件,但使用AWT作爲基礎
Swing中的事件處理機制還是基於AWT
Swing中大部分佈局器都和AWT中相同
AWT的體系結構
在這裏插入圖片描述
AWT Component
Component也稱爲"組件",用來表示圖用戶界面上各種組成元素:按鈕,文本框等.
Component類的主要方法:
setLocation(int x,int y)
setSize(int with,int height)
setBounds(int x,int y,int width,int height)
setVisible(boolean b)
具體方法請查看API文檔.
AWT Container
Container也稱爲"容器",容器可以裝在其他的Component.
Container的主要方法:
Component add(Component comp)
int getComponentCount()
Component[] getComponents()
在這裏插入圖片描述
AWT Frame
Frame是圖形界面中的窗口主類,用於在用戶桌面上顯示一個應用程序窗口.
Frame具有標題欄,可以通過拖動標題欄來改變窗口的位置。
Frame的構造函數Frame(String title)可以指定標題欄顯示的文字。
Frame初始化時不可見,必須調用其setVisible(true)方法才能顯示出來。(其show()方法已經被廢棄,不推薦使用。)
Frame默認就有窗口對應的按鈕,但是其關閉按鈕默認是無效的
AWT Panel
Panel是AWT中最常用的容器,用於組織其他Component的放置和便於定位。
Panel不能獨立存在,必須放在Window或者Frame中
Panel組件放入其他容器中基本看不出來。
Panel和佈局器組合使用之後可以實現強大的界面佈局。
Panel也可以作爲繪圖的畫布使用
AWT ScrollPane
ScrollPane是一種特殊的Panel,它跟Panel的區別在於其帶有滾動條
ScrollPane也不能獨立存在,必須放在頂層容器內部
可以用來裝載其他的容器,當它所裝載的容器大於ScrollPane本身的話,ScrollPane會自動產生滾動條。
一般不允許改變ScrollPane自己的佈局器。
ScrollPane的構造函數ScrollPane(int scrollbarDisplayPolicy)允許在構造是選擇ScrollPane顯示滾動條的策略。
SCROLLBARS_ALWAYS:不管內容是不是大於其本身,都顯示滾動條。
SCROLLBARS_AS_NEEDED :當內容大於其本身才顯示滾動條(默認是這個選項)。
SCROLLBARS_NEVER :不管內容是不是大於其本身,都不顯示滾動條。
AWT常用組件

  • AWT常用的Component
    AWT提供的Component的種類比較全面,基本涵蓋了界面設計的各方各面,可以完成常用的界面設計任務。
    除了前面介紹過的容器組件之外,其他主要的組件有:
    Button:按鈕
    Checkbox:複選框
    CheckboxGroup複選框組,之後一個複選框能被選中
    Choice:下拉選擇框
    Label:標籤,用於顯示一個字符串
    List:列表
    TextField:單行文本框
    TextArea:多行文本區域
    具體用法簡單,更多細節請查看API文檔。
  • Dialog
    Dialog也稱爲對話框,是一種頂級容器,可以獨立存在,不需要放置在其他容器內部。
    Dialog一般從另外一個Window或者Frame內部打開,其具有一個owner屬性,需要設置爲打開它的那個窗口。
    Dialog的構造函數有很多重載,這些重載中主要出現的參數如下:
    owner:是哪個窗口打開了這個對話框?
    title:對話框標題欄顯示的名稱。
    modal:是否打開模式對話框。一旦模式對話框打開後,不能再操作其他窗口中的內容,直到模式對話框被關閉。
  • FileDialog
    FileDialog是Dialog的子類。主要用於打開或者保存文件時選擇文件的位置和名稱。
    構造函數中出現的參數:
    parent:是哪個窗口打開了這個對話框?
    title:對話框的標題欄所顯示的名字。
    mode:以什麼模式打開文件對話框?
    LOAD:打開文件對話框
    SAVE:保存文件對話框
    方法:
    getDirectory():獲得選擇的文件的路徑
    getFile():獲得選擇的文件的名稱
    ☎️☎️FileDialog默認就是模式對話框
    用戶取消選擇後getDirectory()和getFile()值都爲null
    佈局管理器
    ScrollPane裏面的Component爲什麼沒有顯示全?
    因爲ScrollPane本身默認使用了佈局管理器BorderLayout。
    佈局管理器可以實現將容器中的組件自動地以不同的放置方式呈現出來。
    佈局管理器的特點
    跨平臺,在不同的平臺上都有不同的呈現。
    不需要用戶指定組件的大小和位置,自動決定最佳的位置和大小。
    可以根據容器本身的大小自動適應。(在窗口大小改變的時候可以實現自動適應)。
    每個容器都具有自己的默認佈局管理器。
    容器具有setLayout()方法來改變其默認的佈局管理器。
    此外,若指定不使用任何佈局管理器(setLayout(null)),則可以實現讓程序員自己指定空間的位置和大小。

佈局管理器的種類
AWT爲容器提供了5種常用的佈局管理器:
FlowLayout
BorderLayout
GridLayout
GridBagLayout
CardLayout
Swing中提供了另外一種佈局管理器:BoxLayout。

佈局管理器的類結構
在這裏插入圖片描述
LayoutManager
LayoutManager接口聲明瞭5個基本方法:
void addLayoutComponent(String name, Component comp)
void layoutContainer(Container parent)
Dimension minimumLayoutSize(Container parent)
Dimension preferredLayoutSize(Container parent)
void removeLayoutComponent(Component comp)

LayoutManager2
LayoutManager2接口在LayoutManager接口之上添加了4個方法:
void addLayoutComponent(Component comp, Object constraints)
float getLayoutAlignmentX(Container target)
float getLayoutAlignmentY(Container target)
void invalidateLayout(Container target)
Dimension maximumLayoutSize(Container target)

佈局管理器的工作原理
如果這個容器設置了佈局管理器(layoutMgr != null),那麼檢查layoutMgr是否實現的是LayoutManager2接口,如果是就調用佈局管理器的“void addLayoutComponent(Component comp, Object constraints)”方法。
否則(實現的是LayoutManager接口)再判斷constraints是否是String類型,如果是就調用佈局管理器的“void addLayoutComponent(String name, Component comp)”方法。
如果佈局管理器實現的是LayoutManager2接口,那麼它的“void addLayoutComponent(String name, Component comp)”永遠不會被awt框架調用到。
null佈局管理器
null佈局管理器也稱爲“絕對定位佈局管理器”。
程序員可以任意指定容器中Component的大小和位置。
此時Component將以絕對定位的方式放置。
當窗口大小改變時,Component的絕對位置並不會改變。
Component的位置是從它所處的容器的左上角開始計算的。

FlowLayout
以從左到右(從上到下)的順序依次排列加入的Component,在遇到邊界時,從下一行(列)的開頭開始繼續排列。
三個構造函數:
FlowLayout(): 默認構造函數
FlowLayout(int align): 指定對其方式
LEFT, RIGHT, CENTER, LEADING, TRAILING
FlowLayout(int align, int hgap, int vgap):還可以指定水平和垂直間距,默認構造函數使用CENTER對其,hgap和vgap均爲5
Panel容器默認使用FlowLayout。

BorderLayout
BorderLayout把容器的的佈局分爲五個位置:
CENTER、EAST、WEST、NORTH、SOUTH。
往BorderLayout佈局的容器中添加Component時,需要指定添加的位置,否則將添加到中心位置。
BorderLayout的構造函數:
BorderLayout()
BorderLayout(int hgap, int vgap)
Frame、Window和ScrollPane默認使用該佈局。
在這裏插入圖片描述
使用BorderLayout
如何向BorderLayout佈局的容器中放入多個Component?
直接向BorderLayout的任何一個方向中添加多個Component,僅顯示最後添加的那個。
可以多個將多個Panel配合使用來實現複雜的佈局。
Box
Box實際上是一個容器
雖然它不是佈局管理器,但是通常卻作爲佈局管理器工作
它可以實現讓組件水平或者垂直放置
Box通常使用其Box.createHorizontalBox()或者Box.createVerticalBox()靜態方法創建
它通常和Panel組合使用
通過Box.createVerticalStrut()或者Box.createHorizontalStrut()靜態方法可以創建一個水平或者垂直的空白對象用於分割
GridLayout
GridLayout按照構造函數提供的參數,將整個容器分爲大小相等的網格狀。
當往容器中添加Component時,以從上到下,從左到右的方式往網格中添加。
和FlowLayout的區別
GridLayout中的Component自動佔用某個網格,而FlowLayout中的Component可以按自己的大小佔用不同的空間。
GridLayout中每行的Component數量相同,而FlowLayout中每行中Component的數量可能不同。
構造函數:
GridLayout(int rows, int cols)
GridLayout(int rows, int cols, int hgap, int vgap)
GridBagLayout
GridBagLayout是最功(nan)能(yi)強(shi)大(yong)的佈局管理器。
類似GridLayout, GridBagLayout將容器分爲很多網格。
與GridLayout不同:
GridBagLayout的網格數量不是由構造函數決定的。
可以讓Component跨多個Grid。
可以讓每個Grid大小不一致。
窗口大小改變時,GridBagLayout可以精確地控制每個Grid的拉伸變化。
GridBagLayout具有特殊方法:setConstraints(Component c, GridBagConstraints constraints)
將一個GridBagConstraints對象和Component綁定在一起
GridBagConstraints
使用好GridBagLayout的關鍵在於使用GridBagConstraints。
GridBagConstraints可以控制容器中某個Component的佈局特性。
使用GridBagConstraints的關鍵在於精確地設置其屬性值:
gridx和gridy: 設置Component在網格中的橫向和縱向位置。
gridwidth和gridheight:設置Component能在橫向和縱向橫跨多少個網格。
fill:控制Component如何填充網格的區域:
NONE、HORIZONTAL 、VERTICAL 、BOTH 。
ipadx和ipady:設置Component的內部填充大小,即在Component的最小大小上還需要加多少
insets:外部填充大小,類似於Border
GridBagConstraints的anchor屬性
作用:控制Component在網格中顯示的位置
anchor有三種類別的值:absolute、orientation-relative和baseline-relative。
三種類別可取的值爲:
在這裏插入圖片描述
GridBagConstraints的屬性
weightx和weighty:設置在橫向和縱向的佔用比重。
當窗口大小改變的時候,可以使用這兩個屬性來控制Component隨着窗口變化時,Component大小的變化比率。
兩個屬性的默認值爲0,取值範圍[0.0, 1.0]。
窗口大小變化時,比較同一行或者同一列中不同Component所對應的值的比值。
在這裏插入圖片描述
CardLayout
一種三維的佈局管理器,除了容器的高和寬之外,還加入了第三個維度。
每次只顯示一張卡片(Component),可以通過方法切換當前顯示的卡片。(默認顯示第一張。)
構造函數:
CardLayout()
CardLayout(int hgap, int vgap):
主要方法:
first(Container target)
last(Container target)
previous(Container target)
next(Container target)
show(Container target, String name)
事件處理
圖形界面
圖形界面組件僅僅可以搭建出一個可視化的界面,而界面的功能並沒有實現
例如:點擊關閉按鈕後,窗口並不能關閉。
再例如:CardLayout的例子中,點擊按鈕並沒有切換不同的卡片。
原因在於,我們並沒有給用戶點擊相應按鈕後的效果做相應的編程。
事件處理
在界面搭建完成後,一般需要對相應的按鈕等組件的功能提供相應的代碼。
例如:用戶點擊關閉按鈕後,窗口應該關閉。
再例如:CardLayout的例子中,用戶點擊“上一頁”和“下一頁”按鈕後,應該顯示相應的頁面。
在這裏插入圖片描述
什麼是事件(event)?
廣義上說,事件即是某種狀態的改變。
通過馬克思主義哲學我們知道,事物的運動是永恆的,靜止是相對的。永恆的運動意味着事物本身無時無刻不在發生着改變。
我們生活的這個世界和宇宙都有無窮的改變在發生,但是,這當中的絕大多數對你來說並不是事件,或者說並不是你關心的事件。
例如,菜市場上一個小商販賣注水豬肉被工商查處了。這顯然是一個事件。對於在菜市場買菜的人來說,這是一個他們所關心的事件。對於在課堂上的你來說,你並不關心。
在所有的變化中,你能捕獲到的,感興趣的變化,對你來說,才能真正認爲是一個事件。
程序中的事件
對於我們的計算機來說,只要機器開着,裏面的硬件和軟件就會發生狀態的改變。
可是對你要編寫的程序來講,並不是所有的這些改變都是事件。你所需要的事件,只是你對這些變化中感興趣的極小一部分。
例如,窗口打開了、窗口關閉了、某個按鈕被單擊了、某個單選框被選中了、某個菜單被展開了等等。
你只需要找到你感興趣的這樣一種狀態的改變,並且能夠捕獲它,就可以利用事件處理模型來完成你想做的事情了。
什麼是事件處理
當某個事件發生的時候(界面中某個Component的某種狀態改變的時候),我們希望在這個時機執行一些代碼,就需要寫事件處理。
例如:用戶在關閉窗口的時候,我們希望判斷用戶更改過的內容是否已經保存。
再例如:當用戶單擊某個按鈕的時候,我們希望彈出一個對話框。
當這些事件發生的時候,我們希望做的事情,就稱爲事件處理。
Java是一種面向對象的語言,在Java中使用監聽器類來探知一個事件(改變),使用監聽器類中的方法來在事件發生的時機下處理事件。
Java事件處理的三要素
在Java事件處理的模型中,有三種類非常重要,要理解事件處理,必須理解這三種類:
事件源(event source):是這個對象的狀態改變引發的事件,通常是Component。
事件(event):事件源到底什麼狀態發生了改變?例如:按鈕到底是被左鍵單擊了?還是被右鍵單擊了?
事件監聽器(event listener):監聽器被安裝在某個Component上,負責監聽這個Component到底有什麼狀態被改變了。一般僅在感興趣的Component上安裝感興趣的監聽器來監聽感興趣的事件。例如:一般不會監聽TextField對象的事件,而會監聽Button的單擊事件。
AWT事件處理流程
在這裏插入圖片描述
處理用戶單擊按鈕事件
在這裏插入圖片描述
AWT處理事件的模板
在這裏插入圖片描述
☁️☁️不同的Component有不同的事件會發生,可以查看API文檔
添加事件監聽器的方法一般都是addXXXListener(…)
有些監聽器內部有多個方法,可以監聽多種事件,但一般都相關
AWT中的事件
要能正確處理事件首先要確定哪些Component會發生什麼事件。
AWT中事件主要分爲兩大類:低級事件和高級事件。
低級事件:
ComponentEvent:組件事件,當組件尺寸發生改變、位置發生變化、顯示/隱藏狀態發生改變時,就會觸發該事件
ContainerEvent:容器事件,當容器裏增加、刪除組件時,就會觸發該事件
WindowEvent:窗口事件,當窗口狀態發生改變(打開、關閉、最大化、最小化)時,就會觸發該事件
FocusEvent:焦點事件,當組件得到焦點或者失去焦點時,就會觸發該事件
KeyEvent:鍵盤事件,當鍵盤按鍵被按下、鬆開時就會觸發該事件
MouseEvent:鼠標事件,當一個組件被鼠標按下、放開、在其上面移動鼠標時,就會觸發該事件
PaintEvent:繪製事件,當GUI組件調用update()/paint()方法時觸發該事件,該事件並非專用於事件處理模型中,一般也很少直接監聽該事件。
高級事件
高級事件基於語義,並不和特定的動作相關,而依賴於觸發該事件的組件類別。
ActionEvent:動作事件,當按鈕、菜單等能產生Action的項目被單擊,或者在TextField中按下Enter按鈕時,就會觸發該事件。
AdjustmentEvent:調節事件,在滑動條上移動滑塊調節數值時觸發該事件。
ItemEvent:選項事件,當在有很多項目的組件中,選中或者取消選中了某一個項目,就會觸發該事件。
TextEvent:文本事件,當文本框或者文本域這類具有文本的組件中,文本發生變化時,就會觸發該事件。
不同的Event對象,有不同的屬性和方法,可以獲得和該事件相關的一些信息。
AWT中的事件層次關係
在這裏插入圖片描述
eg:窗口事件處理
如何正確關閉窗口?
前面的例子中,窗口無法關閉。
AWT中Frame之所以沒有默認實現關閉方法,是因爲窗口中可能有編輯的內容沒有保存,如果默認就關閉窗口則內容可能丟失。
必須提供一個讓用戶在窗口關閉時保存內容的方法。
WindowListener可以處理這樣的問題。
WindowListener接口有很多方法:
其中windowClosing()方法會在用戶點擊窗口的關閉按鈕後被調用。
可以使用System.exit(0)方法退出程序(不推薦)
也可以使用Frame.dispose()方法關閉窗口,如果該窗口是最後一個被dispose的GUI窗口,則JVM會退出。
⛈️⛈️如果還有窗口沒有被dispose,那麼程序本身不會退出。例如,如果有的窗口被setVisible(false),此時窗口僅僅是不顯示,但是並沒有被銷燬。此時不會顯示任何窗口,但是程序並沒有退出。
監聽器的實現形式
監聽器是一類特殊的Java類/對象。在AWT中,監聽器主要有一下集中實現形式:
監聽器作爲外部類:
優點:規範易於理解、類本身可以重用
缺點:一般情況下不利於實現事件處理中的功能,因爲不易於訪問界面中的屬性和方法
監聽器作爲內部類
優點:可以方便的訪問主類中的任何屬性和方法,包括私有方法
缺點:使得主類過於複雜、不可以在不同界面中重用
監聽器作爲主類本身
優點:跟內部類相似
缺點:使得主類方法過多
監聽器作爲匿名內部類
優點:可以訪問主類的方法
缺點:每個事件都需要寫匿名內部類,不能重用、不利於理解
EventAdapter
EventAdapter也稱爲事件適配器,它和EventListener功能是一致的。
EventListener是接口,而有的監聽器可能存在多個監聽方法,因此必須實現這些方法。
例如:每次使用WindowListener都需要實現所有的7個方法,顯得代碼凌亂。而一般情況下,我們只對windowClosing()這個事件感興趣。
EventAdapter是一個類,它的作用就是一個EventListener的空實現,即所有的方法都實現了,然而沒有寫任何代碼。
使用EventAdapter,我們僅僅需要實現我們感興趣的方法,其他方法自動留空。
如果主類已經繼承了某個類,那麼使用EventAdapter就變成多繼承,因此這種情況下無法使用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章