視窗程式設計 3. Java 視窗入門 Chih Hung Wang Reference: 2. 深入研究Java Swing,上奇資訊股份有限公司,黃嘉輝著 (2011) 3. Java SE 6.0視窗程式設計之道,碁峰出版社,黃嘉輝著 (2008) 4. Java 初學指引,博碩文化,陳錦輝著 (2010) 視窗程式設計 3. Java 視窗入門 Chih Hung Wang
視窗程式設計基本概念 AWT:JDK早期提供的視窗程式開發套件。 Java Foundation Class(JFC)是一套協助程式設計師,以Java語言開發圖形化使用者介面(GUI)的函式庫,發表於1997年的JavaOne developer conference,整個函式庫包含以下5個部分。 AWT:JDK早期提供的視窗程式開發套件。 Swing:從JDK 1.2開始,用於輔助AWT開發視窗程式,且提供許多取代AWT套件內元件的UI元件。 Accessibility API:提供Swing處理輔助技術的函數,以便處理包含語音輸入、觸控式螢幕、螢幕放大…等先進輸入溝通介面。 Java 2D API:提供強大2D繪圖的處理函數。 拖曳及放下(Drag and Drop)功能:提供使用者可以在視窗內、兩個Java視窗程式間或Java與其他視窗程式間,運用滑鼠拖曳與放下之方式執行資料交換,例如:用滑鼠在檔案總管,選取一檔案,以拖曳方式移動或複製到視窗的桌面上。
AWT與Swing 從Java問世後,用於開發視窗程式的AWT(Abstract Window Toolkit)便包含在JDK內。但AWT為了與作業系統溝通,大部分元件將運用特定作業系統使用的原生碼(native code),導致AWT元件缺乏彈性,效率不彰,且跨平台執行亦將產生問題。 而1998年Sun推出的JDK 1.2,則以Swing解決使用AWT所產生的問題,但Swing不是用於取代AWT,而是輔助。使用Swing開發視窗程式時,您還是會用到AWT的功能,例如:版面配置(LayoutManager,第2章)、事件處理(Event Handle,第3章)…等。至於視窗畫面上的元件,則應該捨AWT元件,改用Swing元件。 Swing的MVC架構 Swing以Model-View-Controller(簡稱MVC)架構設計元件,將GUI元件區分為模型(Model)、外觀(View)與控制器(Controller)三部分,各部分說明如下: Model(模型):Model用於儲存/處理GUI元件的資料內容或元件狀態,不論在螢幕上如何顯示元件,元件資料的儲存都相同,而不同型態的元件將有不同模型 View(外觀):在螢幕顯示元件外觀與Model內資料時,不同作業系統下,某些視窗元件可能有些許不同 Controller(控制器):描述元件如何回應使用者動作所產生的事件與回應方式
以上三部分的互動過程如下圖。 以下為捲動軸MVC架構各部分之功能的說明。 Model(模型):捲動軸元件的Model用於儲存捲動軸所能表示的最大值、最小值,以及捲動軸的寬度與捲動方塊位置…等資訊。 View(外觀):View的功能就是在螢幕中顯示捲動軸控制項的外觀,包括利用Model提供的資料,依照比例計算捲動方塊的位置,以及捲動方塊應該顯示的寬度。 Controller(控制器):回應使用者拉動捲動方塊、前端按鈕、尾端按鈕時,觸發事件後,捲動軸的回應行為。 以視窗介面常見的捲動軸元件為例,介紹MVC架構的互動過程。
下圖為使用者按下捲動軸的尾端按鈕,MVC架構反應事件的運作過程。 UI代理模型 Java為了簡化設計,則採用結合View與Controller成為一組元件的模型代理(model delegate)架構設計Swing元件,運用結合後的UI代理(UI-delegate)元件,處理在螢幕上顯示元件與GUI事件的回應。此機制的架構如圖所示。
輕型元件、重型元件 Swing元件依照開發方式,可區分為輕型元件(Lightweight Component)與重型元件(Heavyweight Component)兩種。 輕型元件是指以Java寫成,不需依靠作業系統便可運作,主要為建構視窗程式的各種控制項,如:清單方塊、核取方塊、文字欄位…等。 重型元件則是運用C語言之類的原生碼,以呼叫作業系統功能之方式開發出的元件。Swing元件內,只有JFrame、JDialog、JWindow與JApplet為重型元件。設計視窗程式時,上述重型元件將負責與作業系統溝通,並扮演容器(Container)的角色以建立視窗的主要畫面,供程式設計師置入視窗的各種控制項(輕型元件),完成視窗畫面的建構 第一個視窗程式 – Hello Swing! 建立視窗程式的步驟 本節將說明如何運用Swing元件建立視窗程式,步驟如下: STEP 1、運用JFrame類別建立視窗框架物件 STEP 2、呼叫JFrame的getContentPane()方法取得放置元件的內容面版 STEP 3、產生欲加入視窗的元件 STEP 4、呼叫JFrame的add()方法將元件置入面版 STEP 5、設定關閉視窗的預設動作,設定視窗大小,並顯示視窗。
第一個視窗程式 import javax.swing.*; //引用Swing套件 import java.awt.*; //引用AWT套件 public class HelloSwing { public static void main(String args[]) { //STEP 1、建立視窗框架 JFrame frame = new JFrame("HelloSwing"); //STEP 2、取得可放置元件的內容面版 Container cp = frame.getContentPane(); //STEP 3、宣告加入視窗的按鈕元件 JButton button = new JButton("Hello Swing!"); //STEP 4、將元件加入面版 cp.add(button); //STEP 5、設定視窗關閉動作,調整視窗大小,並顯示視窗 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //設定按下視窗右上角關閉按鈕將關閉視窗並結束應用程式的執行 frame.pack(); //調整視窗大小, 否則將僅顯示視窗的標題列 frame.setVisible(true); //顯示視窗 }
第一個視窗程式執行情形 視窗程式設計的容器觀念 什麼是容器 完成建立的視窗程式如圖所示。整個程式的目的僅在產生一個視窗框架,並於視窗內,加入顯示『Hello Swing!』字串的按鈕。 視窗程式設計的容器觀念 什麼是容器 根面版元件的架構如下。 根面版包含兩個固定的元件 – 圖層面版(layered pane)與玻璃面版(glass pane)。圖層面版用於放置視窗元件,包含功能表列(JMenuBar)與內容面版(content pane)兩個部分。 內容面版是真正放置視窗各種元件的面版,建立視窗畫面時,將元件加入容器前,必須先呼叫getContentPane()方法取得型別為Container類別的內容面版。
建立視窗框架的JFrame類別 JFrame類別是最常運用的Swing元件,將建立視窗框架。繼承架構如下圖所示。 下表將說明其建構子與常用的方法。
範例 1-2 繼承 Jframe 類別 import javax.swing.*; //引用Swing套件 import java.awt.*; //引用AWT套件 public class FrameEX extends JFrame { //宣告主程式類別FrameEX繼承JFrame FrameEX() { super("HelloSwing"); //呼叫JFrame的建構子, 並傳入視窗標題 //STEP 2、取得可放置元件的內容面版 Container cp = getContentPane(); //STEP 3、宣告加入視窗的按鈕元件 JButton button = new JButton("Hello Swing!"); //STEP 4、將元件加入面版 cp.add(button); //STEP 5、設定視窗關閉動作,調整視窗大小,並顯示 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //設定按下視窗右上角關閉按鈕將關閉視窗並結束應用程式的執行 pack(); //調整視窗大小, 否則將僅顯示視窗的標題列 setVisible(true); //顯示視窗 } public static void main(String args[]) { //STEP 1、建立視窗框架 new FrameEX();
以JPanel類別群組控制項 JPanel類別是一個可以容納控制項的容器,在設計程式時,為方便處理版面配置,將把視窗畫面內的控制項,依照功能、用途或排版性質進行分類,再運用JPanel類別組織成數個群組。其繼承架構如下圖所示。 JPanel類別建構子的規格如下: public JPanel() public JPanel(LayoutManager layout) public JPanel(boolean isDoubleBuffered) public JPanel(LayoutManager layout, boolean isDoubleBuffered) 範例1-3將示範運用JPanel類別群組不同的指令按鈕,並可將JPanel容器加入另一個JPanel內,執行結果如下圖所示。
範例 1-3 JPanel 類別-1 import javax.swing.*; //引用Swing套件 import java.awt.*; public class PanelEX extends JFrame { PanelEX() { JPanel jpBottom = new JPanel(); //建立群組控制項的JPanel類別 JPanel jpLeft = new JPanel(); JPanel jpRight = new JPanel(); //運用awt套件內的Color類別之RED屬性設定各面版類別的背景顏色 jpLeft.setBackground(Color.RED); jpBottom.setBackground(Color.YELLOW); jpRight.setBackground(Color.BLUE); jpLeft.add(new JButton("按鈕 1")); //將按鈕加入面版 jpLeft.add(new JButton("按鈕 2")); jpRight.add(new JButton("按鈕 3")); jpRight.add(new JButton("按鈕 4")); jpRight.add(new JButton("按鈕 5")); jpBottom.add(jpLeft); //將面版加入底層面版 jpBottom.add(jpRight);
範例 1-3 JPanel 類別-2 getContentPane().add(jpBottom); //將面版加入內容面版 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); pack(); setVisible(true); } public static void main(String args[]) { new PanelEX(); //建立視窗框架物件
簡介Component類別設定大小、位置的方法 控制容器、元件之大小與位置 簡介Component類別設定大小、位置的方法 javax.swing套件內所有容器與元件均繼承於javax.swing.JComponent類別,而JComponent類別又是java.awt.Component類別的子類別。整個繼承架構如下圖所示。 而swing套件的所有容器與元件,欲設定大小與位置時,將呼叫Component類別所提供的方法。而Java容納元件的容器採用之座標系統,則將以容器的左上角為原點,向下、向右為正,單位為像素(pixels)。 下表將為您介紹JComponent類別的常用方法:
控制視窗的大小與位置 欲控制視窗框架的大小與顯示位置時,可以呼叫JFrame繼承自java.awt.Component類別的方法,設定或取得相關資訊。至於螢幕的座標系統,則與容器採用的座標系統相同,同樣以螢幕的左上角為原點,向右向下為正,度量單位為像素(pixels)。 範例1-4修改自範例1-2將示範如何控制項視窗的顯示位置與大小。將設定視窗顯示於螢幕中央,且其寬度與高度將為螢幕寬度、高度的五分之一。執行結果如圖所示。
範例 1-4 控制視窗大小及位置-1 import javax.swing.*; //引用Swing套件 import java.awt.*; //引用AWT套件 public class SizeLocationEX extends JFrame { SizeLocationEX() { super("HelloSwing"); //呼叫JFrame的建構子, 並傳入視窗標題 //STEP 2、取得可放置元件的內容面版 Container cp = getContentPane(); //STEP 3、宣告加入視窗的按鈕元件 JButton button = new JButton("Hello Swing!"); //STEP 4、將元件加入面版 cp.add(button); Dimension dim = getToolkit().getScreenSize(); //取得螢幕大小 setSize((int)dim.getWidth()/5, (int)dim.getHeight()/5); //設定視窗畫面的大小 setLocation(dim.width/2 - getWidth()/2, dim.height/2 - getHeight()/2); //設定視窗顯示在螢幕的中央
範例 1-4 控制視窗大小及位置-2 //STEP 5、設定視窗關閉動作,調整視窗大小,並顯示 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //設定按下視窗右上角關閉按鈕將關閉視窗並結束應用程式的執行 setVisible(true); //顯示視窗 } public static void main(String args[]) { //STEP 1、建立視窗框架 new SizeLocationEX();
控制容器內元件的大小與位置 由於Swing的容器預設使用佈局管理員(說明於第2章)配置容器內的元件。因此,Swing容器內元件之大小與位置將無法完全由元件之設定決定,而是由佈局管理員依照其管理佈局的特性所決定。 但您仍可以呼叫Component類別的setMinimumSize()方法、setPreferredSize()方法、setMaximumSize()方法設定元件的最小、喜好與最大的大小,以供佈局管理員在需要時使用 當Swing容器不使用佈局管理員時,元件的大小與位置才會依照元件本身的設定顯示,此時,呼叫Component類別的setBounds()、setSize()、setLocation()…等方法,所執行的設定才有效果。相對地,setMinimumSize()方法、setPreferredSize()方法、setMaximumSize()方法所執行的設定將沒有效果。下圖為範例1-5的執行結果。
範例 1-5 控制容器內元件的大小及位置 import javax.swing.*; //引用Swing套件 import java.awt.*; public class ComponentEX extends JFrame { ComponentEX() { Container cp = getContentPane(); //取得內容面版 cp.setLayout(new GridLayout(2, 1)); //設定內容面版使用GridLayout佈局管理員 JPanel jpFirst = new JPanel(); //宣告JPanel容器 jpFirst.setLayout(null); //設定容器不使用佈 局管理員 JButton btnA = new JButton("按鈕A"); //宣告按鈕元件 JButton btnB = new JButton("按鈕B"); Rectangle rec = new Rectangle(50, 50, 100, 100); //宣告表示位置與大小的Rectangle物件 btnA.setBounds(rec); //設定按鈕元件的位置與大小 btnB.setSize(new Dimension(100,100)); //設定按鈕大小 //btnB.setPreferredSize(new Dimension(100, 100)); btnB.setLocation(200, 50); //設定元件位置
jpFirst.add(btnA); //將元件加入容器 jpFirst.add(btnB); JPanel jpSecond = new JPanel(); JButton btnC = new JButton("按鈕C"); JButton btnD = new JButton("按鈕D"); btnC.setMinimumSize(new Dimension(50, 50)); //設定最小大小 btnC.setPreferredSize(new Dimension(75, 75)); //設定喜好大小 btnC.setMaximumSize(new Dimension(100, 100)); //設定最大大小 btnD.setSize(new Dimension(100,100)); //設定元件的大小 jpSecond.add(btnC); //將元件加入容器 jpSecond.add(btnD); cp.add(jpFirst); //將容器加入內容面版 cp.add(jpSecond); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //設定按下視窗右上角關閉按鈕將關閉視窗並結束應用程式的執行 setSize(350, 350); //設定視窗的大小 setVisible(true); //顯示視窗 } public static void main(String args[]) { new ComponentEX(); //建立視窗框架物件