Tải bản đầy đủ - 0 (trang)
Chapter 2.  Lists and Combos

Chapter 2.  Lists and Combos

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

2.1.Hacks1320:Introduction

Listsareunderratedandunderappreciated,anddeveloperswho

don'tappreciateJListsoftenuseJTableswhentheydon'tneed

to.Butlistsseemtobemakingacomebackindesktop

applications,andwithgoodreason.Alotofthedatawedeal

witharesingle-dimensioncollectionssearchresults,recent

URLs,downloadedfiles,etc.andbymakingtheonscreenversion

ofthemmoreappealingandmoreusable,alististherightway

topresentthisdatatotheuser.



Hack13.FilterJLists



Makeyour1,000-itemlistalotmoremanageable.

Oneofthenicestthingsyoucandowithalargelististomake

itmanageablewithafilterbox.Thisisatextareathat,asyou

typeintoit,removeslistelementssothatonlythosethat

containthetypedtextarevisible.

Thehacktodothisbasicallyinvolveshavingalistmodelwith

tworepresentationsofitscontents:everythingthatisinthe

list,andasubsetwithjusttheitemstobedisplayed(i.e.,those

fromthefirstlistthatmatchthefilter).Themodel'sget

methodsarethenrewiredtouseonlythesecondlist.

Theimplementationinthishack,FilteredJList,isasingleclass

withtwoinnersubclasses:FilterModelandFilterField.Thelist

ownsthefield,soacallercancreatetheJListfairlytypically

andthenjustaskforthefieldandadditwhereveritmakes

senseinthelayout.

StartbydeclaringFilteredJListasasubclassofJList,and

provideaconstructorandsomeconveniencemethods,asseen

inExample2-1.



Example2-1.FilterListconstructorand

conveniencemethods

publicclassFilteredJListextendsJList{

privateFilterFieldfilterField;

privateintDEFAULT_FIELD_WIDTH=20;





publicFilteredJList(){

super();

setModel(newFilterModel());

filterField=newFilterField(DEFAULT_FIELD_WIDTH);

}

publicvoidsetModel(ListModelm){

if(!(minstanceofFilterModel))

thrownewIllegalArgumentException();

super.setModel(m);

}

publicvoidaddItem(Objecto){

(FilterModel)getModel()).addElement(o);

}

publicJTextFieldgetFilterField(){

returnfilterField;

}



NoticethatalongwithholdingontotheFilterField,theJListalso

createsitsownFilterModelintheconstructor,andoverrides

setModel()toensurethatyoucan'tpushinanincompatible

model.ItalsocontainsanaddItem()method,whichreallyjust

delegatestotheFilterModel.

FilterModel,showninExample2-2,iswherethemagichappens.



Example2-2.Innerclasstoprovideafiltered

model

