Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

Picboxes, Rectangles, and Refresh

Posted on 2008-10-06
15
Medium Priority
?
539 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 6
15 Comments
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 22654015
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
ID: 22657242
hope you have done Form property : DoubleBuffering=TRUE
0
 

Author Comment

by:harthenry
ID: 22659177
Yes, I have tried double buffering.  The problem is reentrance
0
Efficient way to get backups off site to Azure

This user guide provides instructions on how to deploy and configure both a StoneFly Scale Out NAS Enterprise Cloud Drive virtual machine and Veeam Cloud Connect in the Microsoft Azure Cloud.

 

Author Comment

by:harthenry
ID: 22659278
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 86

Expert Comment

by:Mike Tomlinson
ID: 22663531
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
ID: 22686733
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
 

Author Comment

by:harthenry
ID: 22713672
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 86

Expert Comment

by:Mike Tomlinson
ID: 22715155
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
ID: 22720665
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 86

Expert Comment

by:Mike Tomlinson
ID: 22722593
Check my profile...
0
 

Author Comment

by:harthenry
ID: 22734635
OK - message sent.
0
 
LVL 86

Accepted Solution

by:
Mike Tomlinson earned 500 total points
ID: 22754011
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 86

Expert Comment

by:Mike Tomlinson
ID: 22791166
Hi Henry,

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

Featured Post

[Webinar] Lessons on Recovering from Petya

Skyport is working hard to help customers recover from recent attacks, like the Petya worm. This work has brought to light some important lessons. New malware attacks like this can take down your entire environment. Learn from others mistakes on how to prevent Petya like worms.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
Real-time is more about the business, not the technology. In day-to-day life, to make real-time decisions like buying or investing, business needs the latest information(e.g. Gold Rate/Stock Rate). Unlike traditional days, you need not wait for a fe…
Have you created a query with information for a calendar? ... and then, abra-cadabra, the calendar is done?! I am going to show you how to make that happen. Visualize your data!  ... really see it To use the code to create a calendar from a q…
In this video, Percona Director of Solution Engineering Jon Tobin discusses the function and features of Percona Server for MongoDB. How Percona can help Percona can help you determine if Percona Server for MongoDB is the right solution for …

636 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