Solved

Picboxes, Rectangles, and Refresh

Posted on 2008-10-06
15
506 Views
Last Modified: 2013-11-26
I want to refresh my screen (graphics0, without having to refresh the entire screen.

I am developing an application that has approx. 50 pictureboxes with gradient fill rectangles and a couple lines of text in each (the picture boxes, rectangles, text, etc are in a collection).  These picture boxes are about 100 wide by 50 high  not too big.  I am allowing the user to MouseDown and move the picture boxes anywhere he wants on the screen.  The problem I am having is when I enter the screen (activate)  or just RUN the program, it seems as though the only way I can get all of the 50 picture boxes on the screen is to implement the form_Paint routine.  The form_Paint routine will iterate through the loop of the dynamically created pictureboxes. This is very slow (takes about 2 seconds to generate and gives that flicker annoyance you see on the screen).  Once I have the picture boxes displayed, I can use the individual picturebox_Paint function for each picture box (via an overload upon dynamic substantiation of the control).

Here is the question  how do I get the picture boxes to refresh on the screen in the most time economical fashion/time (both upon Activation and during run)?   And then, how do you keep them refreshed without having to loop through each of the controls multiple times?

For example, below is the OnPaint for the form where the collection of approx 50 picture boxes are written to the screen.  Looking at this code, the myForm_paint function will fire approx 1750 times.  Yikes!  There has to be a better way?

  Private Sub myForm_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint

    Dim UI As UnitInfo

    Try
      For i = 1 To RectColorsAndWords.Count
        UI = RectColorsAndWords(i)
        PaintRectColorsAndWords(UI)
      Next
    Catch ex As Exception
    End Try

  End Sub

0
Comment
Question by:harthenry
  • 6
  • 6
15 Comments
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
How are you generating the Images in the PictureBoxes?...

In your PaintRectColorsAndWords() method, are you using CreateGraphics()?

If so, you should be using the "e.Graphics" supplied in EACH PictureBox.  Then they will update themselves without having to be explicitly told to "refresh" by calling your external method...
0
 
LVL 14

Expert Comment

by:rachitkohli
Comment Utility
hope you have done Form property : DoubleBuffering=TRUE
0
 

Author Comment

by:harthenry
Comment Utility
Yes, I have tried double buffering.  The problem is reentrance
0
 

Author Comment

by:harthenry
Comment Utility
Hello Idle Mind:
Yes, I am using the e.grapaics method.  However, in order for the graphics to appear on the screen for the first time, they need to be "painted".  IE: The only way I have found to do this is through overloading the PAINT method (for the form) or just use the On_Paint method.  The trouble you run into is the reentrance issue.  When using a "paint" method via the loop I presented in the first post, you first paint box 1,  then box 1 and 2, then box 1,2,3, and so on.....  (this is the way the paint method works, anytime there is a change to the screen, the Paint method is "fired".   Here is a snippet of my code

'' =========================
the basic structure of UnitInfo is something like
  Private Structure RectAndStuff
    Dim X1 As Long
    Dim X2 As Long
    Dim Y1 As Long
    Dim Y2 As Long
    Dim cForeColor As Long
    Dim cBackColor As Long
    Dim cBlendColor As Long
    Dim cGraphForeColor1 As Long
    Dim cGraphForeColor2 As Long
    Dim myRectangle As Rectangle
    Dim myPictureBox As PictureBox
    Dim ..... a few other things
  End Structure
'' =========================

  Private Sub PaintRectColorsAndWords(UI as RectAndStuff)
    Dim i As Integer

    ' the brush color for a gradient fill
    Dim lgBrush As Drawing2D.LinearGradientBrush = Nothing

    '  a series of colors used for the rectangle
    Dim cBackColor As Color
    Dim cForeColor As Color
    Dim cBlendColor As Color
    Dim cGraphForeColor1 As Color
    Dim cGraphForeColor2 As Color
    Dim snFontSize As Integer = cGridSize

    Dim myGraphics As Graphics

    Try

        '  change the LONG value of a color to a COLOR type
        With UI
          cBackColor = GetARGBfromUint(UI.cBackColor)
          cForeColor = GetARGBfromUint(UI.cForeColor)
          cBlendColor = GetARGBfromUint(UI.cBlendColor)
          cGraphForeColor1 = GetARGBfromUint(UI.cGraphForeColor1)
          cGraphForeColor2 = GetARGBfromUint(UI.cGraphForeColor2)
        End With

        '  if the height or width of the rectangle is 0 -- get OUT!
        If UI.myRectangle.Height = 0 Or UI.myRectangle.Width = 0 Then

        Else
          myGraphics = Graphics.FromHwnd(hwnd:=UI.myPictureBox.Handle)
          UI.myPictureBox.Visible = True
          UI.myPictureBox.BringToFront()
          lgBrush = New Drawing2D.LinearGradientBrush(UI.myRectangle, cBackColor, cForeColor, _
                Drawing2D.LinearGradientMode.BackwardDiagonal)
          myGraphics.FillRectangle(lgBrush, UI.myRectangle)
          lgBrush.Dispose()

          'Font we'll use
          Dim drawFont As New Drawing.Font("Tahoma", snFontSize, FontStyle.Bold)
          'Brush used to write the text supported with
          'different colors
          Dim myBrush1 As New Drawing.SolidBrush(cGraphForeColor1)

          'Check FormatFlags Enums to see different drawing styles you can use.
          Dim drawFormat As New StringFormat()
          drawFormat.FormatFlags = StringFormatFlags.NoFontFallback

          Dim drawString As String = UI.sUnitName
          myGraphics.DrawString(drawString, drawFont, myBrush1, 0, 0, drawFormat)

          Dim drawString1 As String = UNITBUtoString(UI.bUnitBU)

          Dim myFont As New Drawing.Font("Tahoma", snFontSize)
          Dim myFontBold As New Drawing.Font("Tahoma", snFontSize, FontStyle.Bold)
          Dim StringSize As New SizeF
          Dim myBrush2 As New Drawing.SolidBrush(cGraphForeColor2)

          StringSize = myGraphics.MeasureString(UNITBUtoString(UI.bUnitBU), myFont)

          myGraphics.DrawString(drawString1, drawFont, myBrush2, _
              UI.X2 - UI.X1 - StringSize.Width - 2, UI.Y2 - UI.Y1 - StringSize.Height, drawFormat)

          myBrush1.Dispose()
          myBrush2.Dispose()
          drawFormat.Dispose()
          myFont.Dispose()
          myFontBold.Dispose()
          drawFont.Dispose()

        End If

    Catch ex As Exception

    End Try

  End Sub

0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
You said:

    "Once I have the picture boxes displayed, I can use the individual picturebox_Paint function for each picture box (via an overload upon dynamic substantiation of the control)."

    "However, in order for the graphics to appear on the screen for the first time, they need to be "painted"."

This doesn't jive with my experiences...if you have the INDIVIDUAL Paint() events for each PictureBox working properly...then you don't need any additional code to make them display properly the "first time".

If you have properly wired up the PictureBoxes for painting themselves with their Paint() events then try this:

    Public Class Form1

        Private Sub Form1_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
            For Each ras As RectAndStuff In RectColorsAndWords
                ras.myPictureBox.Refresh()
            Next
        End Sub

    End Class

Otherwise you have most likely added the Paint() Handlers AFTER the PictureBoxes have already been displayed.  If that is the case, then code like above will force them all to refresh...
0
 

Author Comment

by:harthenry
Comment Utility
Hello Idle Mind:
Thanks for the quick response.  Let me write up a small code snippet and paste it in here to help us work this out.  Give me a little bit.

Thanks,
HH
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Author Comment

by:harthenry
Comment Utility
I am adding a ZIP file of code here as an example.  The objective is to dynamically add pictureboxes and inside the picture box is the rectangle.  I have approx 25 pictureboxes dynamically created while adding an "Add Handler" to the "paint" part of the code.  If, I were to place the 25 paint items directly into the On_Paint event of the form (like suggested), yes, the pic boxes will paint.  However, (and this is probably where you can help me), I do not know how many pic boxes I will have until after the code is run.  IE: dynamic creation of pic boxes.  You will also see in the code that I have overloaded the mouse functions, which gives the user the ability to drag, drop, etc. the picture boxes around on the screen.  

Thanks,
HH

=== Note, I am trying to upload a ZIP file with the demo code.  I am getting a message "The extension of one of your files is not allowed...."  eventhough the allowable files are ....txt, xls, and .zip.    The zip file has a small project in it.

Can you help me on that one
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
Rename the files that it doesn't like so that you can upload them...just add .txt to the end of any files it doesn't like.
0
 

Author Comment

by:harthenry
Comment Utility
Not having any success upload a ZIP file.

I think what is happening is that I can only upload a zip file that has bmp doc gif jpeg log mdb pdf txt in it.  I have renamed a number of files, but I keep getting the message

The extension of one or more files in the archive is not in the list of allowed extensions:

Perhaps there is some other way I can get you the ZIP file of the project/solution sample
Thanks,
HH
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
Check my profile...
0
 

Author Comment

by:harthenry
Comment Utility
OK - message sent.
0
 
LVL 85

Accepted Solution

by:
Mike Tomlinson earned 125 total points
Comment Utility
Hi Henry,

I've fixed your UserControl Painting issues with the code below.

Note that I have DELETED the ctrlFrame_Paint() code.

I have added two lines to the SetupRectangles() method after the "Controls.Add(.myPicBox)" entry:

            Controls.Add(.myPicBox)
            AddHandler .myPicBox.Paint, AddressOf picBox_Paint
            .myPicBox.Tag = UI

And then moved all the Paint() code to the picBox_Paint() method.  Each PictureBox draws ITSELF now.

Note that the appropriate UnitInfo data is retrieved from the PictureBoxes Tag() property and we are correctly using e.Graphics():

    Private Sub picBox_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
        Dim UI As UnitInfo = sender.tag
        Dim myGraphics As Graphics = e.Graphics

Could you explain what the code in the Form itself is supposed to be doing?  It looks like you want to be able to drag each individual PictureBox around...is that the case?
Public Class ctrlFrame
 

    Dim bGetOut As Boolean
 

    Public Event picMouseDown(ByVal iButton As Integer, ByVal lX As Long, ByVal lY As Long, ByVal iUnitNum As Integer)

    Public Event picMouseUp()

    Public Event picMouseMove(ByVal lX As Long, ByVal lY As Long)
 

    Dim bMoveIT As Boolean = False

    Dim iCurrentUnitBeingMoved As Integer
 

    ' the TempRecs contain the following

    'Collection name

    'X1 As Long

    'X2 As Long

    'Y1 As Long

    'Y2 As Long

    'cForeColor 

    'cBackColor 

    'cBlendColor 

    'cGraphForeColor1 

    'cGraphForeColor2 
 

    Dim TempRecs() As String = {"0,1,100,1,50,black,white,blue,yellow,brown", "1,125,225,1,50,white,blue,yellow,brown,black", _

                                "2,1,100,70,120,black,yellow,white,blue,brown", "3,125,225,70,120,blue,yellow,brown,black,white", _

                                "0,1,100,1,50,black,white,blue,yellow,brown", "1,125,225,1,50,white,blue,yellow,brown,black", _

                                "2,1,100,70,120,black,yellow,white,blue,brown", "3,125,225,70,120,blue,yellow,brown,black,white", _

                                "0,1,100,1,50,black,white,blue,yellow,brown", "1,125,225,1,50,white,blue,yellow,brown,black", _

                                "2,1,100,70,120,black,yellow,white,blue,brown", "3,125,225,70,120,blue,yellow,brown,black,white", _

                                "0,1,100,1,50,black,white,blue,yellow,brown", "1,125,225,1,50,white,blue,yellow,brown,black", _

                                "2,1,100,70,120,black,yellow,white,blue,brown", "3,125,225,70,120,blue,yellow,brown,black,white", _

                                "0,1,100,1,50,black,white,blue,yellow,brown", "1,125,225,1,50,white,blue,yellow,brown,black", _

                                "2,1,100,70,120,black,yellow,white,blue,brown", "3,125,225,70,120,blue,yellow,brown,black,white", _

                                "0,1,100,1,50,black,white,blue,yellow,brown", "1,125,225,1,50,white,blue,yellow,brown,black", _

                                "2,1,100,70,120,black,yellow,white,blue,brown", "3,125,225,70,120,blue,yellow,brown,black,white", _

                                "0,1,100,1,50,black,white,blue,yellow,brown", "1,125,225,1,50,white,blue,yellow,brown,black", _

                                "2,1,100,70,120,black,yellow,white,blue,brown", "3,125,225,70,120,blue,yellow,brown,black,white", _

                                "0,1,100,1,50,black,white,blue,yellow,brown", "1,125,225,1,50,white,blue,yellow,brown,black", _

                                "2,1,100,70,120,black,yellow,white,blue,brown", "3,125,225,70,120,blue,yellow,brown,black,white"}

    Public iCount As Long
 

    Public Structure UnitInfo

        Dim X1 As Long

        Dim X2 As Long

        Dim Y1 As Long

        Dim Y2 As Long

        Dim cForeColor As Color

        Dim cBackColor As Color

        Dim cBlendColor As Color

        Dim cGraphForeColor1 As Color

        Dim cGraphForeColor2 As Color

        Dim myRectangle As Rectangle

        Dim myPicBox As PictureBox

    End Structure
 

    Public RectangleProfile As New Collection
 

    Public Sub New()

        ' This call is required by the Windows Form Designer.

        InitializeComponent()
 

        ' Add any initialization after the InitializeComponent() call.

    End Sub
 

    Private Function SetupRectangles(ByVal sName As String, _

                                    ByVal X1 As Long, ByVal X2 As Long, ByVal Y1 As Long, ByVal Y2 As Long, _

                                    ByVal ForeColor As Color, _

                                    ByVal BackColor As Color, _

                                    ByVal BlendColor As Color, _

                                    ByVal GraphForeColor1 As Color, _

                                    ByVal GraphForeColor2 As Color)
 
 

        Dim UI As New UnitInfo
 

        Dim lWidth As Long

        Dim lHeight As Long

        Dim snFontSize As Single = 10
 

        lWidth = X2 - X1

        lHeight = Y2 - Y1
 

        With UI

            .X1 = X1

            .X2 = X2

            .Y1 = Y1

            .Y2 = Y2

            .cBackColor = BackColor

            .cBlendColor = ForeColor

            .cForeColor = BlendColor

            .cGraphForeColor1 = GraphForeColor1

            .cGraphForeColor2 = GraphForeColor2

            .myRectangle = New Rectangle(0, 0, .X2 - .X1, .Y2 - .Y1)

            .myPicBox = New PictureBox

            .myPicBox.Name = "picBox" & sName

            .myPicBox.Left = X1

            .myPicBox.Top = Y1

            .myPicBox.Width = X2 - X1

            .myPicBox.Height = Y2 - Y1

            Controls.Add(.myPicBox)

            AddHandler .myPicBox.Paint, AddressOf picBox_Paint

            .myPicBox.Tag = UI

        End With
 

        RectangleProfile.Add(UI, sName)

    End Function
 

    Private Sub picBox_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)

        Dim UI As UnitInfo = sender.tag

        Dim myGraphics As Graphics = e.Graphics

        Dim lgBrush As Drawing2D.LinearGradientBrush = Nothing

        Dim snFontSize As Integer = 10

        

        If UI.myRectangle.Height >= 0 AndAlso UI.myRectangle.Width > 0 Then

            myGraphics.DrawRectangle(Pens.Black, UI.myRectangle)

            lgBrush = New Drawing2D.LinearGradientBrush(UI.myRectangle, UI.cBackColor, UI.cForeColor, Drawing2D.LinearGradientMode.BackwardDiagonal)

            myGraphics.FillRectangle(lgBrush, UI.myRectangle)
 

            'Font we'll use 

            Dim drawFont As New Drawing.Font("Tahoma", snFontSize, FontStyle.Bold)

            'Brush used to write the text supported with 

            'different colors 

            Dim myBrush1 As New Drawing.SolidBrush(UI.cGraphForeColor1)

            'Check FormatFlags Enums to see different drawing styles 

            'you can use.

            Dim drawFormat As New StringFormat()

            drawFormat.FormatFlags = StringFormatFlags.NoFontFallback

            Dim drawString As String = "Top"

            myGraphics.DrawString(drawString, drawFont, myBrush1, 0, 0, drawFormat)

            Dim drawString1 As String = "Bot"

            Dim myFont As New Drawing.Font("Tahoma", snFontSize)

            Dim myFontBold As New Drawing.Font("Tahoma", snFontSize, FontStyle.Bold)

            Dim myBrush2 As New Drawing.SolidBrush(UI.cGraphForeColor2)

            Dim StringSize As SizeF = myGraphics.MeasureString("Bot", myFont)

            myGraphics.DrawString(drawString1, drawFont, myBrush2, _

                  UI.X2 - UI.X1 - StringSize.Width - 2, UI.Y2 - UI.Y1 - StringSize.Height, drawFormat)
 

            myBrush1.Dispose()

            myBrush2.Dispose()

            drawFormat.Dispose()

            myFont.Dispose()

            myFontBold.Dispose()

            drawFont.Dispose()

            lgBrush.Dispose()

        End If

    End Sub
 

  Public Sub DrawRectangles(ByVal sFileName As String)

        ' open sFileName as input as #1

        ' however I am not using is this way, I am using constant Variables TempRecs

        ' as shown above
 

        RectangleProfile.Clear()
 

        Dim i As Int16

        Dim sSplit() As String
 

        ' the TempRecs contain the following

        'Collection name

        'X1 As Long

        'X2 As Long

        'Y1 As Long

        'Y2 As Long

        'cForeColor 

        'cBackColor 

        'cBlendColor 

        'cGraphForeColor1 

        'cGraphForeColor2 

        Dim X1, X2, Y1, Y2 As Long
 

        For i = 0 To TempRecs.Count - 1

            Try

                X1 = (i \ 3) * 50

                X2 = X1 + 45

                Y1 = (i Mod 3) * 50

                Y2 = Y1 + 45
 

                sSplit = Split(TempRecs(i), ",")

                SetupRectangles(Format(i), X1, X2, Y1, Y2, _

                                 Color.FromName(sSplit(5)), Color.FromName(sSplit(6)), _

                                 Color.FromName(sSplit(7)), Color.FromName(sSplit(8)), Color.FromName(sSplit(9)))
 

            Catch ex As Exception
 

            End Try

        Next

  End Sub
 

  Private Sub ctrlFrame_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    DrawRectangles("")

  End Sub
 

    Private Sub ctrlFrame_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown

        Dim i As Integer
 

        If e.Button = MouseButtons.Left Then

            For i = 1 To RectangleProfile.Count

                If RectangleProfile(i).myrectangle.contains(New Point(e.X, e.Y)) Then

                    bMoveIT = True

                    RaiseEvent picMouseDown(MouseButtons.Left, e.X, e.Y, i)

                    Exit For

                End If

            Next

        End If

    End Sub
 

    Private Sub ctrlFrame_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove

        If bMoveIT Then

            RaiseEvent picMouseMove(e.X, e.Y)

        End If

    End Sub
 

    Private Sub ctrlFrame_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp

        bMoveIT = False

        RaiseEvent picMouseUp()

    End Sub
 

End Class

Open in new window

0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
Hi Henry,

Did that help you out at all?...
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

In my previous article (http://www.experts-exchange.com/Programming/Languages/.NET/.NET_Framework_3.x/A_4362-Serialization-in-NET-1.html) we saw the basics of serialization and how types/objects can be serialized to Binary format. In this blog we wi…
It’s quite interesting for me as I worked with Excel using vb.net for some time. Here are some topics which I know want to share with others whom this might help. First of all if you are working with Excel then you need to Download the Following …
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now