<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 18  文章 - 96  trackbacks - 0
    <2007年9月>
    2627282930311
    2345678
    9101112131415
    16171819202122
    23242526272829
    30123456


    常用鏈接

    留言簿(4)

    隨筆檔案

    相冊(cè)

    我的兄弟們

    搜索

    •  

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

         摘要: 很久沒(méi)有回來(lái)這里寫(xiě)技術(shù)BLOG了,這里的氛圍還行,大家都對(duì)一個(gè)問(wèn)題積極的思考(至少之前這里給我的感覺(jué)是這樣的),2年里面自己也忙著做些事情,沒(méi)有寫(xiě),最近有空也就寫(xiě)寫(xiě),偶爾會(huì)去oschine.net看看新聞,然后就在那里看到了一個(gè)人提出的問(wèn)題很有意思,就是怎么表達(dá)式求解,例如(1 + 2) / 3 - 1 * 2 + 5 / (3 + 2)這樣的字符串輸入,怎么樣解析之后輸出結(jié)果。說(shuō)來(lái)也好笑,對(duì)于我...  閱讀全文
    posted @ 2011-11-09 10:36 ruislan 閱讀(1761) | 評(píng)論 (6)編輯 收藏
         摘要: 很久沒(méi)來(lái)了,不是一位朋友給我發(fā)郵件問(wèn)我關(guān)于swing的問(wèn)題,才想起,然后翻看了之前的代碼,發(fā)現(xiàn)當(dāng)年還實(shí)現(xiàn)了一個(gè)Vista風(fēng)格的按鈕沒(méi)有放出來(lái),現(xiàn)在補(bǔ)上,也許現(xiàn)在人們的swing水平對(duì)我這代碼不屑一顧,不過(guò)還是依然拋磚引玉,給未知的人們一個(gè)啟發(fā)。還是老慣例,上效果圖: 正常情況下:(和vista一樣具有焦點(diǎn)的按鈕的顏色漸深漸淺的循環(huán)變化) 鼠標(biāo)在區(qū)域內(nèi)時(shí): 鼠標(biāo)按下去: 然后是代...  閱讀全文
    posted @ 2009-09-12 12:54 ruislan 閱讀(2486) | 評(píng)論 (3)編輯 收藏
    認(rèn)為自己是達(dá)人的就不用看了。只是一點(diǎn)小技巧,不敢班門(mén)弄斧,做個(gè)總結(jié),為那些還不知道的解解惑,隨便告訴大家我還活著。

    最近客戶提了個(gè)小改動(dòng),客戶網(wǎng)站上圖片存放的目錄需要改動(dòng)一下。例如在網(wǎng)上訪問(wèn)是www.tkk7.com/images/*.*,在服務(wù)器上的目錄是D:/<webroot>/images/*.*,客戶想把這個(gè)images目錄下的資源全部移動(dòng)到E:/data/里面去,但是在網(wǎng)上www.tkk7.com/images/*.*還是同樣可以訪問(wèn)得到,我剛開(kāi)始犯了形式主義的錯(cuò)誤,老是想用程序解決,一會(huì)filter,一會(huì)servlet/action,后來(lái)我配置程序的時(shí)候突然看到了server.xml,于是我想到了選擇用映射的方式。正好,server.xml中的<Context>就是做這個(gè)事情的。于是乎我們?cè)?lt;Host></Host>中增加了一個(gè)<Context docBase="E:/data/images" path="/images">,OK,重啟之后,所有檢索www.tkk7.com/images路徑下的資源實(shí)際上都由E:/data/images下的資源提供了。

    posted @ 2008-02-15 16:41 ruislan 閱讀(1272) | 評(píng)論 (3)編輯 收藏
    在寫(xiě)多線程程序的時(shí)候,你就像個(gè)經(jīng)理,手下有那么或多或少的職員,你負(fù)責(zé)協(xié)調(diào)職員之間的工作,如果你稍不留神,職員之間就陷入了相互等待的尷尬狀態(tài)。還好,大多數(shù)時(shí)候多線程都還在我們掌控之內(nèi),即便是遇到這樣的deadlock情況,我們也能夠去修正,但是有的時(shí)候生活就是那么不盡人意,特別是NIO這種你不能掌控的時(shí)候,且看下面的代碼:

    /**
     * @(#)DeadLock.java  v0.1.0  2007-12-13
     
    */
    package ruislan.rswing.test;

    import java.net.InetSocketAddress;
    import java.nio.channels.ClosedChannelException;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.SocketChannel;
    import java.util.concurrent.Executors;

    /**
     * NIO DeadLock
     * 
     * 
    @author ruislan <a href="mailto:z17520@126.com"/>
     * 
    @version 0.1.0
     
    */
    public class DeadLock {
        
    public static void main(String[] args) throws Exception {
            Service service 
    = new Service();
            Executors.newSingleThreadExecutor().execute(service);

            SocketChannel channel 
    = SocketChannel.open();
            channel.configureBlocking(
    false);
            channel.connect(
    new InetSocketAddress("http://www.tkk7.com"80));
            service.addChannel(channel);
        }

        
    static class Service implements Runnable {
            Selector selector;

            
    public Service() {
            }

            
    public void run() {
                
    try {
                    selector 
    = Selector.open();
                    
    while (true) {
                        selector.select();
                        System.out.println(selector.selectedKeys().size());
                    }
                } 
    catch (Exception e) {
                }
            }

            
    public void addChannel(SocketChannel channel) {
                
    try {
                    channel.register(selector, SelectionKey.OP_CONNECT
                            
    | SelectionKey.OP_READ);
                    System.out.println(
    "can reach here?when pigs fly!");
                } 
    catch (ClosedChannelException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    乍看之下,我們的代碼沒(méi)有問(wèn)題,但是運(yùn)行之后你會(huì)發(fā)現(xiàn),這句System.out.println("can reach here?when pigs fly!");永遠(yuǎn)無(wú)法執(zhí)行,也就是說(shuō)register()方法被阻塞了!Oh god bless,讓我們看看JavaDoc是怎么說(shuō)的:

    ...
    可在任意時(shí)間調(diào)用此方法。如果調(diào)用此方法的同時(shí)正在進(jìn)行另一個(gè)此方法或 configureBlocking 方法的調(diào)用,則在另一個(gè)操作完成前將首先阻塞該調(diào)用。然后此方法將在選擇器的鍵集上實(shí)現(xiàn)同步,因此如果調(diào)用此方法時(shí)并發(fā)地調(diào)用了涉及同一選擇器的另一個(gè)注冊(cè)或選擇操作,則可能阻塞此方法的調(diào)用。
    ...

    看這句“可在任意時(shí)間調(diào)用此方法。”,也就是說(shuō)我們調(diào)用的時(shí)間沒(méi)有任何限制,而阻塞的情況只會(huì)出現(xiàn)在“如果調(diào)用此方法的同時(shí)正在進(jìn)行另一個(gè)此方法或 configureBlocking 方法的調(diào)用”的情況下,即便是阻塞了,我相信“正在進(jìn)行另一個(gè)此方法或configureBlocking”也不會(huì)花掉太多的時(shí)間,況且這里沒(méi)有上面這樣的情況出現(xiàn)。那register()是被誰(shuí)擋住了?或者是BUG?

    我們來(lái)分析一下程序,程序有兩個(gè)線程主線程和Service線程,主線程啟動(dòng)后啟動(dòng)了Service線程,Service線程啟動(dòng)Selector然后Service線程陷入select()的阻塞中,同時(shí),主線程調(diào)用Service的addChannel()方法來(lái)添加一個(gè)SocketChannel,嗯,兩個(gè)線程之間唯一的聯(lián)系就是selector,看來(lái)要從selector尋找線索,很可惜,selector的實(shí)現(xiàn)沒(méi)有源代碼可查,不過(guò)可以肯定是channel的register()會(huì)調(diào)用selector的register(),雖然此時(shí)持有selector的Service線程被select()方法所阻塞,但是并不影響其他線程對(duì)其操作吧?那么,剩下的解釋就是Selector的select()方法和register()方法公用了一個(gè)鎖,select()方法阻塞住了,所以register()拿不到這個(gè)鎖了,那么這樣一來(lái)我們就只能保證讓select()或者register()不能同時(shí)調(diào)用或者register()調(diào)用的時(shí)候select()不持有這個(gè)鎖,也就是說(shuō)我們要用Service線程自己來(lái)執(zhí)行addChannel()方法,所以改進(jìn)如下:

    /**
     * @(#)DeadLock.java  v0.1.0  2007-12-13
     
    */
    package ruislan.rswing.test;

    import java.net.InetSocketAddress;
    import java.nio.channels.ClosedChannelException;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.SocketChannel;
    import java.util.Queue;
    import java.util.concurrent.LinkedBlockingQueue;

    /**
     * NIO DeadLock
     * 
     * 
    @author ruislan <a href="mailto:z17520@126.com"/>
     * 
    @version 0.1.0
     
    */
    public class DeadLock {
        
    public static void main(String[] args) {
            Service service 
    = new Service();
            
    new Thread(service).start();
            
    for (int i = 0; i < 5; i++) {
                
    new Thread(new ChannelAdder(service)).start();
            }
        }

        
    static class ChannelAdder implements Runnable {
            
    private Service service;

            
    public ChannelAdder(Service service) {
                
    this.service = service;
            }

            @Override
            
    public void run() {
                
    try {
                    SocketChannel channel 
    = SocketChannel.open();
                    channel.configureBlocking(
    false);
                    channel.connect(
    new InetSocketAddress(
                            
    "http://www.tkk7.com"80));
                    service.addChannel(channel);
                } 
    catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        
    static class Service implements Runnable {
            
    private Selector selector;
            
    private Queue<SocketChannel> pendingRegisters;

            
    public Service() {
                pendingRegisters 
    = new LinkedBlockingQueue<SocketChannel>();
            }

            
    public void run() {
                
    try {
                    selector 
    = Selector.open();
                    
    while (true) {
                        selector.select();
                        System.out.println(selector.selectedKeys().size());
                        handlePendingRegisters();
                    }
                } 
    catch (Exception e) {
                }
            }

            
    public void handlePendingRegisters() {
                
    while (!pendingRegisters.isEmpty()) {
                    SocketChannel channel 
    = pendingRegisters.poll();
                    
    try {
                        channel.register(selector, SelectionKey.OP_CONNECT);
                        System.out.println(
    "can reach here?yeah!");
                    } 
    catch (ClosedChannelException e) {
                        e.printStackTrace();
                    }
                }
            }

            
    public void addChannel(SocketChannel channel) {
                pendingRegisters.offer(channel);
                selector.wakeup();
            }
        }
    }


    新的代碼,我們?cè)赟ervice的線程提供了一個(gè)待處理Channel隊(duì)列,然后在添加一個(gè)SocketChannel到隊(duì)列中時(shí)喚醒這個(gè)selector,取消阻塞,然后在Service的循環(huán)中處理這個(gè)pendingChannel,這樣就避免這個(gè)Deadlock的發(fā)生了。當(dāng)然我們亦可以在那個(gè)代碼上將select的超時(shí)時(shí)間設(shè)置非常的短,然后讓兩個(gè)線程去競(jìng)爭(zhēng),這樣做有太多的不可控性,不推薦了。

    posted @ 2007-12-13 18:31 ruislan 閱讀(1349) | 評(píng)論 (3)編輯 收藏
        UI作為用戶與電腦的交互界面,如何更好的服務(wù)于人,讓人們用起來(lái)方便、簡(jiǎn)單、快捷一直是UI開(kāi)發(fā)者應(yīng)該有的覺(jué)悟,作為開(kāi)發(fā)人員的我們來(lái)說(shuō),不應(yīng)該只是把UI推給電腦平面設(shè)計(jì)人員,更不應(yīng)該一手包辦了(如果你不是一個(gè)人的話)。我們開(kāi)發(fā)人員常常在開(kāi)發(fā)UI的時(shí)候避重就輕,基本上都在強(qiáng)調(diào)code的美學(xué),模式的應(yīng)用而忽略了真實(shí)用戶的感受。我們常常得意于自己技術(shù)的美麗,而將一些比自己水平低的應(yīng)用嗤之以鼻。但是用戶卻從來(lái)不關(guān)心代碼是如何寫(xiě)的,他們關(guān)心這個(gè)應(yīng)用是否對(duì)他們有用,順手乎?聰明乎?所以如果我們只是美麗于自己的設(shè)計(jì),太關(guān)注軟件的本身而忽略了用戶的感受,就跟某些象牙塔里拿著錢(qián)做些無(wú)用的研究的人沒(méi)什么兩樣,或許有個(gè)美麗的名詞,為了科學(xué)。
        那么如何才能算是好的UI人性化的設(shè)計(jì)呢?這個(gè)得看針對(duì)的用戶主要是哪些。我們熟知的操作系統(tǒng)Windows XP,Windows Vista,Vista是微軟最新的操作系統(tǒng),包含了很多開(kāi)發(fā)人員辛苦的結(jié)晶,但是在我身邊的很多人都不愿意裝它,也包括一些新聞的調(diào)查也說(shuō)Vista不如當(dāng)年XP出世那般火爆,他們大多數(shù)不愿裝的都說(shuō)了同樣的話,XP都還有很多不懂,怕Vista更搞不懂,說(shuō)實(shí)話我用過(guò)Vista,就我這么一個(gè)算是業(yè)內(nèi)人士用起來(lái)當(dāng)然駕輕就熟,再加上我們都有勇于創(chuàng)新的精神,所以常常去用新的東西,而普通客戶就不這么想了,我問(wèn)了幾個(gè)不懂電腦才安裝了Vista的用戶的感受,“開(kāi)始菜單的‘開(kāi)始’兩個(gè)字沒(méi)有了,我還以為換了位置”,“界面比XP漂亮啊,但是我的機(jī)器好像有點(diǎn)慢,是不是要設(shè)置個(gè)什么啊”……再來(lái)我們熟知的AJAX,我已經(jīng)接到過(guò)很多次不同的人給我的電話,說(shuō)“為什么網(wǎng)頁(yè)打開(kāi)的時(shí)候突然好卡了,以前不這樣???”,“網(wǎng)頁(yè)瀏覽不了,老說(shuō)請(qǐng)稍候,數(shù)據(jù)加載中,等了很久,就是不出現(xiàn)”……面對(duì)這些電話或許我們會(huì)說(shuō),你們?cè)趺茨敲幢堪?,它卡是因?yàn)樵谙聳|西,在執(zhí)行JS,寫(xiě)JS的人太垃圾,浪費(fèi)了資源,不出現(xiàn)就刷新啊,不要瀏覽那個(gè)不專業(yè)的網(wǎng)站了,等等就OK了等等回答,其實(shí)很多時(shí)候我們可以避免用戶的問(wèn)題出現(xiàn),例如你的AJAX的JS太大的時(shí)候,可以先提示用戶說(shuō),數(shù)據(jù)量較大,請(qǐng)稍后,如果長(zhǎng)時(shí)間無(wú)反應(yīng),請(qǐng)按瀏覽器的刷新按鈕,或者嘗試按下F5鍵。
        我還見(jiàn)過(guò)許多軟件鼓吹自己的功能如何強(qiáng)大,如何厲害,多么的人性化,但是我打開(kāi)他們的軟件,居然發(fā)現(xiàn)只能用鼠標(biāo)操作!!這是多么大的UI設(shè)計(jì)失敗!在舉一個(gè)例子,MSN和QQ兩個(gè)IM,如果你用MSN,在聯(lián)系人框里按上下的話,MSN會(huì)很聰明的明白你是要選擇上一位或者下一位聯(lián)系人,而QQ會(huì)很聰明的明白你是要拖動(dòng)滑動(dòng)條!@#$,還有很多軟件記憶力太差,不管我如何操作,它就是記不住,關(guān)閉軟件重新啟動(dòng)后又回到了最初的模樣,還有的軟件自信心不足,一再問(wèn)我“你確定嗎?”,“真的要這樣做嗎?”,“或許您不小心點(diǎn)了?”而我只是在點(diǎn)關(guān)閉這個(gè)娛樂(lè)性質(zhì)的軟件而已,而有些軟件又特膽肥,做了一個(gè)不可恢復(fù)的操作盡然連提示都沒(méi)有,還有的軟件文化太差,常常把一個(gè)按鈕或者圖標(biāo)該表達(dá)的含義弄得模棱兩可,以至于常常讓我們會(huì)錯(cuò)意,做錯(cuò)操作,或者把一些高風(fēng)險(xiǎn)的操作放在常用操作的旁邊,很容易點(diǎn)錯(cuò),還有的把不常用的操作也放到常用操作區(qū),還不告訴用戶怎么去掉,這樣的例子不勝枚舉。
        出現(xiàn)這些問(wèn)題的原因在于我們與用戶之間的思維方式有著很大的不同。例如在寫(xiě)文章之前我才將老爸從我的電腦椅上請(qǐng)下來(lái),請(qǐng)下來(lái)之前他正在看我吃飯前的網(wǎng)頁(yè)——“界面九宮格”,我說(shuō)您能看得懂嘛,他說(shuō)“不懂,不過(guò)這軟件的界面不都這樣嘛?再說(shuō)了,一張紙就8個(gè)方位,加上中間正好九個(gè),你的東西不擺這里擺哪里?。?#8221;,我正要解釋一下這與軟件設(shè)計(jì)的關(guān)系,但是突然一想,是啊,有道理啊,要是我給他老人家再解釋一下可以放在上面和下面,那不就是3D的了。再比如我一直都很不屑一顧的網(wǎng)絡(luò)實(shí)名,但是當(dāng)它被我在很多人的機(jī)器里面消滅之后,很多人都打電話問(wèn)我,怎么在地址欄里面輸入漢字,跳出搜索界面了,不是那個(gè)漢字的網(wǎng)站了,以前是有的,原來(lái)我只看到了它流氓的一面,忽略了普通用戶是根本記不住網(wǎng)址在哪里,甚至有些用戶不懂英文,你怎么讓他記得住全是英文的網(wǎng)址呢?不過(guò)過(guò)了幾天,他們都說(shuō)不用了,有一個(gè)網(wǎng)站導(dǎo)航網(wǎng)址做了他們的主頁(yè),他們平日想去的網(wǎng)站都在上面列著的,我后來(lái)才知道,就是被我以前同寢室的刪除了半天的hao123。所以我們必須充分考慮我們的應(yīng)用是針對(duì)哪些用戶,他們是哪一類人,習(xí)慣是什么,當(dāng)然還有就是UI設(shè)計(jì)的一些基本的東西,例如鼠標(biāo)能夠完成的動(dòng)作,同樣鍵盤(pán)也能完成等等。

    posted @ 2007-11-11 13:36 ruislan 閱讀(1427) | 評(píng)論 (5)編輯 收藏
    Swing作為一個(gè)完整的UI解決方案,包含了一個(gè)GUI程序所擁有的方方面面,當(dāng)然包括作為普通程序也好,作為GUI程序也好,作為Web程序等等程序都共有的線程概念。

    Swing中的線程有三種:初始線程,事件線程,工作線程

    這三種線程基本上包括了讓一個(gè)GUI完美工作的方方面面,首先,初始線程被用來(lái)創(chuàng)建GUI組件、資源加載和啟動(dòng)GUI組件,眾所周知,Swing是事件驅(qū)動(dòng)的,所以當(dāng)UI出現(xiàn)了之后,初始線程就完成了它的使命,并將接力棒交給了事件線程,Event Dispatch Thread,這個(gè)時(shí)候所有組件的事件行為都交給了這個(gè)線程去處理,當(dāng)然我們自己也要需要用線程來(lái)運(yùn)行許多任務(wù),優(yōu)秀的GUI程序是絕不能讓界面被卡死不動(dòng)的,那會(huì)讓用戶崩潰,所以這個(gè)時(shí)候就需要工作線程了,也可以說(shuō)是在背后運(yùn)行的線程,這種線程是勞動(dòng)階級(jí),任勞任怨的執(zhí)行者長(zhǎng)時(shí)間的工作。

    初始線程的寫(xiě)法很簡(jiǎn)單,這樣就可以了:
    SwingUtilities.invokeLater(new Runnable() {
        
    public void run() {
            initGUI();
            showGUI();
        }
    }

    但是Applet中,你可能需要調(diào)用SwingUtilities.invokeAndWait這個(gè)方法,要是init方法返回了,瀏覽器開(kāi)始展現(xiàn)Applet,但是GUI的創(chuàng)建還在thread中,出錯(cuò)也是可想而知的。
    至于invokeLater和invokeAndWait這兩個(gè)線程的簡(jiǎn)單點(diǎn)的區(qū)別就是invokeLater是異步的,你不知道它什么時(shí)候會(huì)開(kāi)始執(zhí)行,invokeAndWait則是同步的,它會(huì)等到動(dòng)作執(zhí)行完成之后才返回。

    Event Dispatch Thread不是線程安全的,所以要用線程來(lái)與它打交道要注意了,同步問(wèn)題總是讓人頭痛。

    在1.5之前應(yīng)該說(shuō)工作線程都是由開(kāi)發(fā)人員自己去定義的,但是現(xiàn)在Swing推薦了SwingWorker這個(gè)類,包括Swing最新的符合JSR標(biāo)準(zhǔn)的Swing AppFramework也使用了SwingWorker這個(gè)類來(lái)處理所有在GUI背后做的事情。

    了解了Swing中的線程定義,能夠讓我們更好的寫(xiě)出優(yōu)美的基于Swing的GUI程序。

    posted @ 2007-11-04 12:40 ruislan 閱讀(1269) | 評(píng)論 (2)編輯 收藏
    很多人都說(shuō)我們這行的人是偏執(zhí)狂,我也覺(jué)得我是有一點(diǎn)倔脾氣,就像看連續(xù)劇,從第一集開(kāi)始一直到最后一集才會(huì)關(guān)上電腦,一旦一個(gè)研究開(kāi)始,就一定要有一個(gè)結(jié)果或者令自己滿意的結(jié)果才結(jié)束,但是當(dāng)我看到這位“偏執(zhí)狂”之后,我覺(jué)得我只是稍微有一點(diǎn)偏執(zhí)而已。
    研究UI繪制的時(shí)候很容易陷入另外一個(gè)領(lǐng)域,圖像領(lǐng)域,或者是游戲領(lǐng)域,我不喜歡做游戲是因?yàn)槲覑?ài)玩游戲,如果玩和工作綁在一起了的話,那么工作之后的休閑就也是工作了。
    好了,說(shuō)了點(diǎn)廢話,下面是對(duì)FengGUI的介紹.
    FengGUI是一個(gè)建立在OpenGL上的GUI的API,F(xiàn)engGUI提供了很多標(biāo)準(zhǔn)的UI組件,像Button,TextField,Panel之類的,下面先看看截圖:

    GridLayout的截圖

    可分割的面板


    要說(shuō)到最大的特色,莫過(guò)于FengGUI基于OpenGL,并且可以在組件里面直接使用OpenGL,可以輕松的集成jME(java Monkey Engine,一個(gè)非常棒的Java 3D游戲引擎),jogl(Java OpenGL API),lwjgl(輕量級(jí)Java游戲庫(kù)),jPCT(同樣非常棒的Java 3D游戲引擎),但是在跑它的demo時(shí)我也感受到了CPU 80% 工作率的壓力,所以就目前的我膚淺的了解,用它來(lái)做普通的GUI程序估計(jì)還為時(shí)有點(diǎn)早,但是如果是游戲中的組件的話確實(shí)是與上述引擎和API的非常好的補(bǔ)充。
    posted @ 2007-10-27 20:34 ruislan 閱讀(1707) | 評(píng)論 (2)編輯 收藏
        以前或許大家對(duì)一個(gè)UI組件是否透明沒(méi)有那么關(guān)心,但是自從Vista的毛玻璃出現(xiàn)后,UI透明就成了大家非常關(guān)注的一個(gè)話題,于是Java陣營(yíng)開(kāi)始了鋪天蓋地的討論如何實(shí)現(xiàn)透明的效果,但是很不幸的是無(wú)論組件如何透明和變換,但是能夠放置于屏幕任何位置的Window一族就是沒(méi)法透明和變形,原生代碼的問(wèn)題還是交給原生代碼來(lái)解決吧。
        自己寫(xiě)原生代碼是可怕的,特別是對(duì)我這種只知道Java的平凡程序員,所以我們得借助一個(gè)非常方便的跨平臺(tái)的調(diào)用OS function方便的Lib,JNA便是最佳選擇(那個(gè)誰(shuí),這里不是討論JRuby&JPython的)。
        so, all robots, transform!
        下面我們要做一個(gè)界面是圓角四邊形的,中間有一個(gè)滑動(dòng)條來(lái)滑動(dòng)調(diào)節(jié)透明度。先看看做好的截圖。
        
        注意圖中的JFrame邊角已經(jīng)變成了圓弧,滑動(dòng)滑塊,JFrame開(kāi)始透明,桌面的圖標(biāo)顯現(xiàn)出來(lái),下面是代碼。
       
    /**
     * @(#)TransparentFrame.java  v0.1.0  2007-10-21
     
    */
    package ruislan.rswing.test;

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Container;
    import java.awt.Dimension;
    import java.awt.Toolkit;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.geom.RoundRectangle2D;

    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JSlider;
    import javax.swing.border.LineBorder;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ChangeListener;

    import com.sun.jna.examples.WindowUtils;

    /**
     * Transparent JFrame use JNA
     * 
     * 
    @author ruislan <a href="mailto:z17520@126.com"/>
     * 
    @version 0.1.0
     
    */
    public class TransparentFrame {
        
    private JFrame frame;
        
    private JPanel container;
        
    private JSlider slider;
        
    private JPanel titleBar;
        
    private JLabel titleLabel;
        
    private JButton closeButton;

        
    public static void main(String[] args) {
            
    new TransparentFrame().launch();
        }

        
    private void launch() {
            createUI();
            launchUI();
        }

        
    protected void launchUI() {
            frame.setVisible(
    true);
        }

        
    protected void createUI() {
            System.setProperty(
    "sun.java2d.noddraw""true");
            frame 
    = new JFrame();
            frame.setSize(
    200150);
            frame.setAlwaysOnTop(
    true);
            frame.setUndecorated(
    true);

            container 
    = new JPanel();
            frame.setContentPane(container);
            container.setLayout(
    new BorderLayout());
            container.add(
    new JLabel("Ubunto vs Vista, I like both."),
                    BorderLayout.CENTER);
            container.setBorder(
    new LineBorder(Color.BLACK));

            titleBar 
    = new JPanel();
            titleBar.setLayout(
    new BorderLayout());
            titleLabel 
    = new JLabel("JNA is great!");
            titleBar.add(titleLabel, BorderLayout.CENTER);
            titleBar.setBorder(
    new LineBorder(Color.GRAY));
            closeButton 
    = new JButton("X");
            closeButton.setFocusPainted(
    false);
            closeButton.addActionListener(
    new ActionListener() {
                @Override
                
    public void actionPerformed(ActionEvent e) {
                    System.exit(
    0);
                }
            });
            titleBar.add(closeButton, BorderLayout.EAST);
            container.add(titleBar, BorderLayout.NORTH);

            slider 
    = new JSlider(0100);
            slider.setValue(
    100);
            slider.addChangeListener(
    new ChangeListener() {
                @Override
                
    public void stateChanged(ChangeEvent e) {
                    
    float value = slider.getValue();
                    WindowUtils.setWindowAlpha(frame, value 
    * 0.01f);
                }
            });
            container.add(slider, BorderLayout.SOUTH);
            RoundRectangle2D.Float mask 
    = new RoundRectangle2D.Float(00, frame
                    .getWidth(), frame.getHeight(), 
    2020);
            WindowUtils.setWindowMask(frame, mask);
            centerWindow(frame);
        }

        
    public static void centerWindow(Container window) {
            Dimension dim 
    = Toolkit.getDefaultToolkit().getScreenSize();
            
    int w = window.getSize().width;
            
    int h = window.getSize().height;
            
    int x = (dim.width - w) / 2;
            
    int y = (dim.height - h) / 2;
            window.setLocation(x, y);
        }
    }

        利用JNA來(lái)制作透明效果非常簡(jiǎn)單,只需要調(diào)用WindowUtils.setWindowAlpha(window, alpha)就可以了。當(dāng)然這是JNA特別為UI寫(xiě)的工具代碼。如果要改變形狀,用WindowUtils.setWindowMask(window, shape)或者WindowUtils.setWindowMask(window, icon)就可以了,但是要注意一點(diǎn)必須設(shè)置System.setProperty("sun.java2d.noddraw""true"),否則JNA會(huì)告訴你這個(gè)程序不支持透明。當(dāng)然要運(yùn)行起來(lái),還得需要兩個(gè)Jar,jna.jarexamples.jar ,都不是很大,只有200多K。
        雖然這篇文章只是介紹了一下JNA關(guān)于Swing的簡(jiǎn)單用法,但是有了這個(gè)我最先到的便是可以做類似于Yahoo Widget和Google Widget之類的東西了,還可以做好看的fishEye,SideBar,JNA的JAR兩個(gè)合起來(lái)不過(guò)400K,卻能讓這么多復(fù)雜的事情簡(jiǎn)單化,真是精湛的藝術(shù)啊,嗯。

    posted @ 2007-10-21 13:43 ruislan 閱讀(4385) | 評(píng)論 (12)編輯 收藏
    很久沒(méi)有上來(lái)更新了,因?yàn)橐恍┰?。但是,我又回?lái)了,套用MASK的話,小子們,想我嗎?

    回來(lái)了先報(bào)告一個(gè)Blogjava的BUG,就是用Opera9瀏覽器寫(xiě)文章時(shí)不能用鼠標(biāo)點(diǎn)擊編輯區(qū),還好用TAB可以切換過(guò)來(lái),然后就是用Google輸入法的話,標(biāo)點(diǎn)符號(hào)和數(shù)字輸入一次,編輯區(qū)會(huì)出來(lái)兩個(gè),最后就是編輯完之后好像內(nèi)容也保存不了,所以我又換回FF來(lái)編輯了。

    回來(lái)了卻不知從何開(kāi)始了,組件的改造也算拋磚引玉了(當(dāng)然如果你們喜歡,我還可以繼續(xù)改造),冰封的程序要繼續(xù)改造的話就要開(kāi)一個(gè)工程了大家集體參與了,所以那就還是先從上次哪位仁兄提到的組件透明的問(wèn)題,從那個(gè)開(kāi)始吧!show time。

    posted @ 2007-10-20 16:30 ruislan 閱讀(433) | 評(píng)論 (1)編輯 收藏
    昨天我們改進(jìn)了選擇區(qū),今天我們來(lái)繼續(xù)為選擇區(qū)選定之后添加一個(gè)操作框
    下面是改進(jìn)后的截圖:

    正常的情況,右下角出現(xiàn)了一個(gè)操作框

    在三個(gè)(左、右、底)邊際的情況,我們重新計(jì)算了位置。

    三個(gè)按鈕還沒(méi)有功能,也不是圖片,但是我們離QQ的截屏程序又進(jìn)一步了,嗯!

    posted @ 2007-09-14 18:48 ruislan 閱讀(1160) | 評(píng)論 (10)編輯 收藏
    “千里冰封” 兄弟的截屏程序酷斃了,但是好像9月4日之后就沒(méi)有繼續(xù)更新了,我們來(lái)繼續(xù)為他的程序改進(jìn),順便也把我們這幾天都在講的2D繪制用進(jìn)來(lái),我們的目標(biāo)是讓冰封的截屏程序成為截屏程序里的王!
    今天先改進(jìn)一下截圖時(shí)候的選框,還是先放上截圖的截圖(*o*):

    這是原來(lái)的圖片,下面是改進(jìn)后的

    和改進(jìn)的代碼部分:
    這部分代碼插入 Temp類的paintComponent方法中的    if (showTip) 這句的前面
        Graphics2D g2d = (Graphics2D) g.create();
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setComposite(AlphaComposite.getInstance(
                        AlphaComposite.SRC_OVER, 
    0.3F));
                g2d.setColor(Color.RED.brighter().brighter());
                
    int sX = Math.min(startX, endX);
                
    int sY = Math.min(endY, startY);
                g2d.fillRect(sX, sY, Math.abs(endX 
    - startX), Math.abs(endY
                        
    - startY));
                g2d.setComposite(AlphaComposite.getInstance(
                        AlphaComposite.SRC_OVER, 1F));
                
    boolean drawCTip = endX - startX != 0 && endY - startY != 0;
                
    if (drawCTip) {
                    String cTip 
    = String.format("%dX%d", Math.abs(endX - startX),
                            Math.abs(endY 
    - startY));
                    
    int cTipH = 20;
                    Font cTipFont 
    = new Font("system", Font.BOLD, 16);
                    g2d.setFont(cTipFont);
                    
    int cTipW = SwingUtilities.computeStringWidth(
                            getFontMetrics(cTipFont), cTip);
                    g2d.setPaint(Color.BLACK);
                    
    int cStartY = sY - cTipH > 0 ? sY - cTipH : sY;
                    g2d.fillRect(sX, cStartY, cTipW, cTipH);
                    g2d.setPaint(Color.WHITE);
                    g2d.drawString(cTip, sX, cStartY 
    == sY ? sY + cTipH - 3
                            : sY 
    - 3);
                }
                g2d.dispose();

    怎么樣,比起QQ的截圖程序,我們又近一步了,嗯。

    posted @ 2007-09-13 13:28 ruislan 閱讀(1488) | 評(píng)論 (10)編輯 收藏
         摘要: 嗯,BeanSoft的話很有道理,令我敬佩,也許是昨天在下對(duì)那個(gè)“更好的”三個(gè)字感到一時(shí)憤慨,所以看到UI就自己擴(kuò)大了問(wèn)題,想到迎合LookAndFeel上面去了,在此說(shuō)句對(duì)不起了。你的回帖里面偏重于從整個(gè)組件的設(shè)計(jì)和重用性上,我的文章主要講的是如何將2D繪制和組件的繪制結(jié)合起來(lái),看客如果既了解了如何繪制自己想要的組件,又能設(shè)計(jì)得體,重用性高的話也算是對(duì)我拋磚引玉的欣慰了。...  閱讀全文
    posted @ 2007-09-12 13:36 ruislan 閱讀(2440) | 評(píng)論 (11)編輯 收藏
    看來(lái)我們的JTextField之旅也到了一個(gè)階段,已經(jīng)很不錯(cuò)了,現(xiàn)在我們來(lái)改造JButton,讓那個(gè)呆板的Swing看起來(lái)舒服一些。

    還是先放上完成后的效果圖:

    普通的狀態(tài)


    鼠標(biāo)滑過(guò)


    鼠標(biāo)按下

    和代碼:
      1 /**
      2  * @(#)RJButton.java  0.1.0  2007-9-11
      3  */
      4 package ruislan.rswing;
      5 
      6 import java.awt.AlphaComposite;
      7 import java.awt.Color;
      8 import java.awt.Font;
      9 import java.awt.GradientPaint;
     10 import java.awt.Graphics;
     11 import java.awt.Graphics2D;
     12 import java.awt.RenderingHints;
     13 import java.awt.Shape;
     14 import java.awt.event.MouseAdapter;
     15 import java.awt.event.MouseEvent;
     16 import java.awt.geom.RoundRectangle2D;
     17 
     18 import javax.swing.JButton;
     19 
     20 /**
     21  * Custom JButton
     22  * 
     23  * @version 0.1.0
     24  * @author ruislan <a href="mailto:z17520@126.com"/>
     25  */
     26 public class RButton extends JButton {
     27     private static final long serialVersionUID = 39082560987930759L;
     28     public static final Color BUTTON_COLOR1 = new Color(205255205);
     29     public static final Color BUTTON_COLOR2 = new Color(5115447);
     30     // public static final Color BUTTON_COLOR1 = new Color(125, 161, 237);
     31     // public static final Color BUTTON_COLOR2 = new Color(91, 118, 173);
     32     public static final Color BUTTON_FOREGROUND_COLOR = Color.WHITE;
     33     private boolean hover;
     34 
     35     public RButton() {
     36         setFont(new Font("system", Font.PLAIN, 12));
     37         setBorderPainted(false);
     38         setForeground(BUTTON_COLOR2);
     39         setFocusPainted(false);
     40         setContentAreaFilled(false);
     41         addMouseListener(new MouseAdapter() {
     42             @Override
     43             public void mouseEntered(MouseEvent e) {
     44                 setForeground(BUTTON_FOREGROUND_COLOR);
     45                 hover = true;
     46                 repaint();
     47             }
     48 
     49             @Override
     50             public void mouseExited(MouseEvent e) {
     51                 setForeground(BUTTON_COLOR2);
     52                 hover = false;
     53                 repaint();
     54             }
     55         });
     56     }
     57 
     58     @Override
     59     protected void paintComponent(Graphics g) {
     60         Graphics2D g2d = (Graphics2D) g.create();
     61         int h = getHeight();
     62         int w = getWidth();
     63         float tran = 1F;
     64         if (!hover) {
     65             tran = 0.3F;
     66         }
     67 
     68         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
     69                 RenderingHints.VALUE_ANTIALIAS_ON);
     70         GradientPaint p1;
     71         GradientPaint p2;
     72         if (getModel().isPressed()) {
     73             p1 = new GradientPaint(00new Color(000), 0, h - 1,
     74                     new Color(100100100));
     75             p2 = new GradientPaint(01new Color(00050), 0, h - 3,
     76                     new Color(255255255100));
     77         } else {
     78             p1 = new GradientPaint(00new Color(100100100), 0, h - 1,
     79                     new Color(000));
     80             p2 = new GradientPaint(01new Color(255255255100), 0,
     81                     h - 3new Color(00050));
     82         }
     83         g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
     84                 tran));
     85         RoundRectangle2D.Float r2d = new RoundRectangle2D.Float(00, w - 1,
     86                 h - 12020);
     87         Shape clip = g2d.getClip();
     88         g2d.clip(r2d);
     89         GradientPaint gp = new GradientPaint(0.0F0.0F, BUTTON_COLOR1, 0.0F,
     90                 h, BUTTON_COLOR2, true);
     91         g2d.setPaint(gp);
     92         g2d.fillRect(00, w, h);
     93         g2d.setClip(clip);
     94         g2d.setPaint(p1);
     95         g2d.drawRoundRect(00, w - 1, h - 12020);
     96         g2d.setPaint(p2);
     97         g2d.drawRoundRect(11, w - 3, h - 31818);
     98         g2d.dispose();
     99         super.paintComponent(g);
    100     }
    101 }
    102 


    注意代碼中的幾個(gè)部分:

    首先是paintComponent方法中最后一行,我們調(diào)用了父類的paintComponent方法,這是因?yàn)槲覀円扛割悂?lái)繪制字符,但是父類的這個(gè)方法除了繪制字符之外還會(huì)繪制其他的,所以我們需要關(guān)閉掉其他的(當(dāng)然我們也可以自己來(lái)繪制字符,但是JButton提供了方法為什么不用呢),所以我們?cè)跇?gòu)造方法那里調(diào)用了:
    setBorderPainted(false);
    setFocusPainted(false);
    setContentAreaFilled(false);
    告訴父類不用繪制邊框,不用繪制焦點(diǎn),不用繪制內(nèi)容部分,這部分我們自己來(lái)搞*o*。

    然后就是這一句了g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)告訴繪制API我們需要平滑一點(diǎn),否則繪制出來(lái)會(huì)有很多鋸齒喲。

    接下來(lái)的這一句g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,tran))告訴繪圖API我們需要繪制一個(gè)有透明度的,tran就是透明度(0-1)。

    然后就是將邊框的邊角變直角為圓角,我們繪制一個(gè)RoundRectangle2D,這個(gè)就是邊角都為圓角的方形,然后我們根據(jù)這個(gè)方形來(lái)clip我們的方形,這樣方形就被RoundRectangle2D的圓角方形包裹,從而變成了圓角方形。

    最后就是繪制外邊線和內(nèi)邊線,通過(guò)改變內(nèi)邊線和外邊線的色變從而造成陷入或者突出效果。

    整個(gè)JButton改造完畢,如果你能夠活用clip的話,你也可以做一個(gè)五角星的JButton喲。

    整個(gè)源代碼我連同Eclipse工程文件已經(jīng)打包成zip放在我的文件里面,下載鏈接如下:
    http://www.tkk7.com/Files/ruislan/rswing-0.1.0.zip

    posted @ 2007-09-11 12:24 ruislan 閱讀(5553) | 評(píng)論 (20)編輯 收藏
    昨天我們給JTextField增加了一個(gè)泡泡提示窗口,今天我們繼續(xù)昨天的,首先處理在顯示泡泡的時(shí)候忽略輸入的Backspace、Enter、Delete、Esc按鍵,然后加上錯(cuò)誤的時(shí)候的聲音提示,最后再給JTextField換裝備,讓它看起來(lái)像MSN 8.5beta的輸入框,還是先放上圖片:


    這幅圖是MSN的輸入框,輸入框的內(nèi)部到光標(biāo)有一部分是有點(diǎn)毛玻璃的感覺(jué),不過(guò)這個(gè)style是死的,我們改進(jìn)一下,我們的JTextField在輸入之前是看似普通的,在鼠標(biāo)放上去之后,看起來(lái)就與MSN的輸入框類似了,而且我們還給這個(gè)輸入框加入一個(gè)淡黃色的背景。

    好了,現(xiàn)在很明確要做的事情了
    1. 加入鼠標(biāo)事件監(jiān)聽(tīng)器,監(jiān)聽(tīng)MouseEnter和MouseExit事件,根據(jù)這個(gè)兩個(gè)事件設(shè)置不同的背景色和邊框
    2. 做一個(gè)能夠顯示毛玻璃效果的邊框

    以下是邊框的代碼和部分MyJTextField的代碼,完整的代碼待我會(huì)打包傳上來(lái)的
    MyJTextField.java
    在初始化組件的時(shí)候加上Border的初始化:
            hoverBorder = new CoolBorder(HOVER_BORDER_COLOR, 3);
            border 
    = BorderFactory.createCompoundBorder(new LineBorder(
                    BORDER_COLOR, 
    1), new EmptyBorder(new Insets(2222)));

            setBackground(BACKGROUND_COLOR);
            setBorder(border);
    和事件的初始化:
            addMouseListener(new MouseAdapter() {
                @Override
                
    public void mouseEntered(MouseEvent e) {
                    setBorder(hoverBorder);
                    setBackground(HOVER_BACKGROUND_COLOR);
                    repaint();
                }

                @Override
                
    public void mouseExited(MouseEvent e) {
                    setBorder(border);
                    setBackground(BACKGROUND_COLOR);
                    repaint();
                }
            });
    以及屏蔽功能性按鈕和發(fā)出聲音提示的代碼:
    addKeyListener(new KeyAdapter() {
                @Override
                
    public void keyTyped(KeyEvent e) {
                    
    char input = e.getKeyChar();
                    
    // ESC27 ,Backspace 8 ,Enter 10, Del 127, must ignore
                    boolean ignoreInput = input == (char) KeyEvent.VK_ESCAPE
                            
    || input == (char) KeyEvent.VK_BACK_SPACE
                            
    || input == (char) KeyEvent.VK_ENTER
                            
    || input == (char) KeyEvent.VK_DELETE;
                    
    if (ignoreInput) {
                        limitTip.setVisible(
    false);
                        numberTip.setVisible(
    false);
                        
    return;
                    }
                    
    if (getText().length() + 1 > limit) {
                        Toolkit.getDefaultToolkit().beep();
                        deleteInputChar(e);
                        limitTip.setVisible(
    true);
                        
    return;
                    } 
    else {
                        limitTip.setVisible(
    false);
                    }
                    
    if (numberOnly) {
                        
    if (!Character.isDigit(input)) {
                            numberTip.setVisible(
    true);
                            Toolkit.getDefaultToolkit().beep();
                            deleteInputChar(e);
                        } 
    else {
                            numberTip.setVisible(
    false);
                        }
                    }
                }

                
    private void deleteInputChar(KeyEvent source) {
                    source.setKeyChar((
    char) KeyEvent.VK_CLEAR);
                }
            });


    下面是Border的完整代碼:
     1 /**
     2  * @(#)CoolBorder.java  0.1.2  2007-9-10
     3  */
     4 package ruislan;
     5 
     6 import java.awt.Color;
     7 import java.awt.Component;
     8 import java.awt.Dimension;
     9 import java.awt.GradientPaint;
    10 import java.awt.Graphics;
    11 import java.awt.Graphics2D;
    12 import java.awt.Insets;
    13 
    14 import javax.swing.border.Border;
    15 
    16 /**
    17  * Custom Border.
    18  * 
    19  * @version 0.1.2, 2007-9-10
    20  * @author ruislan <a href="mailto:z17520@126.com"/>
    21  */
    22 public class CoolBorder implements Border {
    23     private int thickness;
    24     private Insets insets;
    25     private Dimension lastComponentSize;
    26     private Color color;
    27     private Color color2;
    28 
    29     public CoolBorder(Color color, int thickness) {
    30         this.color = color;
    31         if (color == null) {
    32             this.color = color = Color.gray;
    33         }
    34         color2 = new Color(2102102100);
    35         this.thickness = thickness;
    36     }
    37 
    38     @Override
    39     public Insets getBorderInsets(Component c) {
    40         Dimension currentComponent = c.getSize();
    41 
    42         if (currentComponent.equals(lastComponentSize)) {
    43             return insets;
    44         }
    45 
    46         insets = new Insets(thickness, thickness, thickness, thickness);
    47         lastComponentSize = currentComponent;
    48         return insets;
    49     }
    50 
    51     @Override
    52     public boolean isBorderOpaque() {
    53         return true;
    54     }
    55 
    56     @Override
    57     public void paintBorder(Component c, Graphics g, int x, int y, int width,
    58             int height) {
    59         Graphics2D g2d = (Graphics2D) g.create();
    60         // 畫(huà)上邊緣
    61         GradientPaint gp = new GradientPaint(x, y, color, x, y + thickness,
    62                 color2);
    63         g2d.setPaint(gp);
    64         g2d.fillRect(x, y, width, thickness);
    65         // 畫(huà)下邊緣
    66         gp = new GradientPaint(x, y + height - thickness - 1, color2, x, y
    67                 + height, color);
    68         g2d.setPaint(gp);
    69         g2d.fillRect(x, y + height - thickness - 1, width, thickness);
    70         // 畫(huà)左邊緣
    71         gp = new GradientPaint(x, y, color, x + thickness, y, color2);
    72         g2d.setPaint(gp);
    73         g2d.fillRect(x, y, thickness, height);
    74         // 畫(huà)右邊緣
    75         gp = new GradientPaint(x + width - thickness - 1, y, color2, x + width,
    76                 y, color);
    77         g2d.setPaint(gp);
    78         g2d.fillRect(x + width - thickness - 1, y, thickness, height);
    79         // 畫(huà)外框
    80         g2d.setPaint(color);
    81         g2d.drawRect(x, y, width - 1, height - 1);
    82         g2d.dispose();
    83     }
    84 
    85 }
    86 

    然后來(lái)欣賞我們的結(jié)果吧:

    鼠標(biāo)放上去之前


    鼠標(biāo)放上去之后

    我們輸入了不是數(shù)字的字符

    至此,我們的JTextField又向前走了一步,下次我們還能如何改進(jìn)呢?把JTextField這個(gè)死板的長(zhǎng)方形改造成云狀的或者其他形狀的?

    附源代碼下載地址:http://www.tkk7.com/Files/ruislan/myjtextfield.zip

    posted @ 2007-09-10 13:21 ruislan 閱讀(4347) | 評(píng)論 (3)編輯 收藏
         摘要: 接著昨天的MyJTextField,我們繼續(xù)為JTextField增強(qiáng),今天我們?yōu)镸yJTextField增加一個(gè)泡泡提示。先看圖片: 當(dāng)輸入第三個(gè)字符'a'時(shí),由于昨天我們的MyJTextField做了處理,所以'a'不能被輸入,而且彈出泡泡提示你下次不要了喲! 同樣的,下一張圖片: 為MyJTextField增加泡泡提示功能要做以下幾件事情: 1. 泡泡窗口 2. 顯示的...  閱讀全文
    posted @ 2007-09-09 13:32 ruislan 閱讀(5179) | 評(píng)論 (2)編輯 收藏
    在網(wǎng)上Google了一下,基本上的做法有兩種,第一種是JFormattedTextField;另外一種是自己繼承PlainDocument, Override insertString方法,然后用JTextFiled.setDocument的方法放入自己繼承的對(duì)象實(shí)例。但是最終我都沒(méi)有采用這兩種方法,首 先我對(duì)JFormattedTextField的方式不太舒服,然后感覺(jué)繼承PlainDocument有點(diǎn)太重,所以自己考慮了一種方案,也許有人跟我 的想法雷同,那就純屬巧合了。

    下面放上代碼:
    public class MyJTextField extends JTextField {
        
    private int limit = Integer.MAX_VALUE;
        
    private boolean numberOnly;

        
    public MyJTextField() {
            addKeyListener(
    new KeyAdapter() {
                @Override
                
    public void keyTyped(KeyEvent e) {
                    
    if (getText().length() + 1 > limit) {
                        deleteInputChar(e);
                        
    return;
                    }
                    
    if (numberOnly) {
                        
    char input = e.getKeyChar();
                        
    if (!Character.isDigit(input)) {
                            deleteInputChar(e);
                        }
                    }
                }

                
    private void deleteInputChar(KeyEvent source) {
                    source.setKeyChar((
    char) KeyEvent.VK_CLEAR);
                }
            });

        }

        
    public void setMaxTextLength(int limit) {
            
    if (limit < 0) {
                
    return;
            }
            
    this.limit = limit;
        }

        
    public int getMaxTextLength() {
            
    return limit;
        }

        
    public void setNumberOnly(boolean numberOnly) {
            
    this.numberOnly = numberOnly;
        }

        
    public boolean isNumberOnly() {
            
    return this.numberOnly;
        }
    }

    整個(gè)思路很簡(jiǎn)單,就是檢查T(mén)ype事件,如果超出了限制就刪除新增加的字符,如果設(shè)置了只是數(shù)字,那么不是數(shù)字的就刪除新增加的字符。使用的時(shí)候只需要
    MyJTextField textField = new MyJTextField();
    textField.setLimit(8);
    textField.setNumberOnly(true);
    結(jié)果就是最多輸入8個(gè)字符而且只能是數(shù)字。

    posted @ 2007-09-09 00:41 ruislan 閱讀(1285) | 評(píng)論 (2)編輯 收藏
    其實(shí)認(rèn)識(shí)這里也有一段時(shí)間了,平常也常常上來(lái)看看,也用someone的給一些博主有些留言。但是因?yàn)樽约河辛薭logspot,所以始終沒(méi)有注冊(cè)??上У氖莃logspot被封太久了,我也懶得去改什么東西來(lái)破解,所以遺憾的放棄了blogspot,當(dāng)然這里也并非我退而其次的選擇。今天在這里注冊(cè)了就算正式與blogspot告別了。blogspot上的文章也不打算轉(zhuǎn)過(guò)來(lái)了。從頭開(kāi)始寫(xiě)吧。
    posted @ 2007-09-08 13:59 ruislan 閱讀(207) | 評(píng)論 (1)編輯 收藏
    主站蜘蛛池模板: 亚洲乱码中文字幕在线| 亚洲国产成人精品无码区在线秒播| 亚洲不卡在线观看| 亚洲电影免费在线观看| 国产日韩亚洲大尺度高清| 黄床大片免费30分钟国产精品| 亚洲国产精品日韩专区AV| 综合一区自拍亚洲综合图区| 日韩高清在线高清免费| 久久久久亚洲AV无码去区首| 国产公开免费人成视频| 美女隐私免费视频看| 亚洲?v无码国产在丝袜线观看| 免费人成动漫在线播放r18| 亚洲国产精品综合久久网络| 久久久WWW成人免费精品| 亚洲成A人片在线观看无码不卡 | 亚洲国产精品精华液| 国产一区视频在线免费观看 | 亚洲美女又黄又爽在线观看| CAOPORN国产精品免费视频| 国产v亚洲v天堂无码网站| 8x8x华人永久免费视频| 亚洲一区二区三区免费观看 | 亚洲AⅤ视频一区二区三区 | 亚洲第一se情网站| 精品国产亚洲男女在线线电影| a视频免费在线观看| 亚洲经典在线观看| 日韩视频在线免费| 热久久这里是精品6免费观看| 亚洲色欲或者高潮影院| 天天天欲色欲色WWW免费| 免费亚洲视频在线观看| 国产精品久久久亚洲| 无人在线观看完整免费版视频| 边摸边吃奶边做爽免费视频99 | 亚洲爆乳AAA无码专区| 伊伊人成亚洲综合人网7777| 3344免费播放观看视频| 国产亚洲福利精品一区二区|