Create Mouse Events for controls created by code - vba

I am a beguinner in Access so I need your help with this.
I am try making a "Gannt Chart" and to do that I create some objects by code, but when I do that I can't get the atributes of the event, see
Option Compare Database
Function teste()
MsgBox ("Foi")
End Function
Function gannt()
Dim shpBox As Rectangle
DoCmd.OpenForm "Formulário3", acDesign
Set shpBox = Application.CreateControl("Formulário3", acRectangle, acDetail, "", "", 500, 500, 2000, 500)
shpBox.name = "Objeto1"
shpBox.Visible = True
shpBox.onMouseDown = "=teste()"
DoCmd.OpenForm "Formulário3", acNormal
End Function
The procedure of event has this declaration:
Private Sub Objeto1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
I think that one of solution is getting a mouse position by code, but I don't have a code to do this and probabily this code will bring an absolute position of the mouse.

after thinking a lot I came up with a solution.
First I had create the objects by code assigment public functions to events of MouseDown, MouseUp and MouveMove.
I've declared the public Vars
drag: The object received MouseDown Event
cod_manut: Name of the object
data_manut: Date of the start of maintenance
Option Compare Database
Option Explicit
Public drag(500) As Long
Public cod_manut(500) As Integer
Public data_manut(500, 2) As Date
Public valorX As Long '
Public valorY As Long '
Public clickX As Long '
Public clickY As Long '
Public offset As Long '
Function to populate the Form with the Gannt Objects:
Function gant()
Dim shpBox As Rectangle
Dim inicio As Integer
Dim distancia As Integer
Dim i As Integer
Dim d As Date
Dim aux As Integer
Dim entrada As Integer
Dim largura As Integer
Dim tabela As Recordset
Dim sql As String * 2048
sql = "SELECT [Programadas + status].Código, [Programadas + status].Entrada, [Programadas + status].Saida " _
& "FROM [Programadas + status] " _
& "WHERE ((([Programadas + status].Entrada) < #12/31/2020#) And (([Programadas + status].Saida) >= #1/1/2020#) And (([Programadas + status].Local) = 'SOD')) " _
& "ORDER BY [Programadas + status].Entrada, [Programadas + status].Saida;"
Set tabela = CurrentDb.OpenRecordset(sql)
i = 100
While (Not tabela.EOF)
cod_manut(i) = tabela.Fields("Código").value
d = tabela.Fields("Entrada").value
If (d < #1/1/2020#) Then
d = #1/1/2020#
End If
data_manut(i, 0) = d
d = tabela.Fields("Saida").value
If (d > #12/31/2020#) Then
d = #12/31/2020#
End If
data_manut(i, 1) = d
i = i + 1
tabela.MoveNext
Wend
DoCmd.OpenForm "Formulário4", acDesign
inicio = 1350
distancia = 408
'Set shpBox = Forms!Formulário4!Caixa0
For i = 100 To 173
aux = DateDiff("d", #1/1/2020#, data_manut(i, 0))
entrada = (aux \ 7) * 510 + (aux Mod 7) * 72
aux = DateDiff("d", data_manut(i, 0), data_manut(i, 1))
largura = aux * 72
Set shpBox = Application.CreateControl("Formulário4", acRectangle, acDetail, "", "", entrada, inicio + distancia * (i - 100), largura, 300)
shpBox.name = Replace(Str(i), " ", "")
shpBox.BackColor = 13998939
shpBox.BackStyle = 1
shpBox.Visible = True
shpBox.onMouseDown = Replace("=funcA(""" & Str(i) & """)", " ", "")
shpBox.onMouseUp = Replace("=funcB(""" & Str(i) & """)", " ", "")
shpBox.OnMouseMove = Replace("=funcC(""" & Str(i) & """)", " ", "")
Next i
DoCmd.OpenForm "Formulário4", acNormal
End Function
Function Events
Function funcA(id As String)
Dim b As Integer
Dim i As Integer
Dim nome As String
For i = 0 To 200
nome = (Forms!Formulário4.Controls(i).name)
If nome = id Then
Exit For
End If
Next
b = Get_Cursor_Pos()
clickX = ((valorX - offset) * 15) - Forms!Formulário4.Controls(i).Left
'clickY = (valorX - offset) * 15
drag(i) = True
End Function
Function funcB(id As String)
Dim b As Integer
Dim i As Integer
Dim nome As String
b = Get_Cursor_Pos()
For i = 0 To 200
nome = (Forms!Formulário4.Controls(i).name)
If nome = id Then
Exit For
End If
Next
drag(i) = False
End Function
Function funcC(id As String)
Dim aux As Integer
Dim i As Integer
Dim posX As Integer
Dim posX2 As Integer
Dim nome As String
Dim inicio As Integer
Dim fim As Integer
Dim X As Integer
Dim Y As Integer
inicio = 0
fim = 28720 - 1180
aux = Get_Cursor_Pos()
X = (valorX - offset) * 15
Y = (valorX - offset) * 15
For i = 0 To 200
nome = (Forms!Formulário4.Controls(i).name)
If nome = id Then
Exit For
End If
Next
aux = 0
If drag(i) = True Then 'And Button = acLeftButton Then
'If Shift = acShiftMask Then
posX2 = X - clickX
If Abs(posX2 - posX) > 72 Then
posX = ((posX2 - posX) \ 72) * 72 + posX + 3
posX = posX + (posX \ 504) * 6
End If
'Else
' posX = X - clickX
'End If
If posX < inicio Then
posX = inicio
ElseIf (posX + Forms!Formulário4.Controls(i).Width) > fim Then
posX = fim - Forms!Formulário4.Controls(i).Width
End If
Forms!Formulário4.Controls(i).Left = posX
Forms!Formulário4.mouse1.Caption = ((posX \ 510)) * 7 + (posX - ((posX \ 510) * 510) - 3) \ 72
Forms!Formulário4.Mouse2.Caption = (posX \ 510) + 1
End If
End Function
I had to use this code to get the absolute mouse position, but was necessary do the conversion to use this value
Note.: This value was in pixel, I need to multiply to 15 to get it in twips.
' Access the GetCursorPos function in user32.dll
Declare PtrSafe Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
' Access the GetCursorPos function in user32.dll
Declare PtrSafe Function SetCursorPos Lib "user32" (ByVal X As Long, ByVal Y As Long) As Long
' GetCursorPos requires a variable declared as a custom data type
' that will hold two integers, one for x value and one for y value
Type POINTAPI
X_Pos As Long
Y_Pos As Long
End Type
' Main routine to dimension variables, retrieve cursor position,
' and display coordinates
Function Get_Cursor_Pos()
' Dimension the variable that will hold the x and y cursor positions
Dim Hold As POINTAPI
' Place the cursor positions in variable Hold
GetCursorPos Hold
' Display the cursor position coordinates
valorX = Hold.X_Pos ' \ 15 ' Transform to twips
valorY = Hold.Y_Pos ' \ 15 ' Transform to twips
End Function
And finally I create an object with the defalt arguments of the MouseEvent to the the incremental value of the X and calculate the necessary offset to use:
Private Sub calibracao_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim aux As Integer
aux = Get_Cursor_Pos()
offset = valorX - (X \ 15) ' To Twips
Forms!Formulário4!mouse1.Caption = X ' Twips
Forms!Formulário4.Mouse2.Caption = (valorX - offset) * 15 ' - offset
End Sub
This was the final result:
Gannt Chart
After I drag the manut
Note: I can not make to the file available, because there are confidentially informations.
Thanks for everone that have read and probabily think about a solution, excuse me for some English mistakes.

Related

Graphics drawline scaling vb.net

I'm trying to develop a program that has been made by another person.
What I develop is just for showing the measurement point like the picture below.
There are min and max data that appear in the form and it's showing from the smallest to the largest value and every time the mouse moves from left to right, the measuring point value will adjust to the graph value that has been determined as above.
The problem is data accuracy at the measuring point does not match with the value that has been determined, this is because the graphic is out of frame.
Here is the code for showing graphics;
Private Sub UpdateDiaGraph()
Call Me.ClearGraph(Me.gDia, Me.PicDiaGraph)
Call Me.InitializeGraph(Me.gDia, Me.PicDiaGraph, Me.recDia)
If Me.dsData.Tables("Dia").Rows.Count = 0 Then
Exit Sub
End If
Dim drs() As DataRow = Me.dsData.Tables("Dia").Select("", "[PathNo],[EquipmentNo],[Point]")
Dim pathNo As Integer = 0
Dim equipmentNo As Integer = 0
Dim diaCount As Integer = 0
Dim maxPoint As Integer = 0
Dim longestDiaCount As Integer = 0
Dim upper As New List(Of Decimal)
Dim lower As New List(Of Decimal)
For Each dr As DataRow In drs
If pathNo <> dr("PathNo") Or equipmentNo <> dr("EquipmentNo") Then
pathNo = dr("PathNo")
equipmentNo = dr("EquipmentNo")
'Count the graphics
diaCount += 1
' Get standard width
upper.Add(dr("Upper"))
lower.Add(dr("Lower"))
End If
' Get the max number of graph points and the number of graphs at that time
If maxPoint < dr("Point") Then
maxPoint = dr("Point")
longestDiaCount = diaCount
End If
Next
Dim x1, x2 As Decimal
Dim y1, y2 As Decimal
' Get the width to draw the reference line
Dim oneHeight As Decimal = Me.recDia.Height / (diaCount + 1)
'Initialize the graph
For i As Integer = 1 To diaCount
x1 = Me.recDia.Left + 1
x2 = Me.recDia.Left + Me.recDia.Width - 1
y1 = Me.recDia.Top + oneHeight * i
' Tolerance range
'※0.01mm/1 Point
Me.gDia.FillRectangle(New SolidBrush(Me.toleranceRecColor) _
, x1 _
, y1 - upper(diaCount - i) * 100 _
, Me.recDia.Width - 1 _
, (upper(diaCount - i) - lower(diaCount - i)) * 100)
' reference line
Me.gDia.DrawLine(New Pen(Me.centerLineColor), x1, y1, x2, y1)
Next
' Determine the drawing magnification of the X-axis so that the max number of points can be displayed
Dim xMag As Decimal = Me.recDia.Width / maxPoint
'Draw a graph
Dim counter As Integer = 0
Dim centerLineY As Decimal
Dim center As Decimal = 0
Dim p As Integer = -1
pathNo = 0 : equipmentNo = 0
For Each dr As DataRow In drs
' Get reference line and reference value
If pathNo <> dr("PathNo") Or equipmentNo <> dr("EquipmentNo") Then
pathNo = dr("PathNo")
equipmentNo = dr("EquipmentNo")
counter += 1
centerLineY = Me.recDia.Top + oneHeight * (diaCount - (counter - 1))
center = dr("Center")
'Draw chart title and reference value
Dim num As New Common.Numeric
Dim numFormat As String = num.GetNumericFormat(1, 2)
Dim s As String = dr("MeasuringTarget").ToString & ControlChars.CrLf
Dim sSize As Size = TextRenderer.MeasureText(Me.gDia, s, Me.Font)
Me.gDia.DrawString(s, Me.Font, Brushes.White, Me.recDia.Left - sSize.Width - 2, centerLineY - sSize.Height / 2)
s = ControlChars.CrLf & Format(center, numFormat)
sSize = TextRenderer.MeasureText(Me.gDia, s, Me.Font)
Me.gDia.DrawString(s, Me.Font, Brushes.White, Me.recDia.Left - sSize.Width - 2, centerLineY - sSize.Height / 2)
x1 = 0 : x2 = 0 : y1 = 0 : y2 = 0 : p = -1
End If
p += 1
'Change the drawing direction and starting point of the graph depending on the number of direction changes
If Me.extRevCnt.Item(pathNo) Mod 2 = 0 Then
x2 = Me.recDia.Left + p * xMag
Else
x2 = Me.recDia.Left + Me.recDia.Width - p * xMag
End If
y2 = centerLineY - (dr("Data") - center) * 100
If p <> 0 Then
'graph drawing
If Me.recDia.Top < y2 And y2 < Me.recDia.Top + Me.recDia.Height Then
' Change the drawing color of the graph for each outer diameter
If counter < Me.diaGraphColor.Count Then
Me.gDia.DrawLine(New Pen(Me.diaGraphColor(counter)), x1, y1, x2, y2)
Else
Me.gDia.DrawLine(New Pen(Me.graphColor), x1, y1, x2, y2)
End If
End If
' out of tolerance
If dr("DataFlag") = Common.Constant.DataFlag.NG Then
Me.gDia.DrawLine(New Pen(Me.ngColor), x1, centerLineY, x2, centerLineY)
End If
'Draw a scale every 10m * However, only when drawing the longest graph
'Drawn for the first graph (normal mandrel diameter)
If counter = 1 Then
If p Mod 100 = 0 Then
Me.gDia.DrawLine(Pens.White, x2, Me.recDia.Top + Me.recDia.Height, x2, Me.recDia.Top + Me.recDia.Height - 3)
Dim s As String = (p \ 10).ToString & "m"
Dim sSize As Size = TextRenderer.MeasureText(Me.gDia, s, Me.Font)
Me.gDia.DrawString(s, Me.Font, Brushes.White, x2 - sSize.Width / 2, Me.recDia.Top + Me.recDia.Height + 2)
End If
End If
Else
' determine the corners of a polygon
Dim points As Point() = {New Point(x2, centerLineY - 10), New Point(x2 - 10, centerLineY - 40), New Point(x2 + 10, centerLineY - 40)}
Me.gDia.FillPolygon(Brushes.Blue, points, System.Drawing.Drawing2D.FillMode.Alternate)
' Display the division number in the circle above
Dim s As String = dr("DivNo").ToString
Dim sSize As Size = TextRenderer.MeasureText(Me.gDia, s, Me.Font)
Me.gDia.DrawString(s, New Font(Me.Font, FontStyle.Regular), Brushes.White, x2 - sSize.Width / 2 + 2, centerLineY - 35)
End If
x1 = x2
y1 = y2
Next
Type.Variable.divideTargetDia = Me.DGVDataDia.SelectedRows.Item(0).Index
Call Me.DrawingGraphDia(Me.DGVDataDia.SelectedRows.Item(0).Index)
Me.PicDiaGraph.Refresh()
End Sub
Here is the code for showing data pointer
Private Sub PicDiaGraph_Paint(ByVal gDia As Graphics)
If IsNothing(tblDataDia) = True Then Exit Sub
If tblDataDia.Rows.Count = 0 Then Exit Sub
If IsNothing(tblEquipmentNoDia) = True Then Exit Sub
If tblEquipmentNoDia.Rows.Count = 0 Then Exit Sub
' Allocate the drawing range according to the number of device numbers
Dim allHeight As Integer = Me.PicDiaGraph.Size.Height
'Drawing range per device number
Dim heightPerEN As Integer = allHeight / (tblEquipmentNoDia.Rows.Count + 1)
' Device number count
Dim count As Integer = 0
' Draw a graph for each device number
For Each rEN As DataRow In tblEquipmentNoDia.Rows
Dim eNo As Integer = rEN("EquipmentNo")
Dim tblSource As DataTable = tblDataDia.Clone
For Each r As DataRow In tblDataDia.Select("EquipmentNo = '" & eNo & "'", "Point ASC")
tblSource.ImportRow(r)
Next
' Acquisition of standard value
Dim tblStandard As New DataTable
If Me.Today = False Then
Dim SQL As String = ""
SQL &= "SELECT Standard.Center "
SQL &= "FROM Standard "
SQL &= "WHERE Standard.EquipmentNo = " & eNo & " And Standard.MfgID = '" & barcodeNo.Trim & "' "
SQL &= "GROUP BY Standard.Center;"
daDia = New OleDb.OleDbDataAdapter(SQL, cnMdbDia)
daDia.Fill(tblStandard)
Else
'
End If
Dim center As Single = Format(tblStandard.Rows(0)("center"), "0.00")
' Drawing start position (height)
Dim shift As Integer = heightPerEN * count
'get width of data
Dim margin As Integer = 0
_xMaxDia = tblSource.Select("Point = MAX(Point)")(0)("Point")
_xMinDia = tblSource.Select("Point = MIN(Point)")(0)("Point")
Dim yMax As Single = tblSource.Select("Data = MAX(Data)")(0)("Data")
Dim yMin As Single = tblSource.Select("Data = MIN(Data)")(0)("Data")
'Width on X-axis data
Dim xRange As Integer = _xMaxDia - _xMinDia
'Width on Y-axis data
Dim yRange As Single = yMax - yMin
'Get size of control
Dim height As Integer = heightPerEN - (margin * 2)
Dim width As Integer = Me.PicDiaGraph.Size.Width - 21
' Nominal length per unit
_xUnitDia = width / xRange
Dim yUnit As Single = 200
'graph drawing
For i As Integer = 0 To tblSource.Rows.Count - 2
Dim x1 As Decimal = Me.recDia.Left + 1
' starting point data
Dim row1 As DataRow = tblSource.Rows(i)
Dim point1 As Integer = row1("Point")
Dim data1 As Single = row1("Data")
' end point data
Dim row2 As DataRow = tblSource.Rows(i + 1)
Dim point2 As Integer = row2("Point")
Dim data2 As Single = row2("Data")
If point2 < point1 Then MessageBox.Show("X")
Me.gDia.DrawLine(Pens.White, _
CInt((point1 - _xMinDia) * _xUnitDia), _
height - (data1 - center) * yUnit + margin + shift, _
CInt(point2 - _xMinDia) * _xUnitDia, _
height - (data2 - center) * yUnit + margin + shift)
Next
count += 1
Next
End Sub
The problem might appear in this code

Is there a quicksort routine without calling itself / without using recursion

The well known quicksort routine uses two recursive calls at the end. However, using the quicksort routine in Excel-VBA for large unsorted arrays (> 400 thousand elements) may lead to a memory stack overflow because of the many recursive calls.
Public Sub dQsort(List() As Double, ByVal min As Long, ByVal max As Long)
Dim med_value As Double
Dim hi As Long
Dim lo As Long
Dim i As Long
' If min >= max, the list contains 0 or 1 items so it is sorted.
If min >= max Then GoTo ErrorExit
' Pick the dividing value.
i = (max + min + 1) / 2
med_value = List(i)
' Swap it to the front.
List(i) = List(min)
lo = min
hi = max
Do
' Look down from hi for a value < med_value.
Do While List(hi) >= med_value
hi = hi - 1
If hi <= lo Then Exit Do
Loop
If hi <= lo Then
List(lo) = med_value
Exit Do
End If
' Swap the lo and hi values.
List(lo) = List(hi)
' Look up from lo for a value >= med_value.
lo = lo + 1
Do While List(lo) < med_value
lo = lo + 1
If lo >= hi Then Exit Do
Loop
If lo >= hi Then
lo = hi
List(hi) = med_value
Exit Do
End If
' Swap the lo and hi values.
List(hi) = List(lo)
Loop
' Sort the two sublists.
dQsort List(), min, lo - 1 ' Recursive call which I would like to avoid
dQsort List(), lo + 1, max ' Recursive call which I would like to avoid
End Sub
My question is: Who knows a modified quicksort routine with only a small penalty in extra time compared to the traditional quicksort routine (because of the mentioned memory stack overflow, you can only compare between the "old" and "new" routine for relative small unsorted arrays)?
Answers shown for the "Questions that may already have your answer" are not the answers for my question.
Here is a simple sort for doubles:
Public Sub aSort(ByRef InOut)
Dim i As Long, J As Long, Low As Long
Dim Hi As Long, Temp As Variant
Low = LBound(InOut)
Hi = UBound(InOut)
J = (Hi - Low + 1) \ 2
Do While J > 0
For i = Low To Hi - J
If InOut(i) > InOut(i + J) Then
Temp = InOut(i)
InOut(i) = InOut(i + J)
InOut(i + J) = Temp
End If
Next i
For i = Hi - J To Low Step -1
If InOut(i) > InOut(i + J) Then
Temp = InOut(i)
InOut(i) = InOut(i + J)
InOut(i + J) = Temp
End If
Next i
J = J \ 2
Loop
End Sub
Sub MAIN()
Dim ary(1 To 3) As Double, msg As String
Dim i As Long
ary(1) = 0.4
ary(2) = 0.1
ary(3) = 0.5
Call aSort(ary)
msg = ""
For i = 1 To 3
msg = msg & ary(i) & vbCrLf
Next i
MsgBox msg
End Sub
I don't know if it is "quick" enough.:
The mentioned merge sort has the same disadvantage as the traditional Quicksort: it also uses a recursive call (see the code for Excel’s VBA below, adapted from the named Wiki-page). The TopDownMergeSort sorts only the n-1 array value’s. Therefore, you need to insert the n-th value in the sorted array (of course at the correct place).
Sub Test_Method_MergeSort()
'Array adData with Doubles, starting from index = 1
Call TopDownMergeSort(adData)
Call InsertIntoSortedArray(adData, adData(UBound(adData)), 1, False)
End Sub
'// Array A[] has the items to sort; array B[] is a work array.
Sub TopDownMergeSort(ByRef A() As Double)
Dim B() As Double
Dim n As Long
Dim i As Long
'// duplicate array A[] into B[]
n = UBound(A)
ReDim B(n)
For i = 1 To n
B(i) = A(i)
Next i
'// sort data from B[] into A[]
TopDownSplitMerge B, 1, n, A
End Sub
'Sort the given run of array A[] using array B[] as a source.
'iBegin is inclusive; iEnd is exclusive (A[iEnd] is not in the set).
Sub TopDownSplitMerge(ByRef B() As Double, ByVal iBegin As Long, ByVal iEnd As Long, ByRef A() As Double)
Dim iMiddle As Long
Dim dTmp As Double
If (iEnd - iBegin) < 2 Then Exit Sub ' // if run size == 1
'// split the run longer than 1 item into halves
iMiddle = (iEnd + iBegin) / 2 '// iMiddle = mid point
'// recursively sort both runs from array A[] into B[]
TopDownSplitMerge A, iBegin, iMiddle, B '// sort the left run
TopDownSplitMerge A, iMiddle, iEnd, B '// sort the right run
'// merge the resulting runs from array B[] into A[]
TopDownMerge B, iBegin, iMiddle, iEnd, A
End Sub
'// Left source half is A[ iBegin:iMiddle-1].
'// Right source half is A[iMiddle:iEnd-1].
'// Result is B[ iBegin:iEnd-1].
Sub TopDownMerge(ByRef A() As Double, ByVal iBegin As Long, ByVal iMiddle As Long, ByVal iEnd As Long, ByRef B() As Double)
Dim i As Long
Dim j As Long
Dim k As Long
i = iBegin
j = iMiddle
'// While there are elements in the left or right runs...
For k = iBegin To iEnd - 1
'// If left run head exists and is <= existing right run head.
If ((i < iMiddle) And ((j >= iEnd) Or (A(i) <= A(j)))) Then
B(k) = A(i)
i = i + 1
Else
B(k) = A(j)
j = j + 1
End If
Next k
End Sub
Sub InsertIntoSortedArray(ByRef dSortedArray() As Double, ByVal dNewValue As Double, ByVal LowerBound As Long, Optional ByVal RedimNeeded As Boolean = False) ', xi As Long) As Long
Dim n As Long, ii As Long
n = UBound(dSortedArray)
If RedimNeeded Then
ReDim Preserve dSortedArray(n + 1)
Else
n = n - 1
End If
ii = n + 1
Do Until dSortedArray(ii - 1) <= dNewValue Or ii < (LowerBound + 1)
dSortedArray(ii) = dSortedArray(ii - 1)
ii = ii - 1
Loop
dSortedArray(ii) = dNewValue
End Sub
The solution I was looking for is without any recursive calls. With several additional variables for necessary administration purposes during the sorting steps I succeeded in the following Alternative quicksort “IAMWW_QSort”:
' This code belongs to one and the same Excel’s code module
Private Const msMODULE As String = "M_QSort"
Private alMin() As Long
Private alMax() As Long
Private abTopDownReady() As Boolean
Private aiTopDownIndex() As Integer ' 1 (= TopList) or 2 ( = DownList)
Private alParentIndex() As Long
Sub IAMWW_Qsort(ByRef List() As Double, ByVal Min As Long, ByVal Max As Long)
Dim med_value As Double
Dim hi As Long
Dim lo As Long
Dim i As Long
Dim l_List As Long
' If min >= max, the list contains 0 or 1 items so it is sorted.
If Min >= Max Then GoTo ExitPoint
Call Init(l_List, Min, Max)
Start:
If abTopDownReady(l_List, 1) And abTopDownReady(l_List, 2) Then
abTopDownReady(alParentIndex(l_List), aiTopDownIndex(l_List)) = True
l_List = l_List - 1
If l_List >= 0 Then
GoTo Start
Else
' Ready/list is sorted
GoTo ExitPoint
End If
End If
Min = alMin(l_List)
Max = alMax(l_List)
' -----------------------------------
' The traditional part of QuickSort
' Pick the dividing value.
i = (Max + Min + 1) / 2
med_value = List(i)
' Swap it to the front.
List(i) = List(Min)
lo = Min
hi = Max
Do
' Look down from hi for a value < med_value.
Do While List(hi) >= med_value
hi = hi - 1
If hi <= lo Then Exit Do
Loop
If hi <= lo Then
List(lo) = med_value
Exit Do
End If
' Swap the lo and hi values.
List(lo) = List(hi)
' Look up from lo for a value >= med_value.
lo = lo + 1
Do While List(lo) < med_value
lo = lo + 1
If lo >= hi Then Exit Do
Loop
If lo >= hi Then
lo = hi
List(hi) = med_value
Exit Do
End If
' Swap the lo and hi values.
List(hi) = List(lo)
Loop
' End of the traditional part of QuickSort
' -----------------------------------------
If Max > (lo + 1) Then
' top part as a new sublist
l_List = l_List + 1
Init_NewSubList l_List, l_List - 1, 1, lo + 1, Max
If (lo - 1) > Min Then
' down part as a new sublist
l_List = l_List + 1
Init_NewSubList l_List, l_List - 2, 2, Min, lo - 1
Else
' down part (=2) is sorted/ready
abTopDownReady(l_List - 1, 2) = True
End If
ElseIf (lo - 1) > Min Then
' Top part is sorted/ready...
abTopDownReady(l_List, 1) = True
' ... and down part is a new sublist.
l_List = l_List + 1
Init_NewSubList l_List, l_List - 1, 2, Min, lo - 1
Else
' Both the top (=1) and down part (=2) are sorted/ready ...
abTopDownReady(l_List, 1) = True
abTopDownReady(l_List, 2) = True
' ... and therefore, the parent (sub)list is also sorted/ready ...
abTopDownReady(alParentIndex(l_List), aiTopDownIndex(l_List)) = True
' ... and continue with the before last created new sublist.
l_List = l_List - 1
End If
If l_List >= 0 Then GoTo Start
ExitPoint:
End Sub
Private Sub Init_NewSubList(ByVal Nr As Long, ByVal Nr_Parent As Long, ByVal iTopDownIndex As Integer, ByVal Min As Long, ByVal Max As Long)
' Nr = number of new sublist
' Nr_Parent = the parent's list number of the new sublist
' iTopDownIndex = index for top (=1) or down part (=2) sublist
aiTopDownIndex(Nr) = iTopDownIndex '= 2 ' new sub list is a down part sublist
alParentIndex(Nr) = Nr_Parent 'l_List - 2
abTopDownReady(Nr, 1) = False 'The new sublist has a top part sublist, not ready yet
abTopDownReady(Nr, 2) = False 'The new sublist has a down part sublist, not ready yet
' min and max values of the new sublist
alMin(Nr) = Min
alMax(Nr) = Max 'lo - 1
End Sub
Private Sub Init(ByRef Nr As Long, ByVal Min As Long, ByVal Max As Long)
Dim lArraySize As Long
lArraySize = Max - Min + 1
ReDim alMin(lArraySize)
ReDim alMax(lArraySize)
ReDim abTopDownReady(lArraySize, 2)
ReDim aiTopDownIndex(lArraySize)
ReDim alParentIndex(lArraySize)
Nr = 0
alMin(Nr) = Min
alMax(Nr) = Max
aiTopDownIndex(0) = 2 ' Initial list is assumed to be a down part (= 2)
End Sub
The penalty in extra time because of the additional administrative code lines is very small.

Change subitem backcolor of a listview next item

I have a listview filled with SRT subtitle. I'am trying to change listview color based on subtitle errors. Everything is working fine, but color won't change when subtitles is overlapping. I take end-time of one subtitle and start-time of next subtitle. Based on difference, it decide is there overlapping or not. Calculations are OK but backcolor and forecolor won't change. It does change backcolor for current item but I need to change backcolor for next listview item.
'EXAMPLE #######################################
For i as integer = 0 to listview1.items.count -1
ListView1.Items(i).UseItemStyleForSubItems = False
'this is working #######
ListView1.Items.Item(i).SubItems(1).BackColor = ColorTranslator.FromHtml("#F0A6A7")
'but this is NOT working ( THIS IS WHAT I NEED) ####################
ListView1.Items.Item(i).SubItems(i + 1).BackColor = ColorTranslator.FromHtml("#F0A6A7")
Next i
'########################################################
Public Function Color_Errors(ByVal SubtitleListView As ListView)
For i = 0 To SubtitleListView.Items.Count - 2
SubtitleListView.Items(i).UseItemStyleForSubItems = False
SubtitleListView.Items(i + 1).UseItemStyleForSubItems = False
SubtitleListView.Items.Item(i).SubItems(1).ResetStyle()
SubtitleListView.Items.Item(i).SubItems(2).ResetStyle()
SubtitleListView.Items.Item(i).SubItems(3).ResetStyle()
SubtitleListView.Items.Item(i).SubItems(4).ResetStyle()
SubtitleListView.Items.Item(i).SubItems(5).ResetStyle()
Dim Text As String = SubtitleListView.Items.Item(i + 1).SubItems(5).Text
Dim TextLength As Integer = Get_Longest_Line_Length(Text)
Dim NumberOfLines As Integer = Split(Text, "|").Length
Dim Duration As Double = Convert_Time_to_Milliseconds(SubtitleListView.Items.Item(i).SubItems(4).Text)
Dim Pause As Double = Convert_Time_to_Milliseconds(SubtitleListView.Items.Item(i).SubItems(1).Text)
Dim _Start As Double = Convert_Time_to_Milliseconds(SubtitleListView.Items.Item(i).SubItems(2).Text)
Dim _End As Double = Convert_Time_to_Milliseconds(SubtitleListView.Items.Item(i).SubItems(3).Text)
Dim _NextStart As Double
If i < (SubtitleListView.Items.Count - 1) Then
_NextStart = Convert_TimeSpan_to_Milliseconds(SubtitleListView.Items.Item(i + 1).SubItems(2).Text)
End If
'TOO LONG LINES
If TextLength > MaxLength Then
SubtitleListView.Items.Item(i).SubItems(5).BackColor = ColorTranslator.FromHtml("#F0A6A7")
SubtitleListView.Items.Item(i).SubItems(5).ForeColor = Color.Black
End If
'TOO LONG DURATION
If Duration > 6000 Then
SubtitleListView.Items.Item(i).SubItems(4).BackColor = ColorTranslator.FromHtml("#F5CBD9")
SubtitleListView.Items.Item(i).SubItems(4).ForeColor = ColorTranslator.FromHtml("#6F0021")
SubtitleListView.Items.Item(i).SubItems(3).BackColor = ColorTranslator.FromHtml("#F5CBD9")
SubtitleListView.Items.Item(i).SubItems(3).ForeColor = ColorTranslator.FromHtml("#6F0021")
'SHORTER THAN 2 SECONDS
ElseIf Duration < 2000 AndAlso Duration >= 700 Then
SubtitleListView.Items.Item(i).SubItems(4).BackColor = Color.Red
SubtitleListView.Items.Item(i).SubItems(4).ForeColor = Color.White
'TOO SHORT DURATION
ElseIf Duration < 700 Then
SubtitleListView.Items.Item(i).SubItems(3).BackColor = ColorTranslator.FromHtml("#FFF0E1")
SubtitleListView.Items.Item(i).SubItems(3).ForeColor = ColorTranslator.FromHtml("#A45200")
SubtitleListView.Items.Item(i).SubItems(4).BackColor = ColorTranslator.FromHtml("#FFF0E1")
SubtitleListView.Items.Item(i).SubItems(4).ForeColor = ColorTranslator.FromHtml("#A45200")
End If
''TOO SHORT PAUSE
If Pause < 200 Then
SubtitleListView.Items.Item(i).SubItems(1).BackColor = ColorTranslator.FromHtml("#ACC9E6")
SubtitleListView.Items.Item(i).SubItems(1).ForeColor = Color.Black
SubtitleListView.Items.Item(i).SubItems(2).BackColor = ColorTranslator.FromHtml("#ACC9E6")
SubtitleListView.Items.Item(i).SubItems(2).ForeColor = Color.Black
End If
If NumberOfLines > 2 Then
SubtitleListView.Items.Item(i).SubItems(5).ForeColor = ColorTranslator.FromHtml("#0000FF")
End If
'ERROR PART #################################################
If i < (SubtitleListView.Items.Count - 1) Then
If _End > _NextStart Then
SubtitleListView.Items.Item(i + 1).SubItems(1).BackColor = ColorTranslator.FromHtml("#BB0025")
SubtitleListView.Items.Item(i + 1).SubItems(1).ForeColor = Color.White
SubtitleListView.Items.Item(i).SubItems(2).BackColor = ColorTranslator.FromHtml("#BB0025")
SubtitleListView.Items.Item(i).SubItems(2).ForeColor = Color.White
End If
End If
'############################################################
Next i
Return Nothing
End Function
Public Function Convert_Time_to_Milliseconds(ByVal Time As String)
If Time.Contains(":") = True Then
Dim VremePrviDeo() As String = Split(Time, ":")
If VremePrviDeo.Length = 3 Then
Dim Sati As Integer = VremePrviDeo(0) * 60 * 60 * 1000
Dim Minuti As Integer = VremePrviDeo(1) * 60 * 1000
Dim VremeDrugiDeo() As String = Split(VremePrviDeo(2), ",")
Dim Sekunde As Integer = VremeDrugiDeo(0) * 1000
Dim Milisekunde As Integer = VremeDrugiDeo(1)
Dim Miliseconds As Double = Sati + Minuti + Sekunde + Milisekunde
Return Miliseconds.ToString
ElseIf VremePrviDeo.Length = 2 Then
Dim Minuti As Integer = VremePrviDeo(0) * 60 * 1000
Dim VremeDrugiDeo() As String = Split(VremePrviDeo(2), ",")
Dim Sekunde As Integer = VremeDrugiDeo(0) * 1000
Dim Milisekunde As Integer = VremeDrugiDeo(1)
Dim Miliseconds As Double = Minuti + Sekunde + Milisekunde
Return Miliseconds.ToString
End If
Else
Dim VremePrviDeo() As String = Split(Time, ",")
Dim Sekunde As Integer = VremePrviDeo(0) * 1000
Dim Milisekunde As Integer = VremePrviDeo(1)
Dim Miliseconds As Double = Sekunde + Milisekunde
Return Miliseconds.ToString
End If
Return Nothing
End Function
Public Function Get_Longest_Line_Length(ByVal Text As String)
Dim Duzina As Integer = 0
For Each line As String In Split(Text, "|")
If line.Length > Duzina Then
Duzina = line.Length
End If
Next
Return Duzina
End Function
Public Function Convert_TimeSpan_to_Milliseconds(ByVal Time As String)
'Try
Dim Parsed() As String = Parse_String_to_TimeSpan(Time)
Dim Sat As Double = TimeSpan.FromHours(Parsed(0)).TotalMilliseconds
Dim Minut As Double = TimeSpan.FromMinutes(Parsed(1)).TotalMilliseconds
Dim Sekunda As Double = TimeSpan.FromSeconds(Parsed(2)).TotalMilliseconds
Dim Milisekunda As Double = TimeSpan.FromMilliseconds(Parsed(3)).TotalMilliseconds
Dim TotalTime As Double = Sat + Minut + Sekunda + Milisekunda
Return TotalTime
'Catch ex As Exception
'End Try
'Return Nothing
End Function

TA-Lib using TA_INTEGER_DEFAULT and TA_REAL_DEFAULT in VB.NET 2010

VB.NET 2010 below is working. But I need to use default values as stated in TA-Lib documentation: TA_INTEGER_DEFAULT or TA_REAL_DEFAULT for optional parameters. How I can use that in coding?
Currently I assign values manually (need to know what are the values).
Public Sub CalcMACD()
' CALCULATE allocationSize
Dim lookback As Integer = TicTacTec.TA.Library.Core.MacdLookback(optInFastPeriod, optInSlowPeriod, optInSignalPeriod)
Dim temp As Integer = Math.Max(lookback, startIdx)
If (temp > endIdx) Then
allocationSize = 0 ' No output
Else
allocationSize = endIdx - temp + 1
End If
optInFastPeriod = 12 ' Set optional values <==== HOW TO USE TA_INTEGER_DEFAULT
optInSlowPeriod = 26 ' Set optional values <==== HOW TO USE TA_INTEGER_DEFAULT
optInSignalPeriod = 9 ' Set optional values <==== HOW TO USE TA_INTEGER_DEFAULT
Dim outMACD As Double() ' Declare output variable type
ReDim outMACD(allocationSize)
Dim outMACDSignal As Double() ' Declare output variable type
ReDim outMACDSignal(allocationSize)
Dim outMACDHist As Double() ' Declare output variable type
ReDim outMACDHist(allocationSize)
' the calculation
Dim res As TicTacTec.TA.Library.Core.RetCode = TicTacTec.TA.Library.Core.Macd(startIdx, endIdx, openPrice, optInFastPeriod, optInSlowPeriod, optInSignalPeriod, outBegIdx, outNBElement, outMACD, outMACDSignal, outMACDHist)
' Add result column to Datagridview
' #1 add column to Datagridview1
DataGridView1.ColumnCount = DataGridView1.ColumnCount + 3
Dim columnID As Integer = DataGridView1.ColumnCount - 3
' #2 define column header
DataGridView1.Columns(columnID).HeaderText = "MACD"
DataGridView1.Columns(columnID + 1).HeaderText = "MACD Signal"
DataGridView1.Columns(columnID + 2).HeaderText = "MACD Histogram"
'#3 insert values to column
For i As Integer = startIdx To endIdx
DataGridView1(columnID, i).Value = outMACD(i)
DataGridView1(columnID + 1, i).Value = outMACDSignal(i)
DataGridView1(columnID + 2, i).Value = outMACDHist(i)
Next
End Sub
Public Sub CalcMACD(Optional ByVal optInFastPeriod As Integer = TA_INTEGER_DEFAULT, Optional ByVal optInSlowPeriod As Integer = TA_INTEGER_DEFAULT, Optional ByVal optInSignalPeriod As Integer = TA_INTEGER_DEFAULT)
' CALCULATE allocationSize
Dim allocationSize As Integer = 0
Dim lookback As Integer = TicTacTec.TA.Library.Core.MacdLookback(optInFastPeriod, optInSlowPeriod, optInSignalPeriod)
Dim temp As Integer = Math.Max(lookback, startIdx)
If (temp < endIdx) Then
allocationSize = endIdx - temp + 1
End If
' Declare output variables
Dim outMACD(allocationSize) As Double
Dim outMACDSignal(allocationSize) As Double
Dim outMACDHist(allocationSize) As Double
' the calculation
Dim res As TicTacTec.TA.Library.Core.RetCode = TicTacTec.TA.Library.Core.Macd(startIdx, endIdx, openPrice, optInFastPeriod, optInSlowPeriod, optInSignalPeriod, outBegIdx, outNBElement, outMACD, outMACDSignal, outMACDHist)
' Add result column to Datagridview
' #1 add column to Datagridview1
DataGridView1.ColumnCount = DataGridView1.ColumnCount + 3
Dim columnID As Integer = DataGridView1.ColumnCount - 3
' #2 define column header
DataGridView1.Columns(columnID).HeaderText = "MACD"
DataGridView1.Columns(columnID + 1).HeaderText = "MACD Signal"
DataGridView1.Columns(columnID + 2).HeaderText = "MACD Histogram"
'#3 insert values to column
For i As Integer = startIdx To endIdx
DataGridView1(columnID, i).Value = outMACD(i)
DataGridView1(columnID + 1, i).Value = outMACDSignal(i)
DataGridView1(columnID + 2, i).Value = outMACDHist(i)
Next
End Sub

Normal Distributed Random Number in VB.NET

Is there anybody know how to make normal distributed random number in vb.net?
thank you
From this forum post :
Usage:
GaussNumDist(Mean, Standard Deviation, Sample Size)
Code example below, which will populate GaussNumArray() with the sample of numbers, whose distribution will have the mean and standard deviation specified:
Imports System.Math
Module Module1
Friend GaussNumArray() As Double
Friend intICell As Long
Friend Function GaussNumDist(ByVal Mean As Double, ByVal StdDev As Double, ByVal SampleSize As Integer)
intICell = 1 'Loop variable
ReDim GaussNumArray(SampleSize)
Do While (intICell < (SampleSize + 1))
Call NumDist(Mean, StdDev)
Application.DoEvents()
Loop
End Function
Sub NumDist(ByVal meanin As Double, ByVal sdin As Double)
'---------------------------------------------------------------------------------
'Converts uniform random numbers over the region 0 to 1 into Gaussian distributed
'random numbers using Box-Muller algorithm.
'Adapted from Numerical Recipes in C
'---------------------------------------------------------------------------------
'Defining variables
Dim dblR1 As Double
Dim dblR2 As Double
Dim mean As Double
Dim var As Double
Dim circ As Double
Dim trans As Double
Dim dblY1 As Double
Dim dblY2 As Double
Dim Pi As Double
Pi = 4 * Atan(1)
'Get two random numbers
dblR1 = (2 * UniformRandomNumber()) - 1
dblR2 = (2 * UniformRandomNumber()) - 1
circ = (dblR1 ^ 2) + (dblR2 ^ 2) 'Radius of circle
If circ >= 1 Then 'If outside unit circle, then reject number
Call NumDist(meanin, sdin)
Exit Sub
End If
'Transform to Gaussian
trans = Sqrt(-2 * Log(circ) / circ)
dblY1 = (trans * dblR1 * sdin) + meanin
dblY2 = (trans * dblR2 * sdin) + meanin
GaussNumArray(intICell) = dblY1 'First number
'Increase intICell for next random number
intICell = (intICell + 1)
GaussNumArray(intICell) = dblY2 'Second number
'Increase intICell again ready for next call of ConvertNumberDistribution
intICell = (intICell + 1)
End Sub
Friend Function UniformRandomNumber() As Double
'-----------------------------------------------------------------------------------
'Outputs random numbers with a period of > 2x10^18 in the range 0 to 1 (exclusive)
'Implements a L'Ecuyer generator with Bays-Durham shuffle
'Adapted from Numerical Recipes in C
'-----------------------------------------------------------------------------------
'Defining constants
Const IM1 As Double = 2147483563
Const IM2 As Double = 2147483399
Const AM As Double = (1.0# / IM1)
Const IMM1 As Double = (IM1 - 1.0#)
Const IA1 As Double = 40014
Const IA2 As Double = 40692
Const IQ1 As Double = 53668
Const IQ2 As Double = 52774
Const IR1 As Double = 12211
Const IR2 As Double = 3791
Const NTAB As Double = 32
Const NDIV As Double = (1.0# + IM1 / NTAB)
Const ESP As Double = 0.00000012
Const RNMX As Double = (1.0# - ESP)
Dim iCell As Integer
Dim idum As Double
Dim j As Integer
Dim k As Long
Dim temp As Double
Static idum2 As Long
Static iy As Long
Static iv(NTAB) As Long
idum2 = 123456789
iy = 0
'Seed value required is a negative integer (idum)
Randomize()
idum = (-Rnd() * 1000)
'For loop to generate a sequence of random numbers based on idum
For iCell = 1 To 10
'Initialize generator
If (idum <= 0) Then
'Prevent idum = 0
If (-(idum) < 1) Then
idum = 1
Else
idum = -(idum)
End If
idum2 = idum
For j = (NTAB + 7) To 0
k = ((idum) / IQ1)
idum = ((IA1 * (idum - (k * IQ1))) - (k * IR1))
If (idum < 0) Then
idum = (idum + IM1)
End If
If (j < NTAB) Then
iv(j) = idum
End If
Next j
iy = iv(0)
End If
'Start here when not initializing
k = (idum / IQ1)
idum = ((IA1 * (idum - (k * IQ1))) - (k * IR1))
If (idum < 0) Then
idum = (idum + IM1)
End If
k = (idum2 / IQ2)
idum2 = ((IA2 * (idum2 - (k * IQ2))) - (k * IR2))
If (idum2 < 0) Then
idum2 = idum2 + IM2
End If
j = (iy / NDIV)
iy = (iv(j) - idum2)
iv(j) = idum
If (iy < 1) Then
iy = (iy + IMM1)
End If
temp = AM * iy
If (temp <= RNMX) Then
'Return the value of the random number
UniformRandomNumber = temp
End If
Next iCell
End Function
End Module
You can use following line
Dim x1 as Double = MathNet.Numerics.Distributions.Normal.Sample(MEAN, STDEV)
Math.Net Numeric package can be installed using following NuGet command
Install-Package MathNet.Numerics -Version 4.9.0
You can found more information on NuGet site