none
Question about graphic buffers RRS feed

  • Question

  • With the help of you folks out here I am able to send graphics to a buffer to draw on a picturebox etc. Now I would like to set up another picturebox and send separate graphics to that.  I have a routine called ResizeBuffer which takes care of everything.  Do I need to set up another routine and rename it say resizeBuffer1 and do I need to change the name of backBuffer also to maybe backBuffer1 ?? If that is the case then that just seems to make me have a lot of duplicate code since some of the subs I have write to pictureBox1 but sometimes I want to write to pictureBox2.  Perhaps there are some tricks of the trade here I will leave it to you experts <S>

    Using

    g AsGraphics = Graphics.FromImage(backbuffer),

    Thanks,

    Les

    Monday, January 20, 2020 12:57 AM

Answers

  • Hi Les,

    Boy it is so hard to describe.

    "Do I need to set up another routine and rename it say resizeBuffer1 "

    No you dont need to do that??? However I still dont know for sure how you are drawing right now. So you may need to make simple code examples to explain.

    Here is an example of calling a sub routine and passing the graphics handle to the routine. In the picturebox1 paint event the DrawStringFitToRect sub is called with e.graphics. In the subroutine the drawing is done on the graphics surface and then execution of the code returns to the paint event. Now a second text is drawn by calling again with different properties.

    In addition the picturebox2 paint event calls the same sub and draws some more text on picturebox2 e.graphics.

    So no where is any buffer made or named by us??? What do you mean by buffer? The graphics e.graphics is just a temp reference to a memory area we draw into. The system makes e.graphics for us to draw on the picturebox or control. The system gives us e.graphics to draw upon when it is ready or we can use invalidate to force a paint event. The drawing we do on e.graphics shows up on the computer screen when the system is ready. We dont have to do anything but draw on e.graphics.

    In the paint event we redraw the entire scene every time the event is called. It can happen many times a second.

    If we want to save an image, NOW we make new memory bitmap and draw on that with our subroutine using creategraphics for the graphics drawing surface to a bitmap. Then we can make the memory bitmap we drew on using the graphics surface reference a picturebox.image or we can save it to disc. We can draw the bitmap image on a picturebox e.graphics at say half size. We can draw on a memory bitmap as say half size and rotated. Then save the bitmap to disc and show in picturebox3.backgroundimage.

    So the bitmap is the memory area and the graphics surface is a reference to draw on the bitmap. Its the bitmap that becomes permanent. The graphics is a temporary link to the bitmap or memory area.

    And on and on...

    Here is a fun example that uses a sub routine to draw text I think this is what you ask? See how the paint events call the sub routine passing e.graphics? The example makes the controls just copy and paste the code into an empty form. Change the form name as required.

    'fit text to rotated rectangle using sub routine from paint event
    Imports System.Drawing.Drawing2D
    
    Public Class Form3
        Private WithEvents PictureBox1 As New PictureBox With {.Parent = Me,
            .Location = New Point(50, 10), .Size = New Size(200, 130), .BackColor = Color.White}
        Private WithEvents PictureBox2 As New PictureBox With {.Parent = Me,
            .Location = New Point(50, 160), .Size = New Size(200, 130), .BackColor = Color.White}
    
        Private the_rect As Rectangle
        Private the_font As Font
        Private the_rotation, the_padding As Integer
    
        Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            ClientSize = New Size(300, 300)
            BackColor = Color.Black
    
        End Sub
    
        Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
    
            the_rect = New Rectangle(0, 30, 180, 40)
            the_font = New Font("Arial", the_rect.Height, FontStyle.Bold, GraphicsUnit.Pixel)
            the_rotation = -20
            the_padding = 5
    
            DrawStringFitToRect(e.Graphics, the_rect, "tommytwotrain", the_font,
                                Color.SkyBlue, Color.MidnightBlue, Color.White, Color.Black,
                                the_rotation, the_padding)
    
            the_rect = New Rectangle(70, 80, 120, 50)
            the_font = New Font("Arial", 20, FontStyle.Bold, GraphicsUnit.Pixel)
            the_rotation = 0
            the_padding = 5
    
            DrawStringFitToRect(e.Graphics, the_rect, "tommytwotrain", the_font,
                                Color.White, Color.White, Color.Black, Color.Black,
                                the_rotation, the_padding)
    
        End Sub
    
        Private Sub PictureBox2_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox2.Paint
    
            DrawStringFitToRect(e.Graphics, New Rectangle(10, 30, 180, 80), "tommytwotrain",
                                New Font("Arial", the_rect.Height, FontStyle.Bold, GraphicsUnit.Pixel),
                                Color.White, Color.Goldenrod, Color.Red, Color.Black,
                                10, 0)
    
        End Sub
    
        Private Sub DrawStringFitToRect(g As Graphics, rect As Rectangle, theText As String, theFont As Font, RectFillColor As Color, RectOutlineColor As Color, TextFillColor As Color, TextOutlineColor As Color, rotation As Single, padding As Single)
    
            'draw the string with font fit to rect
            If theText.Trim IsNot "" Then
                g.SmoothingMode = SmoothingMode.AntiAlias
    
                Using sf As New StringFormat,
                text_path As New GraphicsPath,
                rect_path As New GraphicsPath
    
                    sf.Alignment = StringAlignment.Center
                    sf.LineAlignment = StringAlignment.Center
                    text_path.AddString(theText, theFont.FontFamily, FontStyle.Bold, rect.Height, New PointF(0, 0), sf)
                    rect_path.AddRectangle(rect)
    
                    Dim rectf As RectangleF = text_path.GetBounds()
                    Dim pts() As PointF = {New PointF(rect.Left + padding, rect.Top + padding), New PointF(rect.Right - padding, rect.Top + padding), New PointF(rect.Left + padding, rect.Bottom - padding)}
    
                    Using mx As Matrix = New Matrix(rectf, pts)
                        text_path.Transform(mx)
                        mx.Reset()
                        mx.RotateAt(rotation, New Point(CInt(rect.X + (rect.Width / 2)), CInt(rect.Y + (rect.Height / 2))))
                        text_path.Transform(mx)
                        rect_path.Transform(mx)
                    End Using
    
                    g.SmoothingMode = SmoothingMode.AntiAlias
    
                    g.FillPath(New SolidBrush(RectFillColor), rect_path)
                    g.DrawPath(New Pen(RectOutlineColor, 1), rect_path)
    
                    g.FillPath(New SolidBrush(TextFillColor), text_path)
                    g.DrawPath(New Pen(TextOutlineColor, 1), text_path)
    
                End Using
            End If
        End Sub
    
    End Class

    Monday, January 20, 2020 3:32 AM

