GDI Onpaint Problem/Question in Custom control

S

Sagaert Johan

I have made a custom control that draws a rectangle when the mouse is down, and does nothing when the mouse is up.
I set/reset a flag in MouseDown/Mouse up and use this to do the drawing in the OnPaint .

The recangle draws correct when i press the mouse, but when i release the mouse the background is not restored

What should i do in the Onpaint to make sure the background (the form) is restored correctly ?

This problem already keeps me busy for 2 days ...

Johan



copy this code in a new win c# app


using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

using System.Drawing.Imaging;

using System.Reflection;



namespace WindowsApplication2

{

/// <summary>

/// Summary description for Form1.

/// </summary>

public class Form1 : System.Windows.Forms.Form

{

/// <summary>

/// Required designer variable.

/// </summary>

private System.ComponentModel.Container components = null;

private Hotspot spot ;

public Form1()

{

//

// Required for Windows Form Designer support

//

InitializeComponent();

//

// TODO: Add any constructor code after InitializeComponent call

//

}

/// <summary>

/// Clean up any resources being used.

/// </summary>

protected override void Dispose( bool disposing )

{

if( disposing )

{

if (components != null)

{

components.Dispose();

}

}

base.Dispose( disposing );

}

#region Windows Form Designer generated code

/// <summary>

/// Required method for Designer support - do not modify

/// the contents of this method with the code editor.

/// </summary>

private void InitializeComponent()

{

//

// Form1

//

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

this.BackColor = System.Drawing.SystemColors.Desktop;

this.ClientSize = new System.Drawing.Size(152, 141);

this.Name = "Form1";

this.Text = "Form1";

this.Load += new System.EventHandler(this.Form1_Load);

}

#endregion

/// <summary>

/// The main entry point for the application.

/// </summary>

[STAThread]

static void Main()

{

Application.Run(new Form1());

}

private void Form1_Load(object sender, System.EventArgs e)

{

spot=new Hotspot() ;

spot.Size=new Size(50,50);

spot.Location=new Point(40,40);

spot.BringToFront();

spot.Visible=true;

this.Controls.Add(spot);


}



}




public class Hotspot : Control

{

//private Image image;

private bool bPushed;

private Bitmap m_bmpOffscreen;


Brush GrayBrush;

public Hotspot()

{

bPushed = false;

//default minimal size

this.Size = new Size(21, 21);

GrayBrush=new SolidBrush(Color.Gray);

}

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e )

{

Graphics gxOff; //Offscreen graphics


if (m_bmpOffscreen == null) //Bitmap for doublebuffering

{

m_bmpOffscreen = new Bitmap(ClientSize.Width, ClientSize.Height);

}

gxOff = Graphics.FromImage(m_bmpOffscreen);


gxOff.Clear(Color.Empty);


if (bPushed)

{

gxOff.FillRectangle(GrayBrush,5,5,ClientSize.Width-10, ClientSize.Height-10);

e.Graphics.DrawImage(m_bmpOffscreen, 0, 0);


}


base.OnPaint(e);

}

protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e )

{

}

protected override void OnMouseDown ( System.Windows.Forms.MouseEventArgs e )

{

bPushed = true;

Invalidate();

}

protected override void OnMouseUp ( System.Windows.Forms.MouseEventArgs e )

{

bPushed = false;

Invalidate();

}

}


}
 
J

Justin Weinberg

Are you calling the base class paint in your onpaint override?
Are you calling Invalidate() on mouse up?
Did you override background paint - I've seen too many suggestions saying to do this and I don't think for most situations it makes sense.


--
Justin Weinberg

Designing a PrintDocument? Drawing to forms?
Check out GDI+ Architect at www.mrgsoft.com



I have made a custom control that draws a rectangle when the mouse is down, and does nothing when the mouse is up.
I set/reset a flag in MouseDown/Mouse up and use this to do the drawing in the OnPaint .

The recangle draws correct when i press the mouse, but when i release the mouse the background is not restored

What should i do in the Onpaint to make sure the background (the form) is restored correctly ?

This problem already keeps me busy for 2 days ...

Johan



copy this code in a new win c# app


using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

using System.Drawing.Imaging;

