Tải bản đầy đủ - 0 (trang)
Hack 56. Create a Magnifying Glass Component

Hack 56. Create a Magnifying Glass Component

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

todoistohaveaMouseMotionListener,sothatitwillgetupdates

onthecursor'spositionand,whenitchanges,doanewgrab

andrepaint().

TheDetachedMagnifyingGlasscodeisshowninExample8-1.



Example8-1.JComponenttoprovideamagnified

viewofanotherJComponent

publicclassDetachedMagnifyingGlassextendsJComponent



implementsMouseMotionListener{





doublezoom;



JComponentcomp;



Pointpoint;



DimensionmySize;



Robotrobot;









publicDetachedMagnifyingGlass(JComponentcomp,











Dimensionsize,











doublezoom){











































this.comp=comp;

//flagtosaydon'tdrawuntilwegetaMouseM

point=newPoint(-1,-1);

comp.addMouseMotionListener(this);

this.mySize=size;

this.zoom=zoom;

//ifwecan'tgetarobot,thenwejustnever

//paintanything

try{



robot=newRobot();





}catch(AWTExceptionawte){







System.err.println("Can'tgetaRobot"







awte.printStackTrace();











}



}





























publicvoidpaint(Graphicsg){



if((robot==null)||(point.x==-1))



{





g.setColor(Color.blue);





g.fillRect(0,0,mySize.width,mySize.





return;



}



RectanglegrabRect=computeGrabRect();



BufferedImagegrabImg=robot.createScreenCaptu



ImagescaleImg=





grabImg.getScaledInstance(mySize.width











Image.SCALE_

















































}



















publicDimensiongetPreferredSize(){returnmy

publicDimensiongetMinimumSize(){returnmySi

publicDimensiongetMaximumSize(){returnmySi































//MouseMotionListenerimplementations

publicvoidmouseMoved(MouseEvente){



PointoffsetPoint=comp.getLocationOnS



e.translatePoint(offsetPoint.x,offset



point=e.getPoint();



repaint();



g.drawImage(scaleImg,0,0,null);



privateRectanglecomputeGrabRect(){



//width,heightaresizeofthiscomp



intgrabWidth=(int)((double)mySize.



intgrabHeight=(int)((double)mySize



//upper-leftcorneriscurrentpoint



returnnewRectangle(point.x,point.y,

}























}



}

publicvoidmouseDragged(MouseEvente){



mouseMoved(e);

}



Lookingatthecode,theconstructortakesthesource

component,asizeforthemagnifiedcomponent,andazoom

level.Itassignsthesetoitsinstancevariables,andsetsupa

MouseMotionListenertogetupdatesregardingthecursorposition,

whichisinitializedtoa"don'tpaintme"dummyvalueof(-1,

-1).ItalsobuildstheAWTRobot.Sincethiscanfailonsome

OSesorundercertainsecuritysituations,therobot==nullcase

willhavetobehandledgracefullyinthepaintingroutine.

Thepaint()methodbeginsbycheckingforthetwoconditions

thatindicatethemangnifiedcomponentcan'tbepainted:if

there'snoRobotorifthecursorhasneverenteredthesource

component.Ineitherofthesecases,themagnifiedcomponent

simplyfillsitselfwithblueandreturns.

Ontheotherhand,ifvaliddataisavailable,themagnifier

needstofigureoutwhatportionofthesourcecomponentto

grab.Forsimplicity,youcancomputearectanglewhoseupper

leftisthecurrentcursorlocation.Thewidthandheightofthe

rectanglearecomputedbymultiplyingthezoomfactorbythe

magnifyingcomponent'sheightandwidth.So,forazoomof

1.0,thegrabisexactlythesizeofthemagnifier.Forazoomof

0.5,itgrabshalfthewidthandhalftheheight,andfor2.0,it

grabstwicethewidthandheight.

Withagrabrectanglecalculated,callRobot.createScreenCapture()to

grabthosepixelsandreturnthemasaBufferedImage.Unlessyour

zoomfactoris1.0;,thisimagewillbelargerorsmallerthanthe

DetachedMagnifyingGlasscomponent,soyouneedtouse



getScaledInstance()toscaleittoyourcomponentsize.Intermsof



ascalingbehavior,thecodeusestheSCALE_FASTconstant

becausethemovingmousewillbecallingformanyrepaints,

andthusmanygrabsandscales,everysecond.Finally,with

yourproperlysizedimageinmemory,youpainttotheGraphics

togetthegrabbeddataintoyourcomponent.



OneTODOitemIhaven'tshownhere,butthatmightprovidea

performanceboost,wouldbetoflush()thevarioustemporaryimages

afteryou'vecalleddrawImage().



ToensuretheAWTLayoutManagersrespectthesizethat'ssetfor

thecomponent,havegetPreferredSize(),getMinimumSize(),and

getMaximumSize()allreturnthesizethatwasoriginallysenttothe

constructor,sincethesizeofthemagnifiercomponentiscritical

incomputingwhattograbfromthesourcecomponent.

ThelastbitofcodeinthisclassisaMouseMotionListner,whichis

usedtotrackthemouse'slocation.Youneedtodothissoyou'll

alwayshaveanup-to-datepointwhenthepaint()methodis

called.You'llonlygeteventswhenthecursorisoverthesource

component,andit'seasyenoughtocachethepointinthe

MouseEvent,butthere'sacatch:thatpointisrelevanttothe

coordinatesystemofthesourcecomponent,notthescreen,so

unlessthecomponentisattheupper-leftcornerofthescreen,

youwillbegrabbingthewrongpixelsinpaint().Thefixisto

translatethepointfromthesourcecomponent'scoordinate

systemtothescreen'scoordinatesystem.Dothisbygetting

thecomponent'sonscreenlocationwithgetLocationOnScreen(),and

thentranslatethePointwithMouseEvent.translate().



8.2.2.TestingtheMagnifierOut



TotakeDetachedMagnifyingGlassoutforaspin,Example8-2shows

aTestDetachedMagnifyingGlassclass,whichopensanimageina

JFrameandsetsaDetachedMagnifyingGlassnexttoit.



Example8-2.Testingthe

MagnifyingGlassComponent

publicclassTestDetachedMagnifyingGlassextendsObject{





publicTestDetachedMagnifyingGlass(Filef){





//imageframe





ImageIconi=newImageIcon(f.getPath());





JLabell=newJLabel(i);







JFrameimgFrame=newJFrame("Image");





imgFrame.getContentPane().add(l);





imgFrame.pack();





imgFrame.setVisible(true);





//magnifyingglassframe





JFramemagFrame=newJFrame("Mag");





DetachedMagnifyingGlassmag=







newDetachedMagnifyingGlass(l,newDim



magFrame.getContentPane().add(mag);







magFrame.pack();magFrame.setLocation(

imgFrame.getLocation().x+imgFrame.getWidth(),

imgFrame.getLocation().y));







magFrame.setVisible(true);







}













publicstaticvoidmain(String[]args)









JFileChooserchooser=newJFil









chooser.showOpenDialog(null);









Filef=chooser.getSelectedFil









newTestDetachedMagnifyingGlass







}





}



ThisclasssimplybringsupaJFileChoosertopickanimagefile,

whichitloadsintoanImageIconandthenintoaJLabel.Itthen

createsaDetachedMagnifyingGlassfromtheJLabel,withasizeof

150x150andamagnificationfactorof2.0,andmovesittothe

immediaterightofthesourcecomponent.

Figure8-1showswhatthetestlookslikewhenrun.



Figure8-1.UseoftheDetachedMagnifyingGlass



8.2.3.HackingtheHack

TheonlyproblemwiththeRobotapproachisthatitdoesn't

limititselftocapturingfromthesourcecomponentit'lltakeany

onscreenpixelsfromanyapplication.Thatmeansthatwhen

youapproachtheedgesofthesourcecomponent,youcanpick

uppixelsfromthedesktoporotherapps,asseeninFigure8-2.



Figure8-2.Capturingpixelsoutsideofthetarget

component



Isthisaproblem?Someuserswillmindit,somewon't.Toget

ridofit,you'llneedtosmartenupcomputeGrabRect()toboundscheckitsrightandbottomedges(thetopleftisthecursor

position,soitcanneverovershootthetoporleftofthe

component)byaddingtheuntranslatedpointtotheproposed

grabwidthandseeingifthatisgreaterthanthewidthofthe

sourcecomponent,andthendoingthesamefortheheight.

Thiswilltakesomerefactoring,sincecomputeGrabRect()doesn't

haveaccesstotheuntranslatedpoint.Also,ifyou'renot

necessarilygoingtobepaintingtheentiremagnifiedcomponent

everytime,you'llhavetoeraseitatthetopofpaint(),soyou

don'thave"crud"fromthepreviousrepaintleftoverafterthis

repaint.



Hack57.CreateaGlobalRight-Click



Giveyourapplicationaright-clickcontextmenuwithout

havingtoaddalistenertoeverycomponent.

Oftentimes,anapplicationneedstohaveapop-upmenuthatis

accessiblefrommorethanonecomponent.Sometimesthe

entirewindowshouldberight-clickable.Unfortunately,doing

thisthenormalwayinSwingwouldrequireaddingamouse

listenertoeverycomponentinthewindow,whichisn'tavery

appealingsolution,especiallyifyourUIcodeisspreadacross

manyclasses.Itwouldbemuchniceriftherewereasingle

placetoaddthecontextmenu.Thishackshowshowtousea

singleglasspanetoprovidearight-clickablemenutotheentire

application.

AglasspaneisaninvisibleJComponentthatcoversanentire

JFrame.Theglasspanecanbeusedtocatcheventsordrawon

topoftherestoftheapplication.Forthishack,wewillusea

glasspanetocaptureright-clickeventsandtriggerapopup,

alleviatingtheneedtoregisteramouselistenerwithevery

componentintheframe.Thebasicideaisfortheglasspaneto

interceptallmouseeventsandforwardthemontothe

application,exceptfortheright-click.Right-clickswilltrigger

thepop-upmenuinstead.Thiswaythereisonlyonelistener

perframe,insteadofpotentiallyhundreds.

Tostartoff,youneedacomponentthathasareferencetothe

contentpaneoftheframeandapre-builtpop-upmenu.Thisis

thebeginningofjustsuchaclass:

publicclassRightClickGlassPaneextendsJComponent



implementsMouseListener,MouseMotionListener{







privateJPopupMenupopup;



privateContainercontentPane;



publicRightClickGlassPane(ContainercontentPane,JPopupMenume



addMouseListener(this);



addMouseMotionListener(this);



this.contentPane=contentPane;



popup=menu;

}

publicvoidpaint(Graphicsg){

}

//catchallmouseeventsandredispatchthem

publicvoidmouseMoved(MouseEvente){



redispatchMouseEvent(e,false);

}

publicvoidmouseDragged(MouseEvente){



redispatchMouseEvent(e,false);

}

publicvoidmouseClicked(MouseEvente){



redispatchMouseEvent(e,false);

}

publicvoidmouseEntered(MouseEvente){



redispatchMouseEvent(e,false);

}

publicvoidmouseExited(MouseEvente){



redispatchMouseEvent(e,false);

}

publicvoidmousePressed(MouseEvente){



redispatchMouseEvent(e,false);

}

publicvoidmouseReleased(MouseEvente){



redispatchMouseEvent(e,false);

}



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

Hack 56. Create a Magnifying Glass Component

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

×