Creating a class holding some graphics?
Creating a class holding some graphics?
Creating a class holding some graphics?
Creating a class holding some graphics?
Creating a class holding some graphics?
Creating a class holding some graphics? Creating a class holding some graphics? Creating a class holding some graphics? Creating a class holding some graphics? Creating a class holding some graphics? Creating a class holding some graphics? Creating a class holding some graphics? Creating a class holding some graphics?
Creating a class holding some graphics? Creating a class holding some graphics?
Creating a class holding some graphics?
Go Back  Xtreme Visual Basic Talk > > > Creating a class holding some graphics?


Reply
 
Thread Tools Display Modes
  #1  
Old 01-12-2011, 10:43 PM
WhatsMyUsername's Avatar
WhatsMyUsername WhatsMyUsername is offline
Regular
 
Join Date: Jan 2011
Location: Currently? Costa Rica
Posts: 52
Default Creating a class holding some graphics?


Ok, I want to create a class that will handle a special rectangle graphic.

In my form, I want to have two of these special rectangles. So, basically, I need two instances of that class in my form, right?

I manage to initialize two, alright. But, how exactly am I supposed to manage drawing/graphics etc in a class, and the results to be displayed in my form?
Reply With Quote
  #2  
Old 01-12-2011, 11:48 PM
Frog's Avatar
Frog Frog is offline
Freshman
 
Join Date: Aug 2003
Location: Australia
Posts: 47
Default

Try this
Code:
Imports System.Drawing
Imports System.Drawing.Drawing2D
Public Class Form1
    Public mrct As New myRect ' declare class
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    End Sub

    Private Sub bttnDraw_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bttnDraw.Click
        Dim pt As Point
        pt.X = 20
        pt.Y = 30
        mrct.drawRectangle(pt)
    End Sub
End Class
'create myRect class
Imports System.Drawing
Imports System.Drawing.Drawing2D
Public Class myRect

    Public Sub drawRectangle(ByVal pt As Point)
        Dim g As Graphics = Form1.CreateGraphics
        g.DrawRectangle(Pens.Black, pt.X, pt.Y, 200, 200)
    End Sub

End Class
Reply With Quote
  #3  
Old 01-12-2011, 11:54 PM
WhatsMyUsername's Avatar
WhatsMyUsername WhatsMyUsername is offline
Regular
 
Join Date: Jan 2011
Location: Currently? Costa Rica
Posts: 52
Default

That is excellent. Thank you very much!

One question: So I draw my rectangle, but, what if I wanted to move its position? Change its color or something? I would have to clear form1's graphics for then drawing my rectangle again, right? But what if there are other things drawn in the form's graphics? I would have to redraw all of them as well?

Then, is there a way to own my own Graphics in that class, yet it can be displayed perfectly normally in the form?
Reply With Quote
  #4  
Old 01-13-2011, 12:10 AM
Frog's Avatar
Frog Frog is offline
Freshman
 
Join Date: Aug 2003
Location: Australia
Posts: 47
Default

While the rectangle is draw in Form1.Create graphics, the rectangle can be removed by first using Me.Refresh in the button even and then supplying a new point. At the moment if you minimize the form the graphics(rectangle) will disappear. The best way to do this is to draw to a bitmap. I'll have look on my hdd for a drawing example for you
Reply With Quote
  #5  
Old 01-13-2011, 12:17 AM
WhatsMyUsername's Avatar
WhatsMyUsername WhatsMyUsername is offline
Regular
 
Join Date: Jan 2011
Location: Currently? Costa Rica
Posts: 52
Default

Oh, I didn't notice it disappeared on minimize! Hmph, now that's a problem...
Reply With Quote
  #6  
Old 01-13-2011, 12:37 AM
Frog's Avatar
Frog Frog is offline
Freshman
 
Join Date: Aug 2003
Location: Australia
Posts: 47
Default

See how permanent graphics

Edit by Moderator: ZIP file containing binaries removed. Please post source code only.