using System.Reflection;



namespace WindowsApplication2

{

/// <summary>

/// Summary description for Form1.

/// </summary>

public class Form1 : System.Windows.Forms.Form

{

/// <summary>

/// Required designer variable.

/// </summary>

private System.ComponentModel.Container components = null;

private Hotspot spot ;

public Form1()

{

//

// Required for Windows Form Designer support

//

InitializeComponent();

//

// TODO: Add any constructor code after InitializeComponent call

//

}

/// <summary>

/// Clean up any resources being used.

/// </summary>

protected override void Dispose( bool disposing )

{

if( disposing )

{

if (components != null)

{

components.Dispose();

}

}

base.Dispose( disposing );

}

#region Windows Form Designer generated code

/// <summary>

/// Required method for Designer support - do not modify

/// the contents of this method with the code editor.

/// </summary>

private void InitializeComponent()

{

//

// Form1

//

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

this.BackColor = System.Drawing.SystemColors.Desktop;

this.ClientSize = new System.Drawing.Size(152, 141);

this.Name = "Form1";

this.Text = "Form1";

this.Load += new System.EventHandler(this.Form1_Load);

}

#endregion

/// <summary>

/// The main entry point for the application.

/// </summary>

[STAThread]

static void Main()

{

Application.Run(new Form1());

}

private void Form1_Load(object sender, System.EventArgs e)

{

spot=new Hotspot() ;

spot.Size=new Size(50,50);

spot.Location=new Point(40,40);

spot.BringToFront();

spot.Visible=true;

this.Controls.Add(spot);


}



}




public class Hotspot : Control

{

//private Image image;

private bool bPushed;

private Bitmap m_bmpOffscreen;


Brush GrayBrush;

public Hotspot()

{

bPushed = false;

//default minimal size

this.Size = new Size(21, 21);

GrayBrush=new SolidBrush(Color.Gray);

}

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e )

{

Graphics gxOff; //Offscreen graphics


if (m_bmpOffscreen == null) //Bitmap for doublebuffering

{

m_bmpOffscreen = new Bitmap(ClientSize.Width, ClientSize.Height);

}

gxOff = Graphics.FromImage(m_bmpOffscreen);


gxOff.Clear(Color.Empty);


if (bPushed)

{

gxOff.FillRectangle(GrayBrush,5,5,ClientSize.Width-10, ClientSize.Height-10);

e.Graphics.DrawImage(m_bmpOffscreen, 0, 0);


}


base.OnPaint(e);

}

protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e )

{

}

protected override void OnMouseDown ( System.Windows.Forms.MouseEventArgs e )

{

bPushed = true;

Invalidate();

}

protected override void OnMouseUp ( System.Windows.Forms.MouseEventArgs e )

{

bPushed = false;

Invalidate();

}

}


}
 
A

Allen Anderson

there are multiple things wrong in general with your hotspot control
(but they are things you'll learn as you do more with them). However
the two that are causing all your problems is a very small logic error
and a color error.

First, you are clearing your control's surface with the color Empty,
which in fact is no color at all (hence its not clearing anything for
you) and whatever was there before the control took a seat, is still
there after including anything you subsequently draw.

The second is that you seem to have accidently put your drawing to
surface inside your 'bPushed' if statement. This is a subtle but
important error. Since you are drawing to your offscreen bitmap, you
ALWAYS need to draw the bitmap regardless of whether you are doing it
for your pressed or nonpressed state.

Therefore, your draw loop should look as follows,

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e
)
{
Graphics gxOff; //Offscreen graphics

if (m_bmpOffscreen == null) //Bitmap for doublebuffering
m_bmpOffscreen = new Bitmap(ClientSize.Width,
ClientSize.Height);

gxOff = Graphics.FromImage(m_bmpOffscreen);
gxOff.Clear(Color.White); // or whatever color you would
like

if (bPushed)
gxOff.FillRectangle(GrayBrush,5,5,ClientSize.Width-10,
ClientSize.Height-10);

e.Graphics.DrawImage(m_bmpOffscreen, 0, 0);
gxOff.Dispose();

base.OnPaint(e);
}


that will fix your problem.


