Reducing flicker when you change images in a panel - vb.net

How do I reduce flicker in a vb2005 panel?
Inside the parent panel I have 2 other panels that I'm am using.
The outer most panel contains a background sprite and the two innermost panels are overlays that change to fit the places in the background sprite.
When I change the overlay sprites I would like to reduce the flicker and make it a smooth transition from one sprite to the next.
Here is the code that changes the images in the overlay panels
the overlay panel is not changed if the new value is the same as the old value
Private Sub TrackBar2_Scroll(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TrackBar2.Scroll, TrackBar1.Scroll
If (Panel2.Tag <> TrackBar1.Value) Then
Panel2.Tag = TrackBar1.Value
Panel2.BackgroundImage = tops(TrackBar1.Value) //img array for the top panel
Panel2.Update()
End If
If (Panel3.Tag <> TrackBar2.Value) Then
Panel3.Tag = TrackBar2.Value
If (TrackBar2.Value > 0) Then
Panel3.Location = New Point(182, 210)
Else
Panel3.Location = New Point(182, 209)
End If
Panel3.BackgroundImage = bottoms(TrackBar2.Value)//img array for the bottom panel
Panel3.Update()
End If

You're not going to like this answer. The flicker is caused by the fact that the default .NET panel is not double buffered - so it does all the drawing directly in the visible memory, not a back buffer.
You need to subclass the Panel class and enable double buffering on the new class. This can be done by doing a
SetStyle
call in the constructor with the flags OptimisedDoubleBuffering and DoubleBuffering enabled.
Once you have the new panel class that is double buffered, you can use them in your application instead of the standard Panel.
I told you you wouldn't like the answer ;)

Rein is right, subclassing is the best way. In the meantime though, change that call from Update to Invalidate; that might help a little.

Related

Scroll vertical dynamically in tabPage control

In my relatively simple project I have a two page tabControl. tabPage2 consists of dynamically created pictureBoxes (thumbnails, pic_XXX). tabPage2 is of fixed size, with AutoScroll enabled.
On tabPage1, among other things, I can search for a given name (pic_XXX). When I switch to tabPage2 I'd like it to be scrolled, so the row in which pic_XXX is, is visible. Manually scrolling in tabPage2 is working.
I'm struggling to dynamically scroll tabPage2 to accomplish this. The following solution throws an exception:
Dim pos As Point = tabPage2.Controls.Item("pic_" & imgNum).Location
tabPage2.VerticalScroll.Value = pos.Y
tabPage2.refresh()
I run out of ideas!?
So how to scroll the specified child control into view on an auto-scroll enabled control?
You should use method .ScrollControlIntoView( [Control] )
tabPage2.ScrollControlIntoView(tabPage2.Controls.Item("pic_" & imgNum) )
Answer for your question:
Dim pos As Point = tabPage2.Controls.Item("pic_" & imgNum).Location
tabPage2.VerticalScroll.Maximum = tabPage2.Height
tabPage2.VerticalScroll.Value = pos.Y
tabPage2.PerformLayout()
You have to call .PerformLayout() to make the scrolling control update.

Draw Image to Picture Box using AutoScroll but keep a Header Visible

I have a Picturebox which I draw a view to (Gantt View in this case) and it works OK - i.e., the view is drawn and the AutoScroll property allows the image in the PictureBox to be smoothly scrolled.
My problem is, the header of the image (e.g., the date headers in this case) scroll off the top of the display when I scroll down the image.
What I can't work out is how to fix a header to the top. I thought about simply drawing a header into another Picturebox, but then I am not sure how to sync the header with the left-right scrolling of the main PictureBox
Can someone suggest the best approach to handling this, or do I need to revert to doing a direct draw and handle the scrolling myself?
I am using VB with VS 2015.
Many thanks
Phil
Updated - I am now using an off-screen Bitmap, but can someone look at the code below and let me know if there is a faster/better way to do this? It all works, but still learning and so always looking to do things the best way
Public Sub MoveViewPoint(G As Graphics)
' G passed in from controls Paint
G.Clear(Color.WhiteSmoke)
' _Plan is off-screen bitmap of image
' _HeaderHeight is height of the Header area in _Plan
Dim Header_src_rect As New Rectangle(_HScroll.Value, 0, _Plan.Width, _HeaderHeight)
Dim Header_dst_rect As New Rectangle(0, 0, _Plan.Width, _HeaderHeight)
G.DrawImage(_Plan, Header_dst_rect, Header_src_rect, GraphicsUnit.Pixel)
Dim src_rect As New Rectangle(_HScroll.Value, _HeaderHeight + 1 + _VScroll.Value, _Plan.Width, _Plan.Height)
Dim dst_rect As New Rectangle(0, _HeaderHeight + 1, _Plan.Width, _Plan.Height)
G.DrawImage(_Plan, dst_rect, src_rect, GraphicsUnit.Pixel)
_HScroll.LargeChange = G.ClipBounds.Width * 0.9
_VScroll.LargeChange = G.ClipBounds.Height * 0.9
End Sub
I would do all your drawing to an off-screen bitmap using the GDI graphics system. You can draw your headers and the rest of the chart as 2 distinct stages in the same bitmap. You would have to handle the scrolling yourself by watching the MouseMove event and checking the buttons status.

VB.NET Winforms: Overlay two transparent images

I am attempting to overlay two transparent images within a winform, but it keeps rendering the form's background image behind the top transparent image, as opposed to the second image...
My basic set up is I have two panels and in each panel is a picturebox. Each image in the picture boxes have some transparent areas. I've set the BackColor of the panels to color.transparent.
When I make one panel overlay the other I'm seeing the form's backcolor come through as opposed to the underlaying image.
Am I missing a property that I can set?
You only need one picture box. The overlay can be done with graphics.
Imports System.Drawing
Dim OverlayImage As New Bitmap("Some Path", True)
Dim BackImage As New Bitmap("Some Path", True)
g As Graphics = Graphics.FromImage(BackImage)
g.DrawImage(OverlayImage, 0, 0)
pictureBox1.Image = BackImage
If you want to have the timer move the overlayed image, then first, make a variable Dim posX As Integer = 0
then use g.DrawImage(OverlayImage, posX, 0) Now when your timer ticks, increment posX by 10
Here's a complete function to overlay two images (adapted from Blue0500's answer):
''' <summary> Return a new image with one superimposed over the other. </summary>
Function OverlayImgs(ByVal BackgroundImg As System.Drawing.Bitmap, ByVal OverlayImg As System.Drawing.Bitmap, Position As System.Drawing.Point) As System.Drawing.Bitmap
Dim g = System.Drawing.Graphics.FromImage(BackgroundImg)
g.DrawImage(OverlayImg, Position)
Return BackgroundImg
End Function
Usage:
lblTest.Image = OverlayImgs(Img1, Img2, New Point(16, 16))
You don't need a PictureBox for this unless you are using it for the canvas. You can draw all images to a Rectangle structure and move them around. Personally I would create a class object that has a Rectangle, Image and other properties and hold them in a collection. Then you simply draw the class objects by there properties including location. If there images contain transparencies they will overlay for you. This also gives you a method to check for collisions via the Rectangle.IntersectsWith function.

How to Draw above a picture in VB.NET

I am building a 2D game where the user is a circle(:P) and the enemies are rectangles coming at him. However, my problem is that when I placed a very nice picture of space I found on the internet, the screen draws whatever it has to underneath this image. Everything works,I can still see my lives going down when something collides into me - except the fact it is all covered up by this picture.
In a nutshell, my question is: How Do I Draw everything ON Top of this - (I tried using the 'Send To Back' Command)
EDIT: The form draws everything through a timer, and the user controls his character through keys. This probably won't help - but if it does it's here.
Sorry folks didn't think you'd need the code. Here it is:
In the mybase.load procedure:
PicBackGround.Dock = DockStyle.Fill
PicBackGround is the picture box with the image.
In the paint procedure:
e.Graphics.Clear(Color.Black)
e.Graphics.FillEllipse(Brushes.Orange, Player)
'Projectiles
Dim i As Integer = 0
Do
If Current_Projectile(i).IsEmpty = False Then e.Graphics.FillRectangle(Brushes.Red, Current_Projectile(i))
i += 1
Loop Until i = UBound(Current_Projectile)
'Objects
i = 0
Do
If Objects(i).IsEmpty = False Then e.Graphics.FillRectangle(Brushes.Blue, Objects(i))
i += 1
Loop Until i = UBound(Objects)
Okay: Player is a rectangle declared right at the top, Dim Player As New Rectangle(0, 0, 50, 50);
There is then the array Objects, which stores all the data about the enemies coming at the player, Current_Projectiles is simply an array to store data about rectangles(bullets) that the player fires.
Anything else you want to know just let me know.
Yes, a control overlaps anything you draw on the form. A simple solution is to use the form's BackgroundImage property instead. Or draw the image yourself.

I've increased the size of image in picture box but now I want to take it back to its original size

I am working with vb.net and want to increase the size of image when the cursor is over that image, but the image should come back to its original size when the cursor leaves that image area.
I've used the following code to increase the size of image:
Private Sub PictureBox1_MouseHover(ByVal sender As Object, ByVal e As System.EventArgs) Handles PictureBox1.MouseHover
PictureBox1.Size = New Size(300, 250)
End Sub
I've used the default size class but, it gives some different dimensions.
Please guide me by the code that brings the image into its original size that I've been declared into the picture box properties.
You should probably be hooking in to the MouseEnter and MouseLeave events. Links for MSDN reference
Here's the code that will resize the PictureBox to the dimensions of the image:
PictureBox1.Size = PictureBox1.Image.Size
Assuming that the original size of the PictureBox was the image size, then that'll work just fine.
As kaveman suggested, MouseEnter and MouseLeave would be much better events to put the code in ;-)
In order to restore the custom size you've set it to, you'll need some code like this: (make sure its somewhere which won't go out of scope, like in the form, outside of methods)
You'll need a variable to store the original size:
Dim OriginalSize as Size
Then, before changing the size when the user moves the mouse over the image, store the size in the variable: (put this in the MouseEnter event)
OriginalSize = PictureBox1.Size
PictureBox1.Size = New Size(300, 250)
Restoring that size is a simple matter of putting that variable back into the picturebox size: (this goes in the MouseLeave event)
PictureBox1.Size = OriginalSize
=)