Selection Set Order

conveyor1
Enthusiast
Enthusiast

Selection Set Order

conveyor1
Enthusiast
Enthusiast

I am trying to write some VB.net code to allow an AutoCAD user to select some block and based on the order of selection, an attribute within the block will be updated with the number in the selection.  So the first block selected will get a 1 and the fifth will get a five, etc.

 

Does anyone know if the selection set keeps the order of selection or do I need to record the order in some other manner?  If another manner, any recommendations?

 

Please let me know your thoughts.

0 Likes
Reply
2,098 Views
9 Replies
Replies (9)

ActivistInvestor
Advisor
Advisor

The selection set should be ordered in the order that entities in it were explicitly picked (e.g., no window/crossing or other form of selection).  Hence, the user must pick each object individually in the desired order - They can't rely on the order of objects selected using other means.

 

You can force the user to explicitly pick objects by setting the SinglePickInSpace property of the PromptSelectionOptions class to true.

 


@conveyor1 wrote:

I am trying to write some VB.net code to allow an AutoCAD user to select some block and based on the order of selection, an attribute within the block will be updated with the number in the selection.  So the first block selected will get a 1 and the fifth will get a five, etc.

 

Does anyone know if the selection set keeps the order of selection or do I need to record the order in some other manner?  If another manner, any recommendations?

 

Please let me know your thoughts.


 

0 Likes

conveyor1
Enthusiast
Enthusiast

Morning,

I am having an issue were i am unable to restrict the person using cad to select only one item at a time into the selection set.  But I am still able to select multiple items with either a crossing or window.  Would someone be able to look as see what could be incorrect?

 

    Public Sub Single_Pick_SelectionSet()
        Dim myDB As DatabaseServices.Database
        Dim myDWG As ApplicationServices.Document
        Dim myEd As EditorInput.Editor
        Dim myPSR As EditorInput.PromptSelectionResult
        Dim myPSO As New EditorInput.PromptSelectionOptions
        Dim mySS As EditorInput.SelectionSet
        Dim myTV(0) As DatabaseServices.TypedValue
        myTV(0) = New DatabaseServices.TypedValue(0, "INSERT")
        Dim myFilter As New EditorInput.SelectionFilter(myTV)
        Dim myObjIDs As ObjectIdCollection
        Dim myObjID As ObjectId
        myDWG = ApplicationServices.Application.DocumentManager.MdiActiveDocument
        myDB = myDWG.Database
        myEd = myDWG.Editor
        'myPSO.SingleOnly = True
        myPSO.SinglePickInSpace = True
        myPSR = myEd.GetSelection(myPSO, myFilter)
        mySS = myPSR.Value

        Dim myTransMan As DatabaseServices.TransactionManager
        myTransMan = myDB.TransactionManager

        If Not IsNothing(myPSR.Value) Then

            MsgBox(mySS.Count) ' Number of items selected

            Dim myTrans As Transaction = myTransMan.StartTransaction()

            myObjIDs = New DatabaseServices.ObjectIdCollection(myPSR.Value.GetObjectIds)
            For Each myObjID In myObjIDs
                MsgBox(Class1_Obj.ReadAttributeValue(myObjID, "TEMP").ToString)
            Next

            ' End Transactions
            myTrans.Commit()
            myTrans.Dispose()
            myTransMan.Dispose()

        End If

    End Sub

 

 

0 Likes

norman.yuan
Mentor
Mentor

It seems to me that the user has to decide the order of the blocks being selected. In this case, it does not make much sense to use Editor.GetSelection(), because the user could select multiple entities with picking windows/polygons (not to mention that when window is picked from left to right, it is window-selection, from right to left, it is window-crossing-selecting...).

 

If the order is important, you should use Editor.GetEntity() to select one at a time in a loop, something like:

 

int i=1;

while(true)

{

    var opt=new PromptEntityOptions($"\nSelect block {i}:");

    opt.SetRejectMessage("\nNot a block!");

    opt.AddAllowedClass(typeof(BlockRefernce), true);

    var res=ed.GetEntity(opt);

    if (res.Status==PromptStatus.OK)

    {

        //Set the attribute of the selected block with picking order (i, in this case)

       UpdateTheBlock(res.ObjectId, i);

        i++;

    }

    else

    {

        //When user press Esc, break from the loop

        // You can also user keyword with GetEntity() to explicitly ask user to quit

        break;  

    }

}

 

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes

ActivistInvestor
Advisor
Advisor

Contrary to what I wrote above, I don't think it's possible to restrict selection of multiple objects to 'picking only', or at least not with the managed API. If I'm mistaken, then I hope someone can demonstrate how.

 

Even with LISP's (ssget) function there seems to be problems with the '.' mode string, which is likely a result of changes made to accommodate subselection filtering and selection of faces, edges and vertices. The managed API does not support the "." mode string at all.

 

And contrary to what I suggested above, the SinglePickInSpace property doesn't allow for multiple selections by picking only. It will return immediately after the first object is picked.

 

I think the only option is to use GetEntity() in a loop.

 


@conveyor1 wrote:

Morning,

I am having an issue were i am unable to restrict the person using cad to select only one item at a time into the selection set.  But I am still able to select multiple items with either a crossing or window.  Would someone be able to look as see what could be incorrect?

 

    Public Sub Single_Pick_SelectionSet()
        Dim myDB As DatabaseServices.Database
        Dim myDWG As ApplicationServices.Document
        Dim myEd As EditorInput.Editor
        Dim myPSR As EditorInput.PromptSelectionResult
        Dim myPSO As New EditorInput.PromptSelectionOptions
        Dim mySS As EditorInput.SelectionSet
        Dim myTV(0) As DatabaseServices.TypedValue
        myTV(0) = New DatabaseServices.TypedValue(0, "INSERT")
        Dim myFilter As New EditorInput.SelectionFilter(myTV)
        Dim myObjIDs As ObjectIdCollection
        Dim myObjID As ObjectId
        myDWG = ApplicationServices.Application.DocumentManager.MdiActiveDocument
        myDB = myDWG.Database
        myEd = myDWG.Editor
        'myPSO.SingleOnly = True
        myPSO.SinglePickInSpace = True
        myPSR = myEd.GetSelection(myPSO, myFilter)
        mySS = myPSR.Value

        Dim myTransMan As DatabaseServices.TransactionManager
        myTransMan = myDB.TransactionManager

        If Not IsNothing(myPSR.Value) Then

            MsgBox(mySS.Count) ' Number of items selected

            Dim myTrans As Transaction = myTransMan.StartTransaction()

            myObjIDs = New DatabaseServices.ObjectIdCollection(myPSR.Value.GetObjectIds)
            For Each myObjID In myObjIDs
                MsgBox(Class1_Obj.ReadAttributeValue(myObjID, "TEMP").ToString)
            Next

            ' End Transactions
            myTrans.Commit()
            myTrans.Dispose()
            myTransMan.Dispose()

        End If

    End Sub

 

 


 

0 Likes

conveyor1
Enthusiast
Enthusiast
Evening,

I think I like this way better then selecting everything first then running
the updates.

Not familiar with c. Doing this in VB.net.

But in short summary, the user picks the item, it filters the pick and
displays the appropriate message, if everything is good, then it updates
the item and the process repeats until the user hits escape.

If you or someone knows VB.net, what would the code look like for the
selection filters?

Please let me know your thoughts.
0 Likes

norman.yuan
Mentor
Mentor