Allen Anderson
http://www.glacialcomponents.com




I have made a custom control that draws a rectangle when the mouse is down, and does nothing when the mouse is up.
I set/reset a flag in MouseDown/Mouse up and use this to do the drawing in the OnPaint .

The recangle draws correct when i press the mouse, but when i release the mouse the background is not restored

What should i do in the Onpaint to make sure the background (the form) is restored correctly ?

This problem already keeps me busy for 2 days ...

Johan



copy this code in a new win c# app


using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

using System.Drawing.Imaging;

using System.Reflection;



namespace WindowsApplication2

{

/// <summary>

/// Summary description for Form1.

/// </summary>

public class Form1 : System.Windows.Forms.Form

{

/// <summary>

/// Required designer variable.

/// </summary>

private System.ComponentModel.Container components = null;

private Hotspot spot ;

public Form1()

{

//

// Required for Windows Form Designer support

//

InitializeComponent();

//

// TODO: Add any constructor code after InitializeComponent call

//

}

/// <summary>

/// Clean up any resources being used.

/// </summary>

protected override void Dispose( bool disposing )

{

if( disposing )

{

if (components != null)

{

components.Dispose();

}

}

base.Dispose( disposing );

}

#region Windows Form Designer generated code

/// <summary>

/// Required method for Designer support - do not modify

/// the contents of this method with the code editor.

/// </summary>

private void InitializeComponent()

{

//

// Form1

//

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

this.BackColor = System.Drawing.SystemColors.Desktop;

this.ClientSize = new System.Drawing.Size(152, 141);

this.Name = "Form1";

this.Text = "Form1";

this.Load += new System.EventHandler(this.Form1_Load);

}

#endregion

/// <summary>

/// The main entry point for the application.

/// </summary>

[STAThread]

static void Main()

{

Application.Run(new Form1());

}

private void Form1_Load(object sender, System.EventArgs e)

{

spot=new Hotspot() ;

spot.Size=new Size(50,50);

spot.Location=new Point(40,40);

spot.BringToFront();

spot.Visible=true;

this.Controls.Add(spot);


}



}




public class Hotspot : Control

{

//private Image image;

private bool bPushed;

private Bitmap m_bmpOffscreen;


Brush GrayBrush;

public Hotspot()

{

bPushed = false;

//default minimal size

this.Size = new Size(21, 21);

GrayBrush=new SolidBrush(Color.Gray);

}

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e )

{

Graphics gxOff; //Offscreen graphics


if (m_bmpOffscreen == null) //Bitmap for doublebuffering

{

m_bmpOffscreen = new Bitmap(ClientSize.Width, ClientSize.Height);

}

gxOff = Graphics.FromImage(m_bmpOffscreen);


gxOff.Clear(Color.Empty);


if (bPushed)

{

gxOff.FillRectangle(GrayBrush,5,5,ClientSize.Width-10, ClientSize.Height-10);

e.Graphics.DrawImage(m_bmpOffscreen, 0, 0);


}


base.OnPaint(e);

}

protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e )

{

}

protected override void OnMouseDown ( System.Windows.Forms.MouseEventArgs e )

{

bPushed = true;

Invalidate();

}

protected override void OnMouseUp ( System.Windows.Forms.MouseEventArgs e )

{

bPushed = false;

Invalidate();

}

}


}
 
1

100

Hi Johan,

1. Dont use Color.Empty for clearing the bitmap. This won't clear anything.
You should use color instead.

something like:
gxOff.Clear(this.BackColor);

2. Move
e.Graphics.DrawImage(m_bmpOffscreen, 0, 0);
out of the if(bPushed) block. You paint the control only if the button is
down. And you don't paint (clear ) anything if the button is up.

Beside I have one suggestion. If you want to paint the whole clent rectangle
by yourself consider setting control styles:

this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint, true);

Even if you have your own offscreen bitmap you should set
ControlStyles.DoubleBuffer style in order to avoid flickering.

HTH
B\rgds
100
 
S

Sagaert Johan

Thanks for the reply ,

it did'nt solve my problem ,if i don't push the control, i would like
nothing else to see then my form.(my control must appear invisible to the
user whet it's NOT pushed, it should only be draw a when it's pushed)


