Second PictureBox's background goes white when placed over anotherPictureBox

K

kirk

I have a form with a PictureBox control on it. The .Image property is
set to a PNG file(which shows the picture of the US map) with some
transparency in it. The .BackColor property is set to Transparent.
This so far, works perfect.

I now, would like to put another PNG image(an arrow showing
positioning on the map) over the last PictureBox. The problem i'm
having, the background for this second PictureBox only stays
transparent when it is over the form. As soon as I move this second
PictureBox over the first PictureBox, the background turns white.

Am I missing a setting for the second PictureBox or implementing this
wrong?


Thanks.
 
P

Peter Duniho

I have a form with a PictureBox control on it. The .Image property is
set to a PNG file(which shows the picture of the US map) with some
transparency in it. The .BackColor property is set to Transparent.
This so far, works perfect.

I now, would like to put another PNG image(an arrow showing
positioning on the map) over the last PictureBox. The problem i'm
having, the background for this second PictureBox only stays
transparent when it is over the form. As soon as I move this second
PictureBox over the first PictureBox, the background turns white.

Am I missing a setting for the second PictureBox or implementing this
wrong?

I don't know why the background color _changes_. But you're not going to
get the PictureBox to really be transparent. In .NET forms applications,
"transparent" actually just means "use my parent's background color".

You can search this newsgroup for words like "transparent control" and see
previous threads discussing the issue. The short answer is that if you
want to transparently layer two PNG images on top of each other, the
simplest way to do that is to composite them outside the control.

If I recall correctly, I was able to come up with a hack that faked
transparency in a .NET forms control, but I was never really happy with
the technique. It involved copying the underlying control contents into a
bitmap and using that as the background for the control that's supposed to
be transparent. I can't say I'd suggest it except where there are really
no other alternatives. It's got a lot of overhead, and is very fragile
(easy to get it wrong and/or get rendering artifacts).

Pete
 
K

kirk

I don't know why the background color _changes_.  But you're not going to  
get the PictureBox to really be transparent.  In .NET forms applications,  
"transparent" actually just means "use my parent's background color".

You can search this newsgroup for words like "transparent control" and see 
previous threads discussing the issue.  The short answer is that if you  
want to transparently layer two PNG images on top of each other, the  
simplest way to do that is to composite them outside the control.

If I recall correctly, I was able to come up with a hack that faked  
transparency in a .NET forms control, but I was never really happy with  
the technique.  It involved copying the underlying control contents intoa  
bitmap and using that as the background for the control that's supposed to 
be transparent.  I can't say I'd suggest it except where there are really  
no other alternatives.  It's got a lot of overhead, and is very fragile  
(easy to get it wrong and/or get rendering artifacts).

Pete

Thanks for the info Pete.

I attempted deriving from PictureBox and overriding various members,
setting the ExStyle, etc. Seems ok, the overlay image i'm using is an
animated GIF, so i'm getting flicker however. I notice setting
ExStyle to transparent does this quite often. So one option down the
drain.

Another thing i'm experimenting with which I almost having working.
If I set the .BackgroundImage to the US Map, and the .Image to the
animated GIF that is a marker of where I want to indicate selections
on the map, this works. The only thing I can't figure out is how to
move .Image to new X,Y coordinates within the the PictureBox. I
know .SizeMode moves it around to limited spots, so I know there may
be a good possibility if there is something not published or in
Reflection? Any ideas?

Thanks.
 
P

Peter Duniho

[...]
Another thing i'm experimenting with which I almost having working.
If I set the .BackgroundImage to the US Map, and the .Image to the
animated GIF that is a marker of where I want to indicate selections
on the map, this works. The only thing I can't figure out is how to
move .Image to new X,Y coordinates within the the PictureBox. I
know .SizeMode moves it around to limited spots, so I know there may
be a good possibility if there is something not published or in
Reflection? Any ideas?

I would be surprised if there was a reliable way to do it, even using
reflection. At best, you'd maybe find some private methods or fields that
control the positioning, but overriding that behavior might be impossible,
and it'd be tricky to say the least. And once you'd figured it all out,
even a small change in the implementation on the part of the .NET
Framework would completely break your code.

A better approach is to do it within the public .NET API. You have at
least two options: create a new transparent bitmap to be the Image for the
PictureBox, that you generate based on the position of the marker, drawing
the marker into the bitmap. Then this bitmap would just lie right on top
of the background.

IMHO, a solution that's probably even better, assuming you're not using
anything special in PictureBox anyway (it doesn't sound like you really
are) is to create your own custom Control-derived class that does all of
this internally. Then you have complete control over how it renders.

Pete
 
K

kirk

[...]
Another thing i'm experimenting with which I almost having working.
If I set the .BackgroundImage to the US Map, and the .Image to the
animated GIF that is a marker of where I want to indicate selections
on the map, this works.  The only thing I can't figure out is how to
move .Image to new X,Y coordinates within the the PictureBox.  I
know .SizeMode moves it around to limited spots, so I know there may
be a good possibility if there is something not published or in
Reflection?  Any ideas?

