2 years ago, I've asked around and even searched on the net on how to indicate if a given point(in coordinates) belongs inside an ellipse. I've got that code if you guys want (in C++).
However, today I have one simple question, I hope it's simple enough if anyone knows, I am too busy to try out to make a formula for it. Now the question.
You draw a line using the DrawLine function which requires 2 points and of course a pen object.
Take for example i have 2 points, 1 point at coordinate (2,10) and the other point at (30, 47).
The question is how do you determine if a given point let say maybe 7,7 belongs to the line plotted/drawn by the DrawLine
function?
Well, for the line you can simply make the line formula and test the point with it in the range of two points. That's the matter of two lines of code, but even for the line or for more complicated shapes it can be done using GraphicsPath and IsVisible method. Want some code?
Last edited by Lunatic3; Nov 29th, 2003 at 03:39 AM.
'Heading for the automatic overload'
Marillion, Brave, The Great Escape, 1994
'How will WE stand the FIRE TOMORROW?'
Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979
Hi thanks for the reply!. It helps alot!. In the meantime, i have one more question. I am using the panel control as the drawing canvas. I have few objects painted in the panel. Around 20-30 objects which includes lines, ellipses, rectangles, texts, etc. Although there aren't many objects drawn in the panel, each time when a process is done and i need to redraw/refresh all objects, I used the Invalidate/Refresh/Update functions. All of these functions causes flickering. I've tried using the SmoothingMode = SmoothingMode.HighSpeed but it's still flickers horribly. Any suggestion ?
Also my experience with drawing is GraphicsPath offer a higher performance than directly drawing. You add all the objects to the path and then draw the path.
'Heading for the automatic overload'
Marillion, Brave, The Great Escape, 1994
'How will WE stand the FIRE TOMORROW?'
Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979
Hey Lunatic, thanks for the quick reply. There's one more question that i have on mind.
If i have a few objects drawn using the graphicspath, for eg. 3 same objects (maybe ellipses). I can determine if a point is inside any of those objects by using the IsVisible function.
But how do i determine which ellipse has the focus? For eg. if a point is inside the 2nd ellipse, i would like to redraw that ellipse using a different color pen to indicate that the 2nd ellipse is being selected.
I think for 2 reasons you can not do that with a single GraphicsPath (GP).
1- GP is a collection of points not shapes.
2- GP does not contain any data about the pen or brush object you going to paint with. So even if you can decide which ellipse the point belongs to, you can not just draw that part of the GP with another color.
So my advice is to go with a collection of GPs. Then check in the list and see your point is inside what GP, then redraw that path.
'Heading for the automatic overload'
Marillion, Brave, The Great Escape, 1994
'How will WE stand the FIRE TOMORROW?'
Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979
I have a canvas (a panel control) and i need to draw grids in it. Below is the code snippets that i've written:
Code:
Public Sub DrawGrid(ctlCanvas as Panel, szGrid as size)
Dim col, row, cols, rows, x1, y1 As Integer
Dim penGrid As New Pen(Color.DimGray)
hGraphics = ctlCanvas.CreateGraphics
cols = ctlCanvas.Width / szGrid.Width
rows = ctlCanvas.Height / szGrid.Height
x1 = szGrid.Width
y1 = szGrid.Height
For row = 0 To rows - 1
For col = 0 To cols - 1
hGraphics.DrawLine(penGrid, x1, y1, x1 + CSng(0.1), y1 + CSng(0.1))
x1 += szGrid.Width
Next
y1 += szGrid.Height
x1 = szGrid.Width
Next
hGraphics.SmoothingMode = SmoothingMode.HighSpeed
End Sub
I've noticed that the performance are horribly slow(of course without the double buffering yet) especially with a very large canvas size. Just wish to know if there's a better solution than this which could increase the performance.
This function is a frequently called function. I will always need to execute it in the OnPaint event.
Thanks again,
Archaven
Last edited by Archaven; Nov 30th, 2003 at 09:41 PM.
And by the way, I am sure that you can not draw a fraction of a pixel so you may not bother with CSng to draw a tiny dot. This is what I have come across so far:
For example:
DrawLine(1,1,1,1): Draws nothing
DrawLine(1,1,2,1): Draws a 2 pixel long line
DrawLine(1,1,1.5F,1): Draws 1 pixel (anything less than 0.5F and more than 0.0F. Ofcourse this is in theory. Infact it will not draw anything if you add something less than aproximately 0.002F)
DrawLine(1,1,1.51F,1): Draws a 2 pixel long line (anything more than 0.5F and less or equal to 1F)
So using your method, if you come to a x1 + CSng(0.1) and/or a y1 + CSng(0.1) that rounds up, you will have a line that is more than 1 pixel in lenght, vertically, horizontally or both.
Last edited by Lunatic3; Dec 1st, 2003 at 01:29 AM.
'Heading for the automatic overload'
Marillion, Brave, The Great Escape, 1994
'How will WE stand the FIRE TOMORROW?'
Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979
I've tried using the ControlPaint.Drawgrid function and it seems to me that it didn't draw anything to the screen?
Code:
Private Sub pnlCanvas_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles pnlCanvas.Paint
pnlCanvas.SuspendLayout()
Dim rectArea As New Rectangle(pnlCanvas.Left, pnlCanvas.Top, pnlCanvas.Width, pnlCanvas.Height)
Dim hGraphics As Graphics = pnlCanvas.CreateGraphics
ControlPaint.DrawGrid(hGraphics, rectArea, szGrid, Color.DimGray)
pnlCanvas.ResumeLayout()
End Sub
I think i found where the error was. Color.DimGray (Duh!) How silly :P
There are some problems with your code:
1- Leave out those two lines SuspenedLayout and ResumeLayout, they won't do what you need. Look at this thread: http://www.vbforums.com/showthread.p...hreadid=264761
2- The cordinations of the rectangle you want to draw in are relative to your control, so you should set the top and left proprties of it to 0 if you want to draw from the top of the canvas not to pnlCanvas.Left and pnlCanvas.Top as they reflect the position of canvas on its parent control.
3- If you are painting in the paint event of control you can get use of e and not create another graphics, so this line
Dim hGraphics As Graphics = pnlCanvas.CreateGraphics
would better be:
Dim hGraphics As Graphics = e.Graphics
4-There is a size property in controls called ClientSize and that is the size of the control you can draw on, and is not necessarily equal to control width and height, as these contain borders, scrollbars,... but with a borderless panel i guess you can use any of them.
5- The backColor parameter of drawgrid method is used to calculate the fill color of the dots so that the grid is always visible against the background.
Yes, I think you can call the setstyle there or somewhere in the wizard generated code.
Last edited by Lunatic3; Dec 1st, 2003 at 10:53 PM.
'Heading for the automatic overload'
Marillion, Brave, The Great Escape, 1994
'How will WE stand the FIRE TOMORROW?'
Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979
For your grid make a very small memory image 3px x 3px make a cross inside it the use this image to fill your area. instan grid. And although I haven't tested it, it should be super fast.
Double Buffering/Drawing in memory/Drawing off screen is the way to go. it reduces any flicking and mastering it allows you to layer your images like a photoshop documnet. The layers in the a PSD are individual dhc's stacked on a z-oreder. I haven't done more then lite work with GDI+ but it seems okay. I wouldn't use it to make a 3D game engine but it's okay....
I don't mean interruption but for the SetStyle method , it's ideal to put that in the constructor of your form (so you are requestiong double buffer prior to any drawing operation) , if this issue has to do with UC , then put that in the Set part of the property .
Originally posted by Pirate I don't mean interruption but for the SetStyle method , it's ideal to put that in the constructor of your form (so you are requestiong double buffer prior to any drawing operation) , if this issue has to do with UC , then put that in the Set part of the property .
Actually I meant in form constructor by 'somewhere in the wizard generated code'. Thanks for clearing it.
'Heading for the automatic overload'
Marillion, Brave, The Great Escape, 1994
'How will WE stand the FIRE TOMORROW?'
Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979
I tested here and there is no problem with toolbar, I am afriad thats because of you have XP visual styles enabled which is not the case here. Whould you please send me a sample so I test it here?
'Heading for the automatic overload'
Marillion, Brave, The Great Escape, 1994
'How will WE stand the FIRE TOMORROW?'
Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979
Hi Lunatic, I've asked similar question on other boards and got a reply stating that the SetStyle function if instantiated on form load will only enable double buffering on the form itself - not the panel control.
Hence it is advisable to subclass the panel control and called the SetStyle function in its constructor.
I've tried subclassing the panel control and it works and it does not have the toolbar distortion.
However, i have 2 panels in the form. The first panel acts as a frame which resizes when the form resized.
The second panel which i called it a canvas basically being added to the 1st panel.
I can't really debug where the problem is. When the program executes, the grids are not shown. It will only be shown when you scroll the scrollbars.
Also, if you scroll quickly up and down, you will noticed that the grid is not properly drawn.
Perhaps you can help? Attached herewith is the whole project.
The file is quite small around 33Kb if you are using WinAce. But i compressed it using the ZIP format due to it's popularity but actually cause double of the ACE size.
I tested your program. The problem is you are trying to paint in Paint event of the panel with a Graphics object that is different from e.Graphics and that is eventually repainted by e.Graphics and erased, so if you looked carefully it draws the grid and clear it. I recommend you to pass e.Grapihcs as the Graphics object to the the DrawGrid. The same happens when you resize the form in a way that the canvas is repainted and it clears all prevous objects that are drawn.
Last edited by Lunatic3; Dec 2nd, 2003 at 03:57 AM.
'Heading for the automatic overload'
Marillion, Brave, The Great Escape, 1994
'How will WE stand the FIRE TOMORROW?'
Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979
Hi Lunatic. Thank you very much. I was debugging it for awhile till i found out the solution. You are correct, when i pass e.graphics to the DrawGrid function everything function perfectly.
Yup. Fixed that as well. With the double buffering, it's freaking smooth! even with a large canvas size!
I'm going to enhance it where you can drag any object and reposition/move it to any location. Also, i might try drawing those objects using GraphicsPath instead of direct drawing to the panel.
In the meantime, any feedback for the program?
There's a problem that i've noticed now. There's no keydown event for a panel control. I need it so that when user selected object(s) in the canvas and they can delete it by pressing the delete key from the keyboard.
Anyway to resolve this by using the panel control?
Archaven
Last edited by Archaven; Dec 2nd, 2003 at 04:30 AM.
I liked to know if you used the e.Graphics to paint them too or not, as otherwise you would have problem with those too.
And about the program, I dont know what is the primary goal of this program, but i liked your stylish way of coding.
And for your problem, can't you use OnKeyDown ?
Last edited by Lunatic3; Dec 2nd, 2003 at 04:37 AM.
'Heading for the automatic overload'
Marillion, Brave, The Great Escape, 1994
'How will WE stand the FIRE TOMORROW?'
Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979
Anyway do you know how to write a user-defined event?
I've tried adding a keydown event to by subclass panel:
Code:
Public Class BufferedPanel
Inherits System.Windows.Forms.Panel
Public Sub New()
SetStyle(ControlStyles.AllPaintingInWmPaint Or _
ControlStyles.DoubleBuffer Or _
ControlStyles.ResizeRedraw Or _
ControlStyles.UserPaint, True)
End Sub
Public Shadows Event KeyDown(ByVal e As KeyEventArgs)
End Class
And i've tried handling the KeyDown event by the subclassed panel:
Code:
Private Sub pnlCanvas_KeyDown(ByVal e As System.Windows.Forms.KeyEventArgs) Handles pnlCanvas.KeyDown
If e.KeyCode = Keys.Delete Then
'perform deletion
End If
End Sub
The above codes shows no compile error. The weird thing is that it doesnt work/does not respond to the keydown event.
1- I doubt that piece of code compiles without error cause the method lacks 'Byval sender as Object'.
2- Panel seems not to capture the keys cause it does not get focus. So to capture key you must first move focus to it.
3-Even if you move focus to it, you can not capture 'Delete' key in that KeyDown Method. You have to use ProcessCmdKey, something like in the panel subclass:
VB Code:
Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
If keyData = Keys.Delete Then
'perform delete
Return True ' So it wont be passed to KeyDown Event
End If
End Function
or
VB Code:
Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
If keyData = Keys.Delete Then
Return False ' So the key is passed to KeyDown Event, and you perform delete there
End If
End Function
'Heading for the automatic overload'
Marillion, Brave, The Great Escape, 1994
'How will WE stand the FIRE TOMORROW?'
Eloy, Silent Cries and Mighty Echoes, The Vision - Burning, 1979
Hmmm.. one more last question. Are you a professor?
You seem to know everything!
Actually, i'm not from IT background. So don't be surprised if i ask silly question . I learn programming all by myself and sometimes by trial and error. I used to be a hardcore c++ coder. Not anymore now :P
I've added another parameter (sender by object) to the shadows event as well as the overrided ProcessCmdKey function as shown below:
Code:
Public Class BufferedPanel
Inherits System.Windows.Forms.Panel
Public Sub New()
SetStyle(ControlStyles.AllPaintingInWmPaint Or _
ControlStyles.DoubleBuffer Or _
ControlStyles.ResizeRedraw Or _
ControlStyles.UserPaint, True)
End Sub
Public Shadows Event KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs)
Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, keyData As System.Windows.Forms.Keys) As Boolean
If keyData = Keys.Delete Then
Return False
End If
End Function
End Class
Also, i've added the event handling for the OnKeyDown for the subclassed panel:
Code:
Private Sub pnlCanvas_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles pnlCanvas.KeyDown
If e.KeyCode = Keys.Delete Then
'perform deletion
End If
End Sub
Regardless of ProcessCmdKey returns True/False, the KeyDown event does not fire. I've debugged it and found that the ProcessCmdKey works but it just that it didn't fire the KeyDown event of the subclassed panel.
Where might be the possible error? And btw, I did set focus to the panel.
Sorry for such a trouble!
Btw, what are you then?
Last edited by Archaven; Dec 2nd, 2003 at 09:40 PM.
I think i found where the error was.
It was the access level.
Code:
Public Shadows Event KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs)
and the handling event:
Code:
Private Sub pnlCanvas_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles pnlCanvas.KeyDown
If e.KeyCode = Keys.Delete Then
'perform deletion
MsgBox("test")
End If
End Sub
by changing Public to Private seems to solve the problem. Anyway sorry for the trouble!