Allen Anderson said:
there are multiple things wrong in general with your hotspot control
(but they are things you'll learn as you do more with them). However
the two that are causing all your problems is a very small logic error
and a color error.

First, you are clearing your control's surface with the color Empty,
which in fact is no color at all (hence its not clearing anything for
you) and whatever was there before the control took a seat, is still
there after including anything you subsequently draw.

The second is that you seem to have accidently put your drawing to
surface inside your 'bPushed' if statement. This is a subtle but
important error. Since you are drawing to your offscreen bitmap, you
ALWAYS need to draw the bitmap regardless of whether you are doing it
for your pressed or nonpressed state.

Therefore, your draw loop should look as follows,

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e
)
{
Graphics gxOff; //Offscreen graphics

if (m_bmpOffscreen == null) //Bitmap for doublebuffering
m_bmpOffscreen = new Bitmap(ClientSize.Width,
ClientSize.Height);

gxOff = Graphics.FromImage(m_bmpOffscreen);
gxOff.Clear(Color.White); // or whatever color you would
like

if (bPushed)
gxOff.FillRectangle(GrayBrush,5,5,ClientSize.Width-10,
ClientSize.Height-10);

e.Graphics.DrawImage(m_bmpOffscreen, 0, 0);
gxOff.Dispose();

base.OnPaint(e);
}


that will fix your problem.


Allen Anderson
http://www.glacialcomponents.com




I have made a custom control that draws a rectangle when the mouse is down, and does nothing when the mouse is up.
I set/reset a flag in MouseDown/Mouse up and use this to do the drawing in the OnPaint .

The recangle draws correct when i press the mouse, but when i release the mouse the background is not restored

What should i do in the Onpaint to make sure the background (the form) is restored correctly ?

This problem already keeps me busy for 2 days ...

Johan



copy this code in a new win c# app


using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

using System.Drawing.Imaging;

using System.Reflection;



namespace WindowsApplication2

{

/// <summary>

/// Summary description for Form1.

/// </summary>

public class Form1 : System.Windows.Forms.Form

{

/// <summary>

/// Required designer variable.

/// </summary>

private System.ComponentModel.Container components = null;

private Hotspot spot ;

public Form1()

{

//

// Required for Windows Form Designer support

//

InitializeComponent();

//

// TODO: Add any constructor code after InitializeComponent call

//

}

/// <summary>

/// Clean up any resources being used.

/// </summary>

protected override void Dispose( bool disposing )

{

if( disposing )

{

if (components != null)

{

components.Dispose();

}

}

base.Dispose( disposing );

}

#region Windows Form Designer generated code

/// <summary>

/// Required method for Designer support - do not modify

/// the contents of this method with the code editor.

/// </summary>

private void InitializeComponent()

{

//

// Form1

//

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

this.BackColor = System.Drawing.SystemColors.Desktop;

this.ClientSize = new System.Drawing.Size(152, 141);

this.Name = "Form1";

this.Text = "Form1";

this.Load += new System.EventHandler(this.Form1_Load);

}

#endregion

/// <summary>

/// The main entry point for the application.

/// </summary>

[STAThread]

static void Main()

{

Application.Run(new Form1());

}

private void Form1_Load(object sender, System.EventArgs e)

{

spot=new Hotspot() ;

spot.Size=new Size(50,50);

spot.Location=new Point(40,40);

spot.BringToFront();

spot.Visible=true;

this.Controls.Add(spot);


}



}




public class Hotspot : Control

{

//private Image image;

private bool bPushed;

private Bitmap m_bmpOffscreen;


Brush GrayBrush;

public Hotspot()

{

bPushed = false;

//default minimal size

this.Size = new Size(21, 21);

GrayBrush=new SolidBrush(Color.Gray);

}

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e )

{

Graphics gxOff; //Offscreen graphics


if (m_bmpOffscreen == null) //Bitmap for doublebuffering

{

m_bmpOffscreen = new Bitmap(ClientSize.Width, ClientSize.Height);

}

gxOff = Graphics.FromImage(m_bmpOffscreen);


gxOff.Clear(Color.Empty);


if (bPushed)

{

gxOff.FillRectangle(GrayBrush,5,5,ClientSize.Width-10, ClientSize.Height-10);

e.Graphics.DrawImage(m_bmpOffscreen, 0, 0);


}


base.OnPaint(e);

}

protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e )

