上一篇博客介紹了NetBeans Java代碼編輯器,這一篇將介紹用NetBeans 開(kāi)發(fā)基于Swing Application Framework (JSR 296) 的程序,Swing一直以來(lái)是飽受爭(zhēng)議的GUI庫(kù),特別是SWT與Swing的爭(zhēng)論,分別體現(xiàn)在了Eclipse與NetBeans的爭(zhēng)論上。
在此,我無(wú)心討論SWT與Swing孰優(yōu)孰劣,你要是真的對(duì)這個(gè)感興趣,可以到williamchen的博客里的Swing專欄看看,該專欄博主已經(jīng)對(duì)SWT和Swing分析得非常透徹:
http://blog.sina.com.cn/swingjava
Swing在1998年末作為Java 2的一部分發(fā)布了1.0,但是當(dāng)時(shí)發(fā)布的版本不管是性能還是外觀都足以令人失望。雖然當(dāng)時(shí)Swing小組的工程師使用了最前沿的技術(shù),如設(shè)計(jì)模式,但是時(shí)的Swing小組已經(jīng)被性能、本地化外觀一致性問(wèn)題以及許多錯(cuò)誤深深陷住了,這些問(wèn)題幾乎把整個(gè)項(xiàng)目拖垮。
幸虧,Swing小組堅(jiān)持了下來(lái),要不然今天我們就不會(huì)看到像NetBeans這樣的IDE了。自從JDK1.5后,Java的性能已經(jīng)有了巨大的改觀,現(xiàn)在1.6下,Swing的性能已經(jīng)完全不是問(wèn)題。
那么Swing的優(yōu)勢(shì)有那些呢?
l 優(yōu)秀的設(shè)計(jì),正如剛才所說(shuō)的,Swing從九十年代中期開(kāi)始設(shè)計(jì)就用了當(dāng)時(shí)最前沿的開(kāi)發(fā)方法學(xué)。可以說(shuō)Swing在當(dāng)今各種GUI庫(kù)中,設(shè)計(jì)是非常優(yōu)雅的。
l 輕量級(jí)
l 官方的存在JRE中,發(fā)布程序不需要像SWT那樣還要捆綁自己的GUI庫(kù)
l 真正的平臺(tái)獨(dú)立,Swing組件由Java 2D繪制
l 輕易的更改面觀模式
l 強(qiáng)大的IDE支持,現(xiàn)在用NetBeans做界面,幾乎不用你敲一行代碼。
l Swing現(xiàn)在又多了一個(gè)殺手級(jí)框架Swing Application Framework (JSR 296)
下面開(kāi)始我的第二篇Java博客
NetBeans 6.0 提高生產(chǎn)力之Swing Application Framework (JSR 296)
Swing Application Framework簡(jiǎn)介
Swing Application Framework(以下簡(jiǎn)稱SAF)致力于簡(jiǎn)化Swing應(yīng)用程序的開(kāi)發(fā),框架定義了對(duì)大多數(shù)桌面應(yīng)用程序的共有的基礎(chǔ)設(shè)施:
l 應(yīng)用程序生命周期管理,特別是GUI的啟動(dòng)和關(guān)閉。
l 對(duì)資源管理和載入的支持,這些資源是字符串,格式化的消息,圖像,顏色,字體以及桌面應(yīng)用程序共有的其他類型的資源。
l 對(duì)動(dòng)作定義,管理和綁定的支持,其中包含了異步運(yùn)行的動(dòng)作(在后臺(tái)運(yùn)行)。
l 持久化會(huì)話狀態(tài):支持自動(dòng)地,有選擇地保存應(yīng)用程序一次運(yùn)行到下次運(yùn)行的GUI狀態(tài)。比如頂層的窗口幾何位置。
用NetBeans開(kāi)發(fā)SAF
SAF已經(jīng)定義了大多數(shù)桌面應(yīng)用程序的基礎(chǔ)設(shè)施,我們可以更方便的開(kāi)發(fā)Swing程序了,但是手動(dòng)編碼開(kāi)發(fā)GUI還是讓很多人抓狂。能不能提供一個(gè)像VB一樣的環(huán)境,讓程序員更加專注于功能的實(shí)現(xiàn)而不是界面的實(shí)現(xiàn)?答案是肯定的,NetBeans 6.0就為開(kāi)發(fā)SAF提供了這樣一個(gè)環(huán)境,甚至比VB還要做得更好。
那么到底NetBeans6.0為SAF提供了什么樣的優(yōu)勢(shì)呢?
l 生成基礎(chǔ)框架,不必每次新創(chuàng)建一個(gè)程序的時(shí)候都從頭開(kāi)始
l 唾手可得的國(guó)際化支持,在Netbeans里對(duì)SAF程序國(guó)際化,簡(jiǎn)單得不能再簡(jiǎn)單
l 擁有Swing世界里的明星級(jí)UI設(shè)計(jì)工具模塊Matisse提供的免費(fèi)大餐
l 用NetBeans開(kāi)發(fā)SAF,意味著你還可以使用Beans Binding(JSR 295),數(shù)據(jù)綁定將問(wèn)題變得更簡(jiǎn)單
開(kāi)始之前
用NetBeans 6.0開(kāi)發(fā)基于SAF,其實(shí)不用明白SAF,主要遵循一定的開(kāi)發(fā)原則也可以開(kāi)發(fā)出穩(wěn)定高效的SAF程序來(lái)
但是為了你更深入的理解SAF,強(qiáng)烈建議看下面的文章
l Using the Swing Application Framework (JSR 296)
http://java.sun.com/developer/technicalArticles/javase/swingappfr/
l Swing應(yīng)用程序框架(Swing Application Framework)API緒論(JSR-296)之一
http://www.javaeye.com/topic/81326
Swing應(yīng)用程序框架(Swing Application Framework)API緒論(JSR-296)之二
http://www.javaeye.com/topic/81327
l 如果你有更多的時(shí)間,那么請(qǐng)看下面網(wǎng)址有關(guān)Swing的部分
http://blog.sina.com.cn/swingjava
開(kāi)發(fā)環(huán)境準(zhǔn)備
JDK1.6或以上版本
NetBeans6.0或以上版本
提示:Netbeans 網(wǎng)站上提供有六種捆綁包下載
l Web & Java EE
l Mobility
l Java SE
l Ruby
l C/C++
l All
開(kāi)發(fā)Swing Application Framework只需要Java SE下載包就行了
這樣能真正發(fā)揮NetBeans的性能!
創(chuàng)建項(xiàng)目
我們新建一個(gè)項(xiàng)目,從Java種類里選擇 Java Desktop Application,如下圖

