Am 03.08.2010 16:54, schrieb C:
In what way did it not work?
It did not draw the lines. I am appending the corrected code below -
subroutine and the calling routine. I have several small questions -
this VB.net is crazy. I guess I could have learnt this faster if I did
not know VB6.
I can't compile it. You didn't enable Option Strict.
Where should I have Option Strict? At the top of the module or each
module and each Form?
You should start
getting aware of data types. That's what programming is all about. You can't
move data around blindly and hope that conversions will be done automatically
That is how it was before VB.net..
saving you from thinking about what your doing. (sorry for speaking so intensely ;-) )
So...:
No need to save memory.
Changed to Integer.
300.0 is a Double literal. This makes the expression a Double value.
You can't assign a Double to a Single variable. Changed it to 300.0F.
This is also news to me. Nowhere did I read that now we will have to
write numbers with a F at the end. Or perhaps we should be using only
double precision.
The Int function rounds but does not change the data type. Therefore
you can't assign the return value to an integer variable. => added CInt()
Would CInt have been enough instead of CInt(Int())?
"And" changed to "AndAlso".
Why?
Final sub:
Shared Sub draw_h_lines(ByVal g1 As Graphics, ByVal IYmin As Single, _
ByVal IYmax As Single, ByVal DY As Single)
Dim yscale As Single
Dim nl, k As Integer
Dim Ylowest, yk, yy3 As Single
yscale = 300.0F / (IYmax - IYmin)
nl = CInt(Int((IYmax - IYmin) / DY + 0.0001F))
Ylowest = Int(IYmin / DY) * DY
For k = 1 To nl + 1 ' but no plotting too near the edges
yk = Ylowest + CSng(k) * DY
' yy3 = plate_Height - (yk - Ymin) * y2scl
yy3 = 300 - (yk - IYmin) * yscale
If yy3 > 240 AndAlso yy3 < 300 - 240 Then ' else lineswill be too close to the edges
g1.DrawLine(Pens.Green, 100, yy3, 700, yy3)
End If
Next k
End Sub
Now I have
Sub draw_h_lines(ByVal g1 As Graphics, ByVal IYmin As Single,
ByVal IYmax As Single, ByVal DY As Single)
Dim yscale As Single
Dim nl As Short, k As Short
Dim Ylowest As Single, yk As Single, yy3 As Single
yscale = 300.0F / (IYmax - IYmin)
nl = CInt(Int((IYmax - IYmin) / DY + 0.0001F))
' Ymin may not be at a multiple of DY if the user has set
it.
' In that case, lines should be drawn from the lowest
multiple of DY
' if that is not too close to the bottom of the plate
Ylowest = CInt(Int(IYmin / DY)) * DY
For k = 1 To nl + 1 ' but no plotting too near the edges
yk = Ylowest + CSng(k) * DY
yy3 = 300 - (yk - IYmin) * yscale
If yy3 > 240 AndAlso yy3 < 300 - 240 Then ' else lines
will be too close to the edges
g1.DrawLine(Pens.Green, 100, yy3, 700, yy3)
End If
Next k
End Sub
and calling it is this routine from Form3 (call is close to the end of
this routine):
Private Sub cmdPlot_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles cmdPlot.Click
Dim g As Graphics = Graphics.FromImage(frmImage)
Dim XX(501) As Single, Y1(501) As Single
Dim i As Short, xxx1 As Single, yyy1 As Single
Dim k As Short, xxx2 As Single, yyy2 As Single
Dim xmin As Single, xmax As Single, ymin As Single, ymax As
Single
Dim IXmin As Single, IXmax As Single, IXmid As Single
Dim IYmin As Single, IYmax As Single, IYmid As Single
Dim IIN As Single, IOUT As Single
Dim Xsave As Single
Dim DX As Single, DY As Single
Dim xscale As Single, yscale As Single
IIN = List1.SelectedIndex + 1
IOUT = List2.SelectedIndex + 1
Xsave = X(IIN)
ymin = 1.0E+30
ymax = -1.0E+30
If Trim(TextBox1.Text) = "" Then
xmin = Xlim(IIN, 1)
Else
xmin = CSng(TextBox1.Text)
End If
If Trim(TextBox2.Text) = "" Then
xmax = Xlim(IIN, 2)
Else
xmax = CSng(TextBox2.Text)
End If
Call find_range(xmin, xmax, IXmin, IXmax, DX)
IXmid = 0.5 * (IXmin + IXmax)
lblLeft.Text = IXmin
lblRight.Text = IXmax
lblMiddle.Text = IXmid
Debug.Print("xmin = " & xmin)
Debug.Print("IXmin = " & IXmin)
For i = 1 To 501
XX(i) = xmin + CSng(i - 1) * (xmax - xmin) / 500.0
X(IIN) = XX(i)
Call calculatingfunction()
Y1(i) = Y(IOUT)
If Y(IOUT) < ymin Then ymin = Y(IOUT)
If Y(IOUT) > ymax Then ymax = Y(IOUT)
Next i
X(IIN) = Xsave
Call find_range(ymin, ymax, IYmin, IYmax, DY)
IYmid = 0.5 * (IYmin + IYmax)
lblTop.Text = IYmax
lblBottom.Text = IYmin
lblMid.Text = IYmid
Debug.Print("ymin = " & ymin)
Debug.Print("IYmin = " & IYmin)
xscale = 600.0 / (IXmax - IXmin)
yscale = 300.0 / (IYmax - IYmin)
' This part I would like to put in another general subroutine,
and later a class
For i = 1 To 500
xxx1 = (XX(i) - IXmin) * xscale + 100
yyy1 = 300 - (Y1(i) - IYmin) * yscale + 90
xxx2 = (XX(i + 1) - IXmin) * xscale + 100
yyy2 = 300 - (Y1(i + 1) - IYmin) * yscale + 90
g.DrawLine(Pens.Firebrick, xxx1, yyy1, xxx2, yyy2)
Next i
k = 1
Call draw_h_lines(g, IYmin, IYmax, DY)
Me.Invalidate() : g.Dispose()
End Sub
Yes. I did.
But I'd probably write a class "Chart" with a "Render" method that renders
on the internal Bitmap. Then you can render that Bitmap on the Form.
Example:
Public Class Chart
Public ReadOnly Bitmap As Bitmap
[...]
End Class
This will just draw things on the Bitmap. Should I then stick it on
the Form in Paint with e.Graphics.DrawImage(Bitmap)?
Yep, as I wrote above: "Then you can render that Bitmap on the Form."
dim chart as new chart(clientsize)
chart.render(....)
e.graphics.drawimageunscaled(chart.bitmap, ....)
You don't have to create the Chart object in each Paint event.
You can create it whenever the Form is resized. Depends on the application.
Thanks. I hope to learn a few things from this plotting code.