{

}

protected override void OnMouseDown ( System.Windows.Forms.MouseEventArgs e )

{

bPushed = true;

Invalidate();

}

protected override void OnMouseUp ( System.Windows.Forms.MouseEventArgs e )

{

bPushed = false;

Invalidate();

}

}


}
 
S

Sagaert Johan

Yes, see and try my source in the first post

Are you calling the base class paint in your onpaint override?
Are you calling Invalidate() on mouse up?
Did you override background paint - I've seen too many suggestions saying to do this and I don't think for most situations it makes sense.


--
Justin Weinberg

Designing a PrintDocument? Drawing to forms?
Check out GDI+ Architect at www.mrgsoft.com



I have made a custom control that draws a rectangle when the mouse is down, and does nothing when the mouse is up.
I set/reset a flag in MouseDown/Mouse up and use this to do the drawing in the OnPaint .

The recangle draws correct when i press the mouse, but when i release the mouse the background is not restored

What should i do in the Onpaint to make sure the background (the form) is restored correctly ?

This problem already keeps me busy for 2 days ...

Johan



copy this code in a new win c# app


using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

using System.Drawing.Imaging;

using System.Reflection;



namespace WindowsApplication2

{

/// <summary>

/// Summary description for Form1.

/// </summary>

public class Form1 : System.Windows.Forms.Form

{

/// <summary>

/// Required designer variable.

/// </summary>

private System.ComponentModel.Container components = null;

private Hotspot spot ;

public Form1()

{

//

// Required for Windows Form Designer support

//

InitializeComponent();

//

// TODO: Add any constructor code after InitializeComponent call

//

}

/// <summary>

/// Clean up any resources being used.

/// </summary>

protected override void Dispose( bool disposing )

{

if( disposing )

{

if (components != null)

{

components.Dispose();

}

}

base.Dispose( disposing );

}

#region Windows Form Designer generated code

/// <summary>

/// Required method for Designer support - do not modify

/// the contents of this method with the code editor.

/// </summary>

private void InitializeComponent()

{

//

// Form1

//

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

this.BackColor = System.Drawing.SystemColors.Desktop;

this.ClientSize = new System.Drawing.Size(152, 141);

this.Name = "Form1";

this.Text = "Form1";

this.Load += new System.EventHandler(this.Form1_Load);

}

#endregion

/// <summary>

/// The main entry point for the application.

/// </summary>

[STAThread]

static void Main()

{

Application.Run(new Form1());

}

private void Form1_Load(object sender, System.EventArgs e)

{

spot=new Hotspot() ;

spot.Size=new Size(50,50);

spot.Location=new Point(40,40);

spot.BringToFront();

spot.Visible=true;

this.Controls.Add(spot);


}



}




public class Hotspot : Control

{

//private Image image;

private bool bPushed;

private Bitmap m_bmpOffscreen;


Brush GrayBrush;

public Hotspot()

{

bPushed = false;

//default minimal size

this.Size = new Size(21, 21);

GrayBrush=new SolidBrush(Color.Gray);

}

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e )

{

Graphics gxOff; //Offscreen graphics


if (m_bmpOffscreen == null) //Bitmap for doublebuffering

{

m_bmpOffscreen = new Bitmap(ClientSize.Width, ClientSize.Height);

}

gxOff = Graphics.FromImage(m_bmpOffscreen);


gxOff.Clear(Color.Empty);


if (bPushed)

{

gxOff.FillRectangle(GrayBrush,5,5,ClientSize.Width-10, ClientSize.Height-10);

e.Graphics.DrawImage(m_bmpOffscreen, 0, 0);


}


base.OnPaint(e);

}

protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e )

{

}

protected override void OnMouseDown ( System.Windows.Forms.MouseEventArgs e )

{

bPushed = true;

Invalidate();

}

protected override void OnMouseUp ( System.Windows.Forms.MouseEventArgs e )

