Chapter 4 PGML / PUML
4.3 PUML – Pervasive User-interface Markup Language
4.3.4 PUML 範例
其實撰寫 PUML 文件相當容易。PUML 的程式設計師只要有公佈欄的抽象 概念,然後只要想著要在公佈欄上張貼什麼訊息即可。也就是說,若要在公 佈欄上貼圖片的話,就只要在<board>的 element content 中加上<picture>即 可,想要在公佈欄上貼上標籤的話,就只要在<board>的 element content 中 加上<label>即可,其他以此類推。若想使用邏輯運算來完成某些特定的事情 的話,就只要在<board>的 element content 中加上<logic-objects>,然後在
<logic-objects>的 element content 中,使用<object>來指定要使用哪個邏輯物 件(logic object,也就是 PGML 文件)即可。若想要觸發事件以進行邏輯運算 的話,在<board>的 element content 中加上<action>,然後在<action>的 element content 中,根據你想執行的順序,分別加上<use-object>、<change>、
<nextboard>即可,相當直覺。
也就是說,在PUML 中,使用者介面容器(UI container)就是<board> element,
在<board> 的 element content 中 可 以 放 入 <label> 、 <textnote> 、 <logic -objects>、<action>……等等的 elements。PUML 的程式設計師在設計使用 者介面時,便以board 為基本單位,來設計行動應用程式中所有可能出現的 使用者介面。
再來,簡單介紹一下PUML 文件結構的骨架。
PUML 的 root element(document element)為<user-interface>,<user-interface>
包含三種 child element,分別為<layout>、<logic-objects>和<board>。在
<user-interface> 的 element content 中 最 多 只 能 有 一 個 <layout> , 而
<logic-objects>最多也只能有一個,另外<board>則最少要有一個。<board>
包含了六種child element,分別為<picture>、<label>、<textnote>、<listpaper>,
以 及 <logic-objects> 和 <action> , 而 在 <board> 中 最 多 只 能 有 一 個
<logic-objects>。<listpaper>的 child element 為<item>,<logic-objects>的 child element 為<object>,<action>的 child element 為<use-object>、<change>或
<nextboard>。每種 elements 的詳細用法及說明,請參考表 4-3 和本論文中的 範例。
以下為PUML 文件結構的示意圖(圖 4-7):
<?xml version="1.0"?>
<user-interface name=“…l" version="1.2"
xmlns="http://dcsw3.cis.nctu.edu.tw/Project/Pervasive/PUML/">
<layout>…</layout>
<logic-objects>
<object name=“…” source=“…”/>
…
</logic-objects>
<board name=“…" title=“…" seqNO=“…">
<picture/>
<action name=“…" showText=“…">
<use-object name=“…” method=“…”>
<param/>
..
</use-object>
<change container=“…" component=“…" update=“…">
…
<user-interface name="LoginInput" version="1.2"
xmlns="http://dcsw3.cis.nctu.edu.tw/Project/Pervasive/PUML/">
<logic-objects>
<object name="login" source="Login.pgml"/>
</logic-objects>
<board name="loginBoard" title="login page" seqNO="0">
<label name="showMsg1" showText="input your name: "/>
<textnote type="text" name="UserName"/>
<label name="showMsg2" showText="select your sex: "/>
<listpaper iname="isex" mode="single">
<item showText="Boy"/>
<item showText="Girl"/>
</listpaper>
<action name="enter" showText="ENTER">
<use-object name="login" method="verify">
<param select="UserName"/>
<param select="isex"/>
<param type="String" value="Location-NCTU"/>
</use-object>
<nextboard goto="mainBoard"/>
</action>
</board>
<board name="mainBoard" title="main page">
<!--content-->
</board>
</user-interface>
[圖 4-8 PUML 簡單範例]
這個例子是描述一個登入的使用者介面。在這個所描述的使用者介面中,會 要求使用者輸入姓名以及性別,然後在事件觸發後(按下 button 或 command 之後),會將使用者在使用者介面上輸入的資料,送給後端的邏輯運算部份
做運算,運算完之後會將畫面切換到另一個描述的使用者介面。
相對應的J2ME 程式碼如下(圖 4-9、圖 4-10、圖 4-11):
(共產生三個 class:BMngr_LoginInput、B_loginBoard、B_mainBoard)
import javax.microedition.midlet.*; import javax.microedition.lcdui.*;
interface BMngr_Interface {
public void changeBoard(String boardName);
public Displayable getBoard(String boardName);
}
public class BMngr_LoginInput extends MIDlet implements BMngr_Interface{
public static BMngr_LoginInput instance; private Display display;
/*global logic objects*/
public Login lgObj_login = new Login();
/*all displayables corresponding to boards' declaration*/
private B_loginBoard loginBoard = new B_loginBoard(); private B_mainBoard mainBoard = new B_mainBoard();
/*Constructor*/
public BMngr_LoginInput(){ instance = this; } /*Main method*/
public void startApp(){ display = Display.getDisplay(this); display.setCurrent(loginBoard); } /*Handle pausing the MIDlet*/
public void pauseApp(){ } /*Handle destroying the MIDlet*/
public void destroyApp(boolean unconditional){ } /*Quit the MIDlet*/
public static void quitApp(){ instance.destroyApp(true); instance.notifyDestroyed(); instance = null; } /*change UI presentation*/
public void changeBoard(String boardName){
if(boardName.compareTo("loginBoard") == 0){ display.setCurrent(loginBoard); } if(boardName.compareTo("mainBoard") == 0){ display.setCurrent(mainBoard); } }
/*get particular UI container*/
public Displayable getBoard(String boardName){
Displayable displayable = null;
if(boardName.compareTo("loginBoard") == 0){ displayable = loginBoard; } if(boardName.compareTo("mainBoard") == 0){ displayable = mainBoard; } return displayable;
} }
[圖 4-9 class:BMngr_LoginInput]
class B_loginBoard extends Form implements CommandListener { /*local logic objects*/
/*UI components*/
public StringItem showMsg1; public TextField UserName; public StringItem showMsg2; public ChoiceGroup isex;
/*commands*/
private Command enter = new Command("ENTER", Command.SCREEN, 1);
/*Constructor*/
public B_loginBoard() {
/* initialize UI component */
super("login page"); showMsg1 = new StringItem("input your name: ", "");
UserName = new TextField("", "", 50, TextField.ANY);
showMsg2 = new StringItem("select your sex: ", "");
isex = new ChoiceGroup("", ChoiceGroup.EXCLUSIVE);
isex.append("Boy", null); isex.append("Girl", null);
/* set up listeners */
this.setCommandListener(this);
/* append UI component */
this.append(showMsg1); this.append(UserName); this.append(showMsg2); this.append(isex);
/* add commands */
this.addCommand(enter);
}
/*Handle command events*/
public void commandAction(Command command, Displayable displayable){
String selectedStr = null; String oldPath = null; String newPath = null; String align = null;
if(command == enter){
BMngr_LoginInput.instance.lgObj_login.
verify(UserName.getString(), isex.getSelectedIndex()+1, "Location-NCTU");
BMngr_LoginInput.instance.changeBoard("mainBoard");
} } }
[圖 4-10 class:B_loginBoard]
class B_mainBoard extends Form implements CommandListener { /*local logic objects*/
/*UI components*/
/*commands*/
/*Constructor*/
public B_mainBoard() {
/* initialize UI component */
super("main page");
/* set up listeners */
this.setCommandListener(this);
/* append UI component */
/* add commands */
}
/*Handle command events*/
public void commandAction(Command command, Displayable displayable){
String selectedStr = null; String oldPath = null; String newPath = null; String align = null;
} }
[圖 4-11 class:B_mainBoard]
C.
複雜的範例使用PUML 做一個比較複雜的使用者介面描述。在這個例子中, 使用四個
<board>來描述四個使用者介面,而整個例子主要的用意是,展示所有在 PUML 中可以描述出來的使用者介面元件。
第一個<board>主要展示 PUML 可以描述圖片、標籤以及輸入欄位等使用者 介面元件,並且可以將使用者輸入的資料送到後端邏輯部份去處理,處理完 之後,使用者將可以在第二個<board>所描述的使用者介面中看到所輸入的 資料。
第二個<board>主要展示在 PUML 所描述出來的使用者介面中,可以隨時反 應出使用者介面元件的變化,例如:將使用者在第一個使用者介面中所輸入 的資料,透過更新使用者介面元件顯示的方式,將所輸入的資料顯示在第二 個所描述的使用者介面上。另外,在這個使用者介面中,可以透過事件驅動 的方式(按下 button 或 command),選擇要進入第三個或第四個使用者介面。
第三個<board>主要展示 PUML 也可以描述單選模式的選單(single-selection choice group 或 single-selection choice list),並可以將使用者的選擇結果顯示 在同一個使用者介面上。
第四個<board>主要展示 PUML 也可以描述多選模式的選單(multi-selection choice group 或 multi-selection choice list),並可以將使用者的選擇結果顯示 在同一個使用者介面上。
因為篇幅排版的關係,這個範例的 PUML 原始文件檔,以及經過 XSLT 轉 換機制,所轉換出來的J2ME 程式碼和 WML 程式碼,均放在 appendix 中。
另外,本範例也會在 7.2 節中的 Example1 出現,將提供本範例所描述出來 的使用者介面在執行時期的面貌。