<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          java Swing用戶界面組件文本輸入:文本域+密碼域+格式化的輸入域

          共 17273字,需瀏覽 35分鐘

           ·

          2022-06-12 10:59

          文本輸入

          現(xiàn)在終于可以開始介紹Swing用戶界面組件了。首先,介紹具有用戶輸入和編輯文本功能的組件。文本域(JTextField)組件和文本區(qū)(JTextArea)組件用于獲取文本輸入。文本域只能接收單行文本輸入而文本區(qū)可以接收多行文本輸入。

          這兩個(gè)類都繼承于JTextComponent類。由于JTextComponent類是抽象類,所以不能構(gòu)造這個(gè)類的對(duì)象。另外,在Java中常會(huì)看到這種情況,當(dāng)查看API文檔時(shí),發(fā)現(xiàn)自己正在尋找的方法實(shí)際上來自父類JTextComponent,而不是來自派生類自身。例如,在一個(gè)文本域和文本區(qū)內(nèi)獲取(get)、設(shè)置(set)文本的方法實(shí)際上都是JTextComponent類中的方法。

          javax.swing.text.JTextComponent 1.2

          ? void setText(String t)

          改變文本組件的文本。

          參數(shù):t 新文本

          ? String getText( )

          返回文本組件中的文本。

          ? void setEditable(boolean b)

          確定用戶是否可以編輯JTextComponent的內(nèi)容。

          文本域

          把文本域添加到窗口中的常用辦法是把它添加到面板或者其他容器中,這與添加按鈕完全一樣:

          JPanel panel = new JPanel( );

          JTextField textField = new JTextField("Default input", 20);

          panel.add(textField);

          這段代碼將添加一個(gè)文本域,同時(shí)通過放入一個(gè)字符串“Default input”來對(duì)它進(jìn)行初始化。

          構(gòu)造器的第二個(gè)參數(shù)設(shè)置了文本域的寬度。在這個(gè)例子中,寬度值為20“列”。但是,這里所說的列不是一個(gè)精確的測(cè)量單位。一列就是在當(dāng)前使用的字體下一個(gè)字符的寬度。如果希望文本域最多能夠輸入n個(gè)字符,就應(yīng)該把寬度設(shè)置為n列。在實(shí)際中,這樣做效果不是很好,應(yīng)該將最大輸入長度再多設(shè)1~2個(gè)字符。列數(shù)只是給AWT設(shè)定首選(preferred)大小的一個(gè)提示。如果布局管理器需要縮放這個(gè)文本域,它會(huì)調(diào)整文本域的大小。在JTextField的構(gòu)造器中設(shè)定的列寬度并不是用戶能輸入的字符個(gè)數(shù)的上限。用戶可以輸入一個(gè)更長的字符串,但是當(dāng)文本長度超過文本域長度時(shí)輸入就會(huì)滾動(dòng)。用戶通常不喜歡滾動(dòng)文本域,因此應(yīng)該盡量把文本域設(shè)置得大一些。如果需要在運(yùn)行時(shí)重新設(shè)置列數(shù),可以使用setColumns方法。

          提示:使用setColumns方法改變文本框的大小之后,需要調(diào)用包含這個(gè)文本框的容器的revalidate方法。

          textField.setColumns(10);

          panel.revalidate( );

          revalidate方法會(huì)重新計(jì)算容器內(nèi)所有組件的大小,并且對(duì)它們重新進(jìn)行布局。調(diào)用revalidate方法以后,布局管理器會(huì)重新設(shè)置容器的大小,然后就可以看到改變尺寸后的文本域了。

          revalidate方法是JComponent類中的方法。它并不是馬上就改變組件大小,而是標(biāo)記該組件需要改變大小。這樣就避免了多個(gè)組件都要改變大小時(shí)帶來的重復(fù)計(jì)算。

          但是,如果想重新計(jì)算一個(gè)JFrame中的所有組件,就需要調(diào)用validate方法—JFrame沒有擴(kuò)展JComponent。

          通常情況下,希望用戶在文本域中添加文本(或者編輯已經(jīng)存在的文本)。文本域一般初始為空白。只要不為JTextField構(gòu)造器提供字符串參數(shù),就可以建立一個(gè)空白的文本域。

          JTextField textField = new JTextField(20);

          可以在任何時(shí)候調(diào)用setText方法來改變文本域中的內(nèi)容。這個(gè)方法是從前面提到的JTextComponent中繼承而來的。例如:

          textField. setText("Hello!");

          并且,在前面已經(jīng)提到,可以調(diào)用getText方法提取用戶鍵入的文本。這個(gè)方法返回用戶輸入的文本。如果想要把getText方法返回的文本域中的數(shù)據(jù)內(nèi)容的前后空格去掉,就應(yīng)該調(diào)用trim方法:

          String text = textField.getText( ).trim( );

          如果想要改變顯示文本的字體,就使用setFont方法。

          javax.swing.JTextField 1.2

          ? JTextField(int cols)

          構(gòu)造一個(gè)指定列數(shù)的空J(rèn)TextField。

          參數(shù):cols 文本域中的列數(shù)

          ? JTextField(String text, int cols)

          構(gòu)造一個(gè)指定列數(shù)、指定初始字符串的JTextField。

          參數(shù):text 顯示文本

          cols 列數(shù)

          ? void setColumns(int cols)

          告知文本域使用的列數(shù)。

          參數(shù):cols 列數(shù)

          javax.swing.JComponent 1.2

          ? void revalidate( )

          重新計(jì)算組件的位置和大小。

          java.awt.Component 1.0

          ? void validate( )

          重新計(jì)算組件的位置和大小。如果組件是容器,容器的位置和大小將被重新計(jì)算。

          標(biāo)簽與標(biāo)簽組件

          標(biāo)簽是容納文本的組件。它們沒有任何修飾(例如沒有邊界),也不響應(yīng)用戶輸入??梢岳脴?biāo)簽標(biāo)識(shí)組件。例如,與按鈕不同,文本域沒有標(biāo)簽標(biāo)識(shí)它們。要想用標(biāo)識(shí)符標(biāo)識(shí)這種不帶標(biāo)簽的組件,應(yīng)該

          1)用相應(yīng)的文本構(gòu)造JLabel組件。

          2)將標(biāo)簽組件放置在離需要標(biāo)識(shí)的組件足夠近的地方,這樣用戶就會(huì)知道標(biāo)簽標(biāo)識(shí)的組件。

          JLabel的構(gòu)造器允許指定初始文本和圖標(biāo),也可以選擇內(nèi)容的排列方式??梢杂肧wingConstants接口中的常量來指定排列方式。這個(gè)接口定義了幾個(gè)很有用的常量,如LEFT、RIGHT、CENTER、NORTH、EAST等。JLabel是實(shí)現(xiàn)該接口的一個(gè)Swing類。因此,可以指定右對(duì)齊標(biāo)簽:

          JLabel label = new JLabel("Minutes", SwingConstants.RIGHT);

          或者

          JLabel label = new JLabel("Minutes", JLabel.RIGHT);

          利用setText和setIcon方法可以在運(yùn)行期間設(shè)置標(biāo)簽的文本和圖標(biāo)。

          提示:從JDK 1.3開始,可以在按鈕、標(biāo)簽和菜單項(xiàng)上使用無格式文本和HTML文本。

          我們不推薦在按鈕上使用HTML文本—這樣會(huì)影響觀感。但是HTML文本在標(biāo)簽中是非常有效的。只要簡單地將標(biāo)簽字符串放置在. . .中即可:

          label = new JLabel("Requiredentry:");

          警告—包含HTML標(biāo)簽的第一個(gè)組件需要延遲一段時(shí)間才能顯示出來,這是因?yàn)樾枰虞d相當(dāng)復(fù)雜的HTML顯示代碼。

          與其他組件一樣,標(biāo)簽也可以放置在容器中。這就是說,可以利用前面講述的技巧把標(biāo)簽放置在任何需要的地方。

          javax.swing.JLabel 1.2

          ? JLabel(String text)

          構(gòu)造左對(duì)齊文本的標(biāo)簽。

          參數(shù):text 標(biāo)簽中的文本

          ? JLabel(Icon icon)

          構(gòu)造左對(duì)齊圖標(biāo)的標(biāo)簽。

          參數(shù):icon 標(biāo)簽中的圖標(biāo)

          ? JLabel(String text, int align)

          構(gòu)造指定文本和排列方式的標(biāo)簽。

          參數(shù):text 標(biāo)簽中的文本

          align 一個(gè)SwingConstants的常量LEFT、CENTER或者RIGHT

          ? JLabel(String text, Icon icon, int align)

          構(gòu)造具有文本和圖標(biāo)的標(biāo)簽。圖標(biāo)位于文本的左側(cè)。

          參數(shù):text

          標(biāo)簽中的文本

          icon

          標(biāo)簽中的圖標(biāo)

          align

          一個(gè)SwingConstants的常量LEFT、CENTER或者RIGHT

          ? void setText(String text)

          設(shè)定標(biāo)簽的文本。

          參數(shù):text

          標(biāo)簽中的文本

          ? void setIcon(Icon icon)

          設(shè)定標(biāo)簽的圖標(biāo)。

          參數(shù):icon

          標(biāo)簽中的圖標(biāo)

          文本域變化跟蹤

          讓我們應(yīng)用文本域來完成一些操作。圖9-12展示了運(yùn)行例9-2的應(yīng)用程序的外觀。這個(gè)程序顯示了一個(gè)時(shí)鐘,并且?guī)в袃蓚€(gè)文本域用來輸入小時(shí)和分鐘。只要這兩個(gè)文本域中的內(nèi)容發(fā)生改變,時(shí)鐘就會(huì)跟著改變。


          跟蹤文本域的每一次變化需要費(fèi)點(diǎn)功夫。首先,需要注意,監(jiān)視擊鍵并不是一個(gè)好主意。有些擊鍵(如箭頭鍵)并不改變文本。而且,對(duì)于某些觀感來說,鼠標(biāo)動(dòng)作也會(huì)導(dǎo)致文本改變。在本章開頭已經(jīng)看到,Swing文本域以一種非常通用的方法來實(shí)現(xiàn):在文本域中看到的字符串只是底層數(shù)據(jù)結(jié)構(gòu)(模型)的可視化表現(xiàn)(視圖)。當(dāng)然,對(duì)于一個(gè)簡單的文本域來說,二者之間沒有太大的區(qū)別。

          視圖是顯示字符串,而模型是字符串對(duì)象。但是同樣的體系結(jié)構(gòu)也用于更高級(jí)的編輯組件。這些組件可以通過字體、段落以及其他更加復(fù)雜的數(shù)據(jù)結(jié)構(gòu)標(biāo)識(shí)的屬性來提供格式化文本。所有文本組件的模型都由Document接口描述,既包括無格式的文本,也包括格式化的文本(例如HTML)。當(dāng)數(shù)據(jù)改變后,可以要求文檔(而非文本組件)給予通告,這將需要安裝一個(gè)文檔監(jiān)聽器(document listener):

          textField.getDocument( ).addDocumentListener(listener);

          當(dāng)文本發(fā)生改變后,下面所列的DocumentListener方法中的一個(gè)會(huì)被調(diào)用:

          void insertUpdate(DocumentEvent event)

          void removeUpdate(DocumentEvent event)

          void changedUpdate(DocumentEvent event)

          當(dāng)添加或者刪除字符時(shí),應(yīng)該調(diào)用前兩個(gè)方法。文本域根本不會(huì)調(diào)用第三個(gè)方法。對(duì)于復(fù)雜的文檔類型來說,當(dāng)一些內(nèi)容發(fā)生變化時(shí)(例如改變格式),就會(huì)調(diào)用第三個(gè)方法。遺憾的是,沒有任何回調(diào)方法會(huì)通告文本已改變—通常無需考慮它是如何改變的。而且這里也沒有適配器類,因此文檔監(jiān)聽器必須實(shí)現(xiàn)這三個(gè)方法。下面是程序代碼:

          private class ClockFieldListener implements DocumentListener{public void insertUpdate(DocumentEvent event) { setClock( ); }public void removeUpdate(DocumentEvent event) { setClock( ); }public void changedUpdate(DocumentEvent event) {}
          }

          setClock方法使用getText方法從文本域中獲得當(dāng)前用戶輸入的字符串。不過,得到的只是字符串。

          需要使用我們熟悉的(也許是笨拙的)方法將它們轉(zhuǎn)換成整數(shù),如下所示:

          int hours = Integer.parseInt(hourField.getText( ).trim( ));

          int minutes = Integer.parseInt(minuteField.getText( ).trim( ));

          但是當(dāng)用戶在文本域中輸入了非整數(shù)字符串,如“two”或者文本域中為空時(shí),這段代碼就會(huì)產(chǎn)生錯(cuò)誤。在這種情況下,可以捕獲parseInt方法拋出的NumberFormatException異常,如果文本域中的內(nèi)容不是數(shù)字,就不更新時(shí)鐘了。在下一節(jié)中,將會(huì)看到如何在第一時(shí)間阻止用戶的無效輸入。

          注意:除了監(jiān)聽文檔事件以外,還可以把動(dòng)作事件監(jiān)聽器添加到文本域中。當(dāng)用戶按下ENTER鍵時(shí),該動(dòng)作監(jiān)聽器就會(huì)得到通知。我們不推薦此方法,因?yàn)橛脩舫3M浽谳斎胪陻?shù)據(jù)后再敲一下回車鍵。如果使用一個(gè)動(dòng)作監(jiān)聽器,就應(yīng)該同時(shí)也安裝一個(gè)焦點(diǎn)監(jiān)聽器,這樣當(dāng)用戶離開文本域時(shí)就會(huì)得到通知。

          最后,說明ClockPanel構(gòu)造器如何設(shè)置首選的大小:

          當(dāng)框架的pack方法計(jì)算框架大小時(shí),將使用面板首選的大小。

          例9-2 TextTest.java







          javax.swing.JComponent 1.2

          ? void setPreferredSize(Dimension d)

          設(shè)置組件首選的大小。

          javax.swing.text.Document 1.2

          ? int getLength( )

          返回當(dāng)前文檔中的字符個(gè)數(shù)。

          ? String getText(int offset, int length)

          返回文檔中給定部分所包含的文本。

          參數(shù):offset 文本的起始偏移量

          Length 需要的字符串長度

          ? void addDocumentListener(DocumentListener listener)

          注冊(cè)監(jiān)聽器來監(jiān)聽文檔改變時(shí)的通知。

          javax.swing.event.DocumentEvent 1.2

          ? Document getDocument( )

          獲得作為事件源的文檔。

          javax.swing.event.DocumentListener 1.2

          ? void changedUpdate(DocumentEvent event)

          當(dāng)一個(gè)屬性或者屬性集發(fā)生改變時(shí)被調(diào)用。

          ? void insertUpdate(DocumentEvent event)

          當(dāng)文檔發(fā)生一個(gè)插入操作時(shí)被調(diào)用。

          ? void removeUpdate(DocumentEvent event)

          當(dāng)文檔的一部分被刪除時(shí)被調(diào)用。

          密碼域

          密碼域是一種特殊的文本域。為了避免有某種企圖的人看到密碼,用戶輸入的字符不顯示出來。每個(gè)輸入的字符都用回顯字符(echo character)表示,通常用星號(hào)“*”取代。Swing提供了JPasswordField類來實(shí)現(xiàn)這樣的文本域。

          密碼域是另一個(gè)模型-視圖-控制器體系模式的例子。密碼域采用與規(guī)則的文本域相同的模型來存儲(chǔ)數(shù)據(jù),但是它的視圖改為顯示回顯字符,而不是實(shí)際的字符。

          javax.swing.JPasswordField 1.2

          ? JPasswordField(String text, int columns)

          構(gòu)造一個(gè)新的密碼域。

          參數(shù):text 將要顯示的文本,沒有相應(yīng)的文本則為null

          columns 列數(shù)

          ? void setEchoChar(char echo)

          為密碼域設(shè)置回顯字符。注意,特殊的觀感可以選擇自己的回顯字符。0表示重置為默認(rèn)的回顯字符。

          參數(shù):echo 代替文本字符顯示的回顯字符

          ? char[ ] getPassword( )

          返回密碼域中的文本。為了安全起見,在使用之后應(yīng)該覆寫返回的數(shù)組內(nèi)容。(密碼并不是以字符串String型返回的,因?yàn)樽址恢北A粼谔摂M機(jī)上,直到垃圾回收。)

          格式化的輸入域

          在上一個(gè)例子中,希望用戶輸入數(shù)字,而不是任意的字符串。就是說只允許用戶輸入0~9的數(shù)字加上連字符(-)。并且如果是連字符,必須是輸入的第一個(gè)符號(hào)。

          從表面上看,對(duì)輸入進(jìn)行檢驗(yàn)十分簡單。我們可以為文本域安裝一個(gè)鍵盤監(jiān)聽器,并且銷毀所有非數(shù)字或連字符的鍵盤事件。遺憾的是,這只是一種簡單的方法,盡管常常推薦大家用這種方法處理輸入檢驗(yàn),但實(shí)際上效果并不好。首先,不是每個(gè)由有效輸入字符組合的字符串都是有效的數(shù)值,比如--3和3-3就是非法的,盡管它們都由有效輸入字符組成。其次,也是更重要的是,有些改變文本的方法與擊鍵無關(guān)。在某些觀感上,一些特定的鍵組合用于實(shí)現(xiàn)剪切、復(fù)制和粘貼文本操作。例如,在Metal觀感上,組合鍵CTRL+V把緩沖區(qū)中的內(nèi)容粘貼到文本域中。所以,需要監(jiān)視以保證用戶粘貼的是一個(gè)有效的字符。很明顯,試圖通過過濾擊鍵來確保文本域中內(nèi)容的有效性是一件很困難的事情。當(dāng)然這也不是應(yīng)用程序程序員要關(guān)注的問題。

          也許你會(huì)感到奇怪,在JDK 1.4之前,沒有輸入數(shù)值的組件。從本書的第1版開始,我們就提供了一個(gè)用于輸入格式化整型的文本域IntTextField。(在每個(gè)新版本中,都會(huì)改變一些不成熟的驗(yàn)證機(jī)制的實(shí)現(xiàn)。)最終,在JDK 1.4中,Swing設(shè)計(jì)者面對(duì)問題,提供了一個(gè)多功能的JFormattedTextField類,這個(gè)類不僅可以用于輸入數(shù)值,也可以用于輸入時(shí)間和更加復(fù)雜的格式化數(shù)值,如IP地址。

          1. 整型輸入

          下面先從一個(gè)簡單的例子開始:整型輸入的文本域。

          JFormattedTextField intField = new JFormattedTextField(NumberFormat.getIntegerInstance( ));

          NumberFormat. getIntegerInstance返回一個(gè)用當(dāng)前地區(qū)采用的格式來格式化整型數(shù)值的格式器對(duì)象。在US地區(qū),逗號(hào)是十進(jìn)制數(shù)的分隔符,允許用戶輸入如1,729的數(shù)值。在卷II的國際化章節(jié)中將詳細(xì)地解釋如何選擇其他的地區(qū)。

          對(duì)任何文本域,可以設(shè)置列數(shù):

          intField.setColumns(6);

          可以用setValue方法設(shè)置一個(gè)默認(rèn)值。這個(gè)方法有一個(gè)Object類型的參數(shù),需要把int值包裝成Integer對(duì)象:

          intField.setValue(new Integer(100));

          通常,用戶在多個(gè)文本域中輸入,然后點(diǎn)擊一個(gè)按鈕讀取所有值。當(dāng)點(diǎn)擊按鈕時(shí),可以用getValue方法讀取用戶輸入的數(shù)值。這個(gè)方法將返回一個(gè)Object結(jié)果,需要將它強(qiáng)制類型轉(zhuǎn)換為相應(yīng)的類型。如果用戶對(duì)數(shù)值進(jìn)行編輯,JFormattedTextField就會(huì)返回一個(gè)Long類型的對(duì)象。然而,如果用戶沒有做任何修改,就會(huì)返回原來的Integer對(duì)象。因此,應(yīng)該把返回值轉(zhuǎn)換成通用的超類Number:

          Number value = (Number) intField.getValue( );

          int v = value.intValue( );

          在沒有考查用戶進(jìn)行非法輸入后會(huì)發(fā)生什么事情之前,格式化文本域不會(huì)引起人們太大的興趣。下面就討論這個(gè)問題。

          2. 失去焦點(diǎn)的行為

          試想一下當(dāng)用戶在文本域中輸入之后會(huì)發(fā)生什么情況。用戶輸入后最終決定離開這個(gè)區(qū)域,也許是通過鼠標(biāo)點(diǎn)擊另一個(gè)組件。于是,文本域就失去焦點(diǎn)(lose focus)。I型光標(biāo)在文本域中也不見了。鍵盤輸入將作用于另一個(gè)組件。

          當(dāng)格式化的文本域失去焦點(diǎn)時(shí),格式器查看用戶輸入的文本字符串。如果格式器知道如何把文本字符串轉(zhuǎn)換為對(duì)象,文本就有效,否則就無效??梢杂胕sEditValid方法檢測(cè)文本域的當(dāng)前內(nèi)容是否有效。

          失去焦點(diǎn)的默認(rèn)行為被稱為“提交或恢復(fù)”。如果文本字符串是有效的,它將被提交(commit)。

          格式器將它轉(zhuǎn)換為對(duì)象,該對(duì)象成為當(dāng)前文本域的值(就是如前所述的getValue方法返回的值)。

          然后,該值被轉(zhuǎn)換為字符串,成為文本域內(nèi)可見的文本字符串。例如,整型格式器認(rèn)為輸入1729是有效的,設(shè)置當(dāng)前值為new Long(1729),并且把它轉(zhuǎn)換為帶有逗號(hào)的字符串:1,729。

          相反地,如果文本字符串無效,當(dāng)前值就不會(huì)改變。文本域恢復(fù)表示原值的字符串。例如,如果用戶輸入錯(cuò)誤的值(像x1),那么在文本域失去焦點(diǎn)時(shí)就會(huì)恢復(fù)原值。

          注意:如果文本字符串以一個(gè)整型開頭,那么整型格式器就認(rèn)為它是有效的。例如1729x是一個(gè)有效的字符串。它將被轉(zhuǎn)換為1729,然后格式化為字符串1,729。

          可以用setFocusLostBehavior方法設(shè)置其他行為。“提交”行為和默認(rèn)行為有一些微小的差別。

          如果文本字符串無效,文本字符串和文本域的值都不變—它們現(xiàn)在不同步。“持續(xù)”行為更加保守,即使文本字符串有效,文本域和當(dāng)前值也不會(huì)改變。要調(diào)用commitEdit、setValue或者setText方法保證它們同步。最后,“恢復(fù)”行為似乎沒什么用。無論何時(shí)失去焦點(diǎn),用戶輸入都將被拋棄,文本字符串恢復(fù)到原值。

          注意:通常,“提交或恢復(fù)”默認(rèn)行為是合理的。只是存在一個(gè)潛在的問題。假設(shè)一個(gè)對(duì)話框包含一個(gè)整型值的文本域。用戶輸入字符串“1729”,前面有空格,然后點(diǎn)擊OK按鈕。空格導(dǎo)致數(shù)字無效,文本域值恢復(fù)到原值。OK按鈕的動(dòng)作監(jiān)視器得到文本域值并且關(guān)閉對(duì)話框。用戶并不知道他們輸入的新值沒有被接受。

          在這樣的情況下,選擇“提交”行為可能更合適,并且讓OK按鈕監(jiān)聽器在關(guān)閉對(duì)話框前檢測(cè)所有文本框內(nèi)的值是否有效。

          3. 過濾器

          格式化文本域的基本功能簡單明了,在大多數(shù)情況已經(jīng)夠用了。但是,可以進(jìn)一步得到改進(jìn)。我們可能希望完全阻止用戶輸入非數(shù)字,這里可以用文檔過濾器(document filter)達(dá)到此目的?;貞浺幌履P?視圖-控制器體系,控制器把輸入事件轉(zhuǎn)化為命令修改文本域的底層文檔,這就是說,文本字符串存儲(chǔ)在PlainDocument對(duì)象中。例如,無論何時(shí)控制器處理命令,都會(huì)將文本插入文檔中,這稱為“插入字符串”命令。被插入的字符串可以是單個(gè)的字符,也可以粘貼緩沖區(qū)的內(nèi)容。文檔過濾器可以中途截取命令,并改變字符串或者取消插入。下面是過濾器的一段insertString方法代碼,它將分析要插入的字符串,并且只將數(shù)字或者“-”符號(hào)插入到文檔中。(這段代碼的處理可參見第3章解釋的輔助Unicode字符。請(qǐng)參看第12章的StringBuilder類。)



          可以覆蓋DocumentFilter類的replace方法,在文本被選擇或替換的時(shí)候調(diào)用此方法。replace方法的實(shí)現(xiàn)非常簡單,請(qǐng)參照本節(jié)最后的程序。

          現(xiàn)在需要安裝文檔過濾器了??上У氖菦]有一個(gè)直接的方法。需要覆蓋格式器類的getDocumentFilter方法,并傳遞一個(gè)格式器類的對(duì)象給JFormattedTextField。整型文本域使用了InternationalFormatter,它用
          NumberFormat.getIntegerInstance( )進(jìn)行初始化。下面是安裝格式器產(chǎn)生想要的過濾器的程序:


          注意:在JDK文檔中提到,為了避免子類化發(fā)明了DocumentFilter類。直到JDK 1.3,都是通過擴(kuò)展PlainDocument類并且覆蓋insertString和replace方法來實(shí)現(xiàn)文本域過濾的。

          現(xiàn)在PlainDocument類有了可插拔的過濾器,這是一個(gè)顯著的進(jìn)步。如果在格式器類中有可插拔的過濾器會(huì)更好。然而,這里沒有,我們必須子類化格式器。

          試一下本節(jié)最后的FormatTest程序。第三個(gè)文本域安裝了一個(gè)過濾器。只能插入數(shù)字或者負(fù)號(hào)“-”。注意,這里還可以輸入無效的字符串,如“1-2-3”。通常,不可能通過過濾器避免所有的無效字符串。例如:字符串“-”是無效的,但是過濾器沒有拒絕它,因?yàn)樗怯行ё址?1”的前綴。盡管過濾器沒能給出完全的保護(hù),但還是可以用來避免那些明顯的無效輸入。

          提示:過濾器的另一個(gè)用途是把字符串中的所有字符變成大寫。這樣的過濾器很容易編寫。在過濾器的insertString和replace方法中,把要被插入的字符串轉(zhuǎn)換成大寫,然后調(diào)用超類的方法。

          4. 檢驗(yàn)器

          還有另外一種潛在的實(shí)用機(jī)制,它可以用來警告用戶以避免無效的輸入。可以給任何JComponent附加檢驗(yàn)器(verifier)。如果組件失去焦點(diǎn),就詢問檢驗(yàn)器。如果檢驗(yàn)器報(bào)告組件中的內(nèi)容是無效的,組件馬上就會(huì)重獲焦點(diǎn)。因此,用戶在提供其他輸入之前,必須先修正無效的內(nèi)容。

          檢驗(yàn)器必須擴(kuò)展抽象類InputVerifier,并且定義verify方法。定義檢測(cè)格式化文本域的檢驗(yàn)器是非常簡單的。JFormattedTextField類的isEditValid方法調(diào)用格式器,如果格式器可以把文本字符串轉(zhuǎn)化為對(duì)象則返回true。下面是檢驗(yàn)器:

          可以把它附加到任何JFormattedTextField中:

          intField.setInputVerifier(new FormattedTextFieldVerifier( ));

          然而,檢驗(yàn)器并不是萬無一失的。如果點(diǎn)擊按鈕,按鈕會(huì)在無效組件重新獲得焦點(diǎn)之前通知它的動(dòng)作監(jiān)聽器。動(dòng)作監(jiān)聽器就會(huì)從驗(yàn)證失敗的組件得到無效的結(jié)果。采用這種處理方式的原因是,用戶可能想點(diǎn)擊Cancel,這時(shí)不需要對(duì)無效的輸入進(jìn)行修改。

          在示例程序中的第4個(gè)文本域上附加了一個(gè)檢驗(yàn)器。嘗試輸入一個(gè)無效的數(shù)字(如x1729)然后敲擊Tab鍵或者用鼠標(biāo)點(diǎn)擊另外一個(gè)文本域。注意,這個(gè)文本域立刻獲得焦點(diǎn)。但是,如果點(diǎn)擊OK按鈕,動(dòng)作監(jiān)聽器將調(diào)用getValue報(bào)告上一個(gè)有效的數(shù)值。

          5. 其他標(biāo)準(zhǔn)的格式

          除了整型格式器以外,JFormattedTextField還支持幾種其他的格式器。NumberFormat類有下面幾個(gè)靜態(tài)方法:

          getNumberInstance

          getCurrencyInstance

          getPercentInstance

          這些方法產(chǎn)生浮點(diǎn)數(shù)、貨幣數(shù)值和百分?jǐn)?shù)格式器。例如,可以得到用于輸入貨幣數(shù)值的文本域:

          JFormattedTextField currencyField = new JFormattedTextField(NumberFormat.getCurrencyInstance( ));

          編輯日期和時(shí)間需要調(diào)用DateFormat類的靜態(tài)方法之一:

          getDateInstance

          getTimeInstance

          getDateTimeInstance

          例如:

          JFormattedTextField dateField = new JFormattedTextField(DateFormat.getDateInstance( ));

          這個(gè)文本域使用默認(rèn)(“medium”)格式編輯日期:

          Feb 24, 2002

          可以選擇一個(gè)“short”格式替代:

          2/24/02

          使用:

          DateFormat.getDateInstance(DateFormat.SHORT)

          注意:在默認(rèn)情況下,數(shù)據(jù)格式是“不嚴(yán)格的”。也就是說,無效日期(February 31,2002)將滾動(dòng)到下一個(gè)有效日期(March 3, 2002)。這種行為可能會(huì)讓用戶感到吃驚。在這種情況下,調(diào)用DateFormat對(duì)象的setLenient(false)方法。

          DefaultFormatter可以格式化任何類的對(duì)象,只要該類有一個(gè)字符串類型參數(shù)的構(gòu)造器和匹配的toString方法。例如,URL類有一個(gè)URL(String)構(gòu)造器利用字符串構(gòu)造URL,如:

          URL url = new URL("http://java.sun.com");

          因此,可以使用DefaultFormatter格式化URL對(duì)象。格式器針對(duì)文本域值調(diào)用toString方法來初始化文本域的文本。當(dāng)文本域失去焦點(diǎn)時(shí),格式器使用帶有String參數(shù)的構(gòu)造器構(gòu)造相同類的新對(duì)象作為當(dāng)前值。如果構(gòu)造器拋出了異常,編輯就是無效的。可以在示例程序中試驗(yàn)一下,比如輸入一個(gè)不以“http:”前綴開頭的URL。

          注意:在默認(rèn)情況下,DefaultFormatter處于覆寫(overwrite)狀態(tài)。與其他格式器不同,也不很實(shí)用??梢哉{(diào)用setOverwriteMode (false)關(guān)閉覆寫狀態(tài)。

          最后,MaskFormatter對(duì)包含一些常量和一些變量字符的固定大小的樣式很有用。例如,社會(huì)保險(xiǎn)號(hào)(如078-05-1120)可以用

          new MaskFormatter("###-##-####")格式化。#符號(hào)表示一個(gè)單個(gè)數(shù)字,表9-2顯示了可以用在掩碼格式器的符號(hào)。


          可以通過調(diào)用MaskFormatter類的下列方法之一限制輸入文本域的字符:

          setValidCharacters

          setInvalidCharacters

          例如,為了讀取用字符表示的分?jǐn)?shù)(比如A+或者F),可以使用MaskFormatter formatter = new MaskFormatter("U * ");

          Formatter.setValidCharacters("ABCDF+-");

          但是,沒有方法能夠指定第二個(gè)字符不能是一個(gè)字母。

          注意,字符串是被掩碼格式器格式化的,它和掩碼具有完全相同的長度。如果用戶在編輯過程中刪除字符,那么它們將被占位符(holer character)替代。默認(rèn)的占位字符是空格,可以使用setPlaceholderCharacter方法改變它,例如:

          formatter.setPlaceholderCharacter('0');

          在默認(rèn)情況下,掩碼格式器處于overtype狀態(tài),直觀上是這樣,可以在示例程序中試驗(yàn)一下。

          同時(shí)也要注意^符號(hào)的位置在掩碼中跳過了固定字符。

          掩碼格式器對(duì)于固定格式(比如社會(huì)保險(xiǎn)號(hào)和美國電話號(hào)碼)非常有效。然而,也要注意

          到在掩碼格式下不允許有任何不一致的地方。例如,國際電話號(hào)碼就不能使用掩碼格式器,因

          為各個(gè)國家的電話號(hào)碼可能有不同的位數(shù)。

          6. 自定義格式器

          如果所有的標(biāo)準(zhǔn)格式器都不適用,就需要定義自己的格式器,做這件事情很容易。下面看一下4字節(jié)的IP地址,例如:

          130.65.86.66

          不能使用MaskFormatter,因?yàn)槊總€(gè)字節(jié)可能表示為一位、兩位或三位數(shù)字。同時(shí),還希望在格式器中檢查每個(gè)字節(jié)的最大值為255。

          為了自定義格式器,擴(kuò)展DefaultFormatter類并且覆蓋其中的方法。

          String valueToString(Object value)

          Object stringToValue(String text)

          第一個(gè)方法把值轉(zhuǎn)換為顯示在文本域中的字符串。第二個(gè)方法解析用戶輸入的文本并轉(zhuǎn)換為對(duì)象。如果有一個(gè)方法出錯(cuò),將拋出ParseException。

          在示例中,把IP地址存儲(chǔ)在長度為4的byte[ ]數(shù)組中。valueToString方法形成一個(gè)字符串,它用句號(hào)分隔字節(jié)。注意byte值是其值在-128到127之間的符號(hào)數(shù)。為了把負(fù)數(shù)轉(zhuǎn)換為無符號(hào)整數(shù)值,需要加上256。


          與之相反,如果字符串有效,stringToValue方法將解析并生成一個(gè)byte[ ]對(duì)象,如果無效,將拋出ParseException。



          試一下示例中的IP地址域,如果輸入一個(gè)無效的地址,地址域就將恢復(fù)成上一個(gè)有效地址。

          例9-3的程序展示了不同格式化的文本域(參見圖9-13)。點(diǎn)擊OK按鈕從域內(nèi)得到當(dāng)前值。

          注意:“Swing Connection”在線新聞簡訊有一篇簡短的文章描述了一個(gè)格式器,該格式器匹配任何正則表達(dá)式。參看
          http://java.sun.com/products/jfc/tsc/articles/reftf/。


          例9-3 FormatTest.java











          javax.swing.JFormattedTextField 1.4

          ? JFormattedTextField(Format fmt)

          使用給定的格式構(gòu)造一個(gè)文本域。

          ? JFormattedTextField(JFormattedTextField.AbstractFormatter formatter)

          使用給定的格式器構(gòu)造文本域。注意DefaultFormatter和InternationalFormatter是JFormattedText

          Field.AbstractFormatter的子類。

          ? Object getValue( )

          返回文本域的當(dāng)前有效值。注意,它可能和正在編輯的字符串不一致。

          ? void setValue(Object value)

          設(shè)置給定對(duì)象的值。如果格式器不能將對(duì)象轉(zhuǎn)換為字符串,操作失敗。

          ? void commitEdit( )

          用正在編輯的字符串設(shè)置文本域的有效值。如果格式器無法轉(zhuǎn)換該字符串,操作可能失敗。

          ? boolean isEditValid( )

          檢測(cè)正在編輯的一個(gè)字符串是否代表了一個(gè)有效值。

          ? void setFocusLostBehavior(int behavior)

          ? int getFocusLostBehavior( )

          設(shè)置或得到“失去焦點(diǎn)”的行為。behavior的合法值可以是JFormattedTextField類的常量

          COMMIT_ OR_REVERT、REVERT、COMMIT和PERSIST。

          java.text.DateFormat 1.1

          ? static DateFormat getDateInstance( )

          ? static DateFormat getDateInstance(int dateStyle)

          ? static DateFormat getTimeInstance( )

          ? static DateFormat getTimeInstance(int timeStyle)

          ? static DateFormat getDateTimeInstance( )

          ? static DateFormat getDateTimeInstance(int dateStyle, int timeStyle)

          返回Date對(duì)象產(chǎn)生的日期、時(shí)間或日期與時(shí)間。dateStyle與timeStyle的合法值是DateFormat類的常量SHORT、MEDIUM、LONG、FULL以及DEFAULT。

          javax.swing.JFormattedTextField.AbstractFormatter 1.4

          ? abstract String valueToString(Object value)

          將一個(gè)值轉(zhuǎn)換為可編輯字符串。如果value不適合這個(gè)格式器將拋出ParseException異常。

          ? abstract Object stringToValue(String s)

          將一個(gè)字符串轉(zhuǎn)換為值。如果s不適合這個(gè)格式拋出ParseException異常。

          ? DocumentFilter getDocumentFilter( )

          覆蓋該方法以提供一個(gè)文檔過濾器,用來限制對(duì)文本域的輸入。返回值是null表示不需要過濾器。

          javax.swing.text.DefaultFormatter 1.3

          ? void setOverwriteMode(boolean mode)

          ? boolean getOverwriteMode( )

          設(shè)置或得到覆寫的方式。如果mode為true,編輯文本時(shí)用新的字符覆寫已有的字符。

          javax.swing.text.DocumentFilter 1.4

          ? void insertString(DocumentFilter.FilterBypass bypass, int offset, String text, AttributeSet attrib)

          字符串插入文檔之前調(diào)用這一方法。可以覆蓋該方法并修改字符串。也可以不調(diào)用 super.insert

          String禁止插入,或者調(diào)用bypass方法修改文檔而不使用過濾器。

          參數(shù):bypass 一個(gè)對(duì)象,允許執(zhí)行屏蔽過濾器的編輯命令

          offset 插入文本處的偏移

          text 將要插入的字符

          attrib 插入文本的格式屬性

          ? void replace(DocumentFilter.FilterBypass bypass, int offset, int length, String text, AttributeSet attrib)

          該方法在使用新字符串替換部分文檔之前調(diào)用??梢愿采w該方法并修改字符串。也可以調(diào)用super.replace禁止替換,或者調(diào)用bypass方法修改文檔而不使用過濾器。

          參數(shù):bypass 一個(gè)對(duì)象,允許你執(zhí)行一個(gè)屏蔽過濾器的編輯命令

          offset 插入文本處的偏移

          length 被替換部分的長度

          text 將要插入的字符

          attrib 插入文本的格式屬性

          ? void remove(DocumentFilter.FilterBypass bypass, int offset, int length)

          在文檔的一部分被刪除(removed)之前調(diào)用。如果需要分析刪除的效果,調(diào)用bypass.getDocument( ) 獲得文檔。

          參數(shù):bypass 一個(gè)對(duì)象,允許你執(zhí)行一個(gè)屏蔽過濾器的編輯命令

          offset 被刪除部分的偏移

          length 被刪除部分的長度

          javax.swing.text.MaskFormatter 1.4

          ? MaskFormatter(String mask)

          用給定的掩碼構(gòu)造掩碼格式器。掩碼符號(hào)參看表9-2。

          ? void setValidCharacters(String characters)

          ? String getValidCharacters( )

          設(shè)置或得到有效的編輯字符。只有給定字符串中的字符才能作為掩碼的可變部分。

          ? void setInvalidCharacters(String characters)

          ? String getInvalidCharacters( )

          設(shè)置或得到無效的編輯字符。任何給定字符串中的字符都不能輸入。

          ? void setPlaceholderCharacter(char ch)

          ? char getPlaceholderCharacter( )

          設(shè)置或得到占位符,在用戶沒有提供時(shí)該占位符作為掩碼的可變字符使用。默認(rèn)的占位符是空格。

          ? void setPlaceholder(String s)

          ? String getPlaceholder( )

          設(shè)置或得到占位符字符串。如果用戶沒有提供掩碼中所有的可變字符則使用其尾部。如果是null或比掩碼短,用占位符填充剩余的輸入。

          ? void setValueContainsLiteralCharacters(boolean b)

          ? boolean getValueContainsLiteralCharacters( )

          設(shè)置或得到“包含直接量字符的值”標(biāo)志。如果該標(biāo)志為true,文本域中的值包含掩碼的直接量(非可變)部分。如果為false,直接量字符將被移除。默認(rèn)值為true。

          文本區(qū)

          有時(shí),用戶的輸入超過一行。正像前面提到的,需要使用JTextArea組件來接受這樣的輸入。當(dāng)在程序中放置一個(gè)文本區(qū)組件時(shí),用戶就可以輸入多行文本,并用ENTER鍵換行。每行都以一個(gè)'\n'結(jié)尾。如果需要將用戶的輸入分割為多個(gè)單獨(dú)的行,可以使用StringTokenizer類(參見第12章)。圖9-14顯示了一個(gè)工作的文本區(qū)。


          在JTextArea組件構(gòu)造器中,可以指定文本區(qū)的行數(shù)和列數(shù)。例如:

          textArea = new JTextArea(8,40); //8 lines of 40 columns each

          與文本域一樣,出于安全的考慮,應(yīng)該把列數(shù)設(shè)置得大一些。用戶不僅僅限于輸入指定的行數(shù)和列數(shù),當(dāng)輸入過長時(shí),文本會(huì)滾動(dòng)。也可以使用setColumns方法改變列數(shù),用setRows方法改變行數(shù)。這些數(shù)值只是首選大小—布局管理器可能會(huì)對(duì)文本區(qū)進(jìn)行縮放。

          如果文本區(qū)的文本超出顯示的范圍,剩下的文本就會(huì)被剪裁掉??梢允褂脫Q行來避免裁剪過長的行:

          textArea.setLineWrap(true); //long lines are wrapped

          換行只是視覺效果;文檔中的文本沒有改變,在文本中沒有插入'\n'字符。

          在Swing中,文本區(qū)沒有滾動(dòng)條。如果需要滾動(dòng)條,可以把文本區(qū)中插入一個(gè)滾動(dòng)窗格(scroll pane)中。

          textArea =new JTextArea(8, 40);

          JScrollPane scrollPane = new JScrollPane(textArea);

          現(xiàn)在滾動(dòng)窗格管理文本區(qū)的視圖。如果文本超出了文本區(qū)可以顯示的范圍,滾動(dòng)條就會(huì)自動(dòng)出現(xiàn),并且在刪除部分文本后,當(dāng)文本能夠顯示在文本區(qū)范圍內(nèi)時(shí),滾動(dòng)條會(huì)再次消失。滾動(dòng)是由滾動(dòng)窗格內(nèi)部處理的,編寫程序時(shí)無需處理滾動(dòng)事件。

          提示:在Swing中,為組件增加滾動(dòng)條的通用機(jī)制是將組件放置在滾動(dòng)窗格中。

          例9-4給出了文本區(qū)演示的完整代碼。這個(gè)程序只能在文本區(qū)中修改文本。點(diǎn)擊“Insert”將句子插入文本末尾。點(diǎn)擊第二個(gè)按鈕將打開和關(guān)閉換行(它的標(biāo)簽在“Wrap”和“No Wrap”之間切換)。當(dāng)然,可以使用鍵盤來編輯文本區(qū)的文本。注意,可以高亮顯示部分文本并且使用CTRL+X、CTRL+C和CTRL+V鍵來剪切、拷貝和粘貼文本。(快捷鍵有特定的觀感效果。前面幾個(gè)組合鍵在Metal、Windows和Mac中的觀感效果相同。)

          注意:JTextArea組件只顯示無格式的文本,沒有字體或者格式設(shè)置。如果想要顯示格式化文本(如HTML或者RTF),就需要使用JEditorPane和JTextPane類。在卷II將詳細(xì)討論這幾個(gè)類。

          例9-4 TextAreaTest.java




          javax.swing.JTextArea 1.2

          ? JTextArea(int rows, int cols)

          構(gòu)造一個(gè)新的文本區(qū)。

          參數(shù):rows 行數(shù)

          cols 列數(shù)

          ? JTextArea(String text, int rows, int cols)

          用一個(gè)初始文本構(gòu)造一個(gè)新的文本區(qū)。

          參數(shù):text 初始文本

          rows 行數(shù)

          cols 列數(shù)

          ? void setColumns(int cols)

          設(shè)置文本區(qū)應(yīng)該使用的首選的列數(shù)。

          參數(shù):cols 列數(shù)

          ? void setRows(int rows)

          設(shè)置文本區(qū)應(yīng)該使用的首選的行數(shù)。

          參數(shù):rows 行數(shù)

          ? void append(String newText)

          將給定的文本附加到文本區(qū)中已有文本的尾部。

          參數(shù):newText 要附加的文本

          ? void setLineWrap(boolean wrap)

          打開或關(guān)閉換行。

          參數(shù):wrap 應(yīng)該換行,則為true

          ? void setWrapStyleWord(boolean word)

          如果word是true,超長的行會(huì)在字邊界處換行。如果為false,超長的行將被截?cái)喽豢紤]字邊界。

          ? void setTabSize(int c)

          設(shè)置跳格(tab stop)為c列。注意,跳格不會(huì)轉(zhuǎn)化為空格,但是,它們能夠讓文本對(duì)齊到下一個(gè)跳格處。

          參數(shù):c 跳格的列數(shù)

          javax.swing.JScrollPane 1.2

          ? JScrollPane(Component c)

          創(chuàng)建一個(gè)顯示指定組件內(nèi)容的滾動(dòng)窗格。當(dāng)組件內(nèi)容超過顯示范圍時(shí),滾動(dòng)條會(huì)自動(dòng)出現(xiàn)。

          參數(shù):c 需要滾動(dòng)的組件

          那本篇就介紹到這里了,覺得不錯(cuò)的話,可以轉(zhuǎn)發(fā)關(guān)注一波?。?!

          明天給大家分享選擇組件這一塊兒的內(nèi)容~~~~~大家準(zhǔn)時(shí)來圍觀哈~~

          本文就是愿天堂沒有BUG給大家分享的內(nèi)容,大家有收獲的話可以分享下,想學(xué)習(xí)更多的話可以到微信公眾號(hào)里找我,我等你哦。

          瀏覽 77
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄色强奸免费小视频网站 | 俺也去成人视频 | 国产性爱在线视频 | 九九无码专区免费喷水 | 大香蕉婷婷伊人 |