Tải bản đầy đủ - 0 (trang)
Chapter 5.  Windows, Dialogs, and Frames

Chapter 5.  Windows, Dialogs, and Frames

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

5.1.Hacks3340:Introduction

Forfourchapters,we'vehackedawayatSwingwidgets,from

JLabelstoJTables,withoutworryingtoomuchaboutthecontext

inwhichthey'reshowntotheuser.Andyet,everySwingwidget

mustultimatelybecontainedinsomekindofwindowtobeon

thescreenatall.It'snotanexaggerationtosaythatmany

competentSwingprogrammersdon'tevenknoworcareabout

thehierarchyofAWTWindows,Dialogs,andFramesortheir

Swingequivalents,JWindow,JDialog,andJFrame.Yet,it'sthese

sameprogrammerswhodon'tknowthatcommercial

componentslikesplashscreensareallpossibleinSwing;they

seedialogsandframesandassumeeverythinghasatitlebar.

Thisishardlytrue,thoughyoucaneasilyremovethe

decorationsofadialog,orjustworkwiththewindow

superclass.

Sufficeittosaythere'smuchyoucandowithwindowsand

theirsubclasses.Somuchso,infact,thatitfillstwochapters.

Thischapterwilldealwithhacksthatdealwithplacing,moving,

andresizingwindowsinwaysthatarefairlyconsistentwiththe

designofthewindowclasses.Thenextchapterwillbealot

moreaggressiveinbreakingtherules.



Hack33.WindowSnapping



Makeyourwindowssnaptotheedgesofthescreenby

usingaspecialeventlistener.

Backintheprehistoricdaysofdesktopsoftware,asgraphics

programswerebeinginvented,theysolvedtheproblemof

managingthedrawingtoolsbycreatingmini-windowscalled

palettes(andtheirlatervariation,toolbars).Eventually,the

programshadsomanypalettesthattheusersgrewfrustrated

tryingtoorganizethem.Liningthemupontheedgeofthe

screenwasparticularlynasty,sofledglingyoungprogrammers

tookituponthemselvestocreatesnappablewindows.These

werewindowsthatweremagnetic(metaphoricallyspeaking)

andcouldalignthemselvestothescreen'sedges.Thishack

demonstrateshowtorecreatethistechniquewithJava.

Theideaissimple:youcheckwhenevertheusermovesthe

window.Ifthewindowisoffthescreen,thenmoveitbackto

theedge.Movingthewindowisprettyeasy.Thetrickierpartis

knowingwhenthewindowhasmoved.Fortunately,AWThasan

answer:theComponentListenerinterface.

InJava,everyUIcomponent(inbothAWTandSwing)fires

eventswheneveritmoves,resizes,isshown,orishidden.Any

classcanreceivetheseeventsbyimplementingthe

ComponentListenerinterface.Forthepurposesofthishack,you

onlyneedthecomponentMovedevent,sostartbysubclassing

ComponentAdapter,whichprovidesdefaultno-operation

implementationsofallofComponentListener'sdeclaredmethods.

ThenjustoverridethecomponentMoved()method,asseenin

Example5-1.



Example5-1.AComponentListenertosnapa

windowintoplace

publicclassWindowSnapperextendsComponentAdapter{





publicWindowSnapper(){}









privatebooleanlocked=false;

privateintsnap_distance=50;

























































publicvoidcomponentMoved(ComponentEventevt){



if(locked)return;



Dimensionsize=Toolkit.getDefaultToolkit().g



intnx=evt.getComponent().getX();



intny=evt.getComponent().getY();



//top



if(ny<0+snap_distance){





ny=0;



}



//left



if(nx<0+snap_distance){





nx=0;



}



//right



if(nx>size.getWidth()-evt.getComponent().







snap_distance){





nx=(int)size.getWidth()-evt.getCompo



}



//bottom



if(ny>size.getHeight()-evt.getComponent()







snap_distance){





ny=(int)size.getHeight()-evt.getComp



}





//makesurewedon'tgetintoarecursiveloop



//setlocationgeneratesmoreevents



locked=true;



evt.getComponent().setLocation(nx,ny);





locked=false;



}

}



EverytimecomponentMoved()iscalled,itgetsthescreensizeand

currentcoordinatesofthewindow.Becausewindowcoordinates

arealreadyrelativetothescreen'sorigin,thereisnoneedto

translatethem.Nextcomesfourifstatementstodetermine

whetherthewindowisatleastpartiallyoffscreen.Thefirsttwo

handlethetopandlefthandsidesofthescreen.Iftheuser

movesthecomponentoffscreen,orevenmoveswithin

snap_distanceofthescreen'sedges,thismethodmovesthe

windowdirectlyto0.Thesecondtwoifshandlethebottomand

righthandsidesofthescreen,whichisessentiallythesameas

thefirsttwoexcepttheyhavetoaccountforthesizeofthe

windowaswell.Finally,thewindowismovedtothecorrect

location.

Youshouldalsotakenoteofthelockedvariable.Thisisusedto

avoidapotentialinfiniteloop.Essentially,thecomponentMoved()

