java - Mystery (concurrency/component drawing?) bug in very simple Swing dice program -


sorry poor question title, i'm stumped cause of bug , didn't know how phrase question.

i'm learning basic swing , doing this exercise online book introduction programming java.

i haven't followed instructions letter , instead trying this:

  • have window shows visual representation of 2 dice
  • when click on 1 of dice, 'rolls' , shows new value

my implementation:

  • a basic jdie object extends jpanel
  • overridden paintcomponent method draw die representation
  • change die color every time value changed visual clue
  • added listener 'roll' dice when mouse pressed , then
    repaint

the bug quite specific:

  1. run dietest main method
  2. resize window fit 2 die
  3. click on second die roll it
  4. now click on first die roll it
  5. the second die's value changes original value
  6. if resize window second die's value change back

if click on dice roll them, before resize window, bug won't appear...

i guess i'm making basic mistake somewhere has disguised strange behaviour.

i've tried whittle down code as could, took ages working out when bug appeared , when didn't:

import java.awt.*; import java.awt.event.*; import javax.swing.*;  class jdie extends jpanel {      private color color;     private int value;      jdie(){          value = getvalue();         color = color.black;          //add listener         addmouselistener(new mouseadapter(){             @override             public void mousepressed(mouseevent arg0) {                 value = getvalue(); //'roll' die                 repaint();             }         });     }      /*private helper methods */     private int getvalue(){         int v =(int)(math.random()*6) + 1;         //change color show         //value has changed         color = getrandomcolor();         return v;     }     private color getrandomcolor(){         float r = (float)math.random();         float g = (float)math.random();         float b = (float)math.random();         return new color(r, g, b);     }      //draws pips die     @override     public void paintcomponent(graphics g){         super.paintcomponent(g);         g.setcolor(color);           //draw pips         //set pip size         int pip_side = 10;         switch(value){         case 1:             g.fillrect(3*pip_side, 3*pip_side, pip_side, pip_side);             break;         case 2:             g.fillrect(5*pip_side, pip_side, pip_side, pip_side);             g.fillrect(pip_side, 5*pip_side, pip_side, pip_side);             break;         case 3:             g.fillrect(5*pip_side, pip_side, pip_side, pip_side);             g.fillrect(pip_side, 5*pip_side, pip_side, pip_side);             g.fillrect(3*pip_side, 3*pip_side, pip_side, pip_side);             break;         case 4:             g.fillrect(pip_side, pip_side, pip_side, pip_side);             g.fillrect(5*pip_side, 5*pip_side, pip_side, pip_side);             g.fillrect(5*pip_side, pip_side, pip_side, pip_side);             g.fillrect(pip_side, 5*pip_side, pip_side, pip_side);             break;         case 5:             g.fillrect(pip_side, pip_side, pip_side, pip_side);             g.fillrect(5*pip_side, 5*pip_side, pip_side, pip_side);             g.fillrect(5*pip_side, pip_side, pip_side, pip_side);             g.fillrect(pip_side, 5*pip_side, pip_side, pip_side);             g.fillrect(3*pip_side, 3*pip_side, pip_side, pip_side);             break;         case 6:             g.fillrect(pip_side, pip_side, pip_side, pip_side);             g.fillrect(5*pip_side, 5*pip_side, pip_side, pip_side);             g.fillrect(5*pip_side, pip_side, pip_side, pip_side);             g.fillrect(pip_side, 5*pip_side, pip_side, pip_side);             g.fillrect(pip_side, 3*pip_side, pip_side, pip_side);             g.fillrect(5*pip_side, 3*pip_side, pip_side, pip_side);             break;         }     } }  public class dietest extends jframe{      dietest(){         setlayout(new gridlayout());         add(new jdie());         add(new jdie());          setdefaultcloseoperation(jframe.exit_on_close);          //if set size smaller jdie displaying         //and resize window before 'rolling' dice         //then bug appears...?!         setsize(80, 80);         //setting size larger both jdie         //and works fine whether resize or not //      setsize(200, 200);          setvisible(true);      }      public static void main(string[] args) {         swingutilities.invokelater(new runnable(){              @override             public void run() {                 new dietest();             }          });     }  } 

--------------edit-----------------

running code again, i've noticed doesn't happen 100% of time, bug still there. here's gif took of bugging might illustrate problem better:

strange bug

you can see original value original color being redrawn when click first die again. when resize window, second die's value jumps one, previous value had... don't understand this...

---------------edit 2---------------------

  • tried same code on computer (mac) couldn't replicate problem.
  • compiled , ran code on computer outside of eclipse, couldn't replicate problem.
  • ran code eclipse had compiled command line, got problem once, couldn't replicate today.
  • running code eclipse, still problem 1 in 5-10 times? if doesn't show on first 'pass' were, doesn't show @ all. gif illustrates well.

so seems computer set has bearing on well, details are:

  • windows 7 64 bit
  • eclipse kepler service release 1
  • java version 7 update 51
  • java se development kit 7 update 3 (64 bit)

this tricky 1 know longer know whether it's code or other program's causing problem. newb how can know whether future problems result of bad programming or else... frustrating.

----------edit 3-----------

as quick investigation concurrency side of things: set instance fields volatile set methods including paintcomponent synchronized removed math.random() call (although read thread saying thread safe implementation) , replaced instance random objects instead

unfortunately still visual switchback.

another thing i've noticed seems happening lot less 1 in 10 times. keep on getting hopes it's fixed, , next attempt bugs again. in original program working on, seemed more 1 in 3 (i've changed program don't have hand).

--------edit 4--------- have come more stripped down version no longer uses random values , still produces visual switchback. seems happen more code:

import java.awt.*; import java.awt.event.*; import javax.swing.*;  public class colorpanelswindow extends jframe{      class colorpanel extends jpanel {          //color starts off black         //once changed should never          //black again         private color color = color.black;          colorpanel(){             //add listener                     //click on panel rotate color             addmouselistener(new mouseadapter(){                 @override                 public void mousepressed(mouseevent arg0) {                     color = rotatecolor();                     repaint();                 }             });         }         //rotates color black/blue > red > green > blue         private color rotatecolor(){             if (color==color.black || color == color.blue)                 return color.red;             if (color==color.red)                 return color.green;             else return color.blue;         }          @override         public void paintcomponent(graphics g){             g.setcolor(color);             g.fillrect(0, 0, 100, 100);         }     } colorpanelswindow(){     setdefaultcloseoperation(jframe.exit_on_close);      setlayout(new gridlayout(1,0));     add(new colorpanel());     add(new colorpanel());     //the size must set window small     // , 2 colorpanels overlapping     setsize(40, 40);             //setsize(300, 200);      setvisible(true);  }  public static void main(string[] args) {     swingutilities.invokelater(new runnable(){          @override         public void run() {             new colorpanelswindow();         }      }); }  } 

a couple of observations:

  • afaict panels must overlapping @ first
  • if use flow layout, increase size of window, or way stops panels overlapping initially, don't seem problem (or maybe happens less often?)

yes, yes, know you're talking about. suffered same effect on application.

although had hard time figuring out reason, i'm - - not sure if it's indeed think; that's happening, (too technical , not appropriate post here) did fix it, , don't know why works.

so, instead of repainting component itself, repaint container (or container's container - if still didn't fix).

getparent().repaint(); 

hope helps.


Comments

Popular posts from this blog

Android layout hidden on keyboard show -

google app engine - 403 Forbidden POST - Flask WTForms -

c - Why would PK11_GenerateRandom() return an error -8023? -