Form display, transparent holes

Bulldog

Member
Joined
Nov 13, 2006
Messages
10
Programming Experience
Beginner
Hi,

I hope someone can help. If I create a large table, the display of the form is really bad, especially if I add grid lines. I get transparent holes where the controls should be and it takes a long time to draw. I made an example of this below. (Just cut and paste into an empty project).

I've tried everything I can think of, including freezing the form, suspend/resume, hiding the form, but I dont seem to be able to improve it at all. The dynamics of the display is so bad, I dont want to release the app.

Any help appreciated.

VB.NET:
Public Class Form1
    Dim t As New TableLayoutPanel
 
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 
        Me.Refresh()
 
        Me.BackColor = SystemColors.Control
        Me.TransparencyKey = System.Drawing.Color.Empty
        Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
        Me.SetStyle(ControlStyles.UserPaint, True)
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        Me.SetStyle(ControlStyles.SupportsTransparentBackColor, False)
        Me.UpdateStyles()
 
        Me.Width = 500
        Me.Height = 400
        Me.AutoSize = True
        Me.AutoSizeMode = Windows.Forms.AutoSizeMode.GrowOnly
 
        Dim b As New Button
        AddHandler b.Click, AddressOf BClick
        Me.Controls.Add(b)
        b.Location = New Point(0, 0)
        b.Text = "+/- Grid"
        b.Show()
        b.BringToFront()
 
        t.AutoSize = True
        t.AutoSizeMode = Windows.Forms.AutoSizeMode.GrowAndShrink
        t.ColumnCount = 30
        t.RowCount = 60
        t.Dock = DockStyle.Fill
        Me.Refresh()
 
        Dim larray(1800) As Label
        For i = 1 To larray.Length - 1
            Dim l As New Label
            l.AutoSize = True
            l.Text = i.ToString
            l.BackColor = Me.BackColor
            larray(i) = l
        Next
        t.Controls.AddRange(larray)
        Me.Controls.Add(t)
 
    End Sub
 
    Private Sub BClick(ByVal sender As System.Object, ByVal e As System.EventArgs)
        If t.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single Then
            Me.Hide()
            t.CellBorderStyle = TableLayoutPanelCellBorderStyle.None
            Me.Show()
        Else
            Me.Hide()
            t.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single
            Me.Show()
        End If
    End Sub
 
End Class
 
The problem is the number of controls.. 1800 ?! Consider using a DataGridView control or drawing your custom grid control.
 
The example with 1800 was to exaggerate the effect. I get the same problem with a much smaller number of controls (in fact I get it even if I have only one picturebox). It's much worse when the form has to grow as part of the operation.

Also, although I disable transparency, when the form grows, the holes (that will be filled by controls) still appear transparent. If I set the transparencykey to some other color than 'empty', the holes display as black??
 
Me.BackColor = SystemColors.Control
Me.TransparencyKey = System.Drawing.Color.Empty
Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
Me.SetStyle(ControlStyles.UserPaint, True)
Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
Me.SetStyle(ControlStyles.SupportsTransparentBackColor, False)
Me.UpdateStyles()

First of all get rid of all the SetStyle Methods you aren't doing any custom painting so you don't need these style bits on. Also don't event bother messing around with the SetStyle(ControlStyles.Supports...) with a form. The bit i don't understand is why you have the transparancy key set to color.empty
 
I'm not at all surprised that you are getting problems here. Most of what you have declared in the form load event handler should be in the forms constructor.
 
I'm not at all surprised that you are getting problems here. Most of what you have declared in the form load event handler should be in the forms constructor.

It's perfectly valid to set these things in the load event, although it is usual in the constructor. But these problems should not be due to that. I'm convinced it is because of the SetStyle(AllPaintingInWmPaint) style bit as it intercepts the WM_Erasebackground message and can play havoc with the transparency key. But as i have said none of those style bits are necessary here so you may just as well remove them.
 
Thanks for the comments, I removed the lines below from my test case above. (Note that this is not my actual application, just a demo I made up to exaggerate the problem and to allow me to try out some fixes. I get the same problem with a single picturebox).