點(diǎn)擊下一步,接著輸入項(xiàng)目名稱、項(xiàng)目存放地址和程序的主類
在Choose Application Shell里面我們選擇Basic Application,單擊完成

提示:我們?nèi)绻麆?chuàng)建基于Swing的數(shù)據(jù)庫(kù)程序,那么選擇BataBase Application將提供極大的便利。但是在這里我只是介紹Basic Application,也就是現(xiàn)在我們用SAF開(kāi)發(fā)普通的桌面程序。
生成的項(xiàng)目目錄結(jié)構(gòu)

l META-INF/services目錄
該目錄一般存在一個(gè)JAR包里面
META-INF/services目錄涉及一個(gè)模式:服務(wù)提供者模式
引入該模式一般是為了程序松散耦合,而且是IoC(控制反轉(zhuǎn))的另一種實(shí)現(xiàn)方式
服務(wù)提供者模式一般有兩個(gè)角色
² 服務(wù) :一般為一個(gè)抽象類
² 服務(wù)提供者 :抽象類的實(shí)現(xiàn)
存在META-INF/services目錄的JAR包一般為一個(gè)“服務(wù)提供者”
用NetBeans開(kāi)發(fā)中小型程序不需要服務(wù)提供者概念,如果你要深入理解
可以Baidu或Google一下META-INF/services
l foo包
foo包是我們創(chuàng)建程序的主類foo.FooApp時(shí),NetBeans自動(dòng)為我們生成的,
我們來(lái)看看NetBeans為我們生成了什么基礎(chǔ)框架類:
1、FooApp.java

