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.
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.
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
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
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
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
@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
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
Can't find what you're looking for? Ask the community or share your knowledge.