Last edited by webbone; 01-13-2011 at 06:12 PM.
Reply With Quote
  #7  
Old 01-13-2011, 11:06 AM
WhatsMyUsername's Avatar
WhatsMyUsername WhatsMyUsername is offline
Regular
 
Join Date: Jan 2011
Location: Currently? Costa Rica
Posts: 52
Default

Thanks a lot! The example seems to work perfectly fine, I will take a closer look now, thanks =D!
Reply With Quote
  #8  
Old 01-13-2011, 05:06 PM
snarfblam's Avatar
snarfblamCreating a class holding some graphics? snarfblam is offline
Senior Contributor

Forum Leader
* Expert *
 
Join Date: Apr 2005
Location: USA
Posts: 896
Default

I'm not sure I agree with Frog's general approach. If you want to be drawing graphics to a form, the first thing you need to understand is the the invalidation/painting cycle.

The idea is that you separate the code that says when things need to be drawn from the code that does the actual drawing. If a part of your form needs to be drawn, you invalidate the form to signal that it needs to be drawn. In other words, you are telling the form that something has changed and it's graphic state is invalid.

The easiest thing to do is to invalidate the entire form, like this:
Code:
Me.Invalidate()
The problem is that this will cause the entire form to redraw, which may not be ideal. It's better if we only redraw the parts that we have to. So, if for example, you move a rectangle, there are two parts of the form that need to be drawn. The area that the rectangle was moved out of needs to be redrawn without the rectangle, and the area the rectangle was moved to needs to be redrawn with the rectangle.
Code:
Me.Invalidate(oldRectangle)
Me.Invalidate(newRectangle)
The other half of the equation is painting. All of your drawing code should either go in the OnPaint function, or in the Paint event handler.
Code:
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) _
    Handles MyBase.Paint
    'You can draw here
End Sub
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
    MyBase.OnPaint(e)

    'Or you can draw here
End Sub
You don't need to bother manually erasing the form. It is automatically cleared for you each time the Paint event occurs. All you have to do is add code that draws your rectangle.
Code:
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) _
    Handles MyBase.Paint
    
    e.Graphics.DrawRectangle(Brushes.Black, rectangle)
End Sub


If you want to have a rectangle class that manages drawing of the rectangles, no problem. The myRect class can keep a reference to the form, invalidate it when necessary, and handle the paint event to draw itself.
Code:
Public Class myRect
    WithEvents _Owner As Form
    Dim _Bounds As Rectangle
 
    Public Sub New(Owner As Form, Bounds As Rectangle) 
        _Owner = Owner
        _Bounds = Bounds
    End Sub

    ' Add property/properties to edit location/size of rectangle.
    ' When these properties are set, they can invalidate the form.
 
    Private Sub DoPainting(sender As Object, e As PaintEventArgs) Handles _Owner.Paint
        'Do your drawing here
    End Sub
 
    ' Consider having myRect implement IDisposable. The Dispose method
    ' could set _Owner to 'Nothing', effectively "deleting" the rectangle.
End Class
The invalidation/painting cycle is the proper way to do drawing in windows, and if you don't play along with it you're bound to run into problems.
__________________
C# _VB.NET _

Last edited by snarfblam; 01-13-2011 at 05:12 PM.
Reply With Quote
  #9  
Old 01-13-2011, 07:42 PM
WhatsMyUsername's Avatar
WhatsMyUsername WhatsMyUsername is offline
Regular
 
Join Date: Jan 2011
Location: Currently? Costa Rica
Posts: 52
Default

I see... So I have to invalidate the areas that change.... but why?
And, isn't it a bit hard to always know the old area and the new area that require invalidating?

Thank you, sorry, I'm still quite new to VB.NET, but I'm sure I'll be loving it soon =D
Reply With Quote
  #10  
Old 01-13-2011, 08:10 PM
Frog's Avatar
Frog Frog is offline
Freshman
 