public class FooApp extends SingleFrameApplication
{



/** *//**

* 在啟動(dòng)的時(shí)候創(chuàng)建和顯示程序的主框架

*/


@Override protected void startup()
{

show(new FooView(this));

}


/** *//**

*這個(gè)方法是用相應(yīng)的資源注入到特定的Window來(lái)初始化程序

*因?yàn)槲覀冇肗etBeansk開(kāi)發(fā),所以相應(yīng)的資源是通過(guò)Gui生成器來(lái)完成

*也就是不用我們手動(dòng)編寫(xiě)代碼

*所以這個(gè)方法不是必須的

*/


@Override protected void configureWindow(java.awt.Window root)
{

}


/** *//**

* 一個(gè)方便的靜態(tài)獲取器,用來(lái)獲取FooApp類的實(shí)例

*/


public static FooApp getApplication()
{

return Application.getInstance(FooApp.class);

}


/** *//**

* 程序的運(yùn)行入口點(diǎn)

*/


public static void main(String[] args)
{

launch(FooApp.class, args);

}

}

FooApp.java里面的代碼是NetBean為我們生成的,開(kāi)發(fā)簡(jiǎn)單的程序這里基本上不需要更改什么。
2、FooAboutBox.java
每個(gè)程序都應(yīng)該有一個(gè)關(guān)于界面,Netbeans為我們生成了關(guān)于的模板
修改相應(yīng)文字就可以了,當(dāng)然也可以自己做個(gè)About界面

3、FooView.java
FooView.java是程序View部分的關(guān)鍵,由于生成的代碼比較多
在解釋代碼之前,我先看看Design部分

NetBenas給我們生成的框架非常簡(jiǎn)單明了
需要注意的是圖上標(biāo)識(shí)的兩個(gè)地方
標(biāo)有1的地區(qū)為消息地區(qū),我們的程序完成任務(wù)后,在這里提示消息
標(biāo)有2的地區(qū)為任務(wù)進(jìn)度條,程序執(zhí)行任務(wù)時(shí)在這里現(xiàn)實(shí)任務(wù)進(jìn)度,當(dāng)然任務(wù)有確定模式和不確定模式,不確定模式的進(jìn)度條持續(xù)地顯示動(dòng)畫(huà)來(lái)表示正進(jìn)行的操作。
接下來(lái)我們看看FooView.java的構(gòu)造器的代碼:

public FooView(SingleFrameApplication app)
{

super(app);

initComponents();

ResourceMap resourceMap = getResourceMap();

int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");


messageTimer = new Timer(messageTimeout, new ActionListener()
{


public void actionPerformed(ActionEvent e)
{

statusMessageLabel.setText("");

}

});

messageTimer.setRepeats(false);

int busyAnimationRate = resourceMap.getInteger("StatusBar.busyAnimationRate");


for (int i = 0; i < busyIcons.length; i++)
{

busyIcons[i] = resourceMap.getIcon("StatusBar.busyIcons[" + i + "]");

}


busyIconTimer = new Timer(busyAnimationRate, new ActionListener()
{


public void actionPerformed(ActionEvent e)
{

busyIconIndex = (busyIconIndex + 1) % busyIcons.length;

statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);

}

});

idleIcon = resourceMap.getIcon("StatusBar.idleIcon");

statusAnimationLabel.setIcon(idleIcon);

progressBar.setVisible(false);

// connecting action tasks to status bar via TaskMonitor

TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());

taskMonitor.addPropertyChangeListener(


new java.beans.PropertyChangeListener()
{


public void propertyChange(java.beans.PropertyChangeEvent evt)
{

String propertyName = evt.getPropertyName();


if ("started".equals(propertyName))
{


if (!busyIconTimer.isRunning())
{

statusAnimationLabel.setIcon(busyIcons[0]);

busyIconIndex = 0;

busyIconTimer.start();

}

progressBar.setVisible(true);

progressBar.setIndeterminate(true);


} else if ("done".equals(propertyName))
{

busyIconTimer.stop();

statusAnimationLabel.setIcon(idleIcon);

progressBar.setVisible(false);

progressBar.setValue(0);


} else if ("message".equals(propertyName))
{

String text = (String)(evt.getNewValue());

statusMessageLabel.setText((text == null) ? "" : text);

messageTimer.restart();


} else if ("progress".equals(propertyName))
{

int value = (Integer)(evt.getNewValue());

progressBar.setVisible(true);

progressBar.setIndeterminate(false);

progressBar.setValue(value);

}

}

});

}

