Tải bản đầy đủ - 0 (trang)
Hack 26. Search Through JTables Easily

Hack 26. Search Through JTables Easily

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

StartbycreatingaclasscalledTableSearcherthatimplements

TableModel.

Next,createasimpledecorator(orwrapper)thatimplements

alloftheTableModelmethodsandforwardsthecallstotheinner

model.DependingonyourIDE,youmaybeabletoautomate

theprocess(IntelliJIDEAdoesitforme).You'llhavetomodify

afewofthemethods,butmostaregoingtoremainunchanged.

Youdon'thavetotouchthegetColumnName()andgetColumnClass()

methods,forexample.JustforwardthemtotheinnerTableModel:









publicStringgetColumnName(intcolumn){



returntableModel.getColumnName(column);

}











publicClassgetColumnClass(intcolumn){



returntableModel.getColumnClass(column);

}



ThegetColumnCount()methodisslightlydifferentinthatyouhave

tocheckiftheTableModelisnull.Thisisbecausethetablecalls

getColumnCount()firstandcallsothercolumnmethodsonlyifthere

arevalidcolumns.Hereisthecodewiththenullcheck:









publicintgetColumnCount(){



return(tableModel==null)?0:tableModel.ge

}



3.7.3.CreatingLogicalLinkstotheInnerTable

Model



Now,youneedtointroducetheideaoflinksbetweentheinner

tablemodelandthistablemodel.CreateaCollectioncalled

rowToModelIndex.Init,you'llstoreIntegerscorrespondingtothe

innertablemodelrownumber,attheindexthatcorrespondsto

thistablemodel'srow.So,ifthefifthrowintheinnermodelis

thefirstrowinthismodel,youwouldstoreanIntegervalueof5

asthefirstintherowtoModelIndex.

Thismethodclearsthesearchingstatebymakingaone-to-one

mappingoftheinnertablemodeltothistablemodel:

















privatevoidclearSearchingState(){



searchString=null;



rowToModelIndex.clear();



for(intt=0;t




rowToModelIndex.add(newInteger(t));



}

}



Now,youneedtochangetherowreferencemethodstoindirect

throughtherowtomodelindexbeforehittingtheinnertable

model:



publicintgetRowCount(){



return(tableModel==null)?0:rowToModel



}



publicbooleanisCellEditable(introw,intcolumn){









}