All replies

  • Hi

    Using one Sub routine is only capable of handling what it is designed to handle. In other words, if you have made the Sub to take the dependent items as parameters, and the code within to deal with the incoming data - then loosely speaking, you could use it for multiple items.

    It is exactly the same process when you make (say) a Function that is called from many places in the code, perhaps each call passing a different set of parameter (Optional parameters perhaps)

    *

    As for the buffers - one or two or several? That depends on your needs - if they are one time use where you use a buffer and then dispose, well, that might mean that you could reuse it for a second (or several) times just by clearing/refilling. However, any use of arrays may need special care in that they can be very memory hungry if re-dimensioned over and over (in such cases it may be better to just dispose of each one after use and create another.)

    Without seeing the code, it is virtually impossible to advise further (the above is just guessing)


    Regards Les, Livingston, Scotland

    Monday, January 20, 2020 2:47 AM
  • Hi Les,

    Boy it is so hard to describe.

    "Do I need to set up another routine and rename it say resizeBuffer1 "

    No you dont need to do that??? However I still dont know for sure how you are drawing right now. So you may need to make simple code examples to explain.

    Here is an example of calling a sub routine and passing the graphics handle to the routine. In the picturebox1 paint event the DrawStringFitToRect sub is called with e.graphics. In the subroutine the drawing is done on the graphics surface and then execution of the code returns to the paint event. Now a second text is drawn by calling again with different properties.

    In addition the picturebox2 paint event calls the same sub and draws some more text on picturebox2 e.graphics.

    So no where is any buffer made or named by us??? What do you mean by buffer? The graphics e.graphics is just a temp reference to a memory area we draw into. The system makes e.graphics for us to draw on the picturebox or control. The system gives us e.graphics to draw upon when it is ready or we can use invalidate to force a paint event. The drawing we do on e.graphics shows up on the computer screen when the system is ready. We dont have to do anything but draw on e.graphics.

    In the paint event we redraw the entire scene every time the event is called. It can happen many times a second.

    If we want to save an image, NOW we make new memory bitmap and draw on that with our subroutine using creategraphics for the graphics drawing surface to a bitmap. Then we can make the memory bitmap we drew on using the graphics surface reference a picturebox.image or we can save it to disc. We can draw the bitmap image on a picturebox e.graphics at say half size. We can draw on a memory bitmap as say half size and rotated. Then save the bitmap to disc and show in picturebox3.backgroundimage.

    So the bitmap is the memory area and the graphics surface is a reference to draw on the bitmap. Its the bitmap that becomes permanent. The graphics is a temporary link to the bitmap or memory area.

    And on and on...

    Here is a fun example that uses a sub routine to draw text I think this is what you ask? See how the paint events call the sub routine passing e.graphics? The example makes the controls just copy and paste the code into an empty form. Change the form name as required.

    'fit text to rotated rectangle using sub routine from paint event
    Imports System.Drawing.Drawing2D
    
    Public Class Form3
        Private WithEvents PictureBox1 As New PictureBox With {.Parent = Me,
            .Location = New Point(50, 10), .Size = New Size(200, 130), .BackColor = Color.White}
        Private WithEvents PictureBox2 As New PictureBox With {.Parent = Me,
            .Location = New Point(50, 160), .Size = New Size(200, 130), .BackColor = Color.White}
    
        Private the_rect As Rectangle
        Private the_font As Font
        Private the_rotation, the_padding As Integer
    
        Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            ClientSize = New Size(300, 300)
            BackColor = Color.Black
    
        End Sub
    
        Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
    
            the_rect = New Rectangle(0, 30, 180, 40)
            the_font = New Font("Arial", the_rect.Height, FontStyle.Bold, GraphicsUnit.Pixel)
            the_rotation = -20
            the_padding = 5
    
            DrawStringFitToRect(e.Graphics, the_rect, "tommytwotrain", the_font,
                                Color.SkyBlue, Color.MidnightBlue, Color.White, Color.Black,
                                the_rotation, the_padding)
    
            the_rect = New Rectangle(70, 80, 120, 50)
            the_font = New Font("Arial", 20, FontStyle.Bold, GraphicsUnit.Pixel)
            the_rotation = 0
            the_padding = 5
    
            DrawStringFitToRect(e.Graphics, the_rect, "tommytwotrain", the_font,
                                Color.White, Color.White, Color.Black, Color.Black,
                                the_rotation, the_padding)
    
        End Sub
    
        Private Sub PictureBox2_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox2.Paint
    
            DrawStringFitToRect(e.Graphics, New Rectangle(10, 30, 180, 80), "tommytwotrain",
                                New Font("Arial", the_rect.Height, FontStyle.Bold, GraphicsUnit.Pixel),
                                Color.White, Color.Goldenrod, Color.Red, Color.Black,
                                10, 0)
    
        End Sub
    
        Private Sub DrawStringFitToRect(g As Graphics, rect As Rectangle, theText As String, theFont As Font, RectFillColor As Color, RectOutlineColor As Color, TextFillColor As Color, TextOutlineColor As Color, rotation As Single, padding As Single)
    
            'draw the string with font fit to rect
            If theText.Trim IsNot "" Then
                g.SmoothingMode = SmoothingMode.AntiAlias
    
                Using sf As New StringFormat,
                text_path As New GraphicsPath,
                rect_path As New GraphicsPath
    
                    sf.Alignment = StringAlignment.Center
                    sf.LineAlignment = StringAlignment.Center
                    text_path.AddString(theText, theFont.FontFamily, FontStyle.Bold, rect.Height, New PointF(0, 0), sf)
                    rect_path.AddRectangle(rect)
    
                    Dim rectf As RectangleF = text_path.GetBounds()
                    Dim pts() As PointF = {New PointF(rect.Left + padding, rect.Top + padding), New PointF(rect.Right - padding, rect.Top + padding), New PointF(rect.Left + padding, rect.Bottom - padding)}
    
                    Using mx As Matrix = New Matrix(rectf, pts)
                        text_path.Transform(mx)
                        mx.Reset()
                        mx.RotateAt(rotation, New Point(CInt(rect.X + (rect.Width / 2)), CInt(rect.Y + (rect.Height / 2))))
                        text_path.Transform(mx)
                        rect_path.Transform(mx)
                    End Using
    
                    g.SmoothingMode = SmoothingMode.AntiAlias
    
                    g.FillPath(New SolidBrush(RectFillColor), rect_path)
                    g.DrawPath(New Pen(RectOutlineColor, 1), rect_path)
    
                    g.FillPath(New SolidBrush(TextFillColor), text_path)
                    g.DrawPath(New Pen(TextOutlineColor, 1), text_path)
    
                End Using
            End If
        End Sub
    
    End Class

    Monday, January 20, 2020 3:32 AM
  • Hi Leshay,

    Well the graphics is not one time use for sure.  I see that TTT has also responded with some code.  Let me pick through that and get back here.

    Thanks

    Monday, January 20, 2020 4:56 AM
  • Hi Tommy,

    First of all Happy New Year.  You are like a big time graphics guru out here!! <S>  Let me study your example and if need be Tommy I will try to put together a little sample as to what I am doing.

    Thanks,

    Les

    Monday, January 20, 2020 4:58 AM
  • Hi,

    Did you resolve the issue? If you have resolved the issue then please mark the post or posts that helped you as The Answer using the Mark as Answer link at the bottom of the post. Marking answers will help other community members find solutions in the future.

    Best Regards,

    Julie


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, January 20, 2020 9:46 AM
    Moderator
  • Hey Tommy,

    I tried running the code in your sample and have some problems.  On my form3 I have placed picturebox1 and picturebox2.  When I run it spots all the lines in your code that have mention to either picturebox1 or picturebox2??  I pasted your code into the load event of the form3?? Is that perhaps the issue?

    Am I doing something wrong??

    Les

    Monday, January 20, 2020 7:08 PM
  • Hi

    Try pasting Tommys code over the |Load event block. Tommys code already includes a Load event block.


    Regards Les, Livingston, Scotland

    Monday, January 20, 2020 7:12 PM
  • Hi Leshay,

    I will try that now.  So place Tommy code over the load event of form3.

    BRB thx Leshay

    Monday, January 20, 2020 7:23 PM
  • Hi Leshay,

    Okay I tried your suggestion and that appeared to clear up the initial errors now I have this.


    Severity


    Code


    Description


    Project


    File


    Line


    Suppression State


    Warning


    BC40046


    class 'Form3' and partial class 'Form3' conflict in namespace 'WindowsApp7', but are being merged because one of them is declared partial.


    WindowsApp7


    C:\Users\Les Fernandez\source\repos\WindowsApp7\WindowsApp7\Form1.vb


    4


    Active

    I am stepping out for a while but will check back later thanks for your help

    Monday, January 20, 2020 7:33 PM
  • Hi

    I don't want to interfere with Tommys contributions, but I suggest you make a copy of your original code in Form3 and then replace ALL of your Form3 code with Tommys Form3 code and try that.

    There are always issues when copy/pasting code from a forum into existing code.

    If that doesn't help, I'll leave it for Tommy.


    Regards Les, Livingston, Scotland

    Monday, January 20, 2020 7:47 PM
  • Hi

    I don't want to interfere with Tommys contributions, but I suggest you make a copy of your original code in Form3 and then replace ALL of your Form3 code with Tommys Form3 code and try that.

    There are always issues when copy/pasting code from a forum into existing code.

    If that doesn't help, I'll leave it for Tommy.


    Regards Les, Livingston, Scotland

    Yes Les is correct.

    Do not add picturebox controls!!! They are made by the first four lines of code.

    Paste the entire code and change the form name if needed.

    I normally paste it between the existing form:

      Public Class Form6


        'paste the new code and remove these two lines to change the form name
        Public Class Form3

            'this is the new code here

        End Sub   'remove


     
      End Sub


    Monday, January 20, 2020 9:40 PM
  • Hey Tommy as always your suggestion worked. What I did was when I had my original form I changed the form1 instance to form3 to agree with your code but apparently it did not. When I retyped your form3 to form1 it worked !!!  Your examples in the past has always been very helpful to me learning about this area graphics. I thank you for you help and after I have reviewed your code and if I have further questions I will give you a yell.

    Thanks

    Les

    Tuesday, January 21, 2020 1:20 AM
  • Hi Tommy,

    Your code although it is a lot more complex then I need at the moment has been very helpful and has extended some additional information to graphics that I knew nothing about.  What I am doing now is creating a very simple code snippet so I can now show you what I would like to implement into my coding.  I will send it sometime tomorrow since its now 3am in the morning here in NY <S> I love this stuff!! You know coming from MS DOS then to MS Professional Basic then Quick Basic which was so much better then the priors now that I am digging into vb.net 2019 I can not believe how much more powerful this language has been enhanced too.

    Talk soon,

    Les

    Tuesday, January 21, 2020 8:01 AM
  • BTW I meant to tell you I see you started your programming with Fortran. That was what I taught myself back in the early 70's in college. It was Fortran IV and no disk drives we used Hollerith cars, yikes how painful that was <S>
    Tuesday, January 21, 2020 8:04 AM
  • BTW I meant to tell you I see you started your programming with Fortran. That was what I taught myself back in the early 70's in college. It was Fortran IV and no disk drives we used Hollerith cars, yikes how painful that was <S>

     

    "we used Hollerith cars"

    Is that keypunch cards?

    That was fun. Spend hours making your 20 line card deck for computing pi ... run through the card reader and go in the waiting room, and wait.... 20-30 minutes later a little window would open and a printout would be thrown out. Jump up.. is it mine??? yes Joy !!...  open up the 3 page  printout and basically all it would say is "syntax error" job dumped.

    Back to the cards. Search for typos... repeat...


    Tuesday, January 21, 2020 10:37 AM
  • Yes Keypunch cards and like you said you had to wait for the data center to run your program and most of the time the center took their time in getting it back to you only to find out you had a syntax error. I remember a few of us got so mad at the center we wrapped up a form feed inside a loop and were they in for a surprise when they ran that. There printer if I remember ran 300-400 pages per minute. We were hoping that would teach them a lesson when your professor gives you x amount of time to finish your program and then the data center holds it up. Those forms back then were large they had alternating horizontal bars on the paper and was very wide <S>. Just a quick story. BTW with the help of your code and some playing I may have found a way to doing what I wanted. I realize now that I can pass a buffer to a routine which is important. See Tommy with what I am doing is I am using buffer1 to store a series of equation lines and I am using buffer2 so that if the end user wants to see formulas for solving the equation they click on help and up pops the second buffer which is a separate entity to the first buffer. Like you said earlier a lot of times things are difficult to explain. So I have buffer1 for equation stuff and buffer2 for help stuff.

    If I come across and additional problems I will be posting again looking for you <S>

    Thanks Les

    Wednesday, January 22, 2020 3:24 AM