I have problem with the Graphic object. I have a loop which goes through some array and it gets the images from them and It draws them on a picture box. Every thing is fine but When I try to resize or draw another thing which is a little bit more heavy, Every thing start flashing Like when they're painting. I know it's too heavy to draw all that damn things ! but is there any way to avoid tearing?
Thanks.
Edit:
my code:
graphic.Clear(frmmain.Workspace.BackColor)
For i = 0 To mObjectsList.Count - 1
graphic.DrawImage(mObjectsList(i).oGraphic, mObjectsList(i).oX, mObjectsList(i).oY, mObjectsList(i).oWidth, mObjectsList(i).oHeight)
Next
graphic is a variable which I created it from my picturebox Graphic object
A picturebox doesn't have a Graphic object. Do not use its CreateGraphics() method. Whatever you draw through that stays on the screen for only a fraction of a second, barely making a blip. Use e.Graphics in the Paint event handler instead. That draws into the double-buffered bitmap. PictureBox always has its DoubleBuffered property set to true. That bitmap gets drawn when the Paint event completes. Which is why your objects flicker, they get overdrawn again by that bitmap.
Related
Maybe I am missing something, but is it the case that when you set a pictureboxes background to transparent, all it really does is set it to the same color as the forms background?
What I am trying to do is draw an animation for the benefit of this, a bouncing ball - which I paint on the form, then overlay that with a picture frame. End result should be a bouncing ball in a picture frame, I should mention that the picture frame does not have a straight edge, so it is not possible to arrange 4 picture boxes in a frame. The ball needs to vanish behind the frame to change color and then magically bounce back out.
I have tried:
1.Setting the picture box background to pink and then key out the same pink, this basically cuts away everything, including that which is behind the picture box
2.Setting the picture box to transparent, this just displays the picture box background as the same color as the forms background.
3.I have tried painting the image in a rectangle, this had the same effect as drawing it in a picture box.
I am not sure what I am doing wrong, I am wondering if there is any other ways I could try or if someone has made a custom control or library that supports transparency?
Try using a Panel with the background image set. This is because; as you said: the transparent option only takes the backcolour of the parent.
After doing some more in depth research I solved this by drawing both the images to the form using PaintEventArgs and me.paint
Making each image transparent using:
Dim TestImage as Bitmap
TestImage.MakeTransparent(<Transparency Color>)
Thank you to both of you for your replies though.
Hmm... If You want to use Picturebox and get a transparent image,
Try to set picturebox's background as your 'Ball' (probably you need an image editor).
and set picturebox transparent. It worked for me (VS Express 2010) once.
So having looked this up for a while now, I have read probably twenty different implementations but have not yet seen a solid, control-based, framework-based general solution to implementing truly transparent controls that works.
This possibly oversimplified approach doesn't do anything at all and creates a routine (InvalidateEx) that never gets used: http://bytes.com/topic/c-sharp/answers/248836-need-make-user-control-transparent
This seems to be hinting at what the previous answer was getting at: https://web.archive.org/web/20141227200000/http://bobpowell.net/transcontrols.aspx
however it uses a timer tick to execute the InvalidateEx method.
This appears to be abandoning multi-layered controls and handles all drawing on a single layered panel, while glossing over how the label object appears to be implementing its own transparency: http://www.codeproject.com/Articles/25048/How-to-Use-Transparent-Images-and-Labels-in-Window
This is a completely non-framework based method: http://www.codeproject.com/Articles/30135/General-solution-for-transparent-controls
The accepted solution in this answer simply does not work for me: Transparent Control on Transparent control?
The control I get is a generic solid colour (white) with the transparent image drawn over it.
So, I start on my own implementation.
I'd rather not rely on bottom-up GDI drawing, i.e. perform all drawing in the parent-most form, I'd rather not do pre-rendering to transparent bitmaps, I'd rather not inherit from something other than Forms.Control that is performing some clever tricks of its own to short-cut transparency. I really want to get to the bottom of how to draw on a control surface with complete transparency support. Evidently the label control for instance has a full implementation inside itself, how does it work?
Logically, a transparent control cannot rely on simple 1-bit clip regions and needs to stay mostly complete. Multi-layering of controls needs to be handled correctly, i.e. correct drawing order etc. without causing infinite loops.
The first and most common recommendation is this:
SetStyle(ControlStyles.SupportsTransparentBackColor, True)
Me.BackColor = Color.Transparent
where the first line I understand is synonymous with
Protected Overrides ReadOnly Property CreateParams As System.Windows.Forms.CreateParams
Get
Dim result As System.Windows.Forms.CreateParams = MyBase.CreateParams
result.ExStyle = result.ExStyle Or WindowsMessages.WS_EX_TRANSPARENT
Return result
End Get
End Property
Which has very different behaviours depending on which class is being inherited. In the case of Forms.Control, OnPaintBackground chooses to clear the clip rectangle with the parent control's background colour. Not too clever.
Overriding and removing the base OnPaintBackground call causes the control to stay 'dirty' having never overwritten what came below it. Clearing using a transparent colour (optimistic approach) yields a field of black transparent pixels and causes the control to appear completely black.
Logically this makes sense, underlying controls in a bid for efficiency do not redraw the area they anticipate this control with draw over. That area of the form then never gets updated and stays whatever came before the form existed. The painting of a transparent colour onto this is a little confusing, since it implies that the graphics buffer does not even contain the underlying pixels but actual nothings that are replaced with black transparent somethings to make the control appear black.
The first challenge appears to be handling when the control itself redraws, getting all underlying controls to redraw themselves in that region (without automatically invalidating the control itself to start a stack overflow), then painting itself over the underlying and up-to-date pixels. I haven't found a way to do this yet. The closest I have come is through digging around the .net code and finding the ButtonRenderer.DrawParentBackground method. This largely seems to work, though a quick test showed that z order of overlapping components was still not handled correctly, with underlying controls drawing over the top of this control.
The second challenge then is to have the control properly redraw itself when an underlying control changes. By disconnecting the automatic invalidation in challenge one, it makes it difficult to notify the control to invalidate itself and not invalidate its parents.
If someone has solved this problem completely, please provide the code, if not, please provide some experience in how I might handle one or several of the problem's parts.
Many thanks.
Edit:
It appears the assumed detail about WS_EX_TRANSPARENT as per WS_EX_TRANSPARENT - What does it actually do?
Research Update: ButtonRenderer.DrawParentBackground is actually just used by Control itself, only if Application.EnableVisualStyles() is used and simply forces the background draw of the parent. It appears to be a synonym of
InvokePaintBackground(Parent, e.Graphics)
Which will reproduce all background drawn details of the parent control.
I have created the required general transparency control, the solution was a detailed breakdown of the control and all of its siblings in the parent, and preparing a recursive drawing routine on the OnPaintBackground() method relying on the InvokePaint() and InvokePaintBackground() methods. By defining successively smaller clips and intersecting with lower controls, this method minimises drawing overhead.
The complete control includes a method of detecting and responding to sibling controls' Invalidate methods, efficiently drawing the stack of transparent controls and effectively allowing full alpha channel overlays on animated underlying controls.
The control can be interleaved with all permutations of child and parent controls while giving visually accurate transparency.
Hit testing has not been considered in the control.
This control will not overdraw controls whose drawing is not performed during paint events. This is a big limitation.
To use the control one simply inherits from the base and overrides the OnPaint method to perform custom drawing. It is also possible to override the OnPaintBackground method so long as a call to the base method is called first.
Finally, if anyone would like the full code including invalidation handling, let me know. If you have a solution to system drawn components let me know that too. Also if you have a more trivial solution that implies I wasted a bunch of time on this, I wouldn't be upset about receiving that either!
An excerpt of the control on the OnPaintBackground method is presented:
''' <summary>
''' Recursively paint all underlying controls in their relevant regions, stacking drawing operations as necessary.
''' </summary>
''' <param name="pevent"></param>
''' <remarks></remarks>
Protected Overrides Sub OnPaintBackground(pevent As System.Windows.Forms.PaintEventArgs)
'Store clip and transform for reversion
Dim initialClip As Region = pevent.Graphics.Clip
Dim initialTransform As Drawing2D.Matrix = pevent.Graphics.Transform
'Develop list of underlying controls
Dim submarinedControls As New List(Of Control)
For Each Control As Control In m_Siblings
If Control.Visible AndAlso Above(Control) AndAlso Me.ClientRectangle.IntersectsWith(Control.RelativeClientRectangle(Me)) Then submarinedControls.Add(Control)
Next
'Prepare clip for parent draw
Dim parentClip As System.Drawing.Region = New System.Drawing.Region(initialClip.GetRegionData)
For Each Control As Control In submarinedControls
parentClip.Exclude(Control.RelativeClientRectangle(Me))
Next
pevent.Graphics.Clip = parentClip
'Evaluate control relationship to parent, temporarily adjusting transformation for parent redraw. This translation must be relative since the incoming graphics may already have a meaningful transform applied.
Dim translation As Point = Parent.RelationTo(Me)
pevent.Graphics.Transform = New Drawing2D.Matrix(1, 0, 0, 1, initialTransform.OffsetX + translation.X, initialTransform.OffsetY + translation.Y)
'Fully draw parent background
InvokePaintBackground(Parent, pevent)
InvokePaint(Parent, pevent)
'Reset transform for sibling drawing
pevent.Graphics.Transform = initialTransform
'Develop initial clip of submarined siblings
Dim siblingClip As System.Drawing.Region = New System.Drawing.Region(initialClip.GetRegionData)
siblingClip.Exclude(parentClip)
For Each Control As Control In submarinedControls
'Define relative position of submarined sibling to self
translation = Control.RelationTo(Me)
'Define and apply clip *before* transformation
Dim intersectionClip As New Region(Control.RelativeClientRectangle(Me))
intersectionClip.Intersect(siblingClip)
pevent.Graphics.Clip = intersectionClip
'Apply transformation
pevent.Graphics.Transform = New Drawing2D.Matrix(1, 0, 0, 1, initialTransform.OffsetX + translation.X, initialTransform.OffsetY + translation.Y)
'Raise sibling control's paint events
InvokePaintBackground(Control, pevent)
InvokePaint(Control, pevent)
'Revert transformation and exclude region
pevent.Graphics.Transform = initialTransform
siblingClip.Exclude(intersectionClip)
Next
'Revert transform and clip to pre-drawing state
pevent.Graphics.Transform = initialTransform
pevent.Graphics.Clip = initialClip
End Sub
Me.Visible = False
OR
Me.Opacity = 0
OR
Me.Hide()
I have a form and a custom scrollable PictureBox control (a very large PictureBox control inside another smaller PictureBox with 2 sliders to move large PictureBox inside smaller one). While scrolling large PictureBox inside smaller one the graphics that are drawn on large PictureBox get erased.
I would like to use a kind of off-screen buffer technique to cache all the drawing operations and to repaint the "dirty" parts of the view if necessary. There is an example of how to do this with Bitmap class in VB.NET.
Is there any analog of VB.NET's Bitmap class for Visual Basic 6?
I'm sure it's possible to do what you want, but I believe all you are looking for is the AutoRedraw property of the picturebox.
I've a program that draw an image in a picturebox with DrawImage. This image, a ball (.png transparent), every second is overwritten by another ball of different color. After 3-5 second the edge of the ball becomes bad, because of overwriting.
I tried to clean the background with a FillRectangle before any overwrite, but i need to preserve the windows form background. How can i do that?
To anybody who will encounter this in the future:
g.Clear(Color.FromArgb(0,0,0,0)); //Clear the graphics with transparent as background
g.DrawImage(...); //Draw your image
Sometimes, my users will use a 16000x16000 picturebox (which is located in a Panel, for autoscroll).
The picturebox is used like a tiles map. On it, I draw tiles for making maps (yes, it is a map editor)...
But the mere idea of being able to create a picturebox that huge, is terrible for performance.
I am told to "only load the visible area", but, what do they mean by "load" on a picturebox? Can I control that?
You don't want to let the picturebox display complete images. Instead, you use the Paint event to draw the visible image portion yourself