returntableModel.isCellEditable(getModelRow(ro











publicObjectgetValueAt(introw,intcolumn){



returntableModel.getValueAt(getModelRow(row),

}











publicvoidsetValueAt(ObjectaValue,introw,intcolu



tableModel.setValueAt(aValue,getModelRow(row),

}



3.7.4.Indexing

Luceneisadocumentindexingandsearchingtool,available

fromhttp://lucene.apache.org/.ToincorporateitintoaJava

application,yousimplyneedtoputitsJARfile,typicallynamed

somethinglikelucene-version.jar,intoyourclasspath.Forthis

hack,you'llneedthefollowingimportstatements:















importorg.apache.lucene.store.*;

importorg.apache.lucene.document.*;

importorg.apache.lucene.analysis.*;

importorg.apache.lucene.index.*;

importorg.apache.lucene.search.*;

importorg.apache.lucene.queryParser.*;



MostdevelopersuseLucenewithdocuments,butyoucanfake

ittoindexatablemodelinstead.First,youneedtocreatea

Luceneindex,wherealloftheinternalLucenelinksarestored.

YoushoulduseaRAMDirectoryratherthanafile-baseddirectory

inordertokeepeverythingportable.You'llalsoneedanAnalyzer

thathelpscommunicatebetweendataandtheindex,aswellas

anIndexWriterthatactuallywritestotheindex:









directory=newRAMDirectory();

analyzer=newWhitespaceAnalyzer();

IndexWriterwriter=newIndexWriter(directory,analyze



Forthepurposesofindexing,thinkofeveryrowasadocument

andeverycolumnasawordorasetofwords(calledaFieldin

Lucene-speak)forthatdocument.Now,loopthroughthetable

model'srows,creatinganewDocumentforeachrowandadd

Fieldspercolumn:













for(introw=0;row


Documentdocument=newDocument();



//addfields



writer.addDocument(document);

}



First,addafieldwiththerowindexintheinnertablemodel.

You'llusethistolinkbacktothatrowlaterintherow-to-model

index.Eachfieldneedsanameandavalue,socreatea

constantcalledROW_NUMBERthatyou'llrefertolaterwhen

retrievingthelinks:











Documentdocument=newDocument();

document.add(newField(ROW_NUMBER,""+row,true,true

//moreindexingtocome

writer.addDocument(document);



Then,iteratethroughallofthecolumnsandaddaFieldforeach

columnname/valuepair:









for(intcolumn=0;column
StringcolumnName=tableModel.getColumnName(column);

StringcolumnValue=String.valueOf(











tableModel.getValueAt(row,column)











).toLowerCase();

document.add(newField(columnName,columnValue,true,t

}



3.7.5.Searching

Therearetwopartstothesearching.First,youhavetohitthe

Luceneindexwithasearchstring.Thiswillgiveyoualistof

rowsintheinnertablemodelthatmatchthesearch.Thenyou

needtoresettherow-to-modelindex,pointingtothoserows.



3.7.5.1Gettingresultsfromtheindex.

Toactuallygetthesearchresults,youneedanIndexSearcherthat

speakstotheindexandreturnsyoursearchresults:





IndexSearcheris=newIndexSearcher(directory);



Youwanttomakesureallofthefieldsgetsearched,soiterate

throughthetablemodelandputallofthecolumnnamesinan

arraythatyou'llpassintotheLucenesearchcall:











String[]fields=newString[tableModel.getColumnCount(

for(intt=0;t


fields[t]=tableModel.getColumnName(t);

}



Next,createaQueryobjecttopasstotheIndexSearcher;thereisa



helpermethodonMultiFieldQueryParsertodojustthat.Passitthe

fieldsyouwanttosearch,yoursearchString,andtheanalyzer:



Queryquery=MultiFieldQueryParser.parse(searchString,fields,



Thenrunthesearch.Hitsistheobjecttypereturnedbythe

searchcall.You'llprocessthehitsinthenextsectionwhenyou

maptheresultsbacktotheinnertablemodel:

Hitshits=is.search(query);



3.7.5.2Recreatingtheinnertablemodellinks.

Startbyclearingtherow-to-modelindextogetridofthe

previousresults:

rowToModelIndex.clear();



TheHitsobjectcontainsanumberofDocuments,justliketheones

youputintotheindex.Remember,youputafieldineach

DocumentwiththenameROW_NUMBER.So,nowyoucaniterate

throughtheDocumentsandgettherownumberfromthefield

value:













for(intt=0;t
Documentdocument=hits.doc(t);

Fieldfield=document.getField(ROW_NUMBER);

IntegerrowNumber=newInteger(field.stringValue());

}



ThelaststepistoaddanIntegertotherow-to-modelindexwith

therownumberretrievedfromthedocument.Then,tieupall

thelooseendsbyfiringatablemodelupdate.



3.7.6.TryItOut

Becauseyou'recreatingthistablemodelasadecorator,it's

extremelyeasytouse.ThenormalcodetosetupaJTableanda

customtablemodelMyTableModellookslikethis:









JTabletable=newJTable();

MyTableModelmyTableModel=newMyTableModel();

table.setTableModel(myTableModel);



AllyouneedtodoiswraptheMyTableModelwithaTableSearcher

andsetthetablemodelfortheJTableastheTableSearcher:











JTabletable=newJTable();

MyTableModelmyTableModel=newMyTableModel();

TableSearchertableSearcher=newTableSearcher(myTable

table.setTableModel(tableSearcher);



Then,youjustneedtocallthesearchmethodatthe

appropriatetime.Usually,you'llhaveasearchfieldtoenterthe

searchandasearchbuttontostartthesearch,sojustattach

anactionlistenertothembothtofireoffasearch:







finalJTextFieldsearchField=newJTextField();

JButtonsearchButton=newJButton("Go");















ActionListenersearchListener=newActionListener(){

publicvoidactionPerformed(ActionEvente){



searchTableModel.search(searchField.getText().t



searchField.requestFocus();

}



};













searchButton.addActionListener(searchListener);

searchField.addActionListener(searchListener);



3.7.7.FinishingTouches

You'vegotthebarebonesdown,butthereareafewthings

you'llwanttoaddtomakeeverythingalittlemorefunctional.

Hereareacoupleofideas.



3.7.7.1Listentoinnertableupdates.

Iftheinnertablemodelchanges,youneedtoknowaboutit.

Otherwise,yoursearchresultswillnotjivewiththeinnertable

model.ThesimplesolutionistoaddaTableModelListenertothe

innertabletorebuildtheindex,andthenrerunthesearch

againstthenewindex.

Here'sthecode:















privateclassTableModelHandlerimplementsTableModelLi

publicvoidtableChanged(TableModelEvente){



//Ifwe'renotsearching,justpasstheevent



if(!isSearching()){





clearSearchingState();





reindex();





















}



















}





fireTableChanged(e);



return;

}

//Somethinghashappenedtothedatathatmay

//haveinvalidatedthesearch.

reindex();

search(searchString);

fireTableDataChanged();



Youshouldconsiderextendingthishackifyouhaveserious

performanceconsiderations.Youcouldnarrowdowntheareaof

thetablethatchangedtofiremoreaccurateeventstothe

table.



3.7.7.2Clearsearchresultsforblanksearch.

Whenuserssearchwithanemptystring,theytypicallyexpect

thattoclearthesearch.Theeasiestwaytodothisistocheck

foranemptystringinthesearchmethod.Iftheysearchwith

anemptystring,clearthesearchandrerunthemethodthat

indexesalloftheinnertablemodelwithoutasearch:



















publicvoidsearch(StringsearchString){



if(searchString==null||searchString.equals





clearSearchingState();





fireTableDataChanged();





return;





}





//restofsearchmethod



}



Ifyouwantedtohackfurther,youcouldmakethisandother

smallfunctionslikeiteachseparatedecorators.Thenyoucould

combinethematwill,dependingontheneedsofyour

application.



3.7.8.WrappingUp

ThistablemodeldecoratorisnowpartofthemainLucene

distribution.It'spartofanewlucene-contribprojectforSwing.

Inadditiontothistablemodeldecorator,thereisalsoalist

decorator.Iimaginethesearchlogicisgoingtobeefup,so

definitelycheckouttheLucenesiteformoreinformation.You

cangetread-onlywebaccesstotheLucenerepositoryat

http://svn.apache.org/repos/asf/lucene/java/trunk/contrib/swing/

Alsonotethatbecausethesemodelsareofficiallypartof

lucene-contrib,theyaregoingtobedistributedwithallnew

Lucenebuilds.So,theyaregoingtocomefreewithLucenein

thefuture.

JonathanSimon



Hack27.AnimateJTreeDrops



Whosaidworkingwithtreepathswashard?Nowyou

canreorganizetreehierarchieswithdrag-and-drop.

JTreesaregreatforrepresentinghierarchy,butthey'renotso



hotascontrolwidgets.Youmightwanttodragitemsinsidea

tree,oracceptadropfromsomeotherpartofyourapplication,

anditturnsoutnottobewellsuitedtothat.Theproblemis

thattheJTreeisn'treallyacontainer,sofromtheSwing

programmer'spointofview,youseethetree'svisual

representation,butnotthenodeswithinit.

ThegoalofthishackistotakeaJtree,liketheoneshownin

Figure3-11,andallowyoutoreorganizeitthroughdrag-anddrop.Thebulkoftheworkwillbeinanimatingandhandlingthe

drop.Thepayoffisthatmakingasingletreereorderablewill

alsogetyoumostofthewaytomakingitagooddrag-and-drop

participantwiththerestofyourapplication,sincesupporting

drag-and-dropwithintheJTReerequiresyoutomakethetreea

dragsourceandadroptarget.



3.8.1.TheCode

Ifanyoftheforgoingsoundsfamiliar,itshould.Bringingdragand-droptotheJtreeisverysimilartosupportingitforthe

JList.Infact,theJTReeandtheJListhavealotincommonboth

usecellrenderers,botharetypicallyputinJScrollPanes,etc.



Figure3-11.JTreewithdrag-and-dropreordering



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

Hack 26. Search Through JTables Easily

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

×