In my previous article I discussed the AutoCAD Application object class. The most important part of any AutoCAD application is the Document object. This is because users perform all their actions on this Document object. Consequently, I am writing this new blog post, covering the AutoCAD Document object class.
The pyautcad module and its alternatives
Firstly, let me mention the modules I am going to use and what other options are available.
As you might have guessed from the title of this article I am using the pyautocad module for this tutorial. Moreover, in order to be able to access the document itself I am using acad.doc. You will see this in the code below:
from pyautocad import Autocad, APoint, aDouble
acad = Autocad(create_if_not_exists=True)
print(acad.doc.Name)
O/p:
Drawing1.dwg
However, I can use communication modules too. That is, other modules than pyautocad. In the example below I use pythoncom and win32com, so called communication modules, to access the AutoCAD Document object class.
from win32com.client import *
import pythoncom
import win32com
acad1 = win32com.client.Dispatch("AutoCAD.Application")
print(acad1.ActiveDocument.Name)
O/p:
Drawing1.dwg
Properties of the AutoCAD Document object class
To begin with this topic, I am introducing some important properties of the AutoCAD Document object. I find these properties important because they can be used for various automatization purposes.
For example, AutoCAD works with one document at a time. A AutoCAD Document object contains many objects, such as Layers, Layouts, Dimension Styles, Viewport, UCS, and other object types. Amongst these objects, only one can be active at any given point in time.
For instance, a Document object can contain n number of layers. However, only one of these layers can be active at a time.
To check whether the document present is the actually the currently active document I can use the Active method. This method returns a boolean value. You can see this in the example below:
# determine if the document is the active document
print(acad.doc.Active)
O/p:
True
Similarly, to check other Active sub-objects I can use the methods with method names in the format of Active<ObjectName>. Some examples could be ActiveLayout, ActiveLayer, ActiveViewport, and so on.
Object names that can be used are listed below:
- DimStyle
- Layer
- Layout
- Linetype
- Material
- PViewport
- SelectionSet
- Space
- TextStyle
- UCS
- Viewport
I will show how some of these objects can be used.
print(acad.doc.ActiveDimStyle.Name)
print(acad.doc.ActiveLayer.Name)
print(acad.doc.ActiveLayout.Name)
O/p:
ISO-25
0
Model
In the same way, I can use other properties too. These properties return the respective objects which can further be dealt with. I will post more detailed articles covering this in the future.
Accessing the AutoCAD Document object Blocks property
Moving ahead, to get the Blocks objects that are contained by the Document object I can use the Blocks property. This returns a collection of the various AutoCAD Block objects that are present in the AutoCAD Document object.
print(acad.doc.Blocks)
for i in (acad.doc.Blocks):
print(i.Name)
O/p:
<comtypes.client.lazybind.Dispatch object at 0x00000209E60C1D60>
*Model_Space
*Paper_Space
*Paper_Space
If I want to return the database to which the object belongs I can use the Database object. Simply put this returns the database object. It does not have any name attribute.
acad.doc.Database
O/p:
<comtypes.client.lazybind.Dispatch object at 0x0000024FA64175B0>
Sub-objects contained by AutoCAD Document object
Earlier I discussed that a AutoCAD Document object contains multiple sub-objects. These objects are present in the form of their own specific type of objects e.g. Layers, Materials, LineTypes, etc.
To point out the collections I can simply use the methods with their names themselves. And If I want to access each of the objects present inside the collection, then I can iterate over the same. In a similar fashion as I did in the case of Blocks.
The list of object collections is given below:
- Dictionaries
- DimStyles
- Layers
- Layouts
- Linetypes
- Materials
- ModelSpace
- PaperSpace
- PlotConfigurations
- RegisteredApplications
- SelectionSets
- TextStyles
- UserCoordinateSystems
- Viewports
- Views
Now that I have listed all the object collections, let me present an example of how to use these methods.
print(acad.doc.DimStyles)
for i in (acad.doc.DimStyles):
print(i.Name)
O/p:
<comtypes.client.lazybind.Dispatch object at 0x00000209F4F11D00>
Standard
Annotative
ISO-25
In the same way, other important properties can also be fetched as given in the code below.
# height of document window
print(acad.doc.Height)
# width of document window
print(acad.doc.Width)
# lower Left to Upper Right Limits
print(acad.doc.Limits)
# return a boolean value for ObjectSnapMode to check if it is on/off
print(acad.doc.ObjectSnapMode)
# path of Document
print(acad.doc.Path)
# return if Document is ReadOnly/Read-Write using boolean value
print(acad.doc.ReadOnly)
# check if document contains any unsaved changes using boolean value
print(acad.doc.Saved)
# returns SummaryInfo objects which contains document metadata (Title, subject, author, keywords)
print(acad.doc.SummaryInfo)
# returns if window is Minimized, Maximized or in a Normal state
print(acad.doc.WindowState)
# returns the document title
print(acad.doc.WindowTitle)
O/p:
818
1517
(0.0, 0.0, 420.0, 297.0)
False
C:\Users\91998\OneDrive\Documents
False
False
<comtypes.client.lazybind.Dispatch object at 0x000001C227C460D0>
3
Drawing1.dwg
Methods of the Document object class in AutoCAD
Now that I have covered the various properties of the AutoCAD Document object I will move forward to some of the important methods of the AutoCAD Document class.
In fact, the very first method I am talking about is Activate() method. To activate any document I can use this method.
acad.doc.Activate
Thereafter, to evaluate the integrity of any drawing I can use the AuditInfo() method. Here, I can pass true or false as parameters for whether or not I want AutoCAD to fix the problems it encounters.
acad.doc.AuditInfo(True)
Certainly, there are also a few methods for regenerating, saving, and closing.
# regenerate drawing
acad.doc.Regen
# save drawing
acad.doc.Save
# while closing pass boolean to save changes or not followed by drawing name
acad.doc.Close(False, "Drawing2.dwg")3
Finally, to remove unused named references like blocks or layers from the Document I can use the PurgeAll command.
acad.doc.PurgeAll
Summary and concluding remarks
Finally, I conclude the following: Using the AutoCAD Document class methods documented in this article I can automatize different Document object-related tasks. This can be applied to automatize and optimize AutoCAD-related workflows.
Lastly, in case of any doubts, please feel free to comment below in the comment section. I am also open to technical consultation for which you can contact me by using our contact form. Please check out my other blogs covering various aspects of the pyautocad and pywin32 Python modules for AutoCAD automatization.
References to related AutoCAD automatization documentation
And now, a list of links to various AutoCAD automatization posts published by me on this blog:
- Link: Python for AutoCAD pyautocad module
- Link: add() method in pyautocad
- Link: Solved call was rejected by callee in pythoncom
- Link: Tree data structure for AutoCAD objects using Python
- Link: Extending the objects in AutoCAD using pyautocad in Python
- Link: Using Python lists and dictionaries to work with AutoCAD objects with pyautocad
- Link: Hatching objects on AutoCAD template using pywin32 in Python
- Link: Raster image object in AutoCAD with pyautocad in Python
- Link: Working with 3D mesh object in AutoCAD using pyautocad in Python
- Link: Creating adouble constructor using pywin32 in Python
- Link: Creating apoint method using pywin32 in Python
- Link: Python integration with AutoCAD using pywin32 and win32com
- Link: Deleting objects in a AutoCAD template with pyautocad and pywin32 in Python
- Link: Mirror object on a 2D plane with pyautocad in Python
- Link: Working with texts in Autocad using pyautocad in Python
- Link: Polar arrays in AutoCAD using pyautocad in Python
- Link: Rectangular arrays in AutoCAD using pyautocad in Python
- Link: Operations with AutoCAD objects using pyautocad in Python
- Link: Solid objects in AutoCAD using pyautocad in Python
- Link: Working with helices in AutoCAD using pyautocad in Python
- Link: Drawing splines in AutoCAD with pyautocad in Python
- Link: Polylines in pyautocad for drawing AutoCAD polygons in Python
- Link: Drawing ellipse arcs in AutoCAD using pyautocad in Python
- Link: Drawing arcs in AutoCAD using pyautocad in Python
- Link: Near simultaneous factory design and process optimization with Promodel AutoCAD edition
- Link: Python for AutoCAD pyautocad module
- Link: Region object in AutoCAD with Python
- Link: AutoCAD Application object class in Python
Civil engineer interested in automation in core subjects such as civil, mechanical and electrical, using IT skills comprising cloud computing, devops, programming languages and databases along with the technical skills gained while working as a civil engineer since past 3 years.
6 comments
Hello, i am currently using Python to work on AutoCAD Automation, the overall idea is that I am using the For loop to open the required drawings(I can say it is a template, and the later step is to txt file to modify the attribute on the template), import the attribute to the drawings, plot the drawing in pdf format, save as the Drawing with a specified drawing name and close it, the whole process will keep looping until it complete.
May I know is there any command or method to open the required drawings template when there is no drawings opened? As when I finish the first drawings and close it, I can’t use the acad.activeDocument.SendCommand(“QNEW”) to create a new drawing, as i have closed all drawings and i cannot ask python to type QNEW to create a new drawing.
i have try to change the sequence of the program, I create an empty drawing at first, and issue the command acad.ActiveDocument.SendCommand(“closeallother”+chr(13)) later to close the drawing i have saved in the preview for loop. The program runs everything fine in the first for loop, but runtime error in the second for loop.
May I know is there any idea on modifying this program?
Here is my program.
Thank you so much!!!!!!
from pyautocad import Autocad, APoint
import os
import win32com.client
import xlrd
import time
################################################################################
AutoCAD = win32com.client.Dispatch(“AutoCAD.Application”)
acad = Autocad(create_if_not_exists=True)
################################################################################
time.sleep(2.5)
Drive_Location = r”C:\Users\XXX\Desktop\Drawings Testing”
ConfgPath = r”C:\Users\XXX\Desktop\Drawings Testing\Rack Configuration.xlsx”
PrintConfig = r”C:\Users\XXX\Desktop\Drawings Testing\Drawings Ref\Print Ref.dwg”
#Autoprofile = r”C:\Users\XXX\AppData\Local\Autodesk\AutoCAD Electrical 2022\R24.1\enu\Template\acad.dwt”
from xlrd import open_workbook
workbook = xlrd.open_workbook(ConfgPath)
print (workbook)
# acad.ActiveDocument.SendCommand(“filedia” + chr(13)+”0″+ chr(13))
# acad.ActiveDocument.SendCommand(“-expert”+chr(13)+”2″+chr(13))
# acad.ActiveDocument.SendCommand(“attdia”+chr(13)+”0″+chr(13))
AutoCAD.Visible = True
for sh in workbook.sheets():
PartNumber = sh.cell(0,0).value # sh.cell(Row, Column)
DrawingsFile = PartNumber + “.dwg”
DrawingsPath = os.path.join(r’C:\Users\XXX\Desktop\Drawings Testing\Drawings Ref’,DrawingsFile)
print(DrawingsPath)
Drawing_ID = sh.cell(0,1).value
Configtxt = Drawing_ID+”.txt” ###### < the configuration txt file will be the same as the drawings ID, which list in the database. Adding the .txt to complete the full path.
Configtxt_Path= os.path.join(r'C:\Users\XXX\Desktop\Drawings Testing',Configtxt) # complete the full configuration txt path
Printlocat = os.path.join(r'C:\Users\XXX\Desktop\Drawings Testing\Drawings Output',Drawing_ID)
acad.ActiveDocument.Application.Documents.Open(DrawingsPath) #Open the drawings as per the configuraation file mentioned
time.sleep(1)
acad.ActiveDocument.SendCommand("attin" + chr(13)+ Configtxt_Path + chr(13)) #using the autocad command to import the configuration file to the autocad and update all attribute.
time.sleep(1)
acad.ActiveDocument.SendCommand("closeallother"+chr(13))
time.sleep(10)
acad.ActiveDocument.SendCommand("-plot" + chr(13) + "n" + chr(13) + "layout1" + chr(13) + chr(13) + chr(13) + Printlocat + chr(13 ) +"Y" + chr(13) + "Y" + chr(13))
acad.ActiveDocument.SendCommand("tilemode" + chr(13) + "1" + chr(13))
save_as_location = Drive_Location + "/" + Drawing_ID+".dwg" # jointing the Drive Location and the Drawings ID and file type together for next step.
acad.ActiveDocument.SendCommand("saveas" + chr(13)+ "lt2018" + chr(13) + save_as_location + chr(13))#save as a new files and file name is Drawing ID
acad.ActiveDocument.SendCommand("QNEW"+chr(13))
acad.prompt("process completed")
Hello Ken,
Thanks for your question. Could you please send me the error? Also if possible the excel file?
Hello Tanmay,
The below message is the error file.
Traceback (most recent call last):
File “c:\Users\kenk0\Downloads\New Method.py”, line 53, in
acad.ActiveDocument.SendCommand(“-plot” + chr(13) + “n” + chr(13) + “layout1″ + chr(13) + chr(13) + chr(13) + Printlocat + chr(13 ) +”Y” + chr(13) + “Y” + chr(13))
File “C:\Users\kenk0\AppData\Local\Programs\Python\Python310\lib\site-packages\comtypes\client\dynamic.py”, line 111, in __getattr__
dispid = self._comobj.GetIDsOfNames(name)[0]
File “C:\Users\kenk0\AppData\Local\Programs\Python\Python310\lib\site-packages\comtypes\automation.py”, line 725, in GetIDsOfNames
self.__com_GetIDsOfNames(riid_null, arr, len(names), lcid, ids)
_ctypes.COMError: (-2147418111, ‘Call was rejected by callee。’, (None, None, None, 0, None))
PS C:\Users\kenk0\OneDrive\Documents\Autocad Automation>
While for the excel file, please refer to the below link:
https://drive.google.com/drive/folders/17GHcm9rEQiAugV894jlBw1Zf0-FDL9WQ?usp=sharing
The overall symptom is that, if I don’t run the command “acad.ActiveDocument.SendCommand(“closeallother”+chr(13))”, the program works fine, the second for loop can be executed successfully.
I have also tried to put this command in a different line, the program will error after executing the second time of “acad.ActiveDocument.SendCommand(“closeallother”+chr(13))”
If we consider the functionality of the program, it is not possible for AutoCAD to run keep opening the drawings(let’s say 100 drawings, as I am using for loop to change the attributes)
Hi ken,
As you can see the error says “call was rehected by called”. There are two scenarios which could throw this error that i know of.
1. First is manual interruption, like if we open the autocad console while this script is running.
2. Due to system is unable to handle the called with as fast as the script is calling for certain function.
In this scenario I feel it is the second problem causing this issue. Use time.sleep before line 53 i.e. acad.ActiveDocument.SendCommand… with a higher value. I can see that you have used 1 as parameter to that. A trial and error can help you get the lowest required value that you should use to run this script successfully.
Have a great day!
Thanks for your help
Hello!
Thanks for your posts on pyautocad. I’ve got some trouble understanding how can I activate a spesific drawing so that I can draw on the drawing. For example, I’ve got two drawings open “Drawing1.dwg” and “Drawing2.dwg”. How can I make the one I want active? I tried these but I think Drawing2 is active all the time.
for doc in acad.app.Documents:
acad.doc.Activate
print(acad.doc.WindowTitle)
#Output:
# Drawing2.dwg
# Drawing2.dwg
Thanks!