.net - How to prevent a borderless Windows Form from flickering when resizing (C#)? -


[c# .net 4.0]

i'm learning c# , i'm trying build windows form using c# has formborderstyle = formborderstyle.none , can moved/resized using windows api. example, i'm using rounded corner or custom (moveable/resizable) border designs used google chrome , norton 360 basis form.

i've made lot of progress far , gotten work, except when resize form, there black/white flicker along length of right , bottom borders when resize form quickly.

i've tried adding this.doublebuffer = true in constructor , have tried this.setstyles(controlstyles.allpaintinwmpaint | controlstyles.optimizeddoublebuffer | controlstyles.resizeredraw | controlstyles.userpaint, true);.

because i'm sucker graphics side of things, having control on full design of form, can see being forever bother me...so if can me resolve flicker doesn't occur anymore, incredibly useful toward learning process.

i should mention i'm using windows xp, i'm not sure this post me since seems focused on vista/7 (with dwm)...not i'm advanced enough yet understand in post.

the 2 portions of code work api below. have public enumeration wm_nchittest windows api...you can see values in link.

onpaint override method:

protected override void onpaint(painteventargs e) {     system.intptr ptrborder = createroundrectrgn(0, 0,         this.clientsize.width, this.clientsize.height, 15, 15);      setwindowrgn(this.handle, ptrborder, true);      rectangle rc = new rectangle(this.clientsize.width - cgrip,         this.clientsize.height - cgrip, cgrip, cgrip);     controlpaint.drawsizegrip(e.graphics, this.backcolor, rc);     rc = new rectangle(0, 0, this.clientsize.width, 32);     e.graphics.fillrectangle(brushes.slategray, rc); } 

wndproc override method:

protected override void wndproc(ref message m) {     if (m.msg == (int)hittest.wm_nchittest)     {         // trap wm_nchittest         point pos = new point(m.lparam.toint32() & 0xffff, m.lparam.toint32() >> 16);         pos = this.pointtoclient(pos);          if (pos.y < ccaption)         {             m.result = (intptr)hittest.htcaption;             return;         }          if (pos.x <= cgrip && pos.y >= this.clientsize.height - cgrip)         {             m.result = (intptr)hittest.htbottomleft;             return;         }          if (pos.x >= this.clientsize.width - cgrip &&             pos.y >= this.clientsize.height - cgrip)         {             m.result = (intptr)hittest.htbottomright;             return;         }          if (pos.x >= this.clientsize.width - cborder)         {             m.result = (intptr)hittest.htright;             return;         }          if (pos.y >= this.clientsize.height - cborder)         {             m.result = (intptr)hittest.htbottom;             return;         }          if (pos.x <= cborder)         {             m.result = (intptr)hittest.htleft;             return;         }     }      base.wndproc(ref m); } 

and here's full code:

using system; using system.collections.generic; using system.componentmodel; using system.data; using system.drawing; using system.linq; using system.text; using system.windows.forms; using system.runtime.interopservices;  namespace practiceform {     public partial class form2 : form     {         [dllimport("user32.dll")]         private static extern int setwindowrgn(intptr hwnd, intptr hrgn, bool bredraw);          [dllimport("gdi32.dll")]         private static extern intptr createroundrectrgn(int x1, int y1, int x2, int y2, int cx, int cy);          [dllimport("gdi32.dll", entrypoint = "deleteobject")]         private static extern bool deleteobject(system.intptr hobject);          private const int cgrip = 20;         private const int ccaption = 35;         private const int cborder = 7;         private point mouseoffset;          public form2()         {             initializecomponent();             this.formborderstyle = formborderstyle.none;             this.maximumsize = new size(670, 440);             this.doublebuffered = true;             this.setstyle(controlstyles.resizeredraw |                           controlstyles.optimizeddoublebuffer |                           controlstyles.allpaintinginwmpaint |                           controlstyles.userpaint, true);         }          protected override void onpaint(painteventargs e)         {             system.intptr ptrborder = createroundrectrgn(0, 0,                 this.clientsize.width, this.clientsize.height, 15, 15);              setwindowrgn(this.handle, ptrborder, true);              rectangle rc = new rectangle(this.clientsize.width - cgrip,                 this.clientsize.height - cgrip, cgrip, cgrip);             controlpaint.drawsizegrip(e.graphics, this.backcolor, rc);         }          protected override void wndproc(ref message m)         {             if (m.msg == (int)hittest.wm_nchittest)             {                 // trap wm_nchittest                 point pos = new point(m.lparam.toint32() & 0xffff, m.lparam.toint32() >> 16);                 pos = this.pointtoclient(pos);                  if (pos.y < ccaption)                 {                     m.result = (intptr)hittest.htcaption;                     return;                 }                  if (pos.x <= cgrip && pos.y >= this.clientsize.height - cgrip)                 {                     m.result = (intptr)hittest.htbottomleft;                     return;                 }                  if (pos.x >= this.clientsize.width - cgrip &&                     pos.y >= this.clientsize.height - cgrip)                 {                     m.result = (intptr)hittest.htbottomright;                     return;                 }                  if (pos.x >= this.clientsize.width - cborder)                 {                     m.result = (intptr)hittest.htright;                     return;                 }                  if (pos.y >= this.clientsize.height - cborder)                 {                     m.result = (intptr)hittest.htbottom;                     return;                 }                  if (pos.x <= cborder)                 {                     m.result = (intptr)hittest.htleft;                     return;                 }             }              base.wndproc(ref m);         }          private void button1_click(object sender, eventargs e)         {             this.close();         }          private void button2_mouseclick(object sender, mouseeventargs e)         {             this.windowstate = formwindowstate.minimized;         }          private void panel1_mousedown(object sender, mouseeventargs e)         {             mouseoffset = new point(-e.x, -e.y);         }          private void panel1_mousemove(object sender, mouseeventargs e)         {             if (e.button == mousebuttons.left)             {                 point p = control.mouseposition;                 p.offset(mouseoffset.x, mouseoffset.y);                 location = p;             }         }          private void label1_mousedown(object sender, mouseeventargs e)         {             mouseoffset = new point(-e.x, -e.y);         }          private void label1_mousemove(object sender, mouseeventargs e)         {             if (e.button == mousebuttons.left)             {                 point p = control.mouseposition;                 p.offset(mouseoffset.x, mouseoffset.y);                 location = p;             }         }     } } 

thanks help.

flickering happens because areas of display changing colour rapidly, in turn happens because overdrawing - drawing more 1 thing @ same pixel.

this happens because:

  • if redraw slow, stuff on screen (e.g. window borders) drawing on visible while. e.g. user might see 2 copies of scroll bar until have finished wiping away old 1 contents of form.
  • windows automatically erases background of window you., in white. areas of drawing aren't white therefore flash white moment before overdraw correct image.
  • if draw multiple things in same place, you'll see flickering keep changing colour in area of screen

to fix these problems, need combination of things (the more better)

  • disable erase background, or set erase colour dominant colour in image
  • optimise redraw code make faster, flicker less prominent
  • optimise redraw code eliminate on draw. e.g. put border around rectangular page draw background colour , overdraw page, flicker. instead, draw top border rectangle, bottom left , right, drew page in middle. nopixels drawn more once won't flicker
  • enable doublebuffered mode on control. this, drawing happens bitmap image in memory, , final image copied screen, each pixel displayed once , there no flicker.

Comments

Popular posts from this blog

linux - xterm copying to CLIPBOARD using copy-selection causes automatic updating of CLIPBOARD upon mouse selection -

c++ - qgraphicsview horizontal scrolling always has a vertical delta -