Tải bản đầy đủ - 0 (trang)
Hack 96. Debug Components with a Custom Glass Pane

Hack 96. Debug Components with a Custom Glass Pane

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

Example12-17.Ascreenfortheglasspane































publicclassComponentGlassPaneextendsJComponent{

publicstaticvoidmain(String[]args){



JFrameframe=newJFrame("ComponentBoundaryG



Containerroot=frame.getContentPane();



root.setLayout(newBoxLayout(root,BoxLayout.Y_A



finalJButtonactivate=





newJButton("Showcomponentboundaries"



root.add(activate);



root.add(newJLabel("JuiceSettings"));



JPanelpanel=newJPanel();



panel.setLayout(newBoxLayout(panel,BoxLayout.X



panel.add(newJLabel("Flavor"));



panel.add(newJTextField(""));



root.add(panel);















frame.pack();

frame.show();















































}



finalComponentGlassPaneglass=



newComponentGlassPane(frame);

frame.setGlassPane(glass);



activate.addActionListener(newActionListener()



publicvoidactionPerformed(ActionEvent





glass.setVisible(true);



}

});



Thismain()methodcreatesaframewithafewcomponentsand

onenestedpanel(calledpanel).TheComponentGlassPaneisdeclared



asasubclassofJComponentsoitcanbepassedtothe

setGlassPane()methodontheframe.Theglasspaneisnotvisible

initially,whichproducesthesamebehaviorasifitwasn'teven

there.Theactivatebuttonisusedtomaketheglasspane

visible.

ThenextstepistocreatetheComponentGlassPaneconstructor:







































privateJFrameframe;

privatePointcursor;

publicComponentGlassPane(JFrameframe){



this.frame=frame;



cursor=newPoint();



this.addMouseMotionListener(newMouseMotionAdap





publicvoidmouseMoved(MouseEventevt)







cursor=newPoint(evt.getPoint







ComponentGlassPane.this.repaint











}



});



this.addMouseListener(newMouseAdapter(){





publicvoidmouseClicked(MouseEventevt







ComponentGlassPane.this.setVisi





}



});

}



Thismethodsavestheparentframethatwaspassedin,andit

createsanewpointtostorethecursorcoordinates.Thenit

addstwomouselistenerstoitself.Thefirstlistenercopiesthe

currentmousecoordinatesintothecursorobjecteverytimethe

mousemoves.Italsorequestsarepaint,sincetheusermay

havemovedfromonecomponenttoanother,whichwould

changethecurrentlyvisiblelabel.



Thesecondmouselistenersimplywaitsformouseclicks.Ifthe

userclicksthemouse,thenthislistenerturnsoffthe

visualizationeffectbyhidingtheglasspane,andthescreen

goesbacktonormal.

Sofarthishasallbeenprettystraightforward:createacustom

JComponentandsetitastheglasspaneonaJFrame.Nowcomes

thetrickypart:paintingthetranslucentrectanglesandlabels.

First,youneedtooverridethepaint()methodtoretrievethe

rootcomponentoftheframeandpassittotherPaint()method:











publicvoidpaint(Graphicsg){



Containerroot=frame.getContentPane();



rPaint(root,g);

}



rPaint()standsforrecursivepaint.Itneedstorecurseoverthe



entirecomponenttree,paintingarectangleateachstepand

possiblydrawingthelabel.Becausethisissocomplicated,I'll

takeitinstages.Hereistheinitialportionofthemethod:













privatevoidrPaint(Componentcomp,Graphicsg){



intx=comp.getX();



inty=comp.getY();



g.translate(x,y);



cursor.translate(-x,-y);



































intw=comp.getWidth();

inth=comp.getHeight();

//drawbackground

g.setColor(newColor(1.0f,0.5f,0.5f,0.3f));

g.fillRect(0,0,w,h);

g.setColor(Color.red);

g.drawRect(0,0,w,h);



First,therPaint()methodgetsthex-andy-coordinatesofthe

componentandtranslatestheGraphicsobjectandthecursor.

Thegraphicsmustbetranslatedsothatalldrawingwillhappen

relativetotheoriginofthecurrentcomponent.Ifthisweren't

called,thenalloftherectangleswouldbeshovedintothe

upper-lefthandcorneroftheframe.Thecursorisalso

translated,butintheoppositedirection.Thisisbecauseeach

component'soriginmustbesubtractedfromthecursorposition

tomakeitrelativetothecomponent.

Thistranslationofcoordinatesisthekeytoanyrecursivetree

traversal.Withthistechnique,youcanstartatthetopofthe

treeanddoanysortofoperationyouwanttoeachcomponent,

safeintheknowledgethatanydrawingoperationswilllineup

properly.

Aftercoordinateconversion,rPaint()grabsthewidthandheight

ofthecurrentcomponentandthensetsthedrawingcolor.Note

thatthisdrawingcoloriscomposedoffournumbers.Thefirst

threerepresentthevaluesofeachcolorcomponent(red,green,

andblue)from0to1,where1represents100%ofthat

componentand0represents0%.Thevalues1.0f,0.5f,and0.5f

produceamediumpink.



Thefaftereachnumbertellsthecompilerthatthisisafloatingpoint

number.Youcouldwrite(float)1.0togetthesameeffect.



Thelastnumberrepresentsthealphachannel,ortransparency,

goingfrom1foropaqueto0forcompletelytransparent:







//ifthemouseisoverthiscomponent

if(comp.contains(cursor)){







































//drawthetext

Stringcls_name=comp.getClass().getName();

Graphics2Dg2=(Graphics2D)g;

Fontfnt=g.getFont();

FontMetricsfm=g.getFontMetrics();

inttext_width=fm.stringWidth(cls_name);

inttext_height=fm.getHeight();

inttext_ascent=fm.getAscent();







































}



//drawtextbackground

g.setColor(newColor(1f,1f,1f,0.7f));

g.fillRect(0,0,text_width,text_height);

g.setColor(Color.white);

g.drawRect(0,0,text_width,text_height);

//drawtext

g.setColor(Color.black);

g.drawString(cls_name,0,0+text_ascent);



Nowthatthepinkrectangleisfilledin,theglasspaneneedsto

drawthenameofthecurrentcomponentbutonlyifthemouse

isoverthatcomponent.Thatiswhatthecomp.contains(cursor)line

does.Ifcontains()istrue,thenrPaint()calculatesthe

dimensionsoftheclassnameasastring,drawsatranslucent

whitebackground(with70%opacity),drawsasolidwhite

borderrectangle,andthenfinallydrawstheactualtextinsolid

black:

















if(compinstanceofContainer){



Containercont=(Container)comp;



for(inti=0;i




Componentchild=cont.getComponent(i);





rPaint(child,g);



}

}



Nextcomestherecursion.Withoutthisstep,rPaint()wouldjust

workontherootcomponentandstop.Hereitchecksifthe

currentcomponentisajava.awt.Container(whichwouldalwaysbe

trueforanySwingcomponentsincejavax.swing.JComponent

subclassesContainer).Ifthecomponenthaschildren,itcalls

rPaint()recursivelyoneachchild,thustraversingtheentire

treeofcomponents:











cursor.translate(x,y);



g.translate(-x,-y);

}//endrPaint()method



Thislaststepsimplyreversesthegraphicstranslationfromthe

beginningofrPaint().Hadthecoordinatesbeenpassedinas

ints,whicharepassed-by-value,itwouldnotbenecessaryto

undothetranslations.Anychangestoapassed-by-value

variablearelostwhentheenclosingmethodends.However,

sincecursorandgarebothreferencedbyname,thechanges

havetobereversedmanually.

Ifyoucompileandrunthiscode,youwillgetascreenthat

lookslikeFigure12-11.Whenyoupresstheactivatebutton,

youwillseeFigure12-12.Asyoumovethemousearound,the

classnamelabelwillupdate.



Figure12-11.Thenormalwindow



Figure12-12.Thewindowwiththeglasspane

showing



Thishackperformsasimplevisualization:itcreatestranslucent

rectangleswithsolidlabels.Thesametechniquecouldbeused

tocreateamuchmoredynamicinterfacedisplayingmore

detailedinformation,suchasbuttonstate,componentIDs,

colorsettings,oranyotherartifactofSwingcomponents.

Onethingtonoticehereisthattherearetwoormorelabels

visibleatanygiventime.Thisisbecauseofthenestingof

componentsifthecursorisoveratextfieldandthattextfieldis

insideofapanel,thentechnicallythecursorisoverboth

components,producingtwolabels.Youcouldenhancethe

ComponentGlassPanetoonlydrawonelabelbycreativeuseofthe

SwingUtilities.getDeepestComponentAt()method.



Hack97.MirroranApplication



WithcreativeuseoftheAWTeventlog,youcanbindtwo

instancesofanapplicationtogetheroverasocket,

creatingamirroringeffect.

OneofthecoolestandseverelyunderratedfeaturesofJavais

serialization.BecauseJavacoderunsentirelyinavirtual

machine,it'spossibletosendobjectsoverthenetworkto

anotherprogramandhavetheobjectsstillfunctionalwhenthey

getthere.OnedaywhileperusingtheAWTdocumentation,I

cameacrosstheAWTEventListener.Iwonderedwhatinteresting

thingyoucoulddobycapturingalloftheeventsinaprogram.I

couldwritethemtodisk,ofcourse,butitwouldbeevencooler

tosendthemoverthenetworktoanothercopyoftheprogram.

Thatwaythetwoprogramscouldreuseeachother'seventsand

becomemirrors!Withaglobaleventqueueandabitof

serialization,thisturnsouttobequiteeasy.

Toreplicateeventsoverthenetwork,youneedtodothree

things:

1. CaptureallAWTevents.Thiscanbedonewithan

AWTEventListener.

2. Sendtheeventobjectsoverthenetwork.

3. Picktheobjectsupontheotherendofthenetworkand

reposttheminthesecondprogram.

Itsoundsprettysimple,buttherearealwaysafewdragons

hidinginthemist.



12.11.1.SetUpaWindow

Everytestprogrambeginswithaframeandafewcomponents.

Thisprogramisnodifferent,withApplicationMirrorTest(shownin

Example12-18)creatingaframe,button,andtextfieldinits

constructor.



Example12-18.Simpletestprogramformirroring











publicclassApplicationMirrorTest{



publicApplicationMirrorTest(){





JFrameframe=newJFrame();





frame.getContentPane().setLayout(newFl





















finalJButtonbutton=newJButton("act

frame.getContentPane().add(button);



































}



JTextFieldtf=newJTextField("textfi

frame.getContentPane().add(tf);

frame.pack();

frame.show();



12.11.2.BecomeaServerorClient

Thereisonlyoneprogram,butitmustrunintwomodes:one

forsendingAWTeventsandoneforreceiving.Iftheprogram

startsandit'sthefirstinstancerunning,thenitshouldwaitto

receiveevents.Ifit'sthesecondinstancerunning,thenit

shouldsendeventsinstead.Buthowdoestheprogramknowif

itisthefirstorsecondinstance?Theonlyrealwayistolookfor



asharedresource.Iftheresourceisalreadytaken,thenthis

mustbethesecondinstance.Aswithcreatingsingle-launch

applicationsonWindows[Hack#84],anetworksocketisthe

bestchoiceforasharedresourcebecauseyouneeditanyway

tosendtheevents:



























}



publicvoidstart(){



try{



//sendevents



finalSocketsock=newSocket("localhost",6754



openSender(sock);



}catch(Exceptionex){



try{





openReceiver();



}catch(Exceptionex2){





System.out.println("exception:"+ex);



}

}



Thestart()methodheretriestoopenasocketonaknownport

number(6754inthiscase).Ifthesocketcanbeopened,then

thatmeansthereisaprogramontheotherendwaitingfora

connection,inwhichcasethecodecancallopenSender()tostart

sendingevents.Ifthesocketcannotbeopened,thenthereis

nootherprogramandthisisthefirstrunninginstance.Inthat

case,youcancallopenReceiver()andstartwaitingforanother

programtoconnect.



12.11.3.SendMouseEvents

Tosendevents,youfirstneedanoutputstreamtosendthem.

Thejava.iopackagehelpfullyprovidestheObjectOutputStream.It



willtakeanyJavaobject,serializeit,andwriteittothestream

theclassrepresents.Next,youneedtocaptureallrelevant

eventsandpreparethemtogoout.TheAWTToolkitobjectlets

youaddlistenersforanysetofAWTeventsyouwish.Youjust

needtoORtogethermasksfortheeventtypesyouwant:









publicvoidopenSender(Socketsock)throwsException{



finalObjectOutputStreamout=new





ObjectOutputStream(sock.getOutputStream























Toolkit.getDefaultToolkit().addAWTEventListener



newAWTEventListener(){





publicvoideventDispatched(AWT





try{































































},



















}







);



AWTEvent.ACTION_EVENT_MASK|

AWTEvent.MOUSE_EVENT_MASK



if(evtinstanceofMouseEvent){

MouseEventme=(MouseEvent)evt

out.writeObject(evt);

}

}catch(Exceptionex){}

}



First,openSender()createsanewObjectOutputStreamaroundthe

socket'soutputstream.Next,itcreatesanewAWTEventListener

thattakeseacheventandtestsifitisamouseevent;ifso,this

methodwritesittotheoutputstream.Noticethatthesecond

argumentofaddAWTEventListener()istwoeventmasksORed

together(usingthe|operator).



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

Hack 96. Debug Components with a Custom Glass Pane

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

×