Join Date: Aug 2003
Location: Australia
Posts: 47
Default

The sample I gave was drawn on a double buffered panel- so refreshing the entire panel won't flicker much - But invalidating a region is possible
To use paint event in my opinion is good for static graphics and a small amount of shapes
To have an undo event will require serialization of types and points(e,X,e.Y) - which is ok for a cad program
In a simple drawing program you can create say 5 bitmaps for 5 undo points and loop through them as required

Last edited by Frog; 01-13-2011 at 08:37 PM.
Reply With Quote
  #11  
Old 01-14-2011, 09:45 AM
AtmaWeapon's Avatar
AtmaWeaponCreating a class holding some graphics? AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

Disclaimer: Some people get offended when I make this kind of post. It is not meant to personally insult or tear down any specific approach. This is a very familiar topic to me and I'd like to thoroughly explain my opinion on the matter. This requires a comparison between the two approaches, and I have little praise for Frog's approach.

The attachment has been removed for violating the Posting Guidelines, but I'll assume it was using CreateGraphics() to create a Graphics object for the form and using that to draw. In 7 years of .NET development, I have never found a scenario in which that technique was superior to the normal invalidate/paint cycle. If I'm wrong, I suppose I'm wasting my breath, but what follows is still a good defense of the invalidate/paint cycle.

