Terry Dotson has – once again – generously offered an application to be an ADN Plugin of the Month. This little tool, called DrawOrderByLayer, allows you to modify the draw-order of objects in an AutoCAD drawing according to the layer they’re on. I don’t expect this to go live for another month or so (I still have plans for November’s plugin), but I did want to post it in order to give people the chance to provide feedback.
Here’s basically how it works…
You have layers containing geometry – in this case I’ve created circular solid hatches on layers named by their respective colours:
Loading the DLL and launching the DOBYLAYS command shows a simple dialog:
Once you’ve ticked/checked the layers you care about and have moved them into an appropriate relative order, clicking OK selects the objects on each layer and uses the DrawOrderTable to bring them to the top. In our case we have asked for Red, Yellow, Green and Blue to be brought to the the top (Red being the topmost of them):
I’ve made a few cosmetic changes to Terry’s code, but it’s mostly his. There may well be further changes prior to the eventually posting – I’m wondering if it’s worth streamlining the DrawOrderTable calls, for instance – but I (and, I’m sure, Terry, also) would appreciate any feedback people would like to provide, in the meantime.
Here’s the main VB.NET file:
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.Runtime
Imports DrawOrderByLayer.DemandLoading
Public Class Commands
Implements IExtensionApplication
' AutoCAD fires the Initialize Sub when the assembly is loaded,
' so we check to see if the command is registered by looking for
' the existance of the Registry keys. If not found, we attempt
' to add them so the command will automatically load in future
' sessions. This means it only needs to be NETLOADed once.
Public Sub Initialize() Implements IExtensionApplication.Initialize
RegistryUpdate.RegisterForDemandLoading()
End Sub
Public Sub Terminate() Implements IExtensionApplication.Terminate
' Only fires when AutoCAD is shutting down
End Sub
<CommandMethod("ADNPLUGINS", "REMOVEDO", CommandFlags.Modal)> _
Public Shared Sub RemoveDrawOrderByLayer()
RegistryUpdate.UnregisterForDemandLoading()
End Sub
' Establish our command name to use to start the tool. It
' dimensions an instance of the form and displays it with
' AutoCAD's ShowModalDialog. Don't use Windows Form.Show!
<CommandMethod("ADNPLUGINS", "DOBYLAY", CommandFlags.Modal)> _
Public Shared Sub OrderByLayer()
Using dlg As New OrderDialog()
Application.ShowModalDialog(dlg)
End Using
End Sub
End Class
Here’s the dialog implementation file:
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Runtime
Public Class OrderDialog
'Related System Variables
' DRAWORDERCTL: Controls the display order of overlapping objects.
' Improves editing speed in large drawings
' SORTENTS: Controls object sorting in support of draw order for
' several operations.
Private Sub MainForm_Load( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MyBase.Load
' Populate layer list with layers (in order created)
Dim db As Database = _
Application.DocumentManager.MdiActiveDocument.Database
Using tr As Transaction = _
db.TransactionManager.StartTransaction
Dim lt As LayerTable = _
tr.GetObject(db.LayerTableId, OpenMode.ForRead)
For Each id As ObjectId In lt
Dim ltr As LayerTableRecord = _
tr.GetObject(id, OpenMode.ForRead)
If ltr.IsDependent = False Then
LayLst.Items.Add(ltr.Name)
End If
Next
tr.Commit() ' Cheaper to commit than abort
End Using
End Sub
Private Sub Accept_Click( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Accept.Click
If LayLst.CheckedItems.Count > 0 Then
' Build list of layers from those checked, then reverse it
Dim revLst As New List(Of String)
For Each TxtStr As String In LayLst.CheckedItems
revLst.Add(TxtStr)
Next
revLst.Reverse()
' Get modelspace objects on each layer and pass to
' DrawOrderTable.MoveToTop()
Dim doc As Document = _
Application.DocumentManager.MdiActiveDocument
Dim db As Database = doc.Database
Dim ed As Editor = doc.Editor
Using tr As Transaction = _
db.TransactionManager.StartTransaction
Dim bt As BlockTable = _
tr.GetObject(db.BlockTableId, OpenMode.ForWrite)
Dim btr As BlockTableRecord = _
tr.GetObject( _
bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
Dim dot As DrawOrderTable = _
tr.GetObject(btr.DrawOrderTableId, OpenMode.ForWrite)
Using pm As New ProgressMeter
pm.Start("Processing: ")
pm.SetLimit(LayLst.CheckedItems.Count)
For Each lay As String In revLst
Dim psr As PromptSelectionResult
Dim tvs(0) As TypedValue
tvs(0) = New TypedValue(DxfCode.LayerName, lay)
Dim sf As New SelectionFilter(tvs)
psr = ed.SelectAll(sf)
If psr.Value IsNot Nothing Then
dot.MoveToTop( _
New ObjectIdCollection(psr.Value.GetObjectIds))
End If
pm.MeterProgress()
System.Windows.Forms.Application.DoEvents()
Next
pm.Stop()
End Using
tr.Commit()
End Using
ed.Regen()
End If
Me.Close()
End Sub
Private Sub Cancel_Click( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Cancel.Click
Me.Close()
End Sub
Private Sub LayInv_Click( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles LayInv.Click
For AI As Integer = 0 To LayLst.Items.Count - 1
LayLst.SetItemChecked(AI, Not LayLst.GetItemChecked(AI))
Next
End Sub
Private Sub LaySrt_Click( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles LaySrt.Click
LayLst.Sorted = True
LayLst.Sorted = False
End Sub
Private Sub MovUpp_Click( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MovUpp.Click
If LayLst.SelectedIndex > 0 Then
Dim OldChk As Boolean = _
LayLst.GetItemChecked(LayLst.SelectedIndex - 1)
LayLst.Items.Insert( _
LayLst.SelectedIndex + 1, _
LayLst.Items(LayLst.SelectedIndex - 1))
LayLst.Items.RemoveAt( _
LayLst.SelectedIndex - 1)
LayLst.SetItemChecked( _
LayLst.SelectedIndex + 1, OldChk)
End If
End Sub
Private Sub MovDnn_Click( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MovDnn.Click
If LayLst.SelectedIndex < LayLst.Items.Count - 1 Then
Dim OldChk As Boolean = _
LayLst.GetItemChecked(LayLst.SelectedIndex + 1)
LayLst.Items.Insert( _
LayLst.SelectedIndex, LayLst.Items(LayLst.SelectedIndex + 1))
LayLst.Items.RemoveAt( _
LayLst.SelectedIndex + 1)
LayLst.SetItemChecked( _
LayLst.SelectedIndex - 1, OldChk)
End If
End Sub
Private Sub SelAll_Click( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles SelAll.Click
For I As Int16 = 0 To LayLst.Items.Count - 1
LayLst.SetItemChecked(I, True)
Next
End Sub
Private Sub SelNon_Click( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles SelNon.Click
For I As Int16 = 0 To LayLst.Items.Count - 1
LayLst.SetItemChecked(I, False)
Next
End Sub
End Class
And here’s the project. Thanks for providing this sample, Terry!