methodwillbecalledeverytimethewindowmoves.The

componentMoved()methodwillalsocallsetLocation()onthe

window,whichwillthentriggeranothermoveevent.Left

unchecked,thesemethodswillbecalledoverandover,locking

thepaintthread,andcrashingyourprogramwithanout-ofmemoryerror.Itwouldbenicetolookattheeventandtellif

theusermovedthewindoworifthecodedid,buttheAPI

doesn'tprovidesuchafunction.Thesolution:detectrecursive

callsbyusingalockvariable.Iflockedisfalse,thenthisisareal

moveeventdonebytheuser,andit'sOKtodothesnapping.

Then,justbeforesetLocation()iscalled,thecodesetslockedto

TRue.IfcomponentMoved()iscalledagain,thecodeknowsthat

furthermovementshouldbeignored.AftersetLocation()



returns,lockedissetbacktofalse.

TotestouttheWindowSnapper,youhavetoadditasa

ComponentListenertoawindow:



publicstaticvoidmain(String[]args){

JFrameframe=newJFrame("Hack#33:Window

JLabellabel=newJLabel(

"Movethiswindow'stitlebartodemonstratescree

frame.getContentPane().add(label);

frame.pack();



frame.addComponentListener(newWindowSnapper());

frame.setVisible(true);

}



However,thishackhasonemajorflaw.Becausethecomponent

eventsareread-only,itisimpossibletointerceptthemoveand

positionthewindowbeforeithasbeendrawnonscreen.Thus

thewindowwillflashastheusermovesit.Creatingacustom

eventqueuewouldseemtobetheanswerbecauseyoucould

thenmodifytheeventsbeforetheyaresenttothecomponents,

butthiswon'tworkformoveeventsonwindows(orany

subclasslikeJFrame).Windowsarerealstructuresprovidedbythe

operatingsystem,ratherthanpurelyJavaobjects.Thewindow

eventsarecreatedbytheOSitselfandpassedintotheJVM

fromtheClevel,meaningthereisnowaytocapturethese

beforetheytakeeffect.Still,inmanyofyourapplications,the

flashingmaybeanacceptabletrade-offforsnapping.



Hack34.MakeaDraggableWindow



Dragawindowbyclickingonitsbackgroundusinga

specialeventlistener.

Mostwindowsletyoumovethembydraggingthetitlebar.

Someprogramwindows,however,don'thavetitlebars.Inthe

ageofeye-candyinterfaces(seeiTunesandWinAmpforprime

examples)itisverycommontohaveawindowpossiblynonrectangularwithoutanytitlebarorwindowcontrolsatall.This

makesforaprettywindow,buthowdoyoumoveit?Simplyby

dragginganyavailablespaceonthewindow.Thoughnot

terriblyintuitive,suchprogramsarecommonplace,andthis

bookwouldn'tbecalledSwingHackswithoutprovidingaJava

implementationofdraggablewindows,evenwhennotitlebaris

used.

Thesimplestapproachtothisproblemistocreatealistener

thatsimplycatchesalldragsandmovesthewindow:



publicclassMoveMouseListenerimplementsMouseList

{

JComponenttarget;

JFrameframe;

publicMoveMouseListener(JComponenttarget,JFr

this.target=target;

this.frame=frame;

}



publicvoidmouseClicked(MouseEvente){}

publicvoidmouseEntered(MouseEvente){}

publicvoidmouseExited(MouseEvente){}

publicvoidmousePressed(MouseEvente){}



publicvoidmouseReleased(MouseEvente){}

publicvoidmouseMoved(MouseEvente){}

publicvoidmouseDragged(MouseEvente){

frame.setLocation(newPoint(e.getX(),e.get

}

}



ThisclassimplementsMouseListenerandMouseMotionListenerwith

no-opsforallmethodsexceptmouseDragged(),whichmovesthe

frametothecurrentmouselocation.However,thisapproach

hastwoproblems.First,themousecoordinatesaregoingtobe

relativetothecomponent,ratherthanthescreen.Thus,aclick

ona50x50buttoninthebottomrightofthescreenmight

return(25,25)whenitshouldreallybemorelike(1000,700).

Theotherproblemisthatthecodemovestheoriginofthe

frametothemousecursor.Thiswouldlookstrangebecausethe

windowwouldimmediatelyjumpsothatitsupper-leftcorneris

rightunderthecursor.Theproperbehaviorisforthewindowto

stayinthesamepositionrelativetothecursorasthecursor

movesaround.

Thesolutiontothefirstproblem(gettingscreencoordinates

ratherthancomponentcoordinates)istoconvertmouse

coordinatestoabsolutescreencoordinates.Thefollowing

methoddoesjustthat(we'llusethisshortlyinmouseDragged()):



PointgetScreenLocation(MouseEvente){

Pointcursor=e.getPoint();

Pointtarget_location=this.target.getLocationOnS

returnnewPoint(



(int)(target_location.getX()+cursor.getX()),

(int)(target_location.getY()+cursor.getY()))

}



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

Chapter 5.  Windows, Dialogs, and Frames

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

×