Tải bản đầy đủ - 0 (trang)
Hack 49. Force Text Input into Specific Formats

Hack 49. Force Text Input into Specific Formats

Tải bản đầy đủ - 0trang

Example7-2.Adocumentallowinginputthat

matchesonlyaregex

importjavax.swing.text.*;

importjava.util.regex.*;

publicclassRegexConstrainedDocumentextendsPlainDocument{







Patternpattern;

Matchermatcher;

























publicRegexConstrainedDocument(){super();}

publicRegexConstrainedDocument(AbstractDocument.Conte

publicRegexConstrainedDocument(AbstractDocument.Conte



super(c);



setPatternByString(p);

}

publicRegexConstrainedDocument(Stringp){



super();



setPatternByString(p);

}

































publicvoidsetPatternByString(Stringp){



Patternpattern=Pattern.compile(p);



//checksthedocumentagainstthenewpattern



//andremovesthecontentifitnolongermatc



try{





matcher=pattern.matcher(getText(0,g





System.out.println("matcherresetto"





if(!matcher.matches()){







System.out.println("doesnotm







remove(0,getLength());





}



}catch(BadLocationExceptionble){





ble.printStackTrace();//impossible?



}







}







publicPatterngetPattern(){returnpattern;}





publicvoidinsertString(intoffs,Strings,Attribute





throwsBadLocationException{





//considerwhetherthisinsertwillmatch





StringproposedInsert=







getText(0,offs)+







s+







getText(offs,getLength()-offs);





System.out.println("proposingtochangeto:"









proposedInsert);

if(matcher!=null){







matcher.reset(proposedInsert);







System.out.println("matcherreset");







if(!matcher.matches()){









System.out.println("insertdoe









return;







}





}





super.insertString(offs,s,a);



}

}



ThisclassholdsontoaPatternandaMatchertoperformtheregex

matching.Thepatterncanbesetintheconstructor,orlater

withacalltosetPatternByString().Ineithercase,themethod

compilesthepatternandcreatesaMatcherwiththeDocument's

text.Changingthepatterncould,ofcourse,createamismatch

withanyexistingtextintheDocument,sotheMatcherimmediately

callsmatches()andifthetextdoesnotmatch,itdeletesallthe

textfromtheDocument.

PerhapsthemoretypicalcaseiswhentheDocument.insertString()



methodiscalled.Thiswillhappenoneverykeystrokeina

JTextComponent.AssumingtheMatcherisnotnull,meaningthatthe

Patternhasbeensetatsomepoint,yousimplyneedtocall

Matcher.matches()againsttheDocument'snewcontentstoseeifthey

complywiththeregexconstraints.Ifnot,returnearly,never

callingthesuperclass'sinsert()method,andthusdisallowing

theinput.



7.3.2.AddingConstrainedTextFields

SincetheDocumentisn'tactuallyvisible,youneedtoputitin

somethinginordertotestit.TheTestRegexConstrainedDocumentclass

createsaJTextFieldforyoutotypeinaregularexpressionto

enforce,andalongerJTextFieldfortexttotest.Youcreatethis

latterJTextFieldwiththeseldom-seenconstructorthattakesa

Document,aninitial-valueString,andawidth(specifiedin

columns).Obviously,youuseaRegexConstrainedDocumentforthe

firstargument.There'salsoaSetJButtonthattakestheString

valueoftheregexfieldandsetsthatasthenewpatternto

matchthedocumentagainst,withRegexConstrainedDocument's

setPatternByString()method.Therestismostlylayoutcode.The

testclassisshowninExample7-3.



Example7-3.GUItotestthe

RegexConstrainedDocumentinaJTextField

importjava.awt.*;

importjava.awt.event.*;

importjavax.swing.*;

publicclassTestRegexConstrainedDocumentextendsJPanel



implementsActionListener{





JTextFieldregexField,filterField;









JButtonregexButton;

RegexConstrainedDocumentregexDoc;





































}



publicTestRegexConstrainedDocument(){

setLayout(newBoxLayout(this,BoxLayout.Y_AXIS));

//top-regexstuff

JPaneltopPanel=newJPanel();

JLabelrLabel=newJLabel("regex:");

topPanel.add(rLabel);

regexField=newJTextField(20);

topPanel.add(regexField);

regexButton=newJButton("Set");

regexButton.addActionListener(this);

topPanel.add(regexButton);

add(topPanel);

//bottom-filterfield

regexDoc=



newRegexConstrainedDocument();

filterField=newJTextField(regexDoc,"",50);

add(filterField);



publicvoidactionPerformed(ActionEvente){





System.out.println("actionperformed");





if(e.getSource()==regexButton){







System.out.println("regexbutton");







regexDoc.setPatternByString(regexField





}



}

















publicstaticvoidmain(String[]args){



JComponentc=newTestRegexConstrainedDocument



JFramef=newJFrame("Regexfiltering");



f.getContentPane().add(c);



f.pack();



f.setVisible(true);

}



}



Whenrun,thedisplayedGUIlookslikeFigure7-2.Noticethat

byusingtheregex[A-Z]*,youcanenteruppercaselettersand

spaces,butnothingelse.

Whenyoutypeacomma,aquestionmark,orlowercaseletters,

theyareignored.



Figure7-2.FilteringJTextFieldinputwitha

regularexpression



Youcandosmartthingswiththistool,butalsoreallystupid

things.Let'ssayyouwanttorestrictinputtothecharacters

thatwillbeinaNorthAmericanphonenumberoftheform123456-7890.Youcansetthepatternto[0-9\-]*,whichwillallow

theusertotypeinonlynumbersandthehyphen.

Nowyou'refeelingclever,butyoudon'tlikethefactthatthis

stillallowsuserstotypepatternsthataren'tphonenumbers,

like1111111or-1-1-1-1.So,yousetthepatterntoanexact

descriptionofthephonenumberpattern:

[0-9]{3}-[0-9]{3}-[0-9]{4}



Butnowyouruserscan'tenteranything!Why?Because

althoughthatregularexpressiondoesspecifythephone

numberpattern,nosubstringofitwillevermatch.This

expressionspecifiesexactly12characters,sowhenyoutype



thefirstone,there'sonlyonecharacteritdoesn'tmatchthe

pattern,soit'srejected.

Themoralofthestoryhereistobethoughtful.Youmight

decidetowireupaFocusListenersoyouimposetheregex

patternonlywhentheusermovesoffthefield,andchangethe

"deleteeverything"behaviortosomethingalittlelessforceful;

forexample,youcouldpopupadialogtellingtheuserthather

inputisn'tintherightformat.Justdon'tbesurprisedwhen

regularexpressionsgiveyouresultsthatarelogical,but

sometimesunexpected.



Hack50.Auto-CompletingTextFields



TypinginawholeURLisapain.Whentheuserstartsto

type,completehistextwithpreviouslyenteredoptions,

andlettheuserselectoneinsteadoftypingthewhole

URL.

Theauto-completingtextfieldisinstantlyfamiliarfromitsuse

inbrowsers,whereitisprobablymostneeded.Nobodywantsto

havetotrytotypeorforthatmatterevenrememberahugeURL

tosomepagethey'vevisitedbefore,particularlynotsomething

likethoseAmazon.comURLswithinexplicable20-digitnumbers

andbunchesofseeminglyarbitrarycharacters.Ontheother

hand,noteverythingneedstobesavedasabookmark.

Thetextfieldthatpopsupawindowofrecentlyviewedsitesis

ahappycompromise.Itjogsyourmemorybyshowingyou

completionoptions,anditsaveslotsoftypingbylettingyou

simplyclickoneoftheoptionsandhavingthattextinserted

immediatelyintothetextfield.



7.4.1.ASelf-CompletingTextField

ThishacktakesaJTextFieldandhasitmanageaJWindow,which

containsaJListofpossiblecompletionvalues.Therealworkis

donebyaninnerclassthatmanagesthelistofcompletionsand

hasajavax.util.regex.Patternobjecttomatcheachpotential

completionagainstthefield'scurrenttext.Example7-4iswhat

youneedtogetgoing.



Example7-4.AJTextFieldthatmanagesapop-up



listofcompletions

importjava.awt.*;

importjavax.swing.*;

importjavax.swing.event.*;

importjavax.swing.text.*;

importjava.util.*;

importjava.util.regex.*;

publicclassCompletableJTextFieldextendsJTextField



implementsListSelectionListener{













Completercompleter;

JListcompletionList;

DefaultListModelcompletionListModel;

JScrollPanelistScroller;

JWindowlistWindow;





publicCompletableJTextField(intcol){





super(col);





completer=newCompleter();





completionListModel=newDefaultListModel();





completionList=newJList(completionListModel)





completionList.setSelectionMode(ListSelectionM





completionList.addListSelectionListener(this);





listScroller=







newJScrollPane(completionList,









ScrollPaneConstants.VERTICAL_S









ScrollPaneConstants.HORIZONTAL

listWindow=newJWindow();





listWindow.getContentPane().add(listScroller);



}







publicvoidaddCompletion(Strings){



completer.addCompletion(s);}









publicvoidremoveCompletion(Strings){



completer.removeCompletion(s);}









publicvoidclearCompletions(Strings){



completer.clearCompletions();}





publicvoidvalueChanged(ListSelectionEvente){





if(e.getValueIsAdjusting()){return;}





if(completionList.getModel().getSize()==0){





listWindow.setVisible(false);





finalStringcompletionString=

(String)completionList.getSelectedValue();





Threadworker=newThread(){









publicvoidrun(){









setText(completionString);









}







};





SwingUtilities.invokeLater(worker);



}









/**innerclassdoesthematchingoftheJTextField's



documenttocompletionstringskeptinanArray

*/





























classCompleterimplementsDocumentListener{



privatePatternpattern;



privateArrayListcompletions;



publicCompleter(){





completions=newArrayList();





getDocument().addDocumentListener(this



}





publicvoidaddCompletion(Strings){





completions.add(s);





buildAndShowPopup();



}







publicvoidremoveCompletion(Strings){







completions.remove(s);







buildAndShowPopup();





}







publicvoidclearCompletions(){







completions.clear();







buildPopup();







listWindow.setVisible(false);





}





privatevoidbuildPopup(){







completionListModel.clear();







System.out.println("buildPopupfor"+











"completions");







Iteratorit=completions.iterator();







pattern=Pattern.compile(getText()+







while(it.hasNext()){









//checkifmatch









Stringcompletion=(String)it









Matchermatcher=pattern.match









if(matcher.matches()){









//addifmatch









System.out.println("matched"+









completionListModel.add(comple

















}else{









System.out.println("pattern"















"does

completion);

}







}





}





















privatevoidshowPopup(){



if(completionListModel.getSize()==0)





listWindow.setVisible(false);





return;

































































}



}

//figureoutwherethetextfieldis,

//andwhereitsbottomleftis

java.awt.Pointlos=getLocationOnScree

intpopX=los.x;

intpopY=los.y+getHeight();

listWindow.setLocation(popX,popY);

listWindow.pack();

listWindow.setVisible(true);































privatevoidbuildAndShowPopup(){



if(getText().length()<1)





return;



buildPopup();



showPopup();

}























//DocumentListenerimplementation

publicvoidinsertUpdate(DocumentEvente){bu

publicvoidremoveUpdate(DocumentEvente){bu

publicvoidchangedUpdate(DocumentEvente){b





}



}



TheCompletableJTextFieldconstructorisresponsibleforsettingup

theJListanditsmodel;forwiringupthefieldasa

ListSelectionListener;andforpackingthelistintoaJScrollPane,

whichsitsinaninitiallyinvisibleJWindow.Italsocreatesan

instanceoftheinnerclassCompleter,whichisresponsiblefor

managingthelistofcompletions.Notethatthisversionofthe

hacksuppliesonlyoneofthetypicalJTextFieldconstructor

signatures;you'dprobablywanttoprovideotherstomakethe

componentmoreconvenientforcallers.



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Hack 49. Force Text Input into Specific Formats

Tải bản đầy đủ ngay(0 tr)

×