Editor.GetEntity() has its own way to filter what type of entity user can pick, which is Acad API thing, regardless the .NET language (C#, or VB.NET). Here is the VB.NET code of what I posted previously:

 

Dim i As Integer=1

While True

  Dim opt As New PromptEntityOptions(vbCrlf & "Select block " & i & ":")

  ''  Set up "filter" here, so user can only pick block reference

  opt.SetRejectMessage(vbCrLf & "Not a block!")

  opt.AddAllowedClass(GetType(BlockReference), True) 

  Dim res As PromptResult = ed.GetEntity(opt)

  If res.Status=PromptStatus.OK Then

    '' You may also need to test if the picked block is the 

    '' target block before updating its attribute here.

    UpdateTheBlock(res.ObjectId, i)

    i=i+1

  Else

    Exit While

  End If

End While

Norman Yuan

Drive CAD With Code

EESignature

0 Likes

conveyor1
Enthusiast
Enthusiast
Just checking, but what do you mean by this line?

'' target block before updating its attribute here.

It my be linked to reason why I can not get the .objectID to come up with
res.

Please let me know.
0 Likes

kdub_nz
Advisor
Advisor

@conveyor1 wrote:
Just checking, but what do you mean by this line?

'' target block before updating its attribute here.

It my be linked to reason why I can not get the .objectID to come up with
res.


My guess is that Norman is protecting against the accidental selection of an unintended block insertion.

 

Another procedural option to the algorithm is to add the ID of each selected block to a list and process all inserts inside one code block. This would be a slightly faster option, but has the downside of the user not seeing each insert update and may also lead to blocks being selected multiple times.

 

You probably should be posting more code and an indicator or where and how you are having difficulty with obtaining the Insertion ID ... Have you attempted stepping through the code in the debugger and inspecting the variable values ??

 


// Called Kerry in my other life.

Everything will work just as you expect it to, unless your expectations are incorrect.
Sometimes the question is more important than the answer.

class keyThumper<T> : Lazy<T>;      another  Swamper

0 Likes

conveyor1
Enthusiast
Enthusiast

Final code if anyone is interested.

 

    Public Sub UpdatebyPick()
        Dim myDB As DatabaseServices.Database
        Dim myDWG As ApplicationServices.Document
        Dim myEd As EditorInput.Editor
        Dim myPER As EditorInput.PromptEntityResult
        Dim myEnt As DatabaseServices.Entity

        myDWG = ApplicationServices.Application.DocumentManager.MdiActiveDocument
        myDB = myDWG.Database
        myEd = myDWG.Editor

        Dim Count As Integer = 1

        Dim myTransMan As DatabaseServices.TransactionManager

        While True

            Dim myPEO As New EditorInput.PromptEntityOptions(vbCrLf & "Select block " & Count & ":")
            myPEO.SetRejectMessage(vbCrLf & "Not a block!") ' Message For Error
            myPEO.AddAllowedClass(GetType(BlockReference), True) ' filter for a Block's only
            myPER = myEd.GetEntity(myPEO)
            If myPER.Status = PromptStatus.OK Then
                ' Start Transaction
                myTransMan = myDB.TransactionManager
                Dim myTrans As Transaction = myTransMan.StartTransaction()

                'Get information from Selection
                myEnt = myPER.ObjectId.GetObject(DatabaseServices.OpenMode.ForRead)
                Dim myObjID As ObjectId
                myObjID = myEnt.ObjectId

                ' Check for only Conveyor Blocks
                Dim myBTR As DatabaseServices.BlockTableRecord
                Dim myBlkRef As BlockReference
                myBlkRef = myObjID.GetObject(DatabaseServices.OpenMode.ForRead, False)
                If myBlkRef.IsDynamicBlock = False Then
                    myBTR = myBlkRef.BlockTableRecord.GetObject(DatabaseServices.OpenMode.ForRead)
                Else
                    myBTR = myBlkRef.DynamicBlockTableRecord.GetObject(DatabaseServices.OpenMode.ForRead)
                End If

                If myBTR.Name = "GENERAL BLOCK" Then
                    ' Mesage for changing CID in Block
                    MsgBox(Class1_Obj.ReadAttributeValue(myObjID, "CID").ToString & " will change to " & TextBox39.Text)

                    ' End Transactions
                    myTrans.Commit()
                    myTrans.Dispose()
                    myTransMan.Dispose()

                    ' Update Attribute1 in Block
                    Class1_Obj.Setattributes(myObjID, "Attribute1", TextBox39.Text)
                    TextBox39.Text = CInt(TextBox39.Text) + CInt(TextBox40.Text)
                    Count = Count + 1
                Else
                    MsgBox("Not a Vendor Block.  Please Resellect:")
                    myTrans.Dispose()
                    myTransMan.Dispose()
                End If
            Else

                Exit While
            End If
        End While

    End Sub
0 Likes