黑馬程式設計師——Java GUI(圖形使用者介面)
-----------android培訓、java培訓、java學習型技術部落格、期待與您交流!------------
GUI(圖形使用者介面)
一、概述
1.什麼是GUI?
GUI(Graphical User Interface)是使用者與作業系統進行互動的一種方式。該互動方式提供了圖形化介面用以給使用者對作業系統或軟體執行相應命令或操作。
2.java建立GUI的工具:
Java中主要提供了兩個包用來建立GUI,即java.Awt包與javax.Swing包。
java.Awt(Abstract Window ToolKit):表示抽象視窗工具包,需要呼叫本地系統方法實現功能,屬於重量級控制元件。用該工具包建立的GUI會因為作業系統的差異而有所不同。
java.Swing:在AWT的繼承上,建立的一套圖形介面系統,其中提供了更多的元件,而且完全有java實現。增強了移植性,屬於輕量級控制元件。該工具包建立GUI在任何作業系統上執行都是一樣的,即不會受作業系統的差異影響。目前開發主要以java.Swing包為主。
二、架構關係
1.awt工具包的各元件繼承關係:
Component:元件
元件1:該類元件可新增元件2中元件或本類元件。
|--Container:容器
|--Window:視窗
|--Frame:框架
|--Dialog:對話方塊
|--FileDialog:檔案對話方塊
|--Panel:面板
元件2:該類元件不可新增其他元件。
|--Button:按鈕
|--Label:標籤
|--Checkbox:複選框
|--TextComponent:文字元件
|--TextArea:文字區域,用於多行文字
|--TextField:文字框,僅限於單行文字
Component:表示抽象類,是一個具有圖形表示能力的物件,可在螢幕上顯示,並可與使用者進行互動。
元件1:該類元件可新增元件2中元件或本類元件。
Container:表示容器,可以將元件新增到容器中,新增到容器中的元件放在一個列表中。
Window:是一個沒有邊界和選單欄的頂層視窗。視窗的預設佈局是 BorderLayout。由於Window中的建構函式需要傳入Window物件或Frame物件,且沒有提供靜態方法獲得Window物件或Frame物件,因此不能直接建立物件。
Panel:是最簡單的容器類。建立的panel物件,必須裝在頂層容器裡比如嵌入一個frame裡,才能顯示。面板的預設佈局是FlowLayout 。
Frame:是帶有標題和邊框的頂層視窗。可以直接建立一個最初不可見的物件,通過設定setVisible方法的值為true可以顯示窗體。窗體的預設佈局為 BorderLayout。
Dialog:表示對話方塊,是一個帶標題和邊界的頂層視窗。Dialog 的預設佈局為 BorderLayout。
FileDialog:顯示一個對話方塊視窗,使用者可以從中選擇檔案。
注:元件1中的元件,只有Frame、Dialog和FileDialog元件可自身建立窗體物件,並設定以顯示窗體。其中Dialog和FileDialog元件必須依賴於其他窗體元件而存在,如Frame。
元件2:該類元件不可新增其他元件。
Button:此類建立一個標籤按鈕。當按下該按鈕時,應用程式能執行某項動作。
Label:是一個可在容器中放置文字的元件。一個標籤只顯示一行只讀文字。文字可由應用程式更改,但是使用者不能直接對其進行編輯。
Checkbox:複選框是一個可處於“開”(true) 或“關”(false) 狀態的圖形元件。
TextComponent:是所有允許編輯文字的元件的超類。
TextArea:是顯示文字的多行區域。可以將它設定為允許編輯或只讀。
TextField:是允許編輯單行文字的文字元件。
2.常見元件的圖形示例:
1)Frame:框架。
2)Dialog:對話方塊。
3)FileDialog:檔案對話方塊。
4)Label:標籤。
5)TextArea(文字區域)和TextField(文字框)。
6)Checkbox:複選框。
三、常見佈局管理器
1.FlowLayout:流式佈局管理器。
在縱座標方向,會從上向下進行放置填充,在橫座標上會進行居中放置填充。當填充不下時,會自動往下進行放置。該管理器是Panel元件的預設佈局管理器。
圖示:流式佈局管理器
流式佈局的各間距圖示說明:
2.BorderLayout:邊界佈局管理器。
容器劃分為東、西、南、北、中五個區域,每個區域只能放一個元件,是Frame的預設佈局管理器。如果窗體中只有一個元件,將會覆蓋整個窗體。
圖示:邊界佈局管理器。
特點:
1)可以把元件放在這五個位置的任意一個,如果未指定位置,則預設的位置是CENTER。
2)南、北位置控制元件各佔據一行,控制元件寬度將自動佈滿整行。東、西和中間位置佔據一行,若東、西、南、北位置無控制元件,則中間控制元件將自動佈滿整個螢幕。若東、西、南、北位置中無論哪個位置沒有控制元件,則中間位置控制元件將自動佔據沒有控制元件的位置。
3.GridLayout:網格佈局管理器。
容器的空間劃分成M×N列的網格區域, 每個區域只能放置一個元件,類似規則的矩陣。
圖示:網格佈局管理器。
特點:
1)使容器中的各元件呈M行×N列的網格狀分佈。網格每列寬度相同,等於容器的寬度除以網格的列數。網格每行高度相同,等於容器的高度除以網格的行數。
2)各元件的排列方式為:從上到下,從左到右。元件放入容器的次序決定了它在容器中的位置。容器大小改變時,元件的相對位置不變,大小會改變。
3)設定網格佈局行數和列數時,行數或者列數可以有一個為零。若rows為0,cols為3,則列數固定為3,行數不限,每行只能放3個控制元件或容器。若cols為0,rows為3,則行數固定為3,列數不限,且每行必定有控制元件,若元件個數不能整除行數,則除去最後一行外的所有行元件個數為:Math.ceil(元件個數/rows)。
Math.ceil(double x):傳回不小於x的最小整數值。比如行數為3,元件數為13個,則Math.ceil(13/3)=5,即第一行,第二行元件數各為5個,剩下的元件放在最後一行。
4)若元件數超過網格設定的個數,則佈局管理器會自動增加網格個數,原則是保持行數不變。
4.CardLayout:卡片佈局管理器。
卡片佈局能夠讓多個元件共享同一個顯示空間,共享空間的元件之間的關係就像一疊牌,元件疊在一起,初始時顯示該空間中第一個新增的元件,通過CardLayout類提供的方法可以切換該空間中顯示的元件。
5.GridBagLayout:網格包佈局管理器。
GridLayout的升級版,元件仍然是按照行、列放置,但是每個元件可以佔據多個網格,類似非規則矩陣。
圖示:網格包佈局管理器。
四、事件監聽機制
1.組成:監聽器、事件源、事件物件、事件處理方式。
監聽器:將可以觸發某一個事件的動作(可以存在多個動作)都已經封裝到監聽器中。
事件源:指awt包或swing包中的那些圖形介面元件。
事件:每一個事件都有自己特有的對應事件和共性事件。
事件處理方式:對發生的事件進行鍼對性的處理。
注:監聽器、事件源和事件在java中已經封裝好了,直接建立和獲取即可。
2.事件監聽流程圖:
執行過程:將監聽器註冊到事件源上,當外部動作觸發到事件源上動作時,產生一個事件物件並傳給監聽器,監聽器用對應的事件處理方法對事件物件進行鍼對性的處理。
3.問題思考:
1)為什麼執行java程式時,視窗監聽器中的方法windowOpened事件會發生不能被執行的情況?
答:因為視窗開啟事件僅在第一次使視窗可見時才傳遞此事件,因此視覺化操作應放在新增監聽器的後面執行,才能產生windowOpened事件。
4.程式碼練習:
練習1:窗體事件演示。
import java.awt.*;
import java.awt.event.*;
class WindowEventDemo1
{
public static void main(String[] args)
{
//建立框架物件
Frame f=new Frame();
//設定框架的橫向與縱向長度
f.setSize(500,400);
//設定框架距螢幕的橫向與縱向的距離
f.setLocation(300,200);
//設定框架為流式佈局
f.setLayout(new FlowLayout());
//建立按鍵元件
Button b=new Button("一個按鈕");
//把按鈕元件新增到框架
f.add(b);
//向框架新增視窗監聽器
f.addWindowListener(new WindowAdapter()
{
public void windowOpened(WindowEvent e)
{
System.out.println("視窗開啟"+e.toString());
}
public void windowActivated(WindowEvent e)
{
System.out.println("視窗啟用");
f.setLocation(0,0);
}
public void windowClosing(WindowEvent e)
{
System.out.println("視窗關閉");
System.exit(0);
}
public void windowDeactivated(WindowEvent e)
{
System.out.println("視窗停用");
f.setLocation(300,200);
}
});
//視覺化操作應放在新增監聽器的後面,否則windowOpened事件將不被執行
f.setVisible(true);
}
}
程式執行的結果如下截圖所示:
當視窗介面彈出的時候,控制檯輸出“視窗開啟”並且打印出視窗開啟事件的相關資訊。
當視窗介面被啟用時,控制檯輸出“視窗啟用”,並且設定視窗介面距螢幕左上角的橫向與縱向距離都為0。
當視窗介面未被啟用時,控制檯輸出“視窗停用”,並且設定視窗介面的距螢幕左上角的橫向與縱向距離分別為300和200。
當視窗介面被關閉時,控制檯輸出“視窗關閉”,視窗介面消失。
練習2:Action事件演示示例。
import java.awt.*;
import java.awt.event.*;
class ActionEventDemo
{
public static void main(String[] args)
{
new ActionDemo();
}
}
class ActionDemo
{
//定義該窗體所需元件的引用
private Frame f;
private Button but;
//初始化建構函式
ActionDemo()
{
init();
}
//建立窗體與功能實現
public void init()
{
f=new Frame();
//設定窗體的橫向與縱向長度,並設定窗體距螢幕左上角的橫向與縱向距離
f.setBounds(300,100,500,400);
f.setLayout(new FlowLayout());
but=new Button("一個按鈕");
f.add(but);
myEvent();
f.setVisible(true);
}
//對窗體及內部元件註冊事件監聽
public void myEvent()
{
//對窗體註冊事件監聽
f.addWindowListener(new WindowAdapter()
{
public void windowOpened(WindowEvent e)
{
System.out.println("視窗開啟");
}
});
//對按鈕註冊事件監聽
but.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.out.println("關閉視窗");
System.exit(0);
}
});
}
}
程式執行後的生成的窗體截圖如下圖所示:
當彈出窗體時,則在控制檯上會輸出“視窗開啟”。
當用滑鼠點選按鈕時,則在控制檯會輸出“關閉視窗”,並把整個窗體關閉。
練習3:滑鼠事件演示示例。
import java.awt.*;
import java.awt.event.*;
class MouseEventDemo
{
public static void main(String[] args)
{
new MouseDemo();
}
}
class MouseDemo
{
private Frame f;
private Button but;
MouseDemo()
{
init();
}
public void init()
{
f=new Frame();
f.setBounds(300,100,500,400);
f.setLayout(new FlowLayout());
but=new Button("my button");
f.add(but);
myEvent();
f.setVisible(true);
}
//定義事件監聽
public void myEvent()
{
//向窗體註冊窗體事件監聽
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.out.println("視窗關閉");
System.exit(0);
}
});
//向按鈕註冊滑鼠事件監聽
but.addMouseListener(new MouseAdapter()
{
// public void mouseEntered(MouseEvent e)
// {
// System.out.println("滑鼠進入");
// }
//
// public void mouseExited(MouseEvent e)
// {
// System.out.println("滑鼠離開");
// }
public void mouseClicked(MouseEvent e)
{
if (e.getClickCount()==2)
{
System.out.println("雙擊滑鼠");
}
}
// public void mousePressed(MouseEvent e)
// {
// System.out.println("滑鼠按下");
// }
//
// public void mouseReleased(MouseEvent e)
// {
// System.out.println("滑鼠釋放");
// }
});
}
}
程式執行後的結果如下截圖所示:
當雙擊視窗介面的“my button”按鈕時,控制檯輸出“雙擊滑鼠”。
當點選視窗介面的關閉按鈕時,控制檯輸出“視窗關閉”,並且整個窗體消失。
練習4:鍵盤事件演示示例。
import java.awt.*;
import java.awt.event.*;
class KeyEventDemo
{
public static void main(String[] args)
{
new KeyDemo();
}
}
class KeyDemo
{
private Frame f;
private Button but;
private TextField tf;
KeyDemo()
{
init();
}
public void init()
{
f=new Frame();
f.setBounds(300,100,500,400);
f.setLayout(new FlowLayout());
but=new Button("my button");
tf=new TextField(20);
f.add(tf);
f.add(but);
myEvent();
f.setVisible(true);
}
public void myEvent()
{
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.out.println("視窗關閉");
System.exit(0);
}
});
//向文字框元件註冊鍵盤事件監聽
tf.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
//當按下ctrl+enter組合鍵時,退出
if (e.isControlDown()&&e.getKeyCode()==e.VK_ENTER)
{
System.exit(0);
}
// //輸出鍵的字元形式和整數形式,僅限於單個字母
// System.out.println(e.getKeyChar()+"---"+e.getKeyCode());
// //輸出鍵的字元形式和整數形式,更為廣泛
// System.out.println(KeyEvent.getKeyText(e.getKeyCode())+"---"+e.getKeyCode());
}
// public void keyReleased(KeyEvent e)
// {
// System.out.println("鍵盤釋放");
// }
});
}
}
程式執行後的結果如下截圖所示:
當向文字框輸入內容時,如果鍵盤按下組合鍵“ctrl+enter”,則整個窗體介面消失。
當滑鼠點選窗體關閉按鈕時,控制檯輸出“視窗關閉”,並且整個窗體消失。
練習5:列出指定目錄的所有內容。
import java.awt.*;
import java.awt.event.*;
import java.io.*;
class WindowTest
{
public static void main(String[] args)
{
new MyWindow();
}
}
class MyWindow
{
private Frame f;
private TextField tf;
private TextArea ta;
private Button but;
MyWindow()
{
init();
}
public void init()
{
f=new Frame();
f.setBounds(300,200,600,400);
f.setLayout(new FlowLayout());
tf=new TextField(50);
ta=new TextArea(20,70);
but=new Button("轉到");
f.add(tf);
f.add(but);
f.add(ta);
myEvent();
f.setVisible(true);
}
//事件處理
public void myEvent()
{
//對窗體註冊視窗監聽器
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
//對按鈕註冊活動監聽器
but.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
showDir();
}
});
//對文字框註冊鍵盤監聽器
tf.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode()==e.VK_ENTER)
{
showDir();
}
}
});
}
//列出文字框中指定目錄的內容
public void showDir()
{
//獲取文字框的內容
String dir=tf.getText();
File file=new File(dir);
if (file.exists()&&file.isDirectory())
{
//清空文字區域的內容
ta.setText("");
String[] str=file.list();
for(String s:str)
{
//將遍歷的內容追加到文字區域中,並進行換行
ta.append(s+"\t\n");
}
//清空文字框的內容
tf.setText("");
}
}
}
程式執行後的結果如下截圖所示:
當在文字框輸入目錄“E:\heima”時,點選轉動按鈕,則在文字區域中列出了該目錄的所有內容。執行結果如下截圖所示:
五、選單
1.繼承關係:
MenuComponent:選單元件
|--MenuBar:選單欄
|--MenuItem:選單項
|--Menu:選單
MenuComponent:表示選單元件,是所有與選單相關的元件的超類。
MenuBar:表示選單欄,該類封裝繫結到框架的選單欄的平臺概念。通過呼叫該框架的 setMenuBar 方法,將選單欄與 Frame 物件關聯。
MenuItem:表示選單項,選單中的所有項必須屬於類 MenuItem 或其子類之一。
Menu:表示選單,是MenuItem的子類,是從選單欄部署的下拉式選單元件。它可以是 MenuItem 的一個例項、子選單(Menu 的一個例項)、或複選框(CheckboxMenuItem 的一個例項)。
2.元件圖示:
特點:
1)選單欄依賴於框架存在,框架新增選單欄需呼叫SetMenuBar方法。而選單欄新增選單或選單中新增選單項都呼叫add方法。
2)選單中即可以新增選單項也可以新增選單。選單中新增的選單稱為子選單,子選單中可以繼續新增子選單或選單項。
3)選單欄、選單、選單項都可以註冊相應的監聽器。
4)選單欄新增選單的先後順序反應到圖形化介面中為從左到右的排列順序。選單新增子選單或選單項的先後順序反應到圖形化介面中為從上到下的排列順序。
程式碼示例:
import java.awt.*;
import java.awt.event.*;
class MyMenuDemo
{
public static void main(String[] args)
{
new MyMenu();
}
}
class MyMenu
{
//定義所需元件的引用
private Frame f;
private TextArea ta;
private MenuBar mb;
private Menu m,subm,edit,help;
private MenuItem close,submi,open;
//建構函式
MyMenu()
{
init();
}
//窗體設定和功能實現
public void init()
{
f=new Frame();
f.setBounds(300,200,600,400);
ta=new TextArea();
//建立選單欄
mb=new MenuBar();
//建立選單
m=new Menu("檔案");
subm=new Menu("子選單");
edit=new Menu("編輯");
help=new Menu("幫助");
//建立化選單項
open=new MenuItem("開啟");
close=new MenuItem("退出");
submi=new MenuItem("子條目");
f.add(ta);
//在框架上新增選單欄
f.setMenuBar(mb);
//在選單欄上新增選單
mb.add(m);
mb.add(edit);
mb.add(help);
//在選單上新增子選單和選單項,新增的順序不同,顯示效果也不同
m.add(open);
m.add(subm);
m.add(close);
//在子選單上新增子條目
subm.add(submi);
myEvent();
f.setVisible(true);
}
//事件處理
public void myEvent()
{
//對窗體註冊事件監聽器以關閉窗體
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
}
}
程式執行後的效果如下截圖所示:
3.程式碼練習:
練習1:開啟和儲存檔案。
可實現開啟任意純文字檔案,並將內容顯示窗體的檔案區域中。可對窗體文字區域的內容進行任意修改並儲存到指定的目錄檔案中。基本實現類似記事本的開啟儲存功能。
import java.awt.*;
import java.awt.event.*;
import java.io.*;
class MyMenuTest
{
public static void main(String[] args)
{
new MyMenu();
}
}
class MyMenu
{
//定義所需的元件引用
private Frame f;
private TextArea ta;
private MenuBar mb;
private Menu m;
private MenuItem close,open,save;
private FileDialog diaOpen;
private FileDialog diaSave;
private File file;
MyMenu()
{
init();
}
public void init()
{
f=new Frame();
f.setBounds(300,200,600,400);
ta=new TextArea();
//建立選單欄
mb=new MenuBar();
//建立選單
m=new Menu("檔案");
//建立化選單項
open=new MenuItem("開啟");
save=new MenuItem("儲存");
close=new MenuItem("退出");
f.add(ta);
//在框架上新增選單欄
f.setMenuBar(mb);
//在選單欄上新增選單
mb.add(m);
//在選單上新增子選單和選單項,新增的順序不同,顯示效果也不同
m.add(open);
m.add(save);
m.add(close);
//事件處理
myEvent();
f.setVisible(true);
}
//事件處理
public void myEvent()
{
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
//對open選單項註冊活動監聽器,實現檔案開啟功能
open.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//建立檔案對話方塊物件,指定依存的框架f,指定模式屬性為LOAD.
diaOpen=new FileDialog(f,"開啟檔案",FileDialog.LOAD);
//顯示檔案對話方塊
diaOpen.setVisible(true);
//獲取檔案對話方塊的目錄
String dir=diaOpen.getDirectory();
//獲取選定的檔案
String name=diaOpen.getFile();
//如果獲取到的目錄或檔名為null,則退出程式
if (dir==null||name==null)
return;
//如果目錄和檔名都不為null,則清空文字區域內容
ta.setText("");
file=new File(dir,name);
BufferedReader bufr=null;
try
{
bufr=new BufferedReader(new FileReader(file));
String line=null;
while ((line=bufr.readLine())!=null)
{
ta.append(line+"\r\n");
}
}
catch (IOException ex)
{
throw new RuntimeException("開啟檔案失敗");
}
finally
{
if (bufr!=null)
{
try
{
bufr.close();
}
catch (IOException ex)
{
throw new RuntimeException("讀取關閉失敗");
}
}
}
}
});
//對save選單項註冊活動監聽器,實現檔案儲存功能
save.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//如果file指向null,則建立file物件
if (file==null)
{
//建立檔案儲存對話方塊,指定依存的框架f,指定屬性為SAVE
diaSave=new FileDialog(f,"檔案儲存",FileDialog.SAVE);
//顯示檔案儲存對話方塊
diaSave.setVisible(true);
//獲取檔案儲存對話方塊的父目錄及選定檔名
String dir=diaSave.getDirectory();
String name=diaSave.getFile();
if (dir==null||name==null)
return;
//根據獲取的父目錄和檔名,建立檔案物件
file=new File(dir,name);
}
BufferedWriter bufw=null;
try
{
bufw=new BufferedWriter(new FileWriter(file));
//獲取文字區域中的內容
String str=ta.getText();
//將文字區域中的內容寫入緩衝區
bufw.write(str);
// bufw.flush();
}
catch (IOException ex)
{
throw new RuntimeException("儲存失敗");
}
finally
{
if (bufw!=null)
{
try
{
bufw.close();
}
catch (IOException ex)
{
throw new RuntimeException("寫入關閉失敗");
}
}
}
}
});
close.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
});
}
}
六、雙擊jar包執行
雙擊jar包執行可以像圖形化介面那樣,通過雙擊程式即可執行,不必再通過命令列的方式執行程式。
實現步驟如下:
1)建立包。如果java源程式中有建立包,可跳過。如果沒有,需要建立一個包,如“pakage mymenu”。
2)打包。給源程式進行打包,在控制檯執行命令“javac -d E:\heima MyMenuTest.java",則在“E:heima”目錄下的生成一個mymenu包資料夾,在該資料夾下有所有的.class檔案。
3)在 mymenu包資料夾所在目錄,新建一個任意名稱任意型別的檔案,如“MyMenuTest.txt”。在MyMenuTest.txt檔案中寫入指定格式內容:“Main-Class: mymenu.MyMenuTest”,只需寫入引號內的內容即可。格式應注意兩點:1.在冒號後應有一個空格存在;2.在檔案末尾需進行回車。
4) 在控制檯執行命令:jar -cvfm MyMenuTest.jar MyMenuTest.txt mymenu",可看到在“E:heima”目錄下生成了一個可執行檔案MyMenuTest.jar。如果想新增其他資訊,則直接執行jar命令,即可得到相應的命令的幫助資訊。
5)雙擊MyMenuTest.jar,即可執行程式。
注意事項:
1)在固定格式中:
a)如果無空格:在編譯的時候,就會報IO異常,提示無效的頭欄位,即invalidheader field。這說明MyMenuTest.txt在被IO流讀取。
b)如果無回車:在列表清單.MF中不會加入相應的載入主類的資訊,也就是說配置清單的屬性主類名稱不會載入進清單中,也就不會執行。
2)jar檔案必須在系統中註冊,才能執行。