Tải bản đầy đủ - 0 (trang)
Hack 14. Add a Filter History

Hack 14. Add a Filter History

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

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();



}

publicvoidpopMenu(intx,inty){

prevSearchMenu=newJPopupMenu();

Iteratorit=prevSearches.iterator();

while(it.hasNext())

prevSearchMenu.add(

newPrevSearchAction(it.next().toString()));

prevSearchMenu.show(prevSearchButton,x,y);

}

publicvoidactionPerformed(ActionEvente){

//calledonreturn/enter,addstermtoprevSearches

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

prevSearches.addFirst(textField.getText());

if(prevSearches.size()>10)

prevSearches.removeLast();

}

}

publicvoidchangedUpdate(DocumentEvente){

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

}

publicvoidinsertUpdate(DocumentEvente){

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

}

publicvoidremoveUpdate(DocumentEvente){

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

}

}



NoticehowthisversionoftheclassusesaMouseListeneronthe

JButtoninsteadofanActionListener.Eitherwillwork,butthe

MouseEventprovidesthelocationofthemouseclickasaPointin

theJButton'scoordinatespace,whichisusefulforshowingthe

pop-upmenuattheexactpointofthemouseclick.Thereisan

ActionListenerimplementation,butit'sfortheJTextFieldsothat



whentheuserpressestheReturnkey,thefiltertextissavedto

theJPopupMenu(and,iftherearemorethan10items,theoldest

savedsearchisremoved).

TheitemsintheJPopupMenuareinstancesofPrevSearchAction,

whichsubclassesSwing'sAction.Thisisconvenientbecausethey

provideaStringrepresentationtobeshowninthepop-up

menu,yetgetanactionPerformed()whentheirmenuitemis

selected,whichgivesthemachancetoresetthefiltertext.

Here'swhatthePrevSearchActioninnerclasslookslike:

classPrevSearchActionextendsAbstractAction{

Stringterm;

publicPrevSearchAction(Strings){

term=s;

putValue(Action.NAME,term);

}

publicStringtoString(){returnterm;}

publicvoidactionPerformed(ActionEvente){

getFilterField().textField.setText(term);

}

}



Whenaprevioussearchisrecalled,itlookslikeFigure2-4.



Figure2-4.Pop-upmenuwithprevioussearches



Andwhenthemouseclicksononeofthemenuitems,thefield

ispopulatedandthelistisfiltered.Figure2-5showstheresult.



Figure2-5.Listfilteredbypop-upselection



Thegeneralideaofthispopupcanbemodifiedtoworkin

similarwaysfordifferentkindsofsearches,suchaspoppingup

alistofwhichfieldthesearchistobeappliedtoifthelistitems

arecomplex.Anexampleofthisisamailprograminwhichthe

popupmightshowtheoptionsSubject,To,From,etc.,meaning

thatthesearchislimitedtofindingthespecifiedterminonly

theselectedfield.



Hack15.MakeJListsCheckable



Avoidlosing50selectionstoanunshiftedclick.

OnehorribleUIproblemisdealingwithvastcollectionsof

thingsthatneedtobepresentedtotheuserandmade

selectable.If,likeme,you'veeverhad1,000emailsinyour

inbox,youknowwhatImean.Worse,whatifyoupickabunch

ofitemstodelete,butyourfingerslipsoffthekeyusedfor

multi-selection(AltonWindows,CommandontheMac,etc.)

andyouloseallofyourpreviousselections?Overridingthe

nativeselectionbehaviorcanmakethissituationsomewhat

morepalatable.

Becausealistlikethisbehavesdifferentlythananormallist,it

shouldlookdifferent,too,soI'veoptedforacheckbox

metaphor.Eachitemisshownwithacheckbox,andasyouclick

moreitems,theygetchecked,andifyouselectanalreadycheckeditem,itgetsunchecked.



Thisturnsouttobealittleharderthanexpected.Ioncediditwithout

JList,creatingmyownscrollinglayoutofJPanelsandfakingthelist

behavior.ItturnedupafunnySwingbugbecauseIwasusing

GridBagLayoutforthefakelist,anditstartedtotallybombingoutafter

about500itemswereaddedtothelist.ThiswasbecauseGridBagLayout

hasabugwhereitcan'thavemorethan512rows.Consideringthebug

(number4254022ontheJavaBugParade)wasfiledin1999andisstill

open,I'mfiguringitwon'tgetfixedbythetimeyoureadthis.



ThebasisofthecheckablelistisaJList.Thetrickyparthereis

thatthereisn'taway(thatI'vefound)tostealthemouseclicks



fromtheJListandconsumethembeforethenormalcallstothe

ListSelectionModelaremade.Instead,thestrategyistosetupa

ListSelectionListenerandjustfixeverythingafterJListhasdone

itsthing.

Toimplementthecheckboxfunctionality,subclassJListandgive

itacustomListSelectionListenerandaListCellRenderer.Acomplete

listingisshowninExample2-6.



Example2-6.Acheckbox-metaphorJList

publicclassCheckBoxJListextendsJList

