tlfeet
asked on
Drawing OnPaint Custom Control?
I am so confused, so if this is confusing, join the club? ;)
I have a VB.NET Windows application, using Visual Studio.NET (2003)
It hassome TabPages on it, and most of it works fine.
On one of the TabPages is wish to draw, optionally 1 to 4 graphs (based upon data crunched process by the app)
So I set up a Custom Control, which I thought would contain the info/data/controls/lines, etc. necessary for the graph(s).
In a sense so far so good. I have very little experience w the System.Drawing.Graphics naemspace in VB.NET (or even VB).
Anyway, program will instantiate mycustomcontrol, and draw it on the TabPage . . . which is good.
I can also get it to draw a line (which would be/is the x-axis) . . . again no problem.
However, I need more than just one line, the y-axis, a bunch of labels, boxes/rectangles for the data (a histogram is the type, if that matters)
So, I thought I owuld go ahead and add one of my Labels, namely the one for the YAxis, which would have text = "Y AXIS DATA" or such, just to move on to another thing I need on the graph(s).
This is where the problem comes up.
If I run what I have so far, just drawing the x-axis, a line, OK fine.
If I have it attempt to draw the YAxisLabel, it goes thru the OnPaint event handler over & over until it bobms out yielding an error message "System.ComponentModel.Win 32Exceptio n occurred in system.windows.forms.dll"
I kinda get why it is going thru the OnPaint handler over and over, but have no idea as to how to stop it.
In psuedo code form here is my code:
Public Class MyMainForm
'bunch of code
Private Sub ButtonDrawGraph_Click(ByVa l sender As System.Object, ByVal e As System.EventArgs) Handles ButtonDrawGraph.Click
'this handles the user clicking a button on the MainForm, actually one of the TabPages, which would hopefully draw the Graph
'requested, except it gets stuck in a loop, drawing over & over ;)
If Not (MyControl Is Nothing) Then
MyControl.Dispose
'if the graph already exists, clear it, dispose of it, so as to be able to draw the next one/new one
End If
MyControl = New MyControlClass(some parameters)
Me.TabPage5.Controls.Add(M yControl)
End Private Sub
End Class 'MyMainForm
Imports System.Drawing.Graphics
Public MyControlClass
Inherits System.Windows.Forms.UserC ontrol
Protected Overides Sub OnPaint (ByVal e As PaintEventArgs)
g = e.Graphics
DrawXAxis()
AddYAxisLabel()
End Sub
Private Sub DrawXAxis()
Dim BlackPen As New Pen(Color.Black, 1)
Dim startPoint As New Point(5, Me.Height - 20)
Dim endPoint As New Point(Me.Width - 5, Me.Height - 20)
g.DrawLine(BlackPen, startPoint, endPoint)
End Sub
Private Sub AddYAxisLabel()
Me.Controls.Add(yaxislbl)
yaxislbl.Top = margin
yaxislbl.Left = margin
yaxislbl.Text = "Frequency"
yaxislbl.Height = 16
End Sub
End Class
As I said, if I call the DrawXAxis() alone, it works fine.
If I call the AddYAxisLabel, before or after DrawXAxis, w/w/o SuspenedLayout, it goes into an infinite loop and bombs out.
I really do not get a lot about the System.Drawing namespace, and there may be a much better way to do what I am doing.
Any help is greatly appreciated.
Thanks,
Mike.
I have a VB.NET Windows application, using Visual Studio.NET (2003)
It hassome TabPages on it, and most of it works fine.
On one of the TabPages is wish to draw, optionally 1 to 4 graphs (based upon data crunched process by the app)
So I set up a Custom Control, which I thought would contain the info/data/controls/lines, etc. necessary for the graph(s).
In a sense so far so good. I have very little experience w the System.Drawing.Graphics naemspace in VB.NET (or even VB).
Anyway, program will instantiate mycustomcontrol, and draw it on the TabPage . . . which is good.
I can also get it to draw a line (which would be/is the x-axis) . . . again no problem.
However, I need more than just one line, the y-axis, a bunch of labels, boxes/rectangles for the data (a histogram is the type, if that matters)
So, I thought I owuld go ahead and add one of my Labels, namely the one for the YAxis, which would have text = "Y AXIS DATA" or such, just to move on to another thing I need on the graph(s).
This is where the problem comes up.
If I run what I have so far, just drawing the x-axis, a line, OK fine.
If I have it attempt to draw the YAxisLabel, it goes thru the OnPaint event handler over & over until it bobms out yielding an error message "System.ComponentModel.Win
I kinda get why it is going thru the OnPaint handler over and over, but have no idea as to how to stop it.
In psuedo code form here is my code:
Public Class MyMainForm
'bunch of code
Private Sub ButtonDrawGraph_Click(ByVa
'this handles the user clicking a button on the MainForm, actually one of the TabPages, which would hopefully draw the Graph
'requested, except it gets stuck in a loop, drawing over & over ;)
If Not (MyControl Is Nothing) Then
MyControl.Dispose
'if the graph already exists, clear it, dispose of it, so as to be able to draw the next one/new one
End If
MyControl = New MyControlClass(some parameters)
Me.TabPage5.Controls.Add(M
End Private Sub
End Class 'MyMainForm
Imports System.Drawing.Graphics
Public MyControlClass
Inherits System.Windows.Forms.UserC
Protected Overides Sub OnPaint (ByVal e As PaintEventArgs)
g = e.Graphics
DrawXAxis()
AddYAxisLabel()
End Sub
Private Sub DrawXAxis()
Dim BlackPen As New Pen(Color.Black, 1)
Dim startPoint As New Point(5, Me.Height - 20)
Dim endPoint As New Point(Me.Width - 5, Me.Height - 20)
g.DrawLine(BlackPen, startPoint, endPoint)
End Sub
Private Sub AddYAxisLabel()
Me.Controls.Add(yaxislbl)
yaxislbl.Top = margin
yaxislbl.Left = margin
yaxislbl.Text = "Frequency"
yaxislbl.Height = 16
End Sub
End Class
As I said, if I call the DrawXAxis() alone, it works fine.
If I call the AddYAxisLabel, before or after DrawXAxis, w/w/o SuspenedLayout, it goes into an infinite loop and bombs out.
I really do not get a lot about the System.Drawing namespace, and there may be a much better way to do what I am doing.
Any help is greatly appreciated.
Thanks,
Mike.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Hi Jaime,
I am sorry I missed your response.
Essentially, yes, as you state, as as did SRigney, having the add control functiion w/i the the OnPaint handler is/was causing the problem.
Sorry, I missed your response.
Which leads to: what do you guys think is fair in awarding/splitting the points?
Jaime was 6 minutes faster, both anwered the q, solved the problem.
Thanks, to both.
I am sorry I missed your response.
Essentially, yes, as you state, as as did SRigney, having the add control functiion w/i the the OnPaint handler is/was causing the problem.
Sorry, I missed your response.
Which leads to: what do you guys think is fair in awarding/splitting the points?
Jaime was 6 minutes faster, both anwered the q, solved the problem.
Thanks, to both.
Well, it is 500 pts question, so could be enough points for all, although I deserve some extra points for typing faster ;-)
btw. There is an specific VB.NET forum, you can post your VB.net questions there, because vb.net is totally different from Visual Basic (just similar names)
I think there's enough point for everyone, but my goal is to make sure you have something working, the points are an added bonus.
This is a sub chunk of code stolen from a C# Verticle label control, but it should get you close enough to what you need.
Graphics g = e.Graphics;
StringFormat stringFormat = new StringFormat();
stringFormat.Alignment =
StringAlignment.Center;
stringFormat.Trimming = StringTrimming.None;
stringFormat.FormatFlags =
StringFormatFlags.Directio nVertical;
Brush textBrush = new
SolidBrush(this.ForeColor) ;
Matrix storedState = g.Transform;
g.RotateTransform(180f);
g.TranslateTransform(-Clie ntRectangl e.Width, -ClientRectangle.Height);
g.DrawString(
"Y label",
this.Font,
textBrush,
ClientRectangle,
stringFormat);
g.Transform = storedState;
This is a sub chunk of code stolen from a C# Verticle label control, but it should get you close enough to what you need.
Graphics g = e.Graphics;
StringFormat stringFormat = new StringFormat();
stringFormat.Alignment =
StringAlignment.Center;
stringFormat.Trimming = StringTrimming.None;
stringFormat.FormatFlags =
StringFormatFlags.Directio
Brush textBrush = new
SolidBrush(this.ForeColor)
Matrix storedState = g.Transform;
g.RotateTransform(180f);
g.TranslateTransform(-Clie
g.DrawString(
"Y label",
this.Font,
textBrush,
ClientRectangle,
stringFormat);
g.Transform = storedState;
ASKER
Hi Jaime,
Re: "btw. There is an specific VB.NET forum, you can post your VB.net questions there, because vb.net is totally different from Visual Basic (just similar names)"
I thought that is/was where I was done at. Now that you point it out, I am in fact in VB - sorry for any confusion.
I did intend to post in VB.NET
Re: "btw. There is an specific VB.NET forum, you can post your VB.net questions there, because vb.net is totally different from Visual Basic (just similar names)"
I thought that is/was where I was done at. Now that you point it out, I am in fact in VB - sorry for any confusion.
I did intend to post in VB.NET
ASKER
Thanks!!!
ASKER
Hi,
He's back.
Accepted answer too soon.
In trying to incorporate Vertical Text, back to the infinite loop thing.
BTW, found code to draw vertical text in VB.NET help (SRigney's post, led to more searches, which turned up exactly what I was looking for, but which did not appear in my first searches . . . but that is a digression)
The code for drawing Vertical Text, per help is:
Public Sub DrawVerticalString()
Dim formGraphics As System.Drawing.Graphics = Me.CreateGraphics()
Dim drawString As String = "Sample Text"
Dim drawFont As New System.Drawing.Font("Arial ", 16)
Dim drawBrush As New _
System.Drawing.SolidBrush( System.Dra wing.Color .Black)
Dim x As Single = 150.0
Dim y As Single = 50.0
Dim drawFormat As New System.Drawing.StringForma t
drawFormat.FormatFlags = StringFormatFlags.Directio nVertical
g.DrawString(drawString, drawFont, drawBrush, _
x, y, drawFormat)
drawFont.Dispose()
drawBrush.Dispose()
formGraphics.Dispose()
End Sub
Problem, is, that if I place reference/call to this sub outside OnPaint, it does not draw.
If I do place it within the OnPaint, it goes back into an infnite loop, near as I can tell, to draw the X-Axis, then DrawVertical text, then this cause OnPaint to call X-Axis & DrawVertical, and so it goes, ad-infinitum
...again, I have no idea what I am doing, but it seems one can only draw one thing, as subsequent drawings of things/objects, calls the OnPaint agrument to be called yet again, which then causes the whole loop, set of drawings to repeat.
How, do I draw more than one thing/object, w/o getting into an infinite loop where the drawing of the second, subsequent objects cause the OnPaint handler to be called recursively?
Thanks.
He's back.
Accepted answer too soon.
In trying to incorporate Vertical Text, back to the infinite loop thing.
BTW, found code to draw vertical text in VB.NET help (SRigney's post, led to more searches, which turned up exactly what I was looking for, but which did not appear in my first searches . . . but that is a digression)
The code for drawing Vertical Text, per help is:
Public Sub DrawVerticalString()
Dim formGraphics As System.Drawing.Graphics = Me.CreateGraphics()
Dim drawString As String = "Sample Text"
Dim drawFont As New System.Drawing.Font("Arial
Dim drawBrush As New _
System.Drawing.SolidBrush(
Dim x As Single = 150.0
Dim y As Single = 50.0
Dim drawFormat As New System.Drawing.StringForma
drawFormat.FormatFlags = StringFormatFlags.Directio
g.DrawString(drawString, drawFont, drawBrush, _
x, y, drawFormat)
drawFont.Dispose()
drawBrush.Dispose()
formGraphics.Dispose()
End Sub
Problem, is, that if I place reference/call to this sub outside OnPaint, it does not draw.
If I do place it within the OnPaint, it goes back into an infnite loop, near as I can tell, to draw the X-Axis, then DrawVertical text, then this cause OnPaint to call X-Axis & DrawVertical, and so it goes, ad-infinitum
...again, I have no idea what I am doing, but it seems one can only draw one thing, as subsequent drawings of things/objects, calls the OnPaint agrument to be called yet again, which then causes the whole loop, set of drawings to repeat.
How, do I draw more than one thing/object, w/o getting into an infinite loop where the drawing of the second, subsequent objects cause the OnPaint handler to be called recursively?
Thanks.
ASKER
Humm, I understand what you are saying, and I think I have "fixed" the problem.
Yes, I was adding a Control from within the OnPaint event handler.
I moved the addition of the control to outside the OnPaint event handler. And it works fine.
I could in fact, except for one small detail, ;-) put this control in at design time (in fact I just might do that).
The one small exception is that (possibly) it's location and size, would vary from time to time, so figured I might as well make the whole thing dynamic.
So, in short, have moved the adding control code to outside of OnPaint handler, and seems to work fine, OK.
This is related I guess, I need to, well actually would prefer to make the orientation of the text w/i the control to be vertical as opposed to default/standard horizontal.
I assume I would do that with the Graphics features (if it is possible)?