Catia VBA, How to get "Bill of material" to an array - vba

I want to get 2 parameters in "bill of material".
first "Length" in structure workbench, second is "quantity".
I try to find these 2 parameters in
CATIA.Documents.Item(Document).Product.ReferenceProduct
But can't.
I have an idea. I try find a way to get "Bill of material" into an array.
I found a code write Bill of material to excel file.
On Error Resume Next
Dim productDocument1 As productDocument
Set productDocument1 = CATIA.ActiveDocument
Dim product1 As Product
Set product1 = productDocument1.Product
Dim assemblyConvertor1 As AssemblyConvertor
Set assemblyConvertor1 = product1.GetItem("BillOfMaterial")
assemblyConvertor1.[Print] "XLS", "D:\BOM.xls", product1
How to get "Bill of material" data into an array? Thanks

The length parameter of elements of the structure design apparently only available trough the StrComputeServices
Example:
Sub CATMain()
Dim oRootProduct as Product
Dim oInstanceProduct as Product
Dim oStrWB as Workbench
Dim oStrServices As StrComputeServices
Set oRootProduct = CATIA.ActiveDocument.Product
Set oInstanceProduct = oRootProduct.Products.Item(1)
Set oStrWB = CATIA.ActiveDocument.GetWorkbench("StrWorkbench")
Set oStrServices = oStrWB.StrComputeServices
MsgBox CStr(oStrServices.GetLength(oInstanceProduct))
End Sub

I have developed this code below if it can help you :
https://www.catiavb.net/sourceCodeCATIA.php#getbom
You can find the function to get 'MaLangue' in same website (to return language used by CATIA if necessary). Or you can delete every line who refers to 'MaLangue'. To launch the sub you can write GetBOM(Catia.ActiveDocument.Product) if you want to get the BOM of the root product. Or you can launch for for an other product from the root.
You can then read lines of the txt file (thanks to a stream reader) and split by every vbTab to get your array. The advantage is that you will have a bill of materials that either lists all the parts, or only lists the first level as required by certain customer standards
'Genere la BOM
Public Sub GetBOM(p As Product)
Dim NomFichier As String = My. Computer . FileSystem . SpecialDirectories . Temp & "\BOM.txt"
Dim AssConvertor As AssemblyConvertor
AssConvertor = p. GetItem ( "BillOfMaterial" )
Dim nullstr ( 2 )
If MaLangue = "Anglais" Then
nullstr( 0 ) = "Part Number"
nullstr( 1 ) = "Quantity"
nullstr( 2 ) = "Type"
ElseIf MaLangue = "Francais" Then
nullstr( 0 ) = "Référence"
nullstr( 1 ) = "Quantité"
nullstr( 2 ) = "Type"
End If
AssConvertor. SetCurrentFormat (nullstr)
Dim VarMaListNom( 1 )
If MaLangue = "Anglais" Then
VarMaListNom( 0 ) = "Part Number"
VarMaListNom( 1 ) = "Quantity"
ElseIf MaLangue = "Français" Then
VarMaListNom( 0 ) = "Référence"
VarMaListNom( 1 ) = "Quantité"
End If
AssConvertor. SetSecondaryFormat (VarMaListNom)
AssConvertor. Print ( "HTML", NomFichier, p )
ModifFichierNomenclature (My. Computer . FileSystem . SpecialDirectories . Temp & "\BOM.txt" )
End Sub
Sub ModifFichierNomenclature(txt As String )
Dim strtocheck As String = ""
If MaLangue = "Francais" Then
strtocheck = "<b>Total des p"
Else
strtocheck = "<b>Total parts"
End If
Dim FichierNomenclature As String = My. Computer . FileSystem . SpecialDirectories . Temp & "\BOM_.txt"
If IO. File . Exists (FichierNomenclature) Then
IO . File . Delete (FichierNomenclature)
End If
Dim fs As FileStream = Nothing
fs = New FileStream( FichierNomenclature, FileMode. CreateNew )
Using sw As StreamWriter = New StreamWriter( fs, Encoding. GetEncoding ( "iso-8859-1" ) )
If IO. File . Exists (txt) Then
Using sr As StreamReader = New StreamReader(txt, Encoding. GetEncoding ( "iso-8859-1" ) )
Dim BoolStart As Boolean = False
While Not sr. EndOfStream
Dim line As String = sr. ReadLine
If Left (line, 8 ) = "<a name=" Then
If MaLangue = "Français" Then
line = "[" & Right (line, line. Length - 24 )
line = Left (line, line. Length - 8 )
line = line & "]"
sw . WriteLine (line)
Else
line = "[" & Right (line, line. Length - 27 )
line = Left (line, line. Length - 8 )
line = line & "]"
sw . WriteLine (line)
End If
ElseIf line Like " <tr><td><A HREF=*</td> </tr>*" Then
line = Replace (line, "</td><td>Assembly</td> </tr>", "" ) 'pas fait
line = Replace (line, "</td><td>Assemblage</td> </tr> ", "" )
line = Replace (line, " <tr><td><A HREF=", "" )
line = Replace (line, "</A></td><td>", ControlChars. Tab )
line = Replace (line, "#Bill of Material: ", "" )
line = Replace (line, "#Nomenclature : ", "" )
If line. Contains ( ">" ) Then
Dim lines( ) = Strings. Split (line, ">" )
line = lines( 1 )
End If
Dim lines_( ) = Strings. Split (line, ControlChars. Tab )
line = lines_( 0 ) & ControlChars . Tab & lines_( 1 )
If Strings. Left (line, 2 ) = " " Then line = Strings. Right (line, line. Length - 2 )
sw . WriteLine (line)
ElseIf Left (line, 14 ) = strtocheck Then
sw . WriteLine ( "[ALL-BOM-APPKD]" )
ElseIf line Like "*<tr><td>*</td> </tr>*" Then
line = Replace (line, "<tr><td>", "" )
line = Replace (line, "</td> </tr> ", "" )
line = Replace (line, "</td><td>", ControlChars. Tab )
Dim lines_( ) = Strings. Split (line, ControlChars. Tab )
line = lines_( 0 ) & ControlChars . Tab & lines_( 1 )
If Strings. Left (line, 2 ) = " " Then line = Strings. Right (line, line. Length - 2 )
sw . WriteLine (line)
Else
'nothing
End If
End While
sr . Close ( )
End Using
End If
sw . Close ( )
End Using
End Sub