As discussed by snarfblam and as has been observed, there are numerous occasions on which you have to redraw some or all of the form. This happens when a form is resized, minimized, maximized, a control is updated, or the form is occluded by another form. On each of these occasions, the window is invalidated and the Paint event is raised (well, you have to set a property to get it on resize, but it's trivial compared to the alternative); handle that event and you will always redraw when appropriate. If you instead decide to draw with CreateGraphics(), you have to handle all of these events and redraw your form in response:
  • Sizing events
  • Minimize/maximize
  • Focus changes
The last one is because there's no event (other than perhaps Paint) that tells you someone has moved a form over the top of your form. Thus, your only choice is to redraw every time you lose and regain focus. This will be inefficient, because minimizing can count as a focus change so in that case you'll either redraw twice or have to write a mechanism to detect if the focus is changing due to a restore/maximize operation. Or you could just handle Paint and get the right behavior in all scenarios. This goes along with striving for more readable code: you should pick the most clear and obvious implementation for any task, and since invalidate/paint is the redraw cycle it's the most clear and obvious.

You mentioned you used your technique to prevent flicker; it's not necessary. You can configure a form to automatically double-buffer its rendering by setting a property. In the rare cases where this still causes flicker, you're probably invalidating too much of the form at once. That's where the region-based invalidation snarfblam mentioned comes in. I'll switch to question/answer format now to make it more clear what I respond to.

Quote:
Originally Posted by WhatsMyUsername
I see... So I have to invalidate the areas that change.... but why?
You don't always have to invalidate a small region. If you pass no arguments to Invalidate() the entire form will be invalidated. In rare cases, complex drawing operations can still produce flicker in a double-buffered form. If that's happening, it's worth using the overloads of Invalidate() that let you specify a small area rather than a large one.

Quote:
Originally Posted by WhatsMyUsername
And, isn't it a bit hard to always know the old area and the new area that require invalidating?
It all depends on your implementation. Here's some scenarios.
  • Suppose you have a drawing program that responds to mouse input by drawing on a bitmap. To invalidate some small region, you have to take care to calculate the region that changed and copy a small portion of the bitmap. This is fairly complicated.
  • Suppose your drawing program stores a list of operations like "Draw a 10x10 rectangle at (10, 5)" instead of bitmaps. Drawing a 10x10 rectangle at (10, 5) will only affect the area covered by the rectangle; you already know the area to invalidate so it'd be silly to redraw the entire window.
  • Suppose you're writing a fast-paced 2D game that supports many enemies on the screen. Odds are a large portion of the screen will change every frame, so if you were to try and calculate the area that changed you'd get a rectangle *almost* the size of the entire screen. There's no value in calculating the changed area.
  • Suppose you're writing a game like Minesweeper. Every mouseclick has the potential to cause a change in many squares, but since your code has to calculate the affected squares you can calculate the affected region as you're visiting them. It's more or less a free optimization.
  • Suppose you have numerous individual elements to draw, and a complete screen redraw takes some visible amount of time like 750ms. Mahjong might be a good example. If user input results in only a small change, why waste the time redrawing the entire screen?
My point is there's no real rule that tells you when it's a good idea to invalidate a region. You have to ask yourself if there'd be a benefit, and you also have to ask if you could redesign your application to make it easier. Experience is the best teacher.

Quote:
Originally Posted by Frog
To use paint event in my opinion is good for static graphics and a small amount of shapes
That's a good opinion, but its truth depends on the definition of "small amount" and whether invalidating a region is feasible. Making a demo of all the circumstances would be quite complicated. My experience has never brought a case to my attention where the invalidate/paint cycle was inadequate, so I'm going to appeal to that.

Quote:
Originally Posted by Frog
To have an undo event will require serialization of types and points(e,X,e.Y) - which is ok for a cad program
In a simple drawing program you can create say 5 bitmaps for 5 undo points and loop through them as required
I was going to refute your second point but the first point makes it valid. So long as you can serialize your drawing operations as instructions writing an undo stack is efficient and quick. Incidentally, this makes the invalidate/paint model and region invalidation easier as well. If you can't serialize your drawing operations, it's tough to write undo without limiting the history. Hybrid approaches might work; for example a drawing program might save the original image, a serialized list of actions, and 5-10 bitmaps of the last few actions. This makes the first few undo operations fast; if you go back farther it will have to work through the entire list of operations which may be slow, but it's doable. Again, this can affect how you choose to render.
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #12  
Old 01-14-2011, 04:09 PM
Frog's Avatar
Frog Frog is offline
Freshman
 
Join Date: Aug 2003
Location: Australia
Posts: 47
Default

AtmaWeapon
Every one has their own opinion - I'm old and thick skinned so I'm not offended. i have used my example with no ill effects.
Any way please check my new example and let me know if it follows your posting guidelines

Last edited by OnErr0r; 01-14-2011 at 05:40 PM. Reason: Removed attachment containing binaries.
Reply With Quote
  #13  
Old 01-14-2011, 05:18 PM
snarfblam's Avatar
snarfblamCreating a class holding some graphics? snarfblam is offline
Senior Contributor

Forum Leader
* Expert *
 
Join Date: Apr 2005
Location: USA
Posts: 896
Default

Frog, the reason the attachment was deleted is because it contained an executable. You need to delete the "bin" and "obj" folders from the zip, and any other folders containing executables.
__________________
C# _VB.NET _
Reply With Quote
  #14  
Old 01-15-2011, 09:01 PM
WhatsMyUsername's Avatar
WhatsMyUsername WhatsMyUsername is offline
Regular
 
Join Date: Jan 2011
Location: Currently? Costa Rica
Posts: 52
Default

All of you, thank you a lot for discussing all of this.

So, is there some decent performance change if I try to invalidate the least area possible?
Can someone show me a simple example? Like, let's say, there is a graphic, and it will appear anywhere in the form where the mouse clicks. I assume the best thing to do is invalidate only the graphic's old and new area since the graphic is quite small, right?

Thank you a lot for your help!
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
Creating a class holding some graphics?
Creating a class holding some graphics?
Creating a class holding some graphics? Creating a class holding some graphics?
Creating a class holding some graphics?
Creating a class holding some graphics?
Creating a class holding some graphics? Creating a class holding some graphics? Creating a class holding some graphics? Creating a class holding some graphics? Creating a class holding some graphics? Creating a class holding some graphics? Creating a class holding some graphics?
Creating a class holding some graphics?
Creating a class holding some graphics?
 
Creating a class holding some graphics?
Creating a class holding some graphics?
 
-->