一大段代碼,看起來(lái)是不是眼花繚亂啊,其實(shí)這么一大斷代碼是IDE給我們生成的用來(lái)初始發(fā)剛才所示的兩個(gè)區(qū)域的消息區(qū)和進(jìn)度條區(qū)域的。
也就是初始化消息區(qū)域和進(jìn)度條區(qū)域,如果不想自定義消息現(xiàn)實(shí)和任務(wù)進(jìn)度條的實(shí)現(xiàn)方式,上面一大段代碼大可不必理會(huì)。
我們?cè)賮?lái)看一段代碼:
@Action


public void showAboutBox()
{


if (aboutBox == null)
{

JFrame mainFrame = FooApp.getApplication().getMainFrame();

aboutBox = new FooAboutBox(mainFrame);

aboutBox.setLocationRelativeTo(mainFrame);

}

FooApp.getApplication().show(aboutBox);

}

看到方法名我們就知道,這個(gè)是用來(lái)實(shí)現(xiàn)關(guān)于界面的
我們運(yùn)行一下程序,在點(diǎn)擊菜單欄里面的 Help > About..

結(jié)果,關(guān)于界面跳了出來(lái)。
看到這里你也許會(huì)驚訝,因?yàn)榘凑諅鹘y(tǒng)的方法,相應(yīng)的菜單應(yīng)該有相應(yīng)的ActionListener事情監(jiān)聽(tīng)器才能發(fā)生事件啊!
別著急,你看showAboutBox()方法前不是有一個(gè)注解: @Action
這個(gè)注解涉及到SAF對(duì)動(dòng)作的定義,我們后面將詳細(xì)講解
l foo.resources、foo.resources.busyicons包
foo.resources、foo.resources.busyicons包是用來(lái)存放程序的圖像、文字等資源的地方
后面講到程序的國(guó)際化的時(shí)候再作介紹。
忘掉ActionListener事件監(jiān)聽(tīng)器,擁抱@Action
上面我們已經(jīng)提到,沒(méi)有相應(yīng)的ActionListener事件監(jiān)聽(tīng)器,點(diǎn)擊菜單欄里面的 Help > About..也照樣能觸發(fā)事件,這是怎么回事?
原來(lái)是SAF框架對(duì)有@Action注釋的方法進(jìn)行了管理。
既然用原來(lái)的ActionListener已經(jīng)處理得非常好,為什么SAF專家組的人還弄個(gè)@Action,這不是沒(méi)事找事干嗎?呵呵,下面我們通過(guò)幾個(gè)例子來(lái)說(shuō)明引入@Action的好處
l 制作環(huán)境相關(guān)的按鈕

我們經(jīng)常遇到這樣的按鈕或菜單,一般情況下它是不可用的,如上圖畫(huà)圈的三個(gè)按鈕,要等一定的條件他們自動(dòng)啟用。
我舉例用@Action做這樣的按鈕看看,不用擔(dān)心,不必寫(xiě)多少代碼,IDE幫我們完成了大部分的工作
我們要做的功能如下
點(diǎn)擊選擇CheckBox選項(xiàng)后,按鈕自動(dòng)開(kāi)啟,取消選中后按鈕變灰色,不可用。

在右邊的Palette屬性面板中拖出我們需要的兩個(gè)組件到程序主界面,并修改Text文字

右鍵點(diǎn)擊按鈕,選擇 Set Action…

在跳出來(lái)對(duì)話框中,在Action 選擇框中選中Create New Action