Related

Remove a line contains something in VB.Net

in that case how can I change this line to be "" or delete it?
For Each Line As String In TxtListScanTxt.Lines
If (Line.Contains("{ LstScan = , DrwR2 = 0000000000 }")) Then
Line.Remove(Line)
End If
Next
TxtListScanTxt.Lines = TxtListScanTxt.Lines.Where( _
Function(line) Not line.Contains("{ LstScan = , DrwR2 = 0000000000 }") _
).ToArray()

Excel VBA - dropping and adding zeros in a specified character count

I am attempting to build a vba code to build txt files that we use to test with. I am running into an issue. Some of my results will have .00 which I made dropped off using Str = Str & "00" & Left(CashRightJust(Range("h63"), 11), 9)
This basically is telling it to look at cell H63, right justified the amount but left justify the end by 9 to drop cents if it is "00".
My problem is we now need to test for it to have actual change like .25. Using this code alone adds a zero at the end of the change. I need to adjust this code to reflect if it is more then .00 do not edit or add zeros
I hope this makes sense. I am still fairly new at this and have gotten pretty far but there are still some moments I am lost. Thank you.
Spreadsheet created to build code to send to txt file
Function Detail_Rec1()
Dim strlencount As Integer
Dim strspacer As Integer
If Range("b63").Value <> "5" Then
Exit Function
End If
Str = Str & Range("b63").Value **Result: 5**
Str = Str & Range("c63").Value **Result: 400**
Str = Str & Range("d63").Value **Result: 1234567**
Str = Module1.SpaceAdd(Str, 1) **Result: 1 space**
Str = Str & Trim(Range("e63").Value)
strlencount = Len(Trim(Range("e63").Value))
strspacer = 30 - strlencount
Str = Module1.SpaceAdd(Str, strspacer) **Result: Company name with spacefill for 30 character; name is left justified**
Str = Str & Trim(Range("f63").Value)
strlencount = Len(Trim(Range("f63").Value))
strspacer = 11 - strlencount
Str = Module1.SpaceAdd(Str, strspacer) **Result: Company ID number; left justify; space filled total 11 characters**
Str = Str & Range("G63").Value Result: 116
Str = Str & CashRightJust(Range("h63"), 11) **Result: 1000; only 1000 no cents; dollars only; 11 character zero filled right justify**
Str = Str & CashRightJust(Range("i63"), 11)**Result: 1000; only 1000 no cents; dollars only; 11 character zero filled right justify**
Str = Str & CashRightJust(Range("j63"), 11)**Result: 1000; only 1000 no cents; dollars only; 11 character zero filled right justify**
Str = Str & Trim(Range("k63").Value)
strlencount = Len(Trim(Range("k63").Value))
strspacer = 4 - strlencount
Str = Module1.ZeroAdd(Str, strspacer) **Result: Rate of 4 characters entered; 4 character length**
Str = Module1.SpaceAdd(Str, 1) **Result: 1 space**
Str = Str & CashRightJust(Range("l63"), 11) **Result: 3348.75 needs to be 334875. 11 characters, right justified, no decimal.**
Str = Str & CashRightJust(Range("m63"), 11)
Str = Str & CashRightJust(Range("n63"), 11)
Str = Str & CashRightJust(Range("o63"), 11)
Str = Str & "00000" & Right(Range("p63").Value, 6)
strlencount = Len(Trim(Range("p63").Value))
strspacer = 6 - strlencount
Str = Module1.ZeroAdd(Str, strspacer)
[Excel image of line being coded][How text file should appear][2]2]
My end result for what I need is
23.45 - 2345
23.00 - 2300 unless the spec is saying dollars only then it needs to be 23
No rounding.
I hope this helps out more with the visuals
Added Info: My module that is used for the $ amts currently is following:
If Str = 0 Then
CashRightJust = ZeroAdd(Str2, c)
Exit Function
Else
If InStr(Str, ".") > 0 Then
Str2 = Right(Str, 2)
If InStr(Str2, ".") > 0 Then
strnew = Str & "0"
Else
strnew = Str
End If
Else
strnew = Str & "00"
End If
Excel snapshot of info being coded
54001234567 Bob's Tires 987654321 116000000010000000000005000000009503525 00000334875
This is how it is coming out:
54001234567 Bob's Tires 987654321 1160000010000000000005000000000950003525 000334875
I could not post the image of the txt file I don't have enough reputations; sorry; this is how it should appear
Can you try something like this? It assumes your entire string is in cell A1 and that this is the situation where dollars and cents are not required (I assume you can handle the situation where they are because it sounds like you more or less leave the string alone in that case).
lenOfStr = 11
newStr = ""
subStr = Right(Cells(1, 1), lenOfStr)
If Right(subStr, 2) = "00" Then 'we need to keep these
lenOfStr = 9
End If
foundLeftmost = False
For i = 1 To lenOfStr
If Mid(subStr, i, 1) <> "0" and Mid(subStr, i, 1) <> "." Then
newStr = newStr & Mid(subStr, i, 1) 'start collecting for the new string
foundLeftmost = True
End If
If foundLeftmost and Mid(subStr, i, 1) <> "." Then 'need to include zeros that may show up in the middle of the substring
newStr = newStr & Mid(subStr, i, 1)
End If
Next i
subStr = newStr
The end result is stored in subStr. Hopefully I understood your problem correctly. Let me know if I didn't.