I would be surprised if there was a reliable way to do it, even using  
reflection.  At best, you'd maybe find some private methods or fields that  
control the positioning, but overriding that behavior might be impossible, 
and it'd be tricky to say the least.  And once you'd figured it all out, 
even a small change in the implementation on the part of the .NET  
Framework would completely break your code.

A better approach is to do it within the public .NET API.  You have at  
least two options: create a new transparent bitmap to be the Image for the 
PictureBox, that you generate based on the position of the marker, drawing 
the marker into the bitmap.  Then this bitmap would just lie right on top  
of the background.

IMHO, a solution that's probably even better, assuming you're not using  
anything special in PictureBox anyway (it doesn't sound like you really  
are) is to create your own custom Control-derived class that does all of  
this internally.  Then you have complete control over how it renders.

Pete

I figured out how to do dynamic image placement which is actually
pretty simple, however this isn't "truly" using the .Image property as
querying the value of .Image is null.

// one way
Graphics g = PictureBox1.CreateGraphics();
g.DrawImage(myImage, 0, 0); // 0, 0 are the x,y coordinates within the
PictureBox control
PictureBox1.Update();

// another way, using PaintEventArgs from an event on PictureBox
PaintEventArgs.Graphics.DrawImage(myImage, 0, 0);


Both of these work, dynamic image positioning over the background map
is perfect. And the GIF is transparent as it should be. The new
problem. Neither option, animates the GIF. I'm wondering, what is so
special about PictureBox.Image that makes it animate? And is there
anything at my disposal that I can stub in, in place of or to
supplement the .DrawImage calls to get the image animating?
 
P

Peter Duniho

// one way
Graphics g = PictureBox1.CreateGraphics();
g.DrawImage(myImage, 0, 0); // 0, 0 are the x,y coordinates within the
PictureBox control
PictureBox1.Update();

Don't do this. You should only draw from within an OnPaint() method or a
Paint event handler.
// another way, using PaintEventArgs from an event on PictureBox
PaintEventArgs.Graphics.DrawImage(myImage, 0, 0);

This way is fine, but it begs the question as to the point of using the
PictureBox control. If you're going to do the drawing yourself, why
bother?
Both of these work, dynamic image positioning over the background map
is perfect. And the GIF is transparent as it should be. The new
problem. Neither option, animates the GIF. I'm wondering, what is so
special about PictureBox.Image that makes it animate? And is there
anything at my disposal that I can stub in, in place of or to
supplement the .DrawImage calls to get the image animating?

Not that I know of. For sure, if you are managing your own drawing, by
calling DrawImage yourself (in a Paint event handler, for example), then
it will be up to you to correctly deal with the GIF, getting the animation
interval from the image data and then updating the image at appropriate
intervals, using the different frames withing the GIF in sequence.

It's possible that WPF could be helpful here. Unfortuantely, as I have to
point out any time I mention WPF, I have no first-hand experience with it,
so can't offer anything specific. But the fact that WPF has more of a
"retained" data model (i.e. you specific the objects, it handles all the
drawing behavior for you) suggests that it might provide a more automatic
way to implement this.

Pete
 
K

kirk

Don't do this.  You should only draw from within an OnPaint() method or a  
Paint event handler.


This way is fine, but it begs the question as to the point of using the  
PictureBox control.  If you're going to do the drawing yourself, why  
bother?


Not that I know of.  For sure, if you are managing your own drawing, by  
calling DrawImage yourself (in a Paint event handler, for example), then  
it will be up to you to correctly deal with the GIF, getting the animation 
interval from the image data and then updating the image at appropriate  
intervals, using the different frames withing the GIF in sequence.

It's possible that WPF could be helpful here.  Unfortuantely, as I have to  
point out any time I mention WPF, I have no first-hand experience with it, 
so can't offer anything specific.  But the fact that WPF has more of a  
"retained" data model (i.e. you specific the objects, it handles all the  
drawing behavior for you) suggests that it might provide a more automatic  
way to implement this.

Pete

I think i've finally nailed this down pretty good. C# has a class for
animated images.

// stuff this into form class constructor to fire things up
ImageAnimator.Animate(myImage, new EventHandler(this.OnFrameChanged));

// add this method to form class
private void OnFrameChanged(object o, EventArgs e)
{
pictureBox1.Invalidate();
}

// add pictureBox1 _Paint handler that fires from .Invalidate() call
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
ImageAnimator.UpdateFrames();
e.Graphics.DrawImage(myImage, 0, 0);
}
 
P

Peter Duniho

I think i've finally nailed this down pretty good. C# has a class for
animated images.

// stuff this into form class constructor to fire things up
ImageAnimator.Animate(myImage, new EventHandler(this.OnFrameChanged));

Ah, well. There you go! That class appears to do basically all of the
things I said you'd need to do. I didn't realize it was in there.

And just to be nit-picky: the class isn't in C#. It's in the .NET
Framework. :)

Anyway, thanks for posting the solution. Glad you figured it out.

Pete
 

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