接下填寫(xiě)按鈕的相關(guān)信息,這里我做一下簡(jiǎn)單的說(shuō)明
Action’s Class :動(dòng)作方法存放在那個(gè)類中
Action’s Method:動(dòng)作方法的名稱,比如上面提到的跳出關(guān)于對(duì)話框的方法showAboutBox()
Background Task選項(xiàng):這個(gè)暫時(shí)不理它,后面將講到
Attributes :1、Basic標(biāo)簽 設(shè)置按鈕的顯示文字、快捷鍵、按鈕圖像。
2、Advanced標(biāo)簽可要注意了,因?yàn)檫@個(gè)和我們現(xiàn)在要做的例子關(guān)系非常大,我們?cè)?/span>Advanced標(biāo)簽里的Enabled Preproty 寫(xiě)上 hasSelect(名字可以自己寫(xiě)),如下面第二個(gè)圖


單擊OK,馬上看到IDE為我們生成的代碼

這樣我們就可以通過(guò)setHasSelect()方法來(lái)設(shè)置按鈕的可用性,setHasSelect(ture) 時(shí)按鈕開(kāi)啟,setHasSelect(false)時(shí)按鈕不可用。
接下來(lái)選擇CheckBox組件,單擊右鍵,再選擇下圖所示

出來(lái)代碼中寫(xiě)上一行代碼:
setHasSelect( ((JCheckBox)evt.getSource()).isSelected());
最后是這樣子的

private void jCheckBox1ItemStateChanged(java.awt.event.ItemEvent evt)
{

setHasSelect( ((JCheckBox)evt.getSource()).isSelected());

}

自此環(huán)境相關(guān)的按鈕就做完了,我們可以運(yùn)行代碼試試。
從上面的例子中我們看到,做這個(gè)例子真正只寫(xiě)了一行代碼:
setHasSelect( ((JCheckBox)evt.getSource()).isSelected());
其它都是通過(guò)IDE生成的,多虧IDE和SAF的Action我們才能如此高效的制作程序。
l 菜單和按鈕關(guān)聯(lián)
菜單和按鈕經(jīng)常表現(xiàn)為同一個(gè)行為,我們當(dāng)然可以各自實(shí)現(xiàn)它,但是這樣就產(chǎn)生了冗余
編寫(xiě)程序最總要的一點(diǎn)就是不要重復(fù)代碼。在Design模式下右鍵單擊相應(yīng)的菜單,在Set Action…操作里面選擇相應(yīng)Action
這樣菜單和按鈕就關(guān)聯(lián)起來(lái)了,該菜單和按鈕行為相同,SAF如此簡(jiǎn)單的為我們完成了任務(wù)。
這又是Action解決了一大問(wèn)題
l Background Task
剛才在制作環(huán)境相關(guān)的按鈕時(shí),我們忽略一個(gè)選項(xiàng)

現(xiàn)在我們來(lái)介紹這個(gè)非常重要的特性
以前人們不斷抱怨Swing是如何慢,其實(shí)JRE1.5后,特別是1.6后Swing性能已經(jīng)完全不是問(wèn)題,問(wèn)題是開(kāi)發(fā)Swing的程序員沒(méi)有處理好Swing的線程問(wèn)題,比如本該在后臺(tái)運(yùn)行的任務(wù)卻直接寫(xiě)在Swing中,造成Swing程序相應(yīng)緩慢。
在以前你要非常熟練Swing和小心才能寫(xiě)出高質(zhì)量的Swing程序來(lái),但是現(xiàn)在你利用SAF提供的框架支持,處理后臺(tái)任務(wù)變得非常容易。
我們 Set Action 的時(shí)候把Background Task選項(xiàng)選中,最后看一下IDE給我們生成了什么代碼:
原來(lái)的代碼:
@Action(enabledProperty = "hasSelect")


public Task actionMethodName()
{

}

Background Task選項(xiàng)選中后為如下代碼:
@Action(enabledProperty = "hasSelect")


public Task actionMethodName()
{

return new ActionMethodNameTask(getApplication());

}

private class ActionMethodNameTask extends


