Click to See Complete Forum and Search --> : 2 questions about drawing pixels


xusword
March 29th, 2010, 08:39 AM
Hi

I was asked to write a custom control (button) that renders itself. I need to render it pixel by pixel. I was wondering what is the most efficient way of drawing 1 pixel in C#. Drawing a bunch of retangle of 1 pixel?

Also, another question is that how can I draw a transparent pixel? (where 0<alpha<1) The thing is the form that the button lives on has a custom paint function as well, and if I just try using a solid brush to draw the object, the graphic seems to always use black as back color. For example: if I create a color object using Color.FromArgb(128, Color.White) and draw the object, I always get gray at the end no matter where I draw it; if I create a color using Color.FromArgb(0, Color.Red) and draw, I always get black. How can I make it so the graphic object knows where the actual back color is (the form's color at that pixel) instead of black.

I have researched a bit online with no luck. I hope I can find some answer here. Thank you very much

TheGreatCthulhu
March 29th, 2010, 09:48 AM
Draw it pixel by pixel? Hell no - if you can avoid it!
Why you have to do it that way? What's the effect you should get?

There are several approaches, but generally, if you want efficiency, you should work with as many pixels possible at once, and update the control's UI only when all the manipulation is done.

This means that you may have to manipulate the pixel byte-data directly, and this requires some experience. But, maybe there's a better approach; however, you'll have to tell us more about what exactly you are trying to do, before we can help you.

About controls with transparent background, see this MSDN article: Giving Your Control a Transparent Background (http://msdn.microsoft.com/en-us/library/wk5b13s4%28VS.71%29.aspx).

xusword
March 29th, 2010, 10:19 AM
Yup, I will be using bitmap instead
This article seems promising. I will look into it. Thank you so much

xusword
March 29th, 2010, 01:14 PM
I was asked to create a button that looks like an image given to me but resize nicely so it can be put in various places with different text in it. There is a dark boarder around the button's image. If I simply stretch the image when the button needs to be bigger, the button will look terrible.

I am thinking of creating a custom button class with a custom paint method and it would render the button dynamically. (or keep a copy of the bitmap in the memory and only change it when resizing)

My biggest issue for now, is that I am still unable to draw transparent pixels. (since the button has rounded edges)

on the parent form, I have called

SetStyle(ControlStyles.SupportsTransparentBackColor, true);


and when I do: (the following is just a testing, not what the actual button is supposed to look like

private void PaintButton(Graphics g)
{
Bitmap bmap = new Bitmap(Width, Height, g);

float unit = 256f / (float) Width;

for (int x = 0; x < Width; x++)
for (int y = 0; y < Height; y++)
bmap.SetPixel(x, y, Color.FromArgb((int) (unit * (float) x), Color.Gold));

//Image = bmap;
BackgroundImage = bmap;

DrawText(g);
}


I still just get a gradient that fades from black to gold instead of the actual form color to gold.

BigEd781
March 29th, 2010, 02:15 PM
So, I have always had to resort to overriding CreateParams in order to draw a transparent base control in C# as shown in this article.

http://www.c-sharpcorner.com/UploadFile/Nildo%20Soares%20de%20Araujo/TransparentControls11152005074108AM/TransparentControls.aspx

Anyhow, you would also need to set the UserPaint and AllPaintingInWMPaint styles in order to fully override the painting of a control such as a button.

TheGreatCthulhu
March 30th, 2010, 08:18 AM
I tried the CreateParams-approach from the article provided by BigEd781(cp.ExStyle |= 0x20;) and it works. However, after some testing I also discovered that controls can be made transparent without resorting to that.

First, I'd like to append to the MSDN article I referred to a rather important piece of information that guys at MS somehow forgot to mention.

This is the documentation related to ControlStyles.SupportsTransparentBackColor:

"If true, the control accepts a System.Windows.Forms.Control.BackColor with an alpha component of less than 255 to simulate transparency. Transparency will be simulated only if the System.Windows.Forms.ControlStyles.UserPaint bit is set to true and the parent control is derived from System.Windows.Forms.Control."

So:
SetStyle(ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);

Then, another important thing I realized when I swiched from the CreateParams-approach to the "standard" approach:
In order for this to work, if you are overriding the OnPaintBackground() method, MAKE SURE TO CALL base.OnPaintBackground(e)!!! This method is the one that actually does the work that provides you with the transparency effect.

And, finally, don't forget to set the BackColor property to Color.Transparent. Then you can draw anything on top of that.

So, xusword, to sum it all up:

In the constructor, after the call to InitializeComponent(), set both SupportsTransparentBackColor AND UserPaint to true. After that, set BackColor to Color.Transparent.
If you are overriding OnPaintBackground(), call base.OnPaintBackground(e) first. Better yet, don't mess with this method at all - you can override OnPaint() instead.



Some additional advice:

I know you said it's just a test, but avoid using the SetPixel() method of the Bitmap class, since it is (generally) rather slow, especially with large bitmaps. Also note that creating a new Bitmap each time you draw can be expensive.

For the alpha values, it's better to use (int)Math.Round(someValue) than just to typecast to int, since that way you can produce invalid alpha values in some cases.

If you could attach that image that shows how your button should look like, we would be in a better position to help you. The Graphics class has a lot of convenient methods for drawing lines, circles, images, text, etc. I'm sure some of them can be used to achieve what you want to do.

TheGreatCthulhu
March 30th, 2010, 08:41 AM
Some more testing showed that with the "standard" method, the transparency is only simulated with parented controls. If two transparent controls that are not in a parent-child relation overlap, the transparency won't work with them - both will show the background color of their parent control. If one transparent control contains another transparent control, all works well.

If this is unwanted, it appears that the CreateParams-approach must be used. Maybe there's a way to alter this behavior, but I'm currently not aware of it.

xusword
March 30th, 2010, 10:54 AM
thanks BigEd and Cthulhu

actually, I was told I don't have to implement this button anymore, but I will keep in mind what is said here for future reference.

(Don't you hate it when that happens?)