I'm writing macro that will make BOM list from the selected parts in assembly.
I can get a "Part Number" of the part in assembly, I can't get a "Instance name" of the selected parts.
Here code that call Selection tab and then try to get a names.
Set ItemSelection = CATIA.ActiveDocument.Selection
InputObjectType(0) = "Part"
SelectionStatus = ItemSelection.SelectElement3(InputObjectType, "Choose parts", false, CATMultiSelTriggWhenUserValidatesSelection, true)
If SelectionStatus = "Cancel" Then
Exit Sub
End If
If ItemSelection.Count >= 1000 Then
MsgBox "You select more then 1000 parts.", vbExclamation, MsgTextBox & "."
Exit Sub
End If
For i = 1 To ItemSelection.Count
k = k + 1
BOMTable(1,k) = ItemSelection.Item(i).PartNumber
BOMTable(2,k) = ItemSelection.Item(i).Value.Name
MsgBox BOMTable(1,k)
Next
What I do wrong?
You need to select Products if you want instance-ness.
So...
InputObjectType(0) = "Product"
...
sInstanceName = ItemSelection.Item(i).Value.Name
What happens when someone selects an Assembly/Sub-Assembly? Nothing different because Sub-Assemblies have instance names too.
However, if you want to include ONLY actual CATParts, then you have to filter value post-selection something like...
Dim oInstProd as product
set oInstProd = ItemSelection.Item(i).Value
if TypeName(oInstProd.ReferenceProduct.Parent) = "PartDocument" Then
.... do stuff with only parts...
end If
The ReferenceProduct property will give you trouble if you use cache mode (it will throw an error). But their is a workaround for that if you need it.
Related
I am currently attempting to turn a form I am working on into a more dynamic one using vba in word, but I am facing two issues with the option buttons within a repeating section:
The code is not dynamic; when I run the code it does what I need it to but doesn't dynamically recalculate as I change my choice.
The option buttons do not repeat when I add a new section, and the only way for me to include them is by readding them and creating a new module specific for the new option button group.
Below is a picture of the section I am repeating and the code I am using.
enter image description here
Private Sub Yes_Click()
Dim k(0 To 3) As String
k(0) = "Select one"
k(1) = "Pass"
k(2) = "Fail"
k(3) = "N/A"
Dim i As Long
If Yes = True Then
Me.Controls.Clear
Me.Controls1.Clear
For i = 0 To 3
Me.Controls.AddItem k(i)
Me.Controls1.AddItem k(i)
Next i
End If
On Error Resume Next
Me.Controls = "Select one"
Me.Controls1 = "Select one"
If Yes = False Then
Me.Controls = "N/A"
Me.Controls1 = "N/A"
End If
On Error Resume Next
End Sub
Is there a way to approach either issues?
Thanks in advance.
I created a couple of user forms which operate a data in separate report workbook. My script can successfully proceed a value in digit type. Unfortunately the circumstances have changed and now it has to work with a Serial Numbers as: 29160012040000TZ. With that new value script after starting the Sub, open a report, but it never enter into a 'with' statement. It doesn't look for a value or doing something else. Just open a report workbook and freeze.
Below you can see the code lines where issue is present and a little description:
Single_PHA is a text window in User Form where user can enter a a value, proceeding value is 29160012040000TZ
Private Sub Wydaj_button_Click()
Workbooks.Open Filename:="N:\ENGINEERING\1. ENGINEERS\Mateusz Skorupka\PHA_Cleaning_report_path\PHA_CLEANING_REPORT.xlsm", ReadOnly:=False
Dim REPORT As Workbook
Set REPORT = Application.Workbooks("PHA_CLEANING_REPORT.xlsm")
Set TABLE = REPORT.Worksheets("Main_table")
...
With TABLE.Range("A1")
If Single_PHA = True Then
If Not IsError(Application.Match(Single_PHA.Value, .Range("A:A"), 0)) Then
Single_PHA_row = TABLE.Range("A:A").Find(What:=Single_PHA.Value, LookIn:=xlValues).Row
.Offset(Single_PHA_row - 1, 4).Value = Date
REPORT.Close SaveChanges:=True
Single_PHA.Value = ""
Exit Sub
Else
MsgBox "Numer seryjny głowicy nie istnieje w bazie"
REPORT.Close SaveChanges:=False
Exit Sub
End If
End If
End With
In VBA I don't know how to open something like debugger or make the print instruction which would show me how the variables look on specific steps.
I am not sure if VBA read the value as 29160012040000TZ as string. I tried to declare at the beginning a variable as Single_PHA_STR as String and the proceed it as just text, but no wins there:
Dim Single_PHA_STR As String
...
With TABLE.Range("A1")
If Single_PHA = True Then
Single_PHA_STR = Str(Single_PHA.Value)
If Not IsError(Application.Match(Single_PHA_STR, .Range("A:A"), 0)) Then
Single_PHA_row = TABLE.Range("A:A").Find(What:=Single_PHA_STR, LookIn:=xlValues).Row
.Offset(Single_PHA_row - 1, 4).Value = Date
REPORT.Close SaveChanges:=True
Single_PHA.Value = ""
Exit Sub
Else
MsgBox "Numer seryjny głowicy nie istnieje w bazie"
REPORT.Close SaveChanges:=False
Exit Sub
End If
End If
End With
I noticed that if in VBA IDE I write a bold value 29160012040000TZ, I get an error
Expected line number or label or statement or end of statement
and the value is highlighted in red.
Could someone help me in that field and explain the nature of issues:
To reproduce a situation you can create a simply user form with one TextBox and one CommandButton. In the same worksheet as user form in a column A put a values: 29160012040000 and 29160012042027IR
Then make a sub which execute after double click on command button with code:
Private Sub CommandButton1_Click()
With Worksheets("Sheet1").Range("A1")
If Text_box1 = True Then
If Not IsError(Application.Match(Text_box1.Value, .Range("A:A"), 0)) Then
Text_box1_row = Worksheets("Sheet1").Range("A:A").Find(What:=Text_box1.Value, LookIn:=xlValues).Row
.Offset(Text_box1_row - 1, 4).Value = Date
Text_box1.Value = ""
Exit Sub
Else
MsgBox "PHA SN not exist in a database"
Exit Sub
End If
End If
End With
End Sub
Then try to input in a UserForm's TextBox a value = 29160012040000 and you will see that script successfully filled a forth column in row with current date. Then try to input a value 29160012042027IR and you will see that nothing happened. Script don't proceed that value at all.
So that is my issue and question indeed. How to process a value with letters at the end like: 29160012042027IR : )
I also tried to focus a script statement on one specific cell in which is a text value "29160012042027IR" that which I input into a UserForm TextBox. Looking with a debugger both of variables in if statement have the same text value, but still script miss that statement and go to else instructions : (
I mean abut: If Range("A3").Text = Text_box1.Text Then
When I change a statement for "If Range("A3").Value = Text_box1.Value Then" the same thing happen.
Private Sub CommandButton1_Click()
With Worksheets("Sheet1").Range("A:A")
If Text_box1 = True Then
If Range("A3").Text = Text_box1.Text Then
Text_box1_row = Worksheets("Arkusz1").Range("A:A").Find(What:=Text_box1.Value, LookIn:=xlWhole).Row
.Offset(Text_box1_row - 1, 4).Value = Date
Text_box1.Value = ""
Exit Sub
Else
MsgBox "PHA SN not exist in a database"
Exit Sub
End If
Else
MsgBox "Other loop"
End If
End With
End Sub
IMPORTANT NOTICE:
I found the main issue. I made wrong if condition, it should be:
If Single_PHA <> "" Then previously I have got: If Single_PHA = True Then, and there the results is a value not the boolean type.
Everything works. Thank everyone very much for help.
Topic is ready to be closed.
PS: thank you Tom for suggestion and tip with debugger: )
I am a VBA noob and I'm trying to compare the numbers entered in a text form field in ms word, then if a duplicate is found I display a msg box.
The problem I'm having is... I have to compare 33 fields and look for a duplicate of anywhere from 1 to 33. I'm receiving a message that the procedure is too large. I'm sure there must be an easier way to do this. It's a protected document which I unprotect once the user hits the command button. I've even tried breaking it up and assigning macros to some of the fields.
Here is a sample of what I have. There are 33 bookmarks and I'm comparing each field.
If (ActiveDocument.FormFields("s1").Result = "1" And _
ActiveDocument.FormFields("s2").Result = "1") Then
MsgBox ("Your preferences cannot be duplicated.")
Validate = True
If True Then Exit Sub
Else
Validate = False
End If
Perhaps:
Sub CompareFormfields()
Dim i As Long, j As Long
With ActiveDocument
For i = 1 To .FormFields.Count - 1
For j = i + 1 To .FormFields.Count
If (.FormFields(i).Type = wdFieldFormTextInput) And (.FormFields(i).Type = wdFieldFormTextInput) Then
If .FormFields(i).Result = .FormFields(j).Result Then
MsgBox "The data in FormField " & i & " is duplicated in FormField " & j
End If
End If
Next
Next
End With
MsgBox "Done checking"
End Sub
I having trouble with the following code in MS word VBA
For i = 6 To ActiveDocument.Tables(2).Rows.Count
z = Len(ActiveDocument.Tables(2).Cell(i, 2).Range.Text) - 2
x = Len(ActiveDocument.Tables(2).Cell(i, 3).Range.Text) - 2
b = ActiveDocument.Tables(2).Cell(i, 5).Range.ContentControls.Item(1).ShowingPlaceholderText
If (z = 0 And x = 0) Then
If b = True Then
MsgBox "Please do error 1!"
If vbOK Then
Exit Sub
End If
Else
MsgBox "Please do error 2!"
If vbOK Then
Exit Sub
End If
End If
Else
If b = True Then
MsgBox "Please do error 3!"
If vbOK Then
Exit Sub
End If
Else
Confirm = MsgBox("Are you sure to submit?", vbYesNo, "Confirmation")
If Confirm = vbNo Then
Exit Sub
End If
End If
End If
Next i
The for loop won't go into the second line to check if z or x is having value or not
I doubt moving Next i would have solved anything. This code is riddled with badness.
My impression is that your code is intended to check three columns in a table (from rows 6 downwards) - this appears to be a consistency check.
Naming. z, x and b are not very descriptive. Using names like lengthCol2, lengthCol3 and hasPlaceHolderText will help you follow your logic more closely.
Use Option Explicit. Always.
You use a standard MsgBox call, which by default only has a single button ("OK"). The MsgBox is a blocking code element, so the macro will not progress until the user has clicked "OK".
vbOK is an enumerated value (value = 1). So If vbOK then always comes out true. Always. You appear to be seeking some sort of user input, but you are not clear on what that input is.
Address these simple steps gives us:
For i = 6 To ActiveDocument.Tables(2).Rows.Count
lengthCol2 = Len(ActiveDocument.Tables(2).Cell(i, 2).Range.Text) - 2
lengthCol3 = Len(ActiveDocument.Tables(2).Cell(i, 3).Range.Text) - 2
hasPlaceHolderText = ActiveDocument.Tables(2).Cell(i, 5).Range.ContentControls.Item(1).ShowingPlaceholderText
If (lengthCol2 = 0 And lengthCol3 = 0) Then
If hasPlaceHolderText = True Then
MsgBox "Please do error 1!"
Exit Sub
Else
MsgBox "Please do error 2!"
Exit Sub
End If
Else
If hasPlaceHolderText = True Then
MsgBox "Please do error 3!"
Exit Sub
Else
Confirm = MsgBox("Are you sure to submit?", vbYesNo, "Confirmation")
If Confirm = vbNo Then
Exit Sub
End If
End If
End If
Next i
Your logic is negative-biased - that is, intending to find reasons not to do something than to do something. Positive-biased logic is usually easier to understand and maintain - the coder's intent is clearer.
Rewording the logic gives us:
For i = 6 To ActiveDocument.Tables(2).Rows.Count
lengthCol2 = Len(ActiveDocument.Tables(2).Cell(i, 2).Range.Text) - 2
lengthCol3 = Len(ActiveDocument.Tables(2).Cell(i, 3).Range.Text) - 2
hasPlaceHolderText = ActiveDocument.Tables(2).Cell(i, 5).Range.ContentControls.Item(1).ShowingPlaceholderText
If (lengthCol2 > 0 OR lengthCol3 > 0) AND hasPlaceHolderText Then
Confirm = MsgBox("Are you sure to submit?", vbYesNo, "Confirmation")
If Confirm = vbYes Then
'Do submission code here - or call the submission procedure
End If ' Just do nothing if they say "No" - this is what your current code does.
Else
' The next line could be used instead of the nested IF-the-else statements following.
'MsgBox " Table contents are not valid, please ensure columns 2,3 and 5 are completed"
If hasPlaceHolderText then
If (lengthCol2 = 0 And lengthCol3 = 0) Then
MsgBox "Please do error 1!"
Else
MsgBox "Please do error 2!"
EndIF
Else
MsgBox "Please do error 3!"
End If
End If
Next i
Note that in your logic, either Column 2 or Column 3 can be empty and (as long as placeholder text not being shown) you document is ready for submission. Perhaps you meant AND instead of OR (i.e. all columns should be filled).
There is still one problem. Your loop. As currently written, you loop over the logic, thus you ask the user to either check errors or submit the document x number of times based on error checking in each row. But, just moving the Next i does not solve the problem because the only results that are retained are those in the last row. In other words, all the previous rows could be bad/invalid, but you would still be able to submit.
We can fix this last bit by creating cumulative logic. In other words, we track the errors in a short loop, then go into the main logic. This seems to be a little more complex but it really is relative straight forwards. But, we do need more Booleans to make it work.
Dim rowsOK as Boolean
'explicit initialisation - I am working on a positive bias here.
rowsOK = True
For i = 6 To ActiveDocument.Tables(2).Rows.Count
Dim lengthCol2OK as Boolean ' Use these just to make the logic clearer and the code cleaner
Dim lengthCol3OK as Boolean
Dim hasPlaceHolderTextOK as Boolean
lengthCol2OK = Len(ActiveDocument.Tables(2).Cell(i, 2).Range.Text) > 2
lengthCol3OK = Len(ActiveDocument.Tables(2).Cell(i, 3).Range.Text) > 2
hasPlaceHolderTextOK = ActiveDocument.Tables(2).Cell(i, 5).Range.ContentControls.Item(1).ShowingPlaceholderText
rowsOK = rowsOK And ((lengthCol2OK Or lengthCol3OK) And hasPlaceHolderTextOK) ' Note: Using "Or" here as per original code logic
' Extra logic could go here to message the user if any of the above are false.
Next i
If rowsOK Then
Confirm = MsgBox("Are you sure to submit?", vbYesNo, "Confirmation")
If Confirm = vbYes Then
'Do submission code here - or call the submission procedure
End If ' Just do nothing if they say "No" - this is what your current code does.
Else
MsgBox " Table contents are not valid, please ensure columns 2,3 and 5 are completed"
End If
However, this logic works on all the rows, so identifying individual row errors in not possible in the main loop. You could work extra logic in the For-Next loop to message the user for errors.
Now the code is maintainable, and more likely does what you want.
Key points:
Use Option Explicit. This prevents typos and ensures that you are using variables in they way you intend.
Use meaningful variable names. Makes it easier to follow what you want to do.
Don't confuse enumerated values with returns from functions. Don't confuse constants with variables.
Take some time to review your logic chains to ensure they do what you want to do, rather than not do what you don't want to do. The latter has greater chance of missing a non-valid path.
I have a report in which I am asking the users to click buttons to reveal where they need to add their commentary. I have it working but wanted to put in an If statement in case they have already expanded the row.
I have two macros, the first relates to the button they push and sends to the main macro the name of the button and a row number which is part of the section that is either expanded or collapsed
Sub ROccupancy()
'
Dim RecName As String
RecName = "ROccupancy"
Dim RowNum As Integer
RowNum = 27
Call ToogleRec(RecName, RowNum)
End Sub
The next macro is where I am having the trouble
Sub ToogleRec(RecName, RowNum)
'
Dim Toogle As String
Dim MyObj As Object
Set MyObj = ActiveSheet.Shapes.Range(Array(RecName))
Toogle = Left(MyObj.TextFrame2.TextRange.Characters.Text, 4)
TextName = Mid(MyObj.TextFrame2.TextRange.Characters.Text, 5, 100)
If Toogle = "Show" Then
MyObj.ShapeStyle = msoShapeStylePreset9
MyObj.TextFrame2.TextRange.Characters.Text = _
"Hide" & TextName
MsgBox Rows(RowNum).ShowDetail
If Rows(RowNum).ShowDetail = False Then
Rows(RowNum).ShowDetail = True
End If
Else
MyObj.ShapeStyle = msoShapeStylePreset11
MyObj.TextFrame2.TextRange.Characters.Text = _
"Show" & TextName
MsgBox Rows(RowNum).ShowDetail
If Rows(RowNum).ShowDetail = True Then
Rows(RowNum).ShowDetail = False
End If
End If
Range("C" & RowNum).Select
End Sub
The issue is the Rows(RowNum).ShowDetail is always TRUE, no matter if it's expanded or collapsed. I can remove the If section and set it to TRUE or FALSE using "Rows(RowNum).ShowDetail = False" or "Rows(RowNum).ShowDetail = TRUE". However, if the user has manually expanded or collapsed the row it causes an error (which freaks them out)
This question and answer seemed promising but Rows(RowNum).ShowDetail always seems to be TRUE
I put the MsgBox in there for error checking. I'll remove it in the final version.
Have you tried using Hidden property? Something like:
With Sheet1.Rows(5)
.ShowDetail = .Hidden
End With
Take note though that for you to use .ShowDetail method, you'll need to Group the rows first (needs to be in outline form).
True if the outline is expanded for the specified range (so that the detail of the column or row is visible). The specified range must be a single summary column or row in an outline.
Above code toggles hiding/unhiding a grouped row 5. You don't even need an If statement for the toggling. HTH.