org.jdesktop.application.Task<Object, Void>
{


ActionMethodNameTask(org.jdesktop.application.Application app)
{

// Runs on the EDT. Copy GUI state that

// doInBackground() depends on from parameters

// to ActionMethodNameTask fields, here.

super(app);

}


@Override protected Object doInBackground()
{

// Your Task's code here. This method runs

// on a background thread, so don't reference

// the Swing GUI from here.

return null; // return your result

}


@Override protected void succeeded(Object result)
{

// Runs on the EDT. Update the GUI based on

// the result computed by doInBackground().

}

}

可以看到,actionMethodName()方法里運(yùn)行的代碼將在一個(gè)新線程中運(yùn)行
如果你要徹底明白上面的代碼和EDT是什么概念,請(qǐng)瀏覽下面的博客地址
http://blog.sina.com.cn/swingjava中有關(guān)Swing部分。
如果您懶得瀏覽,那么請(qǐng)遵循下面的建議
1、在ActionMethodNameTask構(gòu)造器中
代碼運(yùn)行在EDT(事件分派進(jìn)程)中,在這里復(fù)制doInBackground() 方法中所需要的GUI 的狀態(tài)或參數(shù)到ActionMethodNameTask的成員變量中。
2、doInBackground()方法中,不要存放處理GUI界面的代碼,該方法返回的值將自動(dòng)傳到后面succeeded(Object Result)中
3、succeeded()運(yùn)行在EDT中,任務(wù)成功的執(zhí)行后才執(zhí)行該方法,該方法主要收集doInBackground()方法運(yùn)行后的結(jié)果以用來(lái)更新GUI程序。
我們做一下試驗(yàn),為ActionMethodNameTask增加一些代碼:
private class ActionMethodNameTask extends


org.jdesktop.application.Task<Object, Void>
{


ActionMethodNameTask(org.jdesktop.application.Application app)
{

super(app);

}


@Override protected Object doInBackground()
{


for(int i=0;i<1000000;i++)
{

System.out.println(i);

}

return null;

}


@Override protected void succeeded(Object result)
{

setMessage("運(yùn)行成功");

}

}

運(yùn)行程序后點(diǎn)擊按鈕
任務(wù)開(kāi)始:

任務(wù)結(jié)束:

注意提示信息只顯示一定時(shí)間,這個(gè)時(shí)間可以自己設(shè)定,一定時(shí)間后信息自動(dòng)消失。
l 制作阻塞按鈕

我經(jīng)常要做具有阻塞功能的按鈕,比如我們按一下按鈕,就跳出如上對(duì)話框,程序在后臺(tái)運(yùn)行任務(wù),但是我們不能進(jìn)行其它操作,除非我們點(diǎn)擊取消按鈕。
制作這樣的按鈕,其實(shí)非常簡(jiǎn)單:
在Set Action...進(jìn)行如下設(shè)置就可以了

Blocking Type 可以選擇NONE,ACTION,COMPONENT,WINDOW,APPLICATION指定阻塞的范圍空間,你可以自己嘗試一下,效果是怎樣的。
從上面幾個(gè)小例子可以看到引入@Action巨大好處了吧。
國(guó)際化支持
正如開(kāi)始所說(shuō)的,SAF本身就很好的支持了國(guó)際化,再加上NetBeans輔助,國(guó)際化簡(jiǎn)直易如反掌。
我們知道一些企業(yè)框架比如Structs、JSF是通過(guò)后綴名為properties的文件保存相關(guān)資源的。
SAF也是,我們看看IDE為我們生成的properties文件

從上圖可以看出,
FooApp.java
FooAboutBox.java
FooView.java
這三個(gè)類在foo.resources包分別對(duì)應(yīng)有后綴名為properties的文件
FooApp. properties
FooAboutBox. properties
FooView. Properties
也就是說(shuō),類里面用到文字資源,圖像資源集中放到了一起。這樣國(guó)際化就相當(dāng)簡(jiǎn)單了
這時(shí)也許你會(huì)說(shuō),一開(kāi)始就寫(xiě)properties的文件,豈不是很麻煩?
別忘了,我們NetBeans的支持,做這個(gè)工作幾乎不費(fèi)你任何力氣