implementsListSelectionListener{



staticColorlistForeground,listBackground;

static{

UIDefaultsuid=UIManager.getLookAndFeel().getDefaults(

listForeground=uid.getColor("List.foreground");

listBackground=uid.getColor("List.background");

}

HashSetselectionCache=newHashSet();

inttoggleIndex=-1;

booleantoggleWasSelected;

publicCheckBoxJList(){

super();

setCellRenderer(newCheckBoxListCellRenderer());

addListSelectionListener(this);

}

//valueChanged()listingbelow

publicstaticvoidmain(String[]args){

JListlist=newCheckBoxJList();



DefaultListModeldefModel=newDefaultListModel();

list.setModel(defModel);

String[]listItems={

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

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

};

Iteratorit=Arrays.asList(listItems).iterator();

while(it.hasNext())

defModel.addElement(it.next());

//showlist

JScrollPanescroller=

newJScrollPane(list,

ScrollPaneConstants.VERTICAL_SCROL

ScrollPaneConstants.HORIZONTAL_SCR

JFrameframe=newJFrame("CheckboxJList");

frame.getContentPane().add(scroller);

frame.pack();

frame.setVisible(true);

}

}



Therearetwoimportantsectionstoconsider.Thefirstisthe

valueChanged()methodthatimplementsListSelectionListener.The

followinglistdescribeswhathappensinthatmethod.

1. OnlyreactifListSelectionEvent.isValueAdjusting()returnsfalse.

Ifit'strue,thentheeventispartofaseriesperhapstheuser

isshiftdraggingoverseveralitemstomultiselectthemand

youdon'twanttodoanythinguntiltheseriesofeventshas

completed.

2. RemovetheListSelectionListenersothatchangestothelist

madebyyourcodedon'tfireoffevents,whichwouldlead

toarecursive,stackblowingfiasco.



3. CachealltheselectionsthatresultedfromJList'shandling

oftheevent.Thesewillbeaddedorremovedfromthefinal

selectionslater.

4. Reselectalltheitemsthatwereselectedbeforethe

valueChanged()call.

5. Gothroughthenewselectionsandaddthemtothe

selectioniftheyweren'tselectedbefore.Ontheotherhand,

iftheywereselectedpreviously,deselectthem.

6. CachealltheseselectionsforthenextcalltovalueChanged().

7. AddtheListSelectionListeneragain.

ThelistingforvalueChangedisshowninExample2-7.



Example2-7.AListSelectionListenerforthe

checkableJList

publicvoidvalueChanged(ListSelectionEventlse){

if(!lse.getValueIsAdjusting()){

removeListSelectionListener(this);



//determineifthisselectionhasaddedorremovedite

HashSetnewSelections=newHashSet();

intsize=getModel().getSize();

for(inti=0;i
if(getSelectionModel().isSelectedIndex(i)){

newSelections.add(newInteger(i));

}

}

//turnoneverythingthatwasselectedpreviously

Iteratorit=selectionCache.iterator();

while(it.hasNext()){



intindex=((Integer)it.next()).intValue();

getSelectionModel().addSelectionInterval(index,index);

}



//addorremovethedelta

it=newSelections.iterator();

while(it.hasNext()){

IntegernextInt=(Integer)it.next();

intindex=nextInt.intValue();

if(selectionCache.contains(nextInt))

getSelectionModel().removeSelectionInterval(in

else

getSelectionModel().addSelectionInterval(index

}

//saveselectionsfornexttime

selectionCache.clear();

for(inti=0;i
if(getSelectionModel().isSelectedIndex(i)){

selectionCache.add(newInteger(i));

}

}

addListSelectionListener(this);

}

}



TheotherimportantpartofthisclassisaListCellRendererthat

showsthelistitemswithcheckboxes,andwhichisusedasa

visualcuethatthelisthascheckbox-likebehavior.Asidefrom

addingacheckboxtotherenderercomponentandsettingits

stateappropriately,youshouldhackthecoloringofthecellto

avoidhighlighting(becauseyouarealreadyusingcheckboxes).

Thekeyhereistograbtheplatform'scolorsforunselectedlist

cellforegroundsandbackgrounds,whichyoucangetviathe



UIDefaultsclassandthepropertynamesList.foregroundand

List.background.Thiscellrendereralwaysresetsthelistcellsto



theseunselectedcolors,leavingjustthecheckboxesasan

indicationofwhat'sselectedanddoesitinthecorrectcolors.

Therendererisimplementedasaninnerclassandislistedin

Example2-8.



Example2-8.ListCellRendererforcheckboxbasedJList

classCheckBoxListCellRendererextendsJComponent

implementsListCellRenderer{

DefaultListCellRendererdefaultComp;

JCheckBoxcheckbox;

publicCheckBoxListCellRenderer(){

setLayout(newBorderLayout());

defaultComp=newDefaultListCellRenderer();

checkbox=newJCheckBox();

add(checkbox,BorderLayout.WEST);

add(defaultComp,BorderLayout.CENTER);

}



publicComponentgetListCellRendererComponent(JListlist,

Objectvalue,

intindex,

booleanisSel

booleancellH

defaultComp.getListCellRendererComponent(list,value,index,

isSelected,cellH

checkbox.setSelected(isSelected);

Component[]comps=getComponents();

for(inti=0;i
comps[i].setForeground(listForeground);

comps[i].setBackground(listBackground);

}



returnthis;

}

}



Whenyouclickonitemsinthelist,theirselectionstateis

shownwithcheckboxes,asseeninFigure2-6.



Figure2-6.Usingthecheckbox-metaphorJList



Noticehowthecheckboxesareallyouneedtoseewhat's

selected.Inanearlyversionofthishack,Iwentoutofmyway

tomaintaintheusualselectioncolorsanditlookedlousy,

probablybecausethereweretwocompetingmetaphorstoshow

theselection:thehighlightandthecheckbox.Sincethishack

totallychangeshowtheJListworks,it'sappropriatetoradically

changeitsappearance,too.



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

Hack 14. Add a Filter History

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

×