Using (Create)Graphics outside Paint event

M

minimega

Hello to all NG,
I've this problem: I'd like to give my application a better look, so
I'm trying to use gradient pattern and bitmaps/icons in my forms.

To draw gradient pattern I've write a little code that draws continuos
lines adding a fixed value to each RGB color component and makes the
gradient effect. However the DrawLine can be applied only to a Graphics
object, and the problem is how create this Grapichs object.

Until now I'm only be able to use the Graphics object in the Paint
event of each control in the form (panel, picture, command..) but if I
want to use it outside the Paint object I'm not been able to do it.

Cut and paste this code in button1_Click:

Graphics g = null;

System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(100, 100);
g = System.Drawing.Graphics.FromImage(bitmap);
g.DrawRectangle(new System.Drawing.Pen(Color.Red), new Rectangle(0, 0,
50, 50));
pictureBox1.Image = bitmap;
g.Dispose();

This works! I created a new bitmap (100x100 pixels) in memory, created
a graphics Object from it, drawed a rectangle in it, finally displayed
it in a Picture control. Outside Paint object this works.

g = this.CreateGraphics();
g.DrawRectangle(new System.Drawing.Pen(Color.Red), new Rectangle(0, 0,
50, 50));
g.Dispose();

This works! Creating Graphics object with this.CreateGraphics() is
working also outside Paint event.

g = pictureBox1.CreateGraphics();
g.DrawRectangle(new System.Drawing.Pen(Color.Red), new Rectangle(0, 0,
50, 50));
g.Dispose();

This doesn't works.. I get a "System.NotSupportedException" error in
line g = pictureBox1.CreateGraphics();

g = panel1.CreateGraphics();
g.DrawRectangle(new System.Drawing.Pen(Color.Red), new Rectangle(0, 0,
50, 50));
g.Dispose();

same error as above.

So, it seems that I can safe use CreateGraphics outside Paint event
only with form (this)object, or create a bitmap in memory, then apply
it to a picture object setting it to Picture.Image property. Why
..CreateGraphics() with other controls in the form raises an Exception?

In my form I've more than 15 panels, and for everyone I have to draw a
gradient. Putting it in Paint event I get as result that when forms
appears for the first time, or big parts of the form must be repainted,
I can see the "work in progress" and between the first panel and the
last panel drawer I get at least 500-600 ms, and the effect is no good.

More, if I want to force a repaint of an object, the only way I've is
to .Invalidate() the object, that automatically fires a paint event (I
cant manualli call the Paint event via code because I can't create the
"e" parameter). However the .Invalidate() clears the object with his
..BackColor property, so I get a "flicking" effects because the control
first is filled with a solid color, then redraws the gradient, and this
is not good to see.. Is there a way to .Invalidate the object, to
automatically fire the Paint event, without before clear the control
surface?

How can be well done this mechanism of quick-drawing? Must I create at
form_load many in-memory bitmaps with the size of each control, fill
them with the gradient or other bitmaps/icon I want to display, then on
every control's Paint event draw the in-memory bitmap in the surface of
the control?

Any other ideas?

Thanks,
Massimo
 
G

Guest

Hi,
you could create your own custom panel by deriving from Control
and define your OnPaint method; something like:

public class CustomPanel : Control
{
private Bitmap bmpOffscreen;
private void OnPaint(object sender, PaintEventArgs e)
{
Graphics gxoff; // offscreen graphics
if (bmpOffscreen == null) //Bitmap for doublebuffering
bmpOffscreen = new Bitmap(ClientSize.Width, ClientSize.Height);
gxOff = Graphics.FromImage (bmpOffscreen);

// from here on write your custom drawing like gxOff.DrawRectangle (...)

// finally draw from the memory bitmap
e.Graphics.DrawImage (bmpOffscreen, 0, 0);
}

Hope this helps.
 
M

minimega

Grazie Gian Paolo,

however you use the Paint event too, and for a large number of panels
in the form you get exactly the same problem I've now: between the
first and the last panel repaint it takes 500-600 ms and you can see
the "work in progress"..

More, if I want to call the OnPaint() method I have to Invalidate the
control (or my CustomControl) and this automatically clear the control
surface making a "flicker"effect.

What I have do until now is create and paint the gradient in a
in-memory bitmap and apply it to a picture control placed in then panel
control. In this way the bitmap is always present, I do not have to
draw the gradient in the Paint event (so the code can run quickly), and
I can re-apply the bitmap when I want, without invalidate control and
get the "flicker" effect.

Thanks,
massimo
 
G

Guest

Greetings,
500-600 ms is really a long time.
Have you so many panels to redraw?
Are you sure you can't optimize your drawing code?
Do a try in the offscreen drawing, as I outlined in my previous sample code:
usually the increase in performance is big.

As far as the OnPaint and calling Invalidate from code are concerned,
OnPaint should be called automatically by the Framework whenever your Control
"becomes visible": you shouldn't worry about forcing an Invalidate.
 
M

minimega

Gian Paolo,
think about this scenario: fullscreen form, without min-max buttons,
without title bar and panel I want to use to display the big
application title (640x60 pixels) placed on the top of form with a blue
gradient fill, containing the text of title application. For the text I
can use a label or draw directly to the panel surface on the Paint
event. You know, the label in CF is not transparent, so I get a small
area (outside the label area) with the gradient, but inside the label a
get solid blue color. So? The .DrawText is the only solution that write
a trasparent text leaving under the gradient. Now, I open a new form
and I want to change the text of the title application: the new form
doesn't open over the application text, so the system won't fire the
Paint event for that panel. How do I change the text then if I cannot
access by code to the panel.CreateGraphics()? (remember that text is
writed in the Paint event that can be fired by code only using
..Invalidate method)

I've no so more panels in my form, but I'm triyng to understand the
best method with I can develop my application using "advanced"
graphics.

massimo
 

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