在可視化編輯頁(yè)面,我直接修改相應(yīng)文字,IDE會(huì)自動(dòng)為我們把相應(yīng)的文字保存到對(duì)應(yīng)的properties的文件中。
根本不用自己手動(dòng)敲寫(xiě)下面的文字
jCheckBox1.text=選中按鈕開(kāi)啟
尾聲
關(guān)于用NetBeans開(kāi)發(fā)Swing Application Framework程序其實(shí)還有很多我沒(méi)有說(shuō)清楚,有些也很難說(shuō)清楚,關(guān)鍵還是要自己親身試驗(yàn)一下,正如大牛們所說(shuō)的“理論看不懂就去實(shí)踐,實(shí)踐不懂就去看理論”。
本文僅起到入門(mén)介紹的作用。開(kāi)發(fā)需要的SAF JavaDoc文檔可以下面所示查看:

為了你更好的理解,我用SAF做一個(gè)端口掃描程序,這個(gè)程序很不完善,僅做演示:

點(diǎn)擊這里下載源代碼:
PortScan.rar
(提示:用NetBeans6.X打開(kāi)項(xiàng)目目錄即可)
用SAF做的更完整的程序:
l mp3在線搜索工具

你可以到作者博客查看更詳細(xì)信息:
http://www.tkk7.com/huliqing/archive/2008/03/26/188817.html
l 單詞Mp3隨身寶DIY

本人的英語(yǔ)成績(jī)一直不是很好,特別是詞匯量很低,很多單詞不會(huì)發(fā)音。
所以我就有個(gè)想法,能不能把自己想要背記的單詞做成MP3的形式,單詞和單詞的解釋放到對(duì)應(yīng).lrc文件中,隨意挑選單詞,
制作成帶同步歌詞(LRC文件)的MP3文件,這樣在MP3機(jī)上就能邊聽(tīng)單詞邊同步看單詞及其解釋,單詞先后次序、間隔多長(zhǎng),
可以相應(yīng)自由地調(diào)整,讓我們的MP3機(jī)變成英語(yǔ)學(xué)習(xí)機(jī)!我通過(guò)網(wǎng)絡(luò)尋找這樣的軟件。
但是找了好久就是找不到合適的軟件,只是有一個(gè)《我愛(ài)背單詞》的軟件有類似這樣的一個(gè)功能,但是該軟件是閉源收費(fèi)軟件,
免費(fèi)版的語(yǔ)音是合成的,效果非常差。求人不如求自己,于是產(chǎn)生制作這個(gè)程序的想法。
這個(gè)程序原本就是想開(kāi)源的,但是我拿去參加學(xué)校的電腦作品賽了,比賽的作品先前不能發(fā)布。所以暫時(shí)不發(fā)布程序和源代碼,等比賽結(jié)束再上傳程序和源代碼。這個(gè)可能要一段時(shí)間,請(qǐng)大家耐心等待消息。
l 用NetBeans開(kāi)發(fā)但是沒(méi)有用SAF的YOYOPlayerMp3播放器

詳細(xì)信息請(qǐng)看作者的博客:
http://www.tkk7.com/hadeslee/archive/2007/12/31/171678.html
通過(guò)上面幾個(gè)程序可以體現(xiàn)出NetBeans的強(qiáng)大特性來(lái)(不僅僅是做桌面程序哦)!SAF框架加上NetBeans,我們可以專注程序的功能而不是程序的基礎(chǔ)實(shí)施上,而且即使是初學(xué)者也可以編寫(xiě)出高性能的Swing程序來(lái)。我相信隨著越來(lái)越多的人了解SAF和NetBeans,后面會(huì)不斷涌現(xiàn)出新的Swing桌面程序來(lái),讓我們拭目以待吧!
由于水平有限,文中有些術(shù)語(yǔ)解釋可能不準(zhǔn)確,歡迎批評(píng)指正!(這也是我寫(xiě)博客的原因,通過(guò)他人認(rèn)識(shí)自己的不足)
版權(quán)聲明:
本文由令狐蟲(chóng)原創(chuàng),歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)保留博客地址:
http://www.tkk7.com/linghuchong/