java - Mapping mouse event coordinates -


i've implemented jlayer<jpanel> component paint zoomed graphics of itself, descending components zoomed too. jlayer applied contentpane jframe component.

the main problem zoom applies, indeed, graphic , actual size , position of components remain same. implies mouse events happen in wrong position respectively user see.

i've king of tweaked defining glasspane jcomponent @ top of frame has it's own mouseinputadapter redispatch mouseevents underlying components using swingutilities.getdeepestcomponentat(). accomplished creating new mouseevent mouse coordinates mapped depending on zoom value. (obtained modifying how use rootpanes tutorial)

this method not satisfying because lot of events can't fired (for example mouse_entered events fired descending components). on other hand using layerui.paint() override implies have have remap mouse coordinates.

  1. is there way map mouse coordinates without breaking inner mouseevent processing?

    or

  2. is there way zoom in bitmap of components while modifying real position , size? i've kind of tried calling setsize() of inner component seems someway call layerui.paint() second time bigger graphic disconnected actual widget position

this i've done far madprogrammer , pbar extensions, working jlayer in java 8.

the transformui include in pbar's org.pbjar.jxlayer.plaf.ext.mouseeventui , org.pbjar.jxlayer.plaf.ext.transformui:

package jzoom.transform;  import java.awt.awtevent; import java.awt.component; import java.awt.container; import java.awt.graphics; import java.awt.graphics2d; import java.awt.point; import java.awt.event.mouseevent; import java.awt.event.mousewheelevent; import java.awt.geom.affinetransform; import java.awt.geom.noninvertibletransformexception; import java.util.hashset; import java.util.set;  import javax.swing.jcomponent; import javax.swing.jlayer; import javax.swing.jpanel; import javax.swing.swingutilities; import javax.swing.plaf.layerui;  /**  *   * ui apply {@link affinetransform} visible objects, , apply inversion  *  of same transform mouse event's coordinates  *   * @author andrea.maracci based on pbjar jxlayer extension  *  */ public class transformui extends layerui<jcomponent> {     private static final long serialversionuid = 1l;      private component lastenteredtarget, lastpressedtarget;      private final set<jcomponent> originaldoublebuffered = new hashset<jcomponent>();     private affinetransform transform = new affinetransform();     private jlayer<jcomponent> installedlayer;     private boolean dispatchingmode = false;      /**      * process mouse events , map mouse coordinates inverting internal affine transformation.      *       * @param      * event event dispatched      * layer layer layerui set      *       */     @override     public void eventdispatched(awtevent event, final jlayer<? extends jcomponent> layer) {         if (event instanceof mouseevent) {             mouseevent mouseevent = (mouseevent) event;             /*              * if discriminate between generated , original event.              * removing cause stack overflow caused event being redispatched class.              */             if (!dispatchingmode) {                 // process original mouse event                 dispatchingmode = true;                 try {                     redispatchmouseevent(mouseevent, layer);                 } {                     dispatchingmode = false;                 }             } else {                 /*                  * process generated mouse events                  * added check, because on mouse entered or exited, cursor                  * may set specific dragging cursors.                  */                 if (mouseevent.mouse_entered == mouseevent.getid() || mouseevent.mouse_exited == mouseevent.getid()) {                     layer.getglasspane().setcursor(null);                 } else {                     component component = mouseevent.getcomponent();                     layer.getglasspane().setcursor(component.getcursor());                 }             }         } else {             super.eventdispatched(event, layer);         }         layer.repaint();     }      /**      * set affine transformation applied graphics      * @param transform transformation      */     public void settransform(affinetransform transform) {         if (transform != null) {             this.transform = transform;         }     }      /**      * return affine transformation applied graphics      * @return transformation      */     public affinetransform gettransform() {         return transform;     }      /**      * paint specified component {@code c} applying transformation on it's graphic      *       * @param      * g - graphics context in paint      * c - component being painted      */     @override     public void paint(graphics g, jcomponent c) {         if (g instanceof graphics2d) {             graphics2d g2 = (graphics2d) g.create();             jlayer<? extends jcomponent> l = (jlayer<? extends jcomponent>) c;             g2.transform(transform);             paintlayer(g2, l);             g2.dispose();         }     }      /**      * paint view decorated jlayer {@code layer} , jlayer      *       * @param g2      * @param layer layer layerui set      */     private final void paintlayer(graphics2d g2, jlayer<? extends jcomponent> layer) {         jcomponent view = layer.getview();         if (view != null) {             if (view.getx() < 0 || view.gety() < 0) {                 settonodoublebuffering(view);                 g2.translate(view.getx(), view.gety());                 view.paint(g2);                 (jcomponent jcomp : originaldoublebuffered) {                     jcomp.setdoublebuffered(true);                 }                 originaldoublebuffered.clear();                 return;             }         }         layer.paint(g2);     }      /**      * disable double buffering {@code component} , of it's children      *       * @param component      */     private void settonodoublebuffering(component component) {         if (component instanceof jcomponent) {             jcomponent jcomp = (jcomponent) component;             if (jcomp.isdoublebuffered()) {                 originaldoublebuffered.add(jcomp);                 jcomp.setdoublebuffered(false);             }         }         if (component instanceof container) {             container container = (container) component;             (int index = 0; index < container.getcomponentcount(); index++) {                 settonodoublebuffering(container.getcomponent(index));             }         }     }      /**      * {@inheritdoc}      */     @override     public void uninstallui(jcomponent component) {         if (!(component instanceof jlayer<?>)) {             throw new illegalargumentexception(                     this.getclass().getname() + " invalid class, must jlayer component");         }         jlayer<jcomponent> jlayer = (jlayer<jcomponent>) component;         jlayer.setlayereventmask(0);         super.uninstallui(component);     }      /**      * {@inheritdoc}      */     @override     public void installui(jcomponent component) throws illegalstateexception {         super.installui(component);         if (installedlayer != null) {             throw new illegalstateexception(this.getclass().getname() + " cannot shared between multiple layers");         }         if (!(component instanceof jlayer<?>)) {             throw new illegalargumentexception(                     this.getclass().getname() + " invalid class, must jlayer component");         }         // component.getclass().getdeclaringclass();         installedlayer = (jlayer<jcomponent>) component;         installedlayer.setlayereventmask(awtevent.mouse_event_mask | awtevent.mouse_motion_event_mask                 | awtevent.mouse_wheel_event_mask | awtevent.key_event_mask | awtevent.focus_event_mask);     }      /**      * process mouse events , map mouse coordinates inverting internal affine transformation.      * consume original event, calculates mapped mouse coordinates , find real target of mouse event.      * create new event correct informations in , redispatch target event      *       * @param originalevent event dispatched      * @param layer layer layerui set      */     private void redispatchmouseevent(mouseevent originalevent, jlayer<? extends jcomponent> layer) {         if (layer.getview() != null) {             if (originalevent.getcomponent() != layer.getglasspane()) {                 originalevent.consume();             }             mouseevent newevent = null;              point realpoint = calculatetargetpoint(layer, originalevent);             component realtarget = gettarget(layer, realpoint);              // component realtarget =             // swingutilities.getdeepestcomponentat(layer.getview(),             // realpoint.x, realpoint.y);              if (realtarget != null) {                 //system.out.println(realtarget.getclass().getname());                 realtarget = getlisteningcomponent(originalevent, realtarget);             }              switch (originalevent.getid()) {             case mouseevent.mouse_pressed:                 newevent = transformmouseevent(layer, originalevent, realtarget, realpoint);                 if (newevent != null) {                     lastpressedtarget = newevent.getcomponent();                 }                 break;             case mouseevent.mouse_released:                 newevent = transformmouseevent(layer, originalevent, lastpressedtarget, realpoint);                 lastpressedtarget = null;                 break;             case mouseevent.mouse_clicked:                 newevent = transformmouseevent(layer, originalevent, realtarget, realpoint);                 lastpressedtarget = null;                 break;             case mouseevent.mouse_moved:                 newevent = transformmouseevent(layer, originalevent, realtarget, realpoint);                 generateenterexitevents(layer, originalevent, realtarget, realpoint);                 break;             case mouseevent.mouse_entered:                 generateenterexitevents(layer, originalevent, realtarget, realpoint);                 break;             case mouseevent.mouse_exited:                 generateenterexitevents(layer, originalevent, realtarget, realpoint);                 break;             case mouseevent.mouse_dragged:                 newevent = transformmouseevent(layer, originalevent, lastpressedtarget, realpoint);                 generateenterexitevents(layer, originalevent, realtarget, realpoint);                 break;             case (mouseevent.mouse_wheel):                 // redispatchmousewheelevent((mousewheelevent) originalevent,                 // realtarget, realpoint);                 newevent = transformmousewheelevent(layer, (mousewheelevent) originalevent, realtarget, realpoint);                 break;/**/             }             dispatchmouseevent(newevent);         }     }      /**      * apply inverse transformation {@code point}      *       * @param layer layer layerui set      * @param point starting point      * @return transformed point      */     private point transformpoint(jlayer<? extends jcomponent> layer, point point) {         if (transform != null) {             try {                 transform.inversetransform(point, point);             } catch (noninvertibletransformexception e) {                 e.printstacktrace();             }         }         return point;     }      /**      * find deepest component in awt hierarchy      *       * @param layer  layer ui installed      * @param targetpoint point in layer's coordinates      * @return component in specified point      */     private component gettarget(jlayer<? extends jcomponent> layer, point targetpoint) {         component view = layer.getview();         if (view == null) {             return null;         } else {             point viewpoint = swingutilities.convertpoint(layer, targetpoint, view);             return swingutilities.getdeepestcomponentat(view, viewpoint.x, viewpoint.y);         }     }      /**      * convert {@code mouseevent}'s coordinates {@code layer}'s space      * @param layer layer layerui set      * @param mouseevent original mouse event      * @return {@code mouseevent}'s point transformed {@code layer}'s coordinate space      */     private point calculatetargetpoint(jlayer<? extends jcomponent> layer,             mouseevent mouseevent) {         point point = mouseevent.getpoint();         //swingutilities.convertpointtoscreen(point, mouseevent.getcomponent());         //swingutilities.convertpointfromscreen(point, layer);         point = swingutilities.convertpoint(mouseevent.getcomponent(), point, layer);         return transformpoint(layer, point);          }      private mouseevent transformmouseevent(jlayer<? extends jcomponent> layer, mouseevent mouseevent, component target, point realpoint) {         return transformmouseevent( layer, mouseevent, target, realpoint, mouseevent.getid());     }      /**      * create new event being dispatched      */     private mouseevent transformmouseevent(jlayer<? extends jcomponent> layer, mouseevent mouseevent, component target, point targetpoint, int id) {         if (target == null) {             return null;         } else {             point newpoint = swingutilities.convertpoint(layer, targetpoint, target);             return new mouseevent(target, //                     id, //                     mouseevent.getwhen(), //                     mouseevent.getmodifiers(), //                     newpoint.x, //                     newpoint.y, //                     mouseevent.getclickcount(), //                     mouseevent.ispopuptrigger(), //                     mouseevent.getbutton());         }     }      /**      * create new mouse wheel event being dispached      */     private mousewheelevent transformmousewheelevent( jlayer<? extends jcomponent> layer, mousewheelevent mousewheelevent, component target,             point targetpoint) {         if (target == null) {             return null;         } else {             point newpoint = swingutilities.convertpoint(layer, targetpoint, target);             return new mousewheelevent(target, //                     mousewheelevent.getid(), //                     mousewheelevent.getwhen(), //                     mousewheelevent.getmodifiers(), //                     newpoint.x, //                     newpoint.y, //                     mousewheelevent.getclickcount(), //                     mousewheelevent.ispopuptrigger(), //                     mousewheelevent.getscrolltype(), //                     mousewheelevent.getscrollamount(), //                     mousewheelevent.getwheelrotation() //             );         }     }      /**      * dispatch {@code mouseevent}      * @param mouseevent event dispatched      */     private void dispatchmouseevent(mouseevent mouseevent) {         if (mouseevent != null) {             component target = mouseevent.getcomponent();             target.dispatchevent(mouseevent);         }     }      /**      * listening component associated {@code component}'s {@code event}      */     private component getlisteningcomponent(mouseevent event, component component) {         switch (event.getid()) {         case (mouseevent.mouse_clicked):         case (mouseevent.mouse_entered):         case (mouseevent.mouse_exited):         case (mouseevent.mouse_pressed):         case (mouseevent.mouse_released):             return getmouselisteningcomponent(component);         case (mouseevent.mouse_dragged):         case (mouseevent.mouse_moved):             return getmousemotionlisteningcomponent(component);         case (mouseevent.mouse_wheel):             return getmousewheellisteningcomponent(component);         }         return null;     }      /**      * cycles through {@code component}'s parents find {@link component} associated {@link mouselistener}      */     private component getmouselisteningcomponent(component component) {         if (component.getmouselisteners().length > 0) {             return component;         } else {             container parent = component.getparent();             if (parent != null) {                 return getmouselisteningcomponent(parent);             } else {                 return null;             }         }     }      /**      * cycles through {@code component}'s parents find {@link component} associated {@link mousemotionlistener}      */     private component getmousemotionlisteningcomponent(component component) {         /*          * mouse motion events may result in mouse_entered , mouse_exited.          *           * therefore, components mouselisteners registered should          * returned well.          */         if (component.getmousemotionlisteners().length > 0 || component.getmouselisteners().length > 0) {             return component;         } else {             container parent = component.getparent();             if (parent != null) {                 return getmousemotionlisteningcomponent(parent);             } else {                 return null;             }         }     }      /**      * cycles through {@code component}'s parents find {@link component} associated {@link mousewheellistener}      */     private component getmousewheellisteningcomponent(component component) {         if (component.getmousewheellisteners().length > 0) {             return component;         } else {             container parent = component.getparent();             if (parent != null) {                 return getmousewheellisteningcomponent(parent);             } else {                 return null;             }         }     }      /**      * generate {@code mouse_entered} , {@code mouse_exited} event when target component changed      */     private void generateenterexitevents( jlayer<? extends jcomponent> layer,mouseevent originalevent, component newtarget, point realpoint) {         if (lastenteredtarget != newtarget) {             dispatchmouseevent(                     transformmouseevent(layer, originalevent, lastenteredtarget, realpoint, mouseevent.mouse_exited));             lastenteredtarget = newtarget;             //system.out.println("last " + lastenteredtarget.getclass().getname());             dispatchmouseevent(                     transformmouseevent(layer, originalevent, lastenteredtarget, realpoint, mouseevent.mouse_entered));         }     } } 

zoompanel jpanel include jlayer transformui in it. jlayer contains jpanel springlayout in constraints updated scale factor layout correctly components (jxlayer had it's own layoutmanager in jlayer can't set it)

package jzoom.transform;  import ...  public class zoompanel extends jpanel {      private static final long serialversionuid = 1l;      private affinetransform transform;     private transformui layerui;     private jlayer<jcomponent> layer;      private springlayout layout;     private jpanel springpanel;      private container view = null;      public zoompanel() {         this(null);     }      public zoompanel(container view) {          setlayout(new borderlayout());          this.view = view;         transform = new affinetransform();          layout = new springlayout();         springpanel = new jpanel(layout);         if (view != null) {             updateconstraints();             springpanel.add(view);         }          layerui = new transformui();         layerui.settransform(transform);         layer = new jlayer<jcomponent>(springpanel, layerui);          super.add(layer);      }      private void updateconstraints() {         spring width = layout.getconstraint(springlayout.width, springpanel);         spring height = layout.getconstraint(springlayout.height, springpanel);          springlayout.constraints constraints = layout.getconstraints(view);         constraints.setx(spring.constant(0));         constraints.sety(spring.constant(0));         constraints.setwidth(spring.scale(width, (float) (1 / transform.getscalex())));         constraints.setheight(spring.scale(height, (float) (1 / transform.getscalex())));     }      public void setview(container view) {         if (this.view != null) {             throw new illegalstateexception(                     this.getclass().getname() + " cannot shared between multiple containers");         }          if (view != null) {             this.view = view;             updateconstraints();             springpanel.add(view);         } else {             throw new illegalargumentexception("can't set null view");         }     }      public double getscale() {         return transform.getscalex();     }      public void zoomin() {         setscale(transform.getscalex() + 0.1);     }      public void zoomout() {         setscale(transform.getscalex() - 0.1);     }      public void setscale(double scale) {         if (!(scale < 1)) {             transform.settoidentity();             transform.scale(scale, scale);             updateconstraints();             springpanel.updateui();         }     }      protected component addtoview(component comp, object constraints, int index) {         if (view != null) {             view.add(comp, constraints, index);             return comp;         }          if (comp instanceof container) {             setview((container) comp);             return view;         }          throw new illegalstateexception("you need add or set container view before adding components");     }      @override     public component add(component comp) {         // todo auto-generated method stub         return addtoview(comp, null, this.getcomponentcount());     }      @override     public component add(component comp, int index) {         // todo auto-generated method stub         return addtoview(comp, null, index);     }      @override     public void add(component comp, object constraints) {         // todo auto-generated method stub         addtoview(comp, constraints, this.getcomponentcount());     }      @override     public void add(component comp, object constraints, int index) {         // todo auto-generated method stub         addtoview(comp, constraints, index);     }      private void inspectview(container view) {         printstream ps = null;         try {             ps = new printstream("c:\\users\\andrea.maracci\\documents\\sicrareflectiontemp.txt");             inspectview(view, 0, ps);         } catch (filenotfoundexception e) {             e.printstacktrace();         } {             if (ps != null) {                 ps.close();             }         }     }      private static void inspectview(component component, integer level, printstream ps) {         (integer = 0; < level; i++) {             ps.print("\t");         }         ps.print(level + ")");         ps.println("inspecting " + component.getclass().getname());          int accessiblecount = 0;         if (component.getaccessiblecontext() != null) {             accessiblecount = component.getaccessiblecontext().getaccessiblechildrencount();             if (accessiblecount > 0) {                 ps.println("*********************************************accessible context*********************************************");                 (int = 0; < accessiblecount; i++) {                     ps.println(i + ") " + component.getaccessiblecontext().getaccessiblechild(i).getclass().getname());                 }                 ps.println("************************************************************************************************************");             }         }          if (component instanceof jcomponent) {             jcomponent jcomponent = ((jcomponent)component);              if (jcomponent.getcomponentcount() > 0) {                 component[] children = jcomponent.getcomponents();                 (component child : children) {                     inspectview(child, ++level, ps);                 }             }         }         --level;     } } 

and here horrible test program

package jzoom.test;  import ...  public class testfinal {     public static void main(string[] args) {         new testfinal();     }      public testfinal() {         eventqueue.invokelater(new runnable() {             @override             public void run() {                  try {                     uimanager.setlookandfeel(uimanager.getsystemlookandfeelclassname());                 } catch (classnotfoundexception e) {                     // todo auto-generated catch block                     e.printstacktrace();                 } catch (instantiationexception e) {                     // todo auto-generated catch block                     e.printstacktrace();                 } catch (illegalaccessexception e) {                     // todo auto-generated catch block                     e.printstacktrace();                 } catch (unsupportedlookandfeelexception e) {                     // todo auto-generated catch block                     e.printstacktrace();                 }                  jframe frame = new jframe("testing");                 frame.setdefaultcloseoperation(jframe.exit_on_close);                 frame.setlayout(new borderlayout());                 frame.add(new testpane());                 frame.pack();                 frame.setminimumsize(new dimension(400,500));                 frame.setlocationrelativeto(null);                 frame.setvisible(true);             }         });     }      public class testpane extends jpanel {          private jlayer<jcomponent> layer;         private transformui layerui;         private jpanel content;         private affinetransform transform = new affinetransform();         private zoompanel zoompanel;          public testpane() {              content = new jpanel(new gridbaglayout());             // content = new jpanel(new xylayout());             gridbagconstraints gbc = new gridbagconstraints();             gbc.gridy = 0;             gbc.weighty = 0;             gbc.weightx = 0;             gbc.fill = gridbagconstraints.horizontal;             jlabel label = new jlabel("hello");             jtextfield field = new jtextfield("world", 20);              content.add(label, gbc);             gbc.weightx = 1;             content.add(field, gbc);             // content.add(label, new xyconstraints(50, 20, 50, 22));             // content.add(field, new xyconstraints(100, 20, 200, 22));              gbc.gridy++;             gbc.gridwidth = 2;              final jslider slider = new jslider(100, 200);             slider.setvalue(100);             slider.addchangelistener(new changelistener() {                  @override                 public void statechanged(changeevent e) {                     int value = slider.getvalue();                     double scale = value / 100d;                     zoompanel.setscale(scale);                 }             });             content.add(slider, gbc);             // content.add(slider, new xyconstraints(75, 50, 200, 50));              gbc.gridy++;             gbc.gridwidth = 2;             gbc.weighty = 1;             gbc.fill = gridbagconstraints.both;             jtextarea textarea = new jtextarea();             textarea.seteditable(true);             textarea.settext(                     "pollofritto\npalma\npalmipedone\ncaccoletta\namammata\na\nasd\nasdgfag\nasdafa\nasdfasf\nadsfasdf\nadfadsf\nadsfdasf\nasdfdas\npollofritto\npalma\npalmipedone\ncaccoletta\namammata\na\nasd\nasdgfag\nasdafa\nasdfasf\nadsfasdf\nadfadsf\nadsfdasf\nasdfdas");             // textarea.setpreferredsize(new dimensions());             jscrollpane scrollpane = new jscrollpane(textarea);             scrollpane.setverticalscrollbarpolicy(jscrollpane.vertical_scrollbar_always);             scrollpane.setpreferredsize(new dimension(200, 75));             content.add(scrollpane, gbc);              gbc.gridy++;             gbc.gridwidth = 2;             gbc.weighty = 0;             gbc.weightx = 1;             gbc.fill = gridbagconstraints.horizontal;             string[] petstrings = { "bird", "cat", "dog", "rabbit", "pig" };             jcombobox petlist = new jcombobox(petstrings);             content.add(petlist, gbc);              jbutton zoomin = new jbutton("zoom in");             // zoomin.addmouselistener(new zoommouselistener());             zoomin.addactionlistener(new actionlistener() {                 public void actionperformed(actionevent e) {                     // system.out.println("first");                     // layerui.zoomin();                      //double zoom = transform.getscalex();                     //transform.settoidentity();                     //transform.scale(zoom + 0.1, zoom + 0.1);                     zoompanel.zoomin();                      // jlayer.repaint();                 }             });              jbutton zoomout = new jbutton("zoom out");             zoomout.addactionlistener(new actionlistener() {                 public void actionperformed(actionevent e) {                     zoompanel.zoomout();                      //double zoom = transform.getscalex();                     //transform.settoidentity();                     //transform.scale(zoom - 0.1, zoom - 0.1);                     // jlayer.repaint();                 }             });             gbc.gridy++;             gbc.gridx = 0;             gbc.gridwidth = 0;             gbc.anchor = gridbagconstraints.line_end;              // content.add(zoomout, new xyconstraints(50, 120, 100, 25));             // content.add(zoomin, new xyconstraints(170, 120, 100, 25));              jpanel button = new jpanel();             button.setlayout(new boxlayout(button, boxlayout.line_axis));             button.add(zoomout);             button.add(zoomin);             gbc.fill = gridbagconstraints.none;             content.add(button, gbc);              setlayout(new borderlayout());             setborder(borderfactory.createemptyborder(10, 10, 10, 10));              zoompanel = new zoompanel();             zoompanel.setview(content);             add(zoompanel);         }     } } 

Comments

Popular posts from this blog

javascript - Clear button on addentry page doesn't work -

c# - Selenium Authentication Popup preventing driver close or quit -

tensorflow when input_data MNIST_data , zlib.error: Error -3 while decompressing: invalid block type -