i have this code to make a grid(in a timer): Code: dim g as graphics g=me.creategraphics For x = 0 To 19 For y = 0 To 14 r = New Rectangle(x * 32, y * 32, 32, 32) g.DrawRectangle(Pens.Black, r) Next Next then this code to turn that grid off: Code: crtgrid.Enabled = False Me.Refresh() then this code to draw a line Code: Dim p As New Pen(Color.Black, 3) g.DrawLine(p, curline.startpoint, curline.endpoint) after i call form refresh my line dissapears, i know i will be using multiple lines and i need help in finding a way to store all the lines i draw into a collection then loop through the collection after a form refresh to redraw the lines help
I'm guessing that you're obtaining a reference to the Graphics object outside of the OnPaint event. You have to make sure that the line gets drawn every time you call Me.Refresh() if you want it to persist. You would generally accomplish this by overriding the control's OnPaint method. See MSDN for an example. As a rule of thumb, do all required drawing inside the OnPaint event.
see thats my problem the line is created in runtime by the user and i can't put a line in the on paint event for every line the user could possibly make, so i have to create a new line for every line the user draws outside of that and that works up until i refresh the form. I know it is possible to store those lines in some sort of group of points so that when a new line is made it's points are stored in the group of points,then when i refresh the form call on the group of points to loop through and redraw all the lines P.S i almost have a working example but it connects all the lines instead of individually: Code: (declares) Private lines As New List(Of Point) Private lines2 As New List(Of Point) (code to add points to list) lines.Add(pnt1) lines2.Add(pnt2) (loop in a timer) Dim pen As New Pen(Color.Black, 3) For Each line As Point In lines For Each line2 As Point In lines2 g.DrawLine(pen, line, line2) Next Next and ends up with 2 extra lines like i showed in picture in attachment
Ah that explains it Maybe you could have a Bitmap in-memory, and duplicate the drawings on both the Bitmap and the Form surface, so that when you call Me.Refresh() you will DrawImage() the Bitmap back onto the Form surface.
ah thats an interesting idea, so i take a pic of my form before refresh then refresh then redraw bitmap onto form then coninue drawing lines is that what u meen
Yeah something along those lines You could also create a Bitmap and when the user draws something on the Form, you could duplicate it immediately to the Bitmap, and in OnPaint just replace the whole Form surface with the Bitmap. This way or the other! Tell us how you solved it when you're done (for science)
ok here it is: Code: 'when user clicks refresh button change border style,create blank bitmap,initialize graphics object for screenshot,save screenshot to empty 'bitmap,invalidate form,set form background as bitmap with screenshot,change border back, DONE! 'changing border so that it doesn't appear in screenshot Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None Dim bounds As Rectangle = Me.Bounds Dim screenshot As New Bitmap(bounds.Width, bounds.Height, Imaging.PixelFormat.Format32bppArgb) Dim g2 As Graphics = Graphics.FromImage(screenshot) g2.CopyFromScreen(bounds.Location, New Point(0, 0), bounds.Size, CopyPixelOperation.SourceCopy) Me.Refresh() Me.BackgroundImage = screenshot 'changing border back Me.FormBorderStyle = Windows.Forms.FormBorderStyle.Sizable And the result(after form refresh) :
Very nice, well done. I think you can skip the FormBorderStyle change and instead use the values provided by Me.ClientRectangle to ignore the border (I believe that's how it worked at least). Btw, if you want smoother lines you can set the SmoothingMode property of the Graphics object to for example AntiAlias
OK finished with complete ideas, tried the client rectangle thing and that didn't work so i ended up just changing the starting point to the point without border and changes smoothing mode to high-quality: Code: Dim pen As New Pen(Color.Black, 3) 'change smooothign to hq, drawing line on form with pen point 1 and point 2 g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality g.DrawLine(pen, pnt1, pnt2) Code: Private Sub refresh1_Click(sender As System.Object, e As System.EventArgs) Handles refresh1.Click 'when user clicks refresh button,create variable with form bounds,create point without border,create blank bitmap,initialize graphics object for screenshot,save screenshot to empty 'bitmap,invalidate form,set form background as bitmap with screenshot,change border back, DONE! Dim bounds As Rectangle = Me.Bounds 'hiding the border by changing starting point + or - border width Dim strt As Point = New Point(Me.Bounds.Location.X + 8, Me.Bounds.Location.Y + 30) Dim screenshot As New Bitmap(bounds.Width, bounds.Height, Imaging.PixelFormat.Format32bppArgb) Dim g2 As Graphics = Graphics.FromImage(screenshot) g2.CopyFromScreen(strt, New Point(0, 0), bounds.Size, CopyPixelOperation.SourceCopy) Me.Refresh() Me.BackgroundImage = screenshot End Sub If you want to look at the whole project i uploaded it to megaupload, p.m me if u can't access it: http://www.megaupload.com/?d=7W1TF9TQ
Thanks for posting your solution I thought I should just mention an alternative method that came to mind (no need to change yours though). First, create a class called Line (C#, it's so long since I've worked with VB): Code: class Line { Line m_start, m_end; Public Line(Point start, Point end) { this.m_start = start; this.m_end = end; } public Point Start { get { return this.m_start; } set { this.m_start = value; } } public Point End { get { return this.m_end; } set { this.m_end = value; } } } In the Form1 class you could then have Dim m_lines As List<Line> Now in the MouseUp event you could store the new line as follows: Code: Dim line As New Line(pnt1, pnt2) Me.m_lines.Add(line) Then you could just loop through all the Line's and draw them manually in OnPaint. Sorry if this is confusing, I started out thinking in C#, then I realized this is VB.NET, but yeah The logic is, store input as Line, store each Line in a List, draw Line's in OnPaint. (I will probably never write an image editor )
i kinda understand what ur saying(i can follow c# but barely) my original problem was i couldn't figure out how to store the line into a list of lines then loop though the list if u can tell me how to do that i would love u (1. create a list of lines, 2.loop through the list) P.S i could almost make the list but i just couldnt get the syntax right (first time working with lists)
Sorry for the slow reply This is (theoretically speaking) the correct VB.NET code for the Line class: Code: Class Line Private m_start As Point, m_end As Point Public Sub New(start As Point, [end] As Point) Me.m_start = start Me.m_end = [end] End Sub Public Property Start() As Point Get Return Me.m_start End Get Set(value As Point) Me.m_start = value End Set End Property Public Property [End]() As Point Get Return Me.m_end End Get Set(value As Point) Me.m_end = value End Set End Property End Class To create a Line: Code: Dim line As Line = New Line(p1, p2) ' Where p1 and p2 is two Points. Now to store a list of the Lines you need List<T> from the System.Collections.Generic namespace. Code: Imports System.Collections.Generic ' Place this in the top of your code file Code: Dim list As List(Of Line) = New List(Of Line) ' Refer to the "list" from here on Add Lines to the List by issuing list.Add(line) If something here makes no sense I probably wrote something wrong, so report back in that case
Ok finished what you suggested and it worked perfectly,exactly what i was looking for originally(All i did was add a for loop on form paint): Code: Private Sub Form1_Paint(sender As System.Object, e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint For Each L As Line In list Dim pen As New Pen(Brushes.Black, 3) g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality g.DrawLine(pen, L.Start, L.End) Next End Sub ^ of course declares for g are: Code: Dim g As Graphics (in form load) g=me.creategraphics Link to project: http://www.megaupload.com/?d=3ESXYTTA THANKS MAN I THINK I'VE GOT EVERYTHING I NEED P.S i've got a new problem i started a new thread (About clearing object made in runtime and restoring form to original state before objects were made)
Glad you got it solved mate One thing that you might find useful for other projects: If you haven't already noticed, you can also Refresh a specific region of a Control as well, by using Me.Invalidate(rectangle) where rectangle is the part of the Control you want to redraw. Very useful when you have to refresh a specific area very fast but do not want to be too heavy on the CPU (remember that the kind of drawing we're doing here is handled by the processor, and not the graphics card). Me.Invalidate() is the exact same thing as Me.Refresh().
yea i know i used that when i had to draw the score of a game i made onto the screen very fast,but thanks anyways.