VB.net Auto Newline After Copying

First of all, I'm still new in VB.net and I had encountered one weird issue
I had created a tools that will split content from multilines textbox A into lines of string and add some characters and join them back and display in another multilines textbox B (A -> split content -> add character -> join -> display in B). The sample would be like this
Original Data from A:
This
is
a
test
data
Result Displayed in B:
Row 0 = This
Row 1 = is
Row 2 = a
Row 3 = test
Row 4 = data
Result COPIED from B:
Row 0 = This
Row 1 =
is
Row 2 =
a
Row 3 =
test
Row 4 =
data
The source code is
tempA = ""
tempB = ""
tempA = A.Text()
stringAry = tempA.Split(Environment.NewLine)
For iCounter As Integer = 0 To stringAry.Length - 1
tempB = tempB + "Row " + iCounter.ToString + " = " + stringAry(iCounter).ToString + Environment.NewLine
Next
B.Text() = tempB
So may I know why the copied result will be different from result displayed and how could I solve this?
You should remove any unwanted new line characters from the stringAry(iCounter) value.
tempA = ""
tempB = ""
tempA = A.Text()
stringAry = tempA.Split(Environment.NewLine)
For iCounter As Integer = 0 To stringAry.Length - 1
tempB = tempB + "Row " + iCounter.ToString + " = " + stringAry(iCounter).ToString.Replace(Environment.NewLine, string.Empty) + Environment.NewLine
Next
B.Text() = tempB