{

bPushed = false;

Invalidate();

}

}


}
 
S

Sagaert Johan

100 said:
Hi Johan,

1. Dont use Color.Empty for clearing the bitmap. This won't clear anything.
You should use color instead.

something like:
gxOff.Clear(this.BackColor);

2. Move
e.Graphics.DrawImage(m_bmpOffscreen, 0, 0);
out of the if(bPushed) block. You paint the control only if the button is
down. And you don't paint (clear ) anything if the button is up.


Thats just my problem,i don't want anything to be painted when i don't
press my control,
the only thing i want to see is the form , or the image i draw on the form .

In my form i draw a background image in the forms paint event, and the i
would like to use

my control to create hotspots almost identical as they create hotspots on
images of html pages.

I don't understand why part of the form the is'nt painted correctly if my
control does'nt do any painting by itself.Even if i call the forms
invalidate, the form paint routine seems to skip the area where my control
is.

Johan
 
1

100

Hi Johan,

Now I see what your issue is. Ok, the problem is that when a control is
created the framework by default sets WS_CLIPCHILDREN windows style to the
underlaying window. This style cause any part of of the client area covered
by a child control to be excluded of the invalid region. As a result all
drawing in those areas are clipped.
What you can do is to reset this style. I don't know if it is good idea to
use such platform dependant features, but this solves your problem. So what
you can do is:

1. Add the following property to your main form:
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
createParams.Style &= ~0x02000000; //reset WS_CLIPCHILDREN
return createParams;
}
}

2. Now you have to restore the main form's clent area when the mouse button
is released. You can't simply ignore OnPaint event in the child control.
This will not repaint the main form. You have to do something to fire Paint
event in the parent form. There is my suggestion for the child control's
Paint event implementation:

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e )
{
base.OnPaint(e); //If you needed it it's better to call it before your
painting
if (bPushed)
{

Graphics gxOff; //Offscreen graphics
if (m_bmpOffscreen == null) //Bitmap for doublebuffering
{
m_bmpOffscreen = new Bitmap(ClientSize.Width, ClientSize.Height,
e.Graphics); //I believe is better to use this constructor
}
gxOff = Graphics.FromImage(m_bmpOffscreen);
//gxOff.Clear(Color.Empty); - I believe it is not necessary sice it
doesnt do anything
gxOff.FillRectangle(GrayBrush,5,5,ClientSize.Width-10,
ClientSize.Height-10);
e.Graphics.DrawImage(m_bmpOffscreen, 0, 0);
}
else
{
Parent.Invalidate(this.Bounds, false); //Fires parent's paint event
}
}


HTH
B\rgds
100
 
1

100

A little correction. It seems like calling invalidate with
invalidateChildren=false is not enough to stop Paint event for the child
control. As a result Parent.Invalidate is called over and over again (like
infinite loop of messages).
More logic has to be put in childe's control Paint event.

The idea I came up with is to use a flag in the child's control class

public class Hotspot : Control

{
private bool mStopPaint = false;
//..... other members

protected override void OnPaint(System.Windows.Forms.PaintEventArgs
e )
{
if(mStopPaint) return;
base.OnPaint(e); //If you needed it it's better to call it before
your painting

if (bPushed)
{
//..... not changed
}
else
{
mStopPaint = true;
Parent.Invalidate(this.Bounds, false); //Fires parent's
paint event
Parent.Update(); //This want return until the parent is not
repainted. We need that in order to mStopPaint flag to work
mStopPaint = false;
}

}
//.....The rest of the class
}


HTH
B\rgds
100
 
S

Sagaert Johan

Hi
Thanks for your reply , now it works just as i would like !!!!!!!!!!!

I have put the Parent.Invalidate in the controls MouseUp event ,this seems
to be enough.

Now my next problem is how to solve this issue in the Compact framework
,since CF does not have the CreateParams method...

Best regards Johan http://www.qsl.net/on5di/
 
1

100

