圖1. Abacus GUI編譯器.
為什么做我們自己的GUI工具?
為什么我們選擇寫自己的工具?開始,我們決定我們的工具應該包括以下五個要求:
1. 輕易使用
2.不需要布局治理器的使用經驗
3. 不需要Swing的使用經驗
4. 不需要輸出Swing代碼
5. 實現商業邏輯與UI的分離
我們在評估當時可用的GUI開發工具時發現好的IDE都是手寫Swing代碼,這就不符合我們的第一個和最要害要求。
我們定義的輕易使用是指任一開發者不管他/她的Java Swing經驗,都具有在幾分鐘而不是幾小時內開發一個可運行的GUI表單,因此就要是開發者的精力集中在商業邏輯上而不是框架的細節。一開始我們的開發者就需要所見即所得的環境,以便能夠真實地感知當應用程序發布的時候的情況。這一功能的實現節省了開發者的大量時間。但當時我們評估的工具沒有一個能夠實現這個功能;設計的屏幕與輸出的屏幕并不一樣還有糟糕的調度算法,對我們來說簡直就是巨大的倒退。AbaGUIBuilder通過預覽模式來實現這一功能,你可以在開發時看到它運行起來的樣子。
為什么Abacus Research要求UI和商業邏輯的分離?因為企業要處理不斷變換的政府規則,例如稅收和工資計算;我們需要在一個獨立的包裝模塊里維護規則和公式時保持UI不變的能力,使得當公式改變時,應用程序JAR(UI)并不需要變化。因此只有改變的公式需要測試,使得發布的進程簡單化。
為了滿足這個需求,我們設計的GUI編譯器將應用程序和事件匯編到一個應用程序JAR,JAR隱藏了所有的GUI Swing 代碼并且通過一個renderer類(AdaRenderer)在運行時來執行應用程序。
不需要Swing經驗
為了確保開發工具能夠做到真正的所見即所得,我們決定采用類似Delphi和VB中用XY坐標來定位的布局治理方式。采用這種方式,Swing JFrame就是一個畫布,開發者可以將Swing組件放入JFrame的XY布局中。有了XY布局治理器,我們的開發者不需要理解Swing中并不熟悉的,復雜的布局治理器,這樣我們的應用程序開發者就可以把精力集中到應用程序UI和它的商業邏輯中。
事實上,AbaGUIBuilder包含了大部分的Swing可視組件,從面板到制表符頁,還有對菜單﹑菜單項,帶有Java數據庫連接的數據庫感知組件,JFreeChart組件的支持,和導入第三方可視類庫的能力。所有這些組件都可以從組件選擇區拖入一個空框架來開發你的GUI應用程序。
示例項目: 跟蹤開發商的聯絡信息
最佳的展示AbaGUIBuilder RAD(快速應用程序開發)的方式就是開發一個帶有菜單欄的多文本制表符面板的示例程序。首先,你必須通過在組件選擇區選擇JFrame,將其拖入應用程序畫布中來實現將JFrame對象放入空的表單面板中。然后,將所有的可視組件托在JFrame上。注重:當你開始一個新的項目時,必須先放入JFrame,使其成為你的對象畫布,見圖2。
圖2. 應用程序JFrame 作為畫布. 點擊縮略圖查看完整圖.
其次,增加一個制表符格和兩個制表符頁。在組件選擇區的容器區內選擇JTabbedPane將其拖入JFrame1。當JTabbedPane放置好后,右鍵,在彈出菜單中選擇 Add JATabPage在面板上增加兩個制表符頁。如圖3。
圖3. 增機制表符頁: 右鍵制表符頁選擇Add JATabPage.
然后,在屬性欄中選擇TaBTitle為每個制表符頁設置標題。
圖4.可以放入Swing組件的空制表符頁.
這時,你已經有了兩個空的制表符頁,你可以從組件選擇區選擇任意的Swing組件放入其中。在我們的例子中,開發者制表符頁中包含兩個屏面,上面有一系列的JLabel和JTextField對象。你能夠很快的開發出一個類似圖5的應用程序。作為一個可視化應用程序開發者,你能夠體會到使用Abacus GUI編譯器能給你開發復雜的GUI應用程序所帶來的方便。
圖5. 短時開發的應用程序.
編譯器帶的透視圖模式是一個很有用的特征,因為它能夠預覽運行時的應用程序。通過選擇工具欄的Run選項或者按F9鍵,即可進入透視圖模式
圖6. 所見即所得: 開發時檢查視覺效果.
這時保存你的工作,按下Ctrl-S或者選擇Save選項,給項目起名叫devteam,將其保存到示例目錄中。在你保存完項目后,打開AbaGUIBuilder的示例目錄,打開文件devteam.PRoj。proj文件是一個xml文件,其中定義了應用程序中的所有類,對象,對象的性質,甚至是代碼。這是一個對你的可視項目的表達平臺。
增加事件句柄
為每個對象增加事件句柄是一個直截了當的過程。你所要做的就是點擊對象,從事件列表中選擇你希望中斷產生的事件,并為事件填寫合適的Java代碼。再一次證實,AbaGUIBuilder的設計符合Delphi和VB的模式。我們的目標是對應用程序開發者隱藏UI的實現,例如事件監聽器等。舉個例子,如圖7,為了實現按下Exit(退出)按鈕時,彈出一個確認對話框,首先選擇Exit按鈕的actionPerformed事件,然后填入如下Java代碼
圖7. 為可視化組件增加事件句柄.
切記,事件句柄在IDE透視圖模式下并不能使用,只有在運行時才被激活,所以你必須編譯,運行應用程序才能檢查結果。
可視化地增加一個菜單和菜單項是另一個強大的并節省時間的特征。你所要做的就是從組件選擇區選擇JMenuBar并將其放在框架的任意地方。JMenuBar一般放在頂部且XY坐標無關。然后右鍵點擊JMenuBar,彈出一個彈出框,如圖8。為菜單增加JMenu,JMenuItem(s),和事件句柄。
圖8. 可視化增加菜單和菜單項.
然后,復制Exit按鈕的actionPerformed事件代碼到Exit菜單項中,使得不管選擇Exit按鈕還是Exit菜單項都回彈出一樣的確認對話框。最后,點擊工具欄中的Save(With Compile)?,F在你完成了你的第一個AbaGUIBuilder應用程序。
代碼到哪里去了?
我們經常聽到這樣的問題:代碼去哪了?AbaGUIBuilder并不是不創造Java代碼,只不過是編譯器內部生成的Java代碼不被看到和用到而已。GUI編譯器通過運行獨立的包裝程序(renderer)將內部代碼編譯到應用程序的jar文件中。事實上,你可以在/bin/output目錄下檢測AbaGUIBuilder產生的Java代碼。但是切記,這些代碼并使被外部使用的;它只不過作為一個輔助工具,當編譯器生成的代碼萬一有問題時使用。
生成項目文件(.proj)后,GUI編譯器生成兩個文件,你的應用程序jar文件和decl文件。隨后當你寫包裝器文件時,decl文件會有幫助。它包含了所有的對象定義和一個通用入口函數getReferences(),并且它將UI表單的所有可視元素寫為私有變量。我們可以使用decl文件程序段中的這些私有變量實現商業邏輯和UI的分離。
開發過程中,我們推薦你使用例子文件夾中的runproz腳本來運行你的應用程序jar文件。這個腳本文件設置了classpath,填交了所有需要的JAR,使用示例Java包裝器來運行應用程序JAR。如圖9,當你運行devteam應用程序時,命令如下:runproz /abaguibuilder-1.7/samples/devteam.jar
圖9. 部署應用程序.
理解runproz的機制很重要,雖然很簡單,讓我們注重下行:"%JAVA_HOME%/bin/java.exe" exec %1
exec是示例包裝器AbaRenderer提供的默認加載機制,參數%1指的是AbaGUIBuilder應用程序JAR的名字。當JAR的路徑和名字傳給exec.java時,它將加載和運行指定的應用程序JAR。這就是應用程序JAR運行的機制。
編寫自己的包裝器
AbaRenderer包裝器是一個用AbaRenderer 對象來加載應用程序jar的Java程序。包裝器是一個僅僅需要幾行代碼的簡單程序。
public class exec
{
public static AbaRenderer m_AbaRenderer ;
// Assignments for this user interface
public static void main(String[] args)
{
String docname = new String(args[0]);
try
{
System.out.println("Loading.." + docname);
m_AbaRenderer = new AbaRenderer(docname, true , null);
boolean bTestLoad = m_AbaRenderer.load();
if(bTestLoad)
m_AbaRenderer.renderInterface(); }
catch(Exception e)
{e.printStackTrace();}
}
}
public class exec2
{
public static AbaRenderer m_AbaRenderer ;
// Declarations of variables for this user interface.
…….
private JComboBox JStComboBox;
// Assignments for this user interface
public void getReferences()
{
…..
//Loads the visual object JComboBox1 to private data JComboBox1
JStComboBox= (JComboBox)m_AbaRenderer.getObject("JComboBox1");
…..
}
// Assignments for this user interface
public static void main(String[] args)
{
String docname = new String(args[0]);
try
{
System.out.println("Loading.." + docname);
m_AbaRenderer = new AbaRenderer(docname, true , null);
boolean bTestLoad = m_AbaRenderer.load();
if(bTestLoad)
{
m_AbaRenderer.renderInterface();
getReferences();
// Sample access to objects
JStComboBox.addItem("FL");
JStComboBox.addItem("CA");
JStComboBox.addItem("WA");
JStComboBox.addItem("MD");
JStComboBox.addItem("PA");
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
新聞熱點
疑難解答