VB.NET:
[SIZE=2]
[/SIZE][SIZE=2][COLOR=#008000]'Me.TransparencyKey = System.Drawing.Color.Empty
[/COLOR][/SIZE][SIZE=2][/SIZE][SIZE=2][COLOR=#008000]'Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
[/COLOR][/SIZE][SIZE=2][/SIZE][SIZE=2][COLOR=#008000]'Me.SetStyle(ControlStyles.UserPaint, True)
[/COLOR][/SIZE][SIZE=2][/SIZE][SIZE=2][COLOR=#008000]'Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
[/COLOR][/SIZE][SIZE=2][/SIZE][SIZE=2][COLOR=#008000]'Me.SetStyle(ControlStyles.SupportsTransparentBackColor, False)
[/COLOR][/SIZE][SIZE=2][/SIZE][SIZE=2][COLOR=#008000]'Me.UpdateStyles()
[/COLOR][/SIZE]

Unfortunately, no effect. I also edited the double buffering back in and it was about the same.

A friend of mine suggested taking a snapshot of the form, displaying it in a docked picture box over the top of the actual form. Do the operation, then remove the picturebox (that hid the chaos underneath). I will at least call this idea 'inventive', but it would only conceal the problem rather than fixing it.

If I could at least prevent or control the color of the 'transparent holes', that might be good enough for now, the holes re-appear if the window is moved too. I also tried painting on a background color, but the window appears before the graphics can draw. I also tried moving the window off the screen and then back on, same problem.

In googling around, I've found several examples of the same problem, so it seems I am not alone. I cant help thinking there is a simple fix to this, as Im sure I've seen other apps displaying pictureboxes etc. without these visual disturbances.
 
Right, a couple of possibilities here...

1. Set the forms opacity to zero in forms constructor. Use a timer component to slowly fade the form in incrementing the opacity in the tick event until it reaches 1.0 (opacity is a double) This may give the form a chance to paint before the holes become noticable.

2. Have a look into the LockWindowUpdate API. Essentially it tells a form to ignore any WM_PAINT messages that are sent to although the processing for the WM_PAINT message occurs. Then use the LockWindowUpdate API again to 'unlock' the window a WM_PAINT will be sent and the form should re-draw. This is a theory and could work but i'm not sure.
 
You sir (or madam) are a genius!

The following works very well, no flicker, no nothing.

VB.NET:
[SIZE=2]
[/SIZE][SIZE=2][COLOR=#0000ff]For[/COLOR][/SIZE][SIZE=2] i [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2] [/SIZE][SIZE=2][COLOR=#0000ff]Double[/COLOR][/SIZE][SIZE=2] = 1 [/SIZE][SIZE=2][COLOR=#0000ff]To[/COLOR][/SIZE][SIZE=2] 0 [/SIZE][SIZE=2][COLOR=#0000ff]Step[/COLOR][/SIZE][SIZE=2] -0.2
[/SIZE][SIZE=2][COLOR=#0000ff]Me[/COLOR][/SIZE][SIZE=2].Opacity = i
[/SIZE][SIZE=2][COLOR=#0000ff]Next
[/COLOR][/SIZE][SIZE=2][/SIZE][SIZE=2][COLOR=#0000ff]Me[/COLOR][/SIZE][SIZE=2].Hide()
t.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single
[/SIZE][SIZE=2][COLOR=#0000ff]Me[/COLOR][/SIZE][SIZE=2].Show()
[/SIZE][SIZE=2][COLOR=#0000ff]Me[/COLOR][/SIZE][SIZE=2].Refresh()
[/SIZE][SIZE=2][COLOR=#0000ff]For[/COLOR][/SIZE][SIZE=2] i [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2] [/SIZE][SIZE=2][COLOR=#0000ff]Double[/COLOR][/SIZE][SIZE=2] = 0 [/SIZE][SIZE=2][COLOR=#0000ff]To[/COLOR][/SIZE][SIZE=2] 1.0 [/SIZE][SIZE=2][COLOR=#0000ff]Step[/COLOR][/SIZE][SIZE=2] 0.2
[/SIZE][SIZE=2][COLOR=#0000ff]Me[/COLOR][/SIZE][SIZE=2].Opacity = i
[/SIZE][SIZE=2][COLOR=#0000ff]Next
[/COLOR][/SIZE]

Although it looks a little odd, hiding the form while its invisible, I spent quite some time getting this recipe right. All of the statements need to be there and in that sequence.

So... thanks to your creativity, there is a solution! Now I need to update the actual app and ship it! (I was beginning to think I might need to do a rewrite).

Thank you!
 
Just a little note about moving the form etc, when doing a lot of things with GDI+ in the IDE it runs really slow. But build into a release version and run it from the .exe and you will see a dramatic improvment.
 
Indeed.

In actual fact, the code can be simplified slightly further;

VB.NET:
[SIZE=2]
[/SIZE][SIZE=2][COLOR=#0000ff]Me[/COLOR][/SIZE][SIZE=2].Hide()
[/SIZE][SIZE=2][COLOR=#0000ff]Me[/COLOR][/SIZE][SIZE=2].Opacity = 0
t.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single
[/SIZE][SIZE=2][COLOR=#0000ff]Me[/COLOR][/SIZE][SIZE=2].Show()
[/SIZE][SIZE=2][COLOR=#0000ff]Me[/COLOR][/SIZE][SIZE=2].Refresh()
[/SIZE][SIZE=2][COLOR=#0000ff]Me[/COLOR][/SIZE][SIZE=2].Opacity = 1
[/SIZE]
 
Back
Top