Calculate words value in vb.net

I have a textbox on a form where the user types some text. Each letter is assigned a different value like a = 1, b = 2, c = 3 and so forth. For example, if the user types "aa bb ccc" the output on a label should be like:
aa = 2
bb = 4
dd = 6
Total value is (12)
I was able to get the total value by looping through the textbox string, but how do I display the total for each word. This is what I have so far:
For letter_counter = 1 To word_length
letter = Mid(txtBox1.Text, letter_counter, 1)
If letter.ToUpper = "A" Then
letter_value = 1
End If
If letter.ToUpper = "B" Then
letter_value = 2
End If
If letter.ToUpper = "C" Then
letter_value = 3
End If
If letter.ToUpper = "D" Then
letter_value = 4
End If
If letter.ToUpper = "E" Then
letter_value = 5
End If
If letter.ToUpper = " " Then
letter_value = 0
End If
totalletter = totalletter + letter_value
Label1.Text = Label1.Text & letter_value & " "
txtBox2.Text = txtBox2.Text & letter_value & " "
Next letter_counter
This simple little routine should do the trick:
Private Sub CountLetters(Input As String)
Label1.Text = ""
Dim total As Integer = 0
Dim dicLetters As New Dictionary(Of Char, Integer)
dicLetters.Add("a"c, 1)
dicLetters.Add("b"c, 5)
dicLetters.Add("c"c, 7)
For Each word As String In Input.Split
Dim wordtotal As Integer = 0
For Each c As Char In word
wordtotal += dicLetters(Char.ToLower(c))
Next
total += wordtotal
'Display word totals here
Label1.Text += word.PadRight(12) + "=" + wordtotal.ToString.PadLeft(5) + vbNewLine
Next
'Display total here
Label1.Text += "Total".PadRight(12) + "=" + total.ToString.PadLeft(5)
End Sub
This should give you an idea:
Dim listOfWordValues As New List(Of Integer)
For letter_counter = 1 To word_length
letter = Mid(txtBox1.Text, letter_counter, 1)
If letter = " " Then
totalletter= totalletter + letter_value
listOfWordValues.Add(letter_value)
letter_value = 0
Else
letter_value += Asc(letter.ToUpper) - 64
End If
Next letter_counter
totalletter = totalletter + letter_value
If Not txtBox1.Text.EndsWith(" ") Then listOfWordValues.Add(letter_value)
txtBox2.Text = txtBox2.Text & string.Join(", ", listOFWordValues);
You can try something like this. Assuming txtBox1 is the string the user enters and " " (space) is the word delimiter:
Dim words As String() = txtBox1.Text.Split(New Char() {" "}, StringSplitOptions.RemoveEmptyEntries)
Dim totalValue As Integer = 0
Dim wordValue As Integer = 0
For Each word As String In words
wordValue = 0
For letter_counter = 1 To word.Length
Dim letter As String = Mid(txtBox1.Text, letter_counter, 1)
Select letter.ToUpper()
Case "A":
wordValue = wordValue + 1
Case "B":
wordValue = wordValue + 2
' And so on
End Select
Next
totalValue = toalValue + wordValue
Next
The above code first takes the entered text from the user and splits it on " " (space).
Next it sets two variables - one for the total value and one for the individual word values, and initializes them to 0.
The outer loop goes through each word in the array from the Split performed on the user entered text. At the start of this loop, it resets the wordValue counter to 0.
The inner loop goes through the current word, and totals up the values of the letter via a Select statement.
Once the inner loop exits, the total value for that word is added to the running totalValue, and the next word is evaluated.
At the end of these two loops you will have calculated the values for each word as well as the total for all the worlds.
The only thing not included in my sample is updating your label(s).
Try this ..
Dim s As String = TextBox1.Text
Dim c As String = "ABCDE"
Dim s0 As String
Dim totalletter As Integer
For x As Integer = 0 To s.Length - 1
s0 = s.Substring(x, 1).ToUpper
If c.Contains(s0) Then
totalletter += c.IndexOf(s0) + 1
End If
Next
MsgBox(totalletter)
I would solve this problem using a dictionary that maps each letter to a number.
Private Shared ReadOnly LetterValues As Dictionary(Of Char, Integer) = GetValues()
Private Shared Function GetValues() As IEnumerable(Of KeyValuePair(Of Char, Integer))
Dim values As New Dictionary(Of Char, Integer)
Dim value As Integer = 0
For Each letter As Char In "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
value += 1
values.Add(letter, value)
Next
Return values
End Function
Public Function CalculateValue(input As String) As Integer
Dim sum As Integer = 0
For Each letter As Char In input.ToUpperInvariant()
If LetterValues.ContainsKey(letter) Then
sum += LetterValues.Item(letter)
End If
Next
Return sum
End Function
Usage example:
Dim sum As Integer = 0
For Each segment As String In "aa bb ccc".Split()
Dim value = CalculateValue(segment)
Console.WriteLine("{0} = {1}", segment, value)
sum += value
Next
Console.WriteLine("Total value is {0}", sum)
' Output
' aa = 2
' bb = 4
' ccc = 9
' Total value is 15

