Search code examples
vbaautocadautocad-plugin

Filtering block by attribute after I have already filtered by another


I am creating a console that finds blocks with a certain attribute value and replace it with another (akin to find(textbox1) and replace(textbox2) in Word).

For Each blk In ss
        If (blk.HasAttributes) Then
            attr = blk.GetAttributes()
            For i = 0 To UBound(attr)
                If attr(i).TagString = "item" And _
                    attr(i).TextString = TextBox1.Value Then
                    attr(i).TextString = TextBox2.Value
                    Exit For
                End If
            Next
            End If
    Next

Although I have solved it, a new problem arose. My colleagues now want to filter by 2 attributes. For example, the attribute with the tag "item" can have the value "coke". But you might want to change only the name of the blocks that contain the soda and not the drug. As such, I picked another attribute which differentiates them (textbox11).

For Each blk In ss
        If (blk.HasAttributes) Then
            attr = blk.GetAttributes()
            For i = 0 To UBound(attr)
            If attr(i).TagString = "origin" And attr(i).TextString = TextBox11.Value Then
            attr = 0
            attr = blk.GetAttributes()

            For o = 0 To UBound(attr)
                If attr(i).TagString = "item" And _
                    attr(i).TextString = TextBox1.Value Then
                    attr(i).TextString = TextBox2.Value
                    Exit For
                End If
                End If
            Next
            End If
    Next

But it's not working. How would you approach the problem?


Solution

  • Assuming that I've correctly understood what you are looking to achieve with the program, perhaps the following approach would suffice:

    Dim flg As Boolean
    Dim idx As Long
    
    For Each blk In ss
        If blk.HasAttributes Then
            attr = blk.GetAttributes()
            flg = False
            idx = -1
            For i = 0 To UBound(attr)
                Select Case attr(i).TagString
                    Case "origin"
                        If attr(i).TextString = TextBox11.Value Then flg = True
                    Case "item"
                        idx = i
                End Select
            Next i
            If flg And idx >= 0 Then
                If attr(idx).TextString = TextBox1.Value Then
                    attr(idx).TextString = TextBox2.Value
                End If
            End If
        End If
    Next blk
    

    Since we cannot make the assumption that the origin attribute will be encountered before the item attribute within the array of attributes held by the block, the above code iterates over the entire array and populates the values of two variables if given conditions are satisfied (specifically, if the origin attribute is encountered and contains a specific value, and if the item attribute is encountered whilst iterating over the array).

    You could slightly improve the efficiency for blocks with many attributes by testing the values of flg & idx on each iteration of the for loop and exiting the for loop if these hold appropriate values, or alternatively, you could use a Do or While loop which tests these variables on each iteration (along with the magnitude of the i variable) to avoid the use of Exit; but I should imagine that the performance improvement would be negligible in both cases.