java - Components disappear after resizing JPanel -


i trying create jpanel draggable crosses appear after mouse clicking. works fine when resize jpanel crosses disappear. tried override paintcomponent method in jpanel crosses @ coordinates (0,0). how can fix it?

import java.awt.*; import java.awt.event.mouseadapter; import java.awt.event.mouseevent; import java.awt.event.mouselistener; import java.awt.event.mousemotionadapter; import java.util.arraylist; import javax.swing.jcomponent; import javax.swing.jframe; import javax.swing.jpanel;  public class crosspanel extends jpanel implements mouselistener {  private int orderofcross = 0; private arraylist<cross> crosses; private int defaultsizeofcrosses = 10;  crosspanel() {     setopaque(false);     addmouselistener(this);     crosses = new arraylist<cross>(); }  @override public void mouseclicked(mouseevent e) {     int x = e.getx();     int y = e.gety();     cross cross = new cross(orderofcross++, defaultsizeofcrosses);     crosses.add(cross);     cross.setlocation(x - defaultsizeofcrosses, y - defaultsizeofcrosses);     add(cross);     repaint(); }  @override public void paintcomponent(graphics g) {     super.paintcomponent(g);     //        (int = 0; < crosses.size(); i++) {     //            crosses.get(i).paint(g);     //        } }  @override public void mousepressed(mouseevent e) {}  @override public void mousereleased(mouseevent e) {}  @override public void mouseentered(mouseevent e) {}  @override public void mouseexited(mouseevent e) {}  public static void main(string[] args) {     jframe f = new jframe();     f.setdefaultcloseoperation(jframe.exit_on_close);     crosspanel crosspane = new crosspanel();     f.getcontentpane().add(crosspane);     f.setsize(600, 500);     f.setlocation(200, 200);     f.setvisible(true); } }  class cross extends jcomponent {  private int order; protected cursor draggingcursor = cursor.getpredefinedcursor(cursor.hand_cursor); private volatile int draggedatx, draggedaty; int size;  public cross(int order, int size) {     this.order = order;     this.size = size;     this.setbounds(0, 0, 4 * size, 3 * size + 10);     adddraglisteners();     setcursor(draggingcursor); }  @override protected void paintcomponent(graphics g) {     super.paintcomponent(g);     graphics2d g2 = (graphics2d) g;     g2.setcolor(color.red);     g2.setstroke(new basicstroke(3));     g2.drawline(0, size, size + size, size);     g2.drawline(size, 0, size, size + size);     font f = new font("monospaced", font.bold, size + 10);     g2.setfont(f);     g2.drawstring(string.valueof(order), size - size / 2, 3 * size + 10); }  private void adddraglisteners() {     addmouselistener(new mouseadapter() {         @override         public void mousepressed(mouseevent e) {             draggedatx = e.getx();             draggedaty = e.gety();         }     });   addmousemotionlistener(new mousemotionadapter() {         @override         public void mousedragged(mouseevent e) {             point newlocation = new point(e.getx() - draggedatx + getlocation().x,  e.gety() - draggedaty + getlocation().y);             setlocation(newlocation);         }     }); } } 

i see use null layout, perceived benefits, there many draw backs.

the entire swing api has been designed around use of layout managers you'd crazy (imho) throw work away.

if find in position available layout managers don't seem want, might more worth while write own.

here, i've presented propertionallayoutmanager intention provide layout capabilities place components on container based percentage of width/height of parent component. means, parent component resized, child components reposition @ percentage of parent size.

enter image description hereenter image description here

import java.awt.basicstroke; import java.awt.color; import java.awt.component; import java.awt.container; import java.awt.cursor; import java.awt.dimension; import java.awt.font; import java.awt.fontmetrics; import java.awt.graphics; import java.awt.graphics2d; import java.awt.layoutmanager2; import java.awt.point; import java.awt.event.mouseadapter; import java.awt.event.mouseevent; import java.awt.event.mouselistener; import java.awt.event.mousemotionadapter; import java.text.numberformat; import java.util.arraylist; import java.util.hashmap; import java.util.map; import javax.swing.jcomponent; import javax.swing.jframe; import javax.swing.jpanel;  public class crosspanel extends jpanel implements mouselistener {      private int orderofcross = 0;     private arraylist<cross> crosses;     private int defaultsizeofcrosses = 10;      crosspanel() {         setopaque(false);         addmouselistener(this);         crosses = new arraylist<cross>();         setlayout(new propertionallayoutmanager());     }      @override     public void mouseclicked(mouseevent e) {         int x = e.getx();         int y = e.gety();         cross cross = new cross(orderofcross++, defaultsizeofcrosses);          float xpos = (float)x / (float)getwidth();         float ypos = (float)y / (float)getheight();          crosses.add(cross);          add(cross, new propertionalconstraints(xpos, ypos));         revalidate();     }      public static string format(float value) {         return numberformat.getnumberinstance().format(value);     }      @override     public void mousepressed(mouseevent e) {     }      @override     public void mousereleased(mouseevent e) {     }      @override     public void mouseentered(mouseevent e) {     }      @override     public void mouseexited(mouseevent e) {     }      public static void main(string[] args) {         jframe f = new jframe();         f.setdefaultcloseoperation(jframe.exit_on_close);         crosspanel crosspane = new crosspanel();         f.getcontentpane().add(crosspane);         f.setsize(600, 500);         f.setlocation(200, 200);         f.setvisible(true);     }      public class cross extends jcomponent {          private int order;         protected cursor draggingcursor = cursor.getpredefinedcursor(cursor.hand_cursor);         private volatile int draggedatx, draggedaty;         int size;          public cross(int order, int size) {             this.order = order;             this.size = size; //            this.setbounds(0, 0, 4 * size, 3 * size + 10);             adddraglisteners();             setcursor(draggingcursor);             font f = new font("monospaced", font.bold, size + 10);             setfont(f);          }          @override         public dimension getpreferredsize() {             // dangrous, making assumptions platforms             // have no eviednce support.             fontmetrics fm = getfontmetrics(getfont());             return new dimension(math.max(fm.stringwidth(string.valueof(order)), size), size + fm.getheight());         }          @override         protected void paintcomponent(graphics g) {             super.paintcomponent(g);             graphics2d g2 = (graphics2d) g;             g2.setcolor(color.red);             g2.setstroke(new basicstroke(3));              fontmetrics fm = g2.getfontmetrics();              int width = getwidth() - 1;             int height = getheight() - 1;              int x = (width - fm.stringwidth(string.valueof(order))) / 2;             int y = fm.getascent();             g2.drawstring(string.valueof(order), x, y);              int crosssize = math.min(width, height - fm.getheight());             x = (width - crosssize) / 2;             y = fm.getheight();             g2.drawline(x, y, x + crosssize, y + crosssize);             g2.drawline(x + crosssize, y, x, y + crosssize);         }          private void adddraglisteners() {             addmouselistener(new mouseadapter() {                 @override                 public void mousepressed(mouseevent e) {                     draggedatx = e.getx();                     draggedaty = e.gety();                 }              });             addmousemotionlistener(new mousemotionadapter() {                 @override                 public void mousedragged(mouseevent e) {                     point newlocation = new point(e.getx() - draggedatx + getlocation().x, e.gety() - draggedaty + getlocation().y);                     setlocation(newlocation);                 }              });         }      }      public class propertionalconstraints {          private float x;         private float y;          public propertionalconstraints(float x, float y) {             this.x = x;             this.y = y;         }          public float getx() {             return x;         }          public float gety() {             return y;         }          public void setx(float x) {             if (x > 1f) {                 x = 1f;             } else if (x < -0f) {                 x = 0f;             }             this.x = x;         }          public void sety(float y) {             if (y > 1f) {                 y = 1f;             } else if (y < -0f) {                 y = 0f;             }             this.y = y;         }      }      public class propertionallayoutmanager implements layoutmanager2 {          private map<component, propertionalconstraints> mapconstraints;          public propertionallayoutmanager() {             mapconstraints = new hashmap<>(25);         }          public propertionalconstraints getconstraintsfor(component comp) {             return mapconstraints.get(comp);         }          public void setconstraintsfor(component comp, propertionalconstraints pc) {             mapconstraints.put(comp, pc);         }          @override         public void addlayoutcomponent(component comp, object constraints) {             if (constraints instanceof propertionalconstraints) {                 mapconstraints.put(comp, (propertionalconstraints) constraints);             } else {                 throw new illegalargumentexception("constraints must propertionalconstraints");             }         }          @override         public dimension maximumlayoutsize(container target) {             return preferredlayoutsize(target);         }          @override         public float getlayoutalignmentx(container target) {             return 0.5f;         }          @override         public float getlayoutalignmenty(container target) {             return 0.5f;         }          @override         public void invalidatelayout(container target) {          }          @override         public void addlayoutcomponent(string name, component comp) {          }          @override         public void removelayoutcomponent(component comp) {             mapconstraints.remove(comp);         }          @override         public dimension preferredlayoutsize(container parent) {             return parent.getsize();         }          @override         public dimension minimumlayoutsize(container parent) {             return preferredlayoutsize(parent);         }          @override         public void layoutcontainer(container parent) {             int width = parent.getwidth();             int height = parent.getheight();             (component comp : parent.getcomponents()) {                 propertionalconstraints con = mapconstraints.get(comp);                 if (con != null) {                     int x = (int)(width * con.getx());                     int y = (int)(height * con.gety());                     comp.setsize(comp.getpreferredsize());                     comp.setlocation(x, y);                 } else {                     comp.setbounds(0, 0, 0, 0);                 }             }         }      }  } 

on side notes, using "magic" numbers determine size , rendering position of elements. bad idea. should, when painting or printing, base these values on empirical values.

in example, i've reverted using fontmertrics provide required information more accurately calculate size , positions of various elements. allow better cross platform support, not fonts rendered same across platforms ;)


Comments