Hi Joahn,
I didn't know that you are going to use it with CF. In CF there is no
underlaying native control so there is not Handle, CreateParameters, etc
properties and methods to manimpulating the underlaying window. That's why I
told you this is platform dependent and it's not good idea to use it.
Now I'm posting you the whole source of my next suggestion, which I believe
will work for CF. You can find my comments inline.
The new things are:
1. New event in the Hotspot control class + event handler in the form class
(PaintParent).
The full version of the framework has method InvokePaint that can be
used instead. CF doesn's suported it, though, so I added this event.
2. New method in the Hotspot control class (PaintBackground)

HTH
B\rgds
100

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Drawing.Imaging;
using System.Reflection;


namespace WindowsApplication2

{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
private Hotspot spot ;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//The following is not supported by CF so don't set it. It will make the
things better for not CF, though.
//Set this to remove flickering.
//SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.DoubleBuffer | ControlStyles.UserPaint, true);
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code

/// <summary>

/// Required method for Designer support - do not modify

/// the contents of this method with the code editor.

/// </summary>

private void InitializeComponent()

{
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.BackColor = System.Drawing.SystemColors.Info;
this.ClientSize = new System.Drawing.Size(304, 213);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);

}

#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void Form1_Load(object sender, System.EventArgs e)
{
spot=new Hotspot() ;
spot.Size=new Size(50,50);
spot.Location=new Point(40,40);
spot.BringToFront();
spot.Visible=true;
spot.PaintParent += new PaintEventHandler(spot_PaintParent);
this.Controls.Add(spot);
}

protected override void OnPaint(PaintEventArgs e)
{
//Draw some stuff here
base.OnPaint (e);
e.Graphics.DrawLine(Pens.Red, 0, 0, this.ClientSize.Width,
this.ClientSize.Height);
e.Graphics.DrawLine(Pens.Red, this.ClientSize.Width, 0, 0,
this.ClientSize.Height);
}

private void spot_PaintParent(object sender, PaintEventArgs e)
{
//CF dosen't support background painting
//OnPaintBackground(e);
//Use the same event handler as for Pint event
OnPaint(e);
}
}

public class Hotspot : Control
{
//Requesting parent form to draw iteself on the control's surface
public PaintEventHandler PaintParent;
private bool bPushed;
private Bitmap m_bmpOffscreen;
Brush GrayBrush;
public Hotspot()
{
bPushed = false;
//default minimal size
this.Size = new Size(21, 21);
GrayBrush=new SolidBrush(Color.Gray);
//The following is not supported by CF so don't set it. It will make the
things better for not CF, though.
//Set this to remove flickering.
//SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.DoubleBuffer | ControlStyles.UserPaint, true);
}

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e )
{
base.OnPaint(e); //If you needed it it's better to call it before your
painting
PaintBackground(e);
if (bPushed)
{
e.Graphics.FillRectangle(GrayBrush,5,5,ClientSize.Width-10,
ClientSize.Height-10);
}

}

private void PaintBackground(PaintEventArgs e)
{
Graphics gxOff; //Offscreen graphics
//Beacause the form is resizable the bitmap has to be recreated everytime
the form changes its size.
if (m_bmpOffscreen == null) //Bitmap for doublebuffering
{
//CF doesn't support transforamtions so we need to create bit map for
the whole parent client.
m_bmpOffscreen = new Bitmap(this.Parent.ClientSize.Width,
this.Parent.ClientSize.Height); //I believe is better to use this
constructor
}

gxOff = Graphics.FromImage(m_bmpOffscreen);
//Setting the clip region may increase the perforamnce
gxOff.Clip = new Region(this.Bounds);
PaintEventArgs pea = new PaintEventArgs(gxOff, this.Bounds);
//Raises OnPaintParent event
OnPaintParent(pea);
gxOff.Dispose();
e.Graphics.DrawImage(m_bmpOffscreen, 0, 0, this.Bounds,
GraphicsUnit.Pixel);

}
//Raises PaintParent event.
protected virtual void OnPaintParent(PaintEventArgs e)
{
if(PaintParent != null)
{
PaintParent(this, e);
}
}

protected override void OnMouseDown ( System.Windows.Forms.MouseEventArgs
e )
{
bPushed = true;
Invalidate();
}

protected override void OnMouseUp ( System.Windows.Forms.MouseEventArgs
e )
{
bPushed = false;
Invalidate();
}
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top