classFilterModelextendsAbstractListModel{



ArrayListitems;

ArrayListfilterItems;

publicFilterModel(){

super();

items=newArrayList();

filterItems=newArrayList();

}

publicObjectgetElementAt(intindex){

if(index
returnfilterItems.get(index);

else

returnnull;

}

publicintgetSize(){

returnfilterItems.size();

}







publicvoidaddElement(Objecto){

items.add(o);

refilter();



}

privatevoidrefilter(){

filterItems.clear();

Stringterm=getFilterField().getText();

for(inti=0;i
if(items.get(i).toString().indexOf(term,0)!=

filterItems.add(items.get(i));

fireContentsChanged(this,0,getSize());

}

}

//FilterFieldinnerclasslistedbelow

}



ThismodelhastwoArrayListsforitscontents:itemscontainsall

theitemsthathavebeenaddedtothemodel;filterItems



containsonlytheitemsthatmatchthefilter.ThegetSize()and

getElementAt()methods,requiredbyListModel,drawnotfromthe

realitemslist,butfromthefilterItemslist.ThefilterItemslistis

reconstitutedviacallstotherefilter()method,whichfiresoffa

ListDataEventtoinformtheJListthatthecontentshavechanged

andrequirearepaint.



Therefilter()methodworksontheStringrepresentationofthelist

contentsifyourobjectsaremoresophisticated,youmightneedto

adaptthematchinglogic;e.g.,searchingthecontentofemail

messagesrepresentedasobjects.



There'salsoanaddItem()method,patternedaftertheequivalent

methodinDefaultListModelthat,unlikeAbstractListModel,assumes

mutability(i.e.,theabilitytoaddandremovelistcontents).A

morecompleteimplementationofthismodelwouldprobably

needtoprovideequivalentsforallofDefaultListModel'saddand

removemethods.NoticethataddItem()callsrefilter()oneach

add,sothatanaddeditemisimmediatelyaddedtothevisible

list,assumingthatitmatchesthesearchterm.

TheFilterField,showninExample2-3,isfairlytrivial,anditis

responsibleforforcingarefilterwhenitscontentschange.



Example2-3.Textfieldthatrefiltersthemodelon

eachkeystroke



//innerclassprovidesfilter-by-keystrokefield

classFilterFieldextendsJTextFieldimplementsDocumentListene

publicFilterField(intwidth){

super(width);

getDocument().addDocumentListener(this);

}



publicvoidchangedUpdate(DocumentEvente){

((FilterModel)getModel()).refilter();

}

publicvoidinsertUpdate(DocumentEvente){

((FilterModel)getModel()).refilter();

}

publicvoidremoveUpdate(DocumentEvente){

((FilterModel)getModel()).refilter();

}

}



TheFilterField'sDocumentListenercallsforarefilteroneachofthe

possibleDocumentEvents.Forefficiency,itmightbefasterforthe

modeltoprovidearefiltermethodthatstartswiththefiltered

listandnarrowsitdownfurther.Thiscouldbecalledby

insertUpdate()becauseaddingcharacterstothefiltertermcan

onlymakeitmorerestrictive,meaningthereisnopoint

consideringanyitemsthataren'talreadymatches.

TotesttheFilterJList,Example2-4showsasimplemain()

methodthatpopulatesthelistwithsomenamesandputsthe

listanditsfilterfieldinaJFrame.



Example2-4.SimpletestGUIforFilteredJList

publicstaticvoidmain(String[]args){

String[]listItems={

"Chris","Joshua","Daniel","Michael",

"Don","Kimi","Kelly","Keagan"

};

JFrameframe=newJFrame("FilteredJList");

frame.getContentPane().setLayout(newBorderLayout());

//populatelist

FilteredJListlist=newFilteredJList();



for(inti=0;i
list.addItem(listItems[i]);

//addtogui

JScrollPanepane=

newJScrollPane(list,

ScrollPaneConstants.VERTICAL_SCROLLBAR

ScrollPaneConstants.HORIZONTAL_SCROLLB

frame.getContentPane().add(pane,BorderLayout.CENTER);

frame.getContentPane().add(list.getFilterField(),

BorderLayout.NORTH);

frame.pack();

frame.setVisible(true);

}



Whenrun,allthelistitemsaredisplayedinitially,asinFigure

2-1.



Figure2-1.Unfilteredcontentsofalist



ButwhenyoutypeanuppercaseK(theindexofsearchin

refilter()iscasesensitive),thelistimmediatelyshrinkstothree

items,showninFigure2-2.



Figure2-2.Filteringonakeystroke



TheonlymatchesforKare"Kimi,""Kelly,"and"Keagan."Now

typeane,and"Kimi"willbefilteredout,asinFigure2-3.



Figure2-3.Refilteringonsuccessivekeystrokes



Hack14.AddaFilterHistory



Rememberprevioussearchesandresearchwithone

click.

Chancesaregoodthatifyou'vesearchedforsomethingonce,

it'simportantenoughthatyoumightwellsearchforitagain.In

Apple'sSafaribrowser,asearchwidgetattheupperrighthasa

littlemagnifyingglassthatremembersyourlast10searches.

Clickthemagnifyingglassandapopupappearswiththe

previoussearches.Selectoneanditpopulatesthefieldand

doesthesearchimmediately.

Here'sanimplementationofthesameidea,graftedontothe

previoushack.Inotherwords,thisrememberspreviousfilters.

Itdoesn'tremembereverykeystrokewhybotherremembering

thesearches"J"and"Jo"whenyou'rereallyjustinterestedin

"Joe"andonlyaddsasearchtermtothefilterwhentheuser

pressesreturn.

Intheprevioushack,youjustneededtohaveatextfieldanda

JList.NowaJButtonneedstobeattachedtothetextfield,sothe

twoarebundledtogetherintheinnerclassFilterField.This

classisresponsiblefor:

Tellingthemodeltorefilteroneachkeystrokeinthe

JTextField,asbefore.

RememberingtheJTextField'scontentsasasavedsearch

anytimetheReturnorEnterkeyispressed.

CatchingclicksontheJButtonandpoppingupamenuwith



previoussearches.

PopulatingtheJTextFieldwithaprevioussearchwhenoneis

selectedfromthelist.Itdoesn'tneedtoexplicitlytellthe

modeltorefilterbecausechangingthetextareawillfirea

DocumentEventthatisalreadyaccountedforbytheJTextField's

DocumentListener.

Example2-5showsthenewFilterFieldclass.



Example2-5.Listfilteringcomponentwithtext

fieldandhistorybutton



classFilterFieldextendsJComponent

implementsDocumentListener,ActionListener{

LinkedListprevSearches;

JTextFieldtextField;

JButtonprevSearchButton;

JPopupMenuprevSearchMenu;

publicFilterField(intwidth){

super();

setLayout(newBorderLayout());

textField=newJTextField(width);

textField.getDocument().addDocumentListener(this);

textField.addActionListener(this);

prevSearchButton=

newJButton(newImageIcon("mag-glass.png"));

prevSearchButton.setBorder(null);

prevSearchButton.addMouseListener(newMouseAdapter(){

publicvoidmousePressed(MouseEventme){

}

});

add(prevSearchButton,BorderLayout.WEST);

add(textField,BorderLayout.CENTER);

prevSearches=newLinkedList();



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

Chapter 2.  Lists and Combos

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

×