Automatic chart update with new data entry

My chart loads data from a DataGridView.
I want to automatically update my chart with new data if new values are inserted into the DataGridView.
My chart is bound to table1 and table2 in my DataGridView which gets values from a DataTable. Here is a small portion of the code:
Dim myData As New DataTable
wcAdapter.SelectCommand = wcCommand
wcAdapter.Fill(myData)
-
Chart1.DataSource = myData
Chart1.Series("Series1").ValueMemberX = "table1"
Chart1.Series("Series1").ValueMembersY = "table2"
Here is the complete code:
Try
wcconn.Open()
Dim wcCommand As New MySqlCommand()
''telesales name
' Dim wcQuery = "SELECT ID, Telesales, SUBSTRING(lastupdatedate, 1, 10) as 'Day', SUBSTRING(lastupdatetime FROM -9 FOR 6) as 'Time' FROM ratingout where Telesales='" & cbTelesales.Text & "' and lastupdatedate= '" & newDate & "' and lastupdatedate is not null and lastupdatetime is not null ORDER BY lastupdatetime ;"
' wcCommand.Connection = wcconn
' wcCommand.CommandText = wcQuery
Dim newDate As String
newDate = dateWorkCheck.Text
newDate = newDate.Replace("/", "-")
Dim y, m, d As String
y = newDate.Substring(6, 4)
m = newDate.Substring(3, 2)
d = newDate.Substring(0, 2)
newDate = y & "-" & m & "-" & d
Dim wcQuery = "SELECT ID, Telesales, lastupdatedate as 'Day', SUBSTRING(lastupdatetime FROM -8 FOR 2) as 'Time' FROM ratingout where Telesales='" & cbTelesales.Text & "' and lastupdatedate= '" & newDate & "' and lastupdatedate is not null and lastupdatetime is not null ORDER BY lastupdatetime ;"
wcCommand.Connection = wcconn
wcCommand.CommandText = wcQuery
Dim wcData As New DataTable
wcAdapter.SelectCommand = wcCommand
wcAdapter.Fill(wcData)
Dim i = 0
If wcData.Rows.Count = 0 Then
wcAdapter.Dispose()
Try
Dim wQuery = "SELECT ID, Telesales, lastupdatedate as 'Day', SUBSTRING(lastupdatetime FROM -8 FOR 2) as 'Time' FROM ratingout where Telesales='" & cbTelesales.Text & "' and lastupdatedate= '" & dateWorkCheck.Text & "' and lastupdatedate is not null and lastupdatetime is not null ORDER BY lastupdatetime ;"
wcCommand.Connection = wcconn
wcCommand.CommandText = wQuery
Dim wData As New DataTable
wcAdapter.SelectCommand = wcCommand
wcAdapter.Fill(wData)
wData.Columns.Add("tt")
wData.Columns.Add("num")
wcData.Columns.Add("tt")
wcData.Columns.Add("num")
'dgvWorkCheck.AutoSizeRowsMode = DataGridViewAutoSizeRowMode.AllCells
Dim dr As DataRow
For Each dr In wData.Rows
If lastV Is Nothing OrElse Not ColumnEqual(lastV, dr("Time")) Then
''check if first value is nothing
If lastV = Nothing Then
lastV = "00"
l = "0"
Else
dr("tt") = lastV
dr("num") = l
'wcData.Tables("ratingout").Rows(I)("ID") = dr("ID")
End If
ListBox1.Items.Add(lastV & " <--> " & l)
lastV = dr("Time")
l = 1
ElseIf lastV Is Nothing OrElse ColumnEqual(lastV, dr("Time")) Then
l += 1
'Dim series1 As New Series()
'series1.Points.Add(l)
End If
For I = I To wData.Rows.Count
If I <> wData.Rows.Count Then
I += 1
If i = wData.Rows.Count Then
dr("tt") = lastV
dr("num") = l
ListBox1.BeginUpdate()
ListBox1.Items.Add(dr("Telesales") & " between[" & lastV & " and 17:00, ] <--> " & l & "[ records ]")
ListBox1.EndUpdate()
End If
GoTo n
Else
MsgBox("last data")
End If
Next
n:
Next
txtRec.Text = wData.Rows.Count
dgvWorkCheck.DataSource = wData
''chart
Dim ChartArea2 As ChartArea = New ChartArea()
Dim Legend2 As Legend = New Legend()
Dim Series2 As Series = New Series()
Dim Chart2 = New Chart()
Me.Controls.Add(Chart2)
ChartArea2.AxisX.LabelStyle.Angle = -90
ChartArea2.AxisX.LabelStyle.Interval = 1
ChartArea2.AxisY.LabelStyle.Angle = -90
ChartArea2.AxisY.LabelStyle.Interval = 5
ChartArea2.Name = "ChartArea2"
Chart2.ChartAreas.Add(ChartArea2)
Legend2.Name = "Legend2"
Chart2.Legends.Add(Legend2)
Chart2.Location = New System.Drawing.Point(12, 113)
Chart2.Name = "Chart2"
Series2.ChartArea = "ChartArea2"
Series2.Legend = "Legend2"
Series2.Name = "Series2"
Chart2.Series.Add(Series2)
Chart2.Size = New System.Drawing.Size(1145, 604)
Chart2.TabIndex = 0
Chart2.Text = "Chart2"
Chart2.Series("Series2").XValueMember = "tt"
Chart2.Series("Series2").YValueMembers = "num"
Chart2.DataSource = dgvWorkCheck.DataSource
Chart2.DataBind()
Catch ex As Exception
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
Exit Try
since the new data is inserted into a database, you will only need to rebind the gridview to it's source in order to display the new incoming data.
You should isolate the code that binds data to your chart in a function and have it called every time a new field gets inserted:
Function FillChartWithData()
Dim myData As New DataTable
wcAdapter.SelectCommand = wcCommand
wcAdapter.Fill(myData)
...
Chart1.Series("Series1").ValueMemberX = "table1"
Chart1.Series("Series1").ValueMembersY = "table2"
End Function
EDIT
I looked at your coded and it seems you're missing the part responsible for inserting new data inside the 'ratingout' table. You should create a function that allows you to insert new data, something along the line of:
Dim insertRating = "INSERT INTO ratingout VALUES (#NewTeleSalesName, #NewDate);"
Dim insertCmd As New MySqlCommand(insertRating, wcconn)
insertCmd.Parameters.Add("#NewTeleSalesName", MySqlDbType.VarChar, 255, "teleSalesName")
insertCmd.Parameters.Add("#NewDate", MySqlDbType.Datetime, 8, New DateTime(2010, 8, 5))
insertCmd.ExecuteNonQuery()
In order to update my chart bargraph named CashChart (which was databound to a BindingSource) I had to do the following:
To clear the chart information,
Clear the bounding source information
And then re-assign the bounding source information: for example:
CashChart.Series(0).Points.Clear()
CashChart.DataSource = ""
CashChart.DataSource = ESTADOINSTANTANEOBindingSource
Before, only my DataTable was updating, but after these commands, I was able to get the bargraph to update with new values in the table.