Jump to content

Recommended Posts

Posted (edited)

I can't find a better place - please move the topic if I missed it.

 

Edit: TL,DR: how to cancel current command using pyautocad or win32com?

 

Full version:

I'm working an a simple code that takes info from excel and uses it to insert block(s) and change attribute values. The code works fine. I used a VBA version for a long time, but I decided to rewrite it due to speed problems in python using pyautocad and win32com libraries. I solved or safeguarded most of the problems, but I struggle to send double escape to cancel user input. The code is fully independent from user input and it does not need any user interaction. I want to prevent accidental typing into AutoCAD user prompt as it upsets the code.

I can send double escape when there is nothing in the command prompt, but as soon as there is something there - the send command stops working, probably waiting for user input.

 

Anyway  - if there is anyone experienced with the python / AutoCAD integration I can prepare a sample code to show the problem.

Edited by pefi
add tldr
Posted

I have some experience with python / AutoCAD integration with the wrappers I’m working on

https://github.com/CEXT-Dan/PyRx

 

Its all in process though, I don’t have much experience out of process though.

Post a sample, I’ll try to help

  • Like 1
Posted
from pyautocad import Autocad
import win32com.client

print("Setting up pyautocad access...", end='')
acad = Autocad(create_if_not_exists=True)
print("done")

print("Setting up win32com access...", end='')
acad32 = win32com.client.Dispatch("AutoCAD.Application")
print("done")

print("Adding blank drawing...", end='')
dwg = acad.Application.Documents.Add('')
print("done")

print("Sending a command with pyautocad...", end='')
acad.doc.SendCommand("-PURGE\nAll\n\nN\n")
print("done")

print("Getting active document...", end='')
ad = acad32.ActiveDocument
print("done")

print("Sending a command with win32com...", end='')
ad.SendCommand("-PURGE\nAll\n\nN\n")
print("done")

If you run the code with AutoCAD closed or running it works fine as long as there is nothing typed in the command prompt. If there is something typed in the command prompt the code will fail with:

Setting up pyautocad access...done
Setting up win32com access...done
Adding blank drawing...Traceback (most recent call last):
  File "C:/loop-generator/dwg-generator/error_demo.py", line 13, in <module>
    dwg = acad.Application.Documents.Add('')
  File "C:\Users\firsztp\AppData\Local\Programs\Python\Python313\Lib\site-packages\comtypes\client\dynamic.py", line 120, in __getattr__
    dispid = self._comobj.GetIDsOfNames(name)[0]
  File "C:\Users\firsztp\AppData\Local\Programs\Python\Python313\Lib\site-packages\comtypes\automation.py", line 828, in GetIDsOfNames
    self.__com_GetIDsOfNames(riid_null, arr, len(names), lcid, ids)  # type: ignore
_ctypes.COMError: (-2147418111, 'Call was rejected by callee.', (None, None, None, 0, None))

 

 

Posted

I'm testing a solution created after a session with an AI:

import win32com.client
import time

# Create an instance of AutoCAD application
acad = win32com.client.Dispatch("AutoCAD.Application")
acad.Visible = True

# Ensure AutoCAD is in focus
shell = win32com.client.Dispatch("WScript.Shell")
shell.AppActivate("AutoCAD")

# Send the Escape key
shell.SendKeys("{ESC}")

# Allow a moment for the command to cancel
time.sleep(1)

 

Posted

Usually, the escape prefix is ‘^C^C’ as mentioned here, I.e. acad.doc.SendCommand("^C^C-PURGE…. ")

https://www.keanw.com/2006/08/cancelling_an_a.html

 

If a command is actually running, then there’s not much you can do because the document is most likely locked.

However, you can test if AutoCAD is ready to except a command by using the Application.GetAcadState method

https://help.autodesk.com/view/ACD/2024/ENU/?guid=GUID-0225808C-8C91-407B-990C-15AB966FFFA8

 

if you don’t need to be running out of process, and your version of CAD is compatible, you should try to run PyRx. It’s literally 100s of times faster than pyautocad. You get all or ActiveX and a big subset of ObjectArx

 

 

 

 

  • Like 1
Posted (edited)

Just a thought can you send this (chr 27) it is the escape key. Send character in Python.

 

Edited by BIGAL
Posted

Thank you! I need to check closer PyRx...I have no clue about ActiveX or ObjectArx, but for the purpose of "insert block, replace attributes" should not be too hard to understand. Sending chr(27) was working only when there was blank prompt, I didn't try ^C, but the problem was not with what to send, but with the AutoCAD to accepting anything.

 

P.S. I need to try ^C anyway....

Posted

Replacing:

self.acad.doc.SendCommand("_-INSERT" + " " + full_block_path + "\n" + "0,0,0" + "\n\n\n\n")

with

self.acad.doc.SendCommand("^C^C_-INSERT" + " " + full_block_path + "\n" + "0,0,0" + "\n\n\n\n")

produces this:

Command: ^C^C_-INSERT Unknown command "^C^C_-INSERT".  Press F1 for help.

 

Posted

“but with the AutoCAD to accepting anything.”

then test IAcadState.

state : Ax.IAcadState = theApp.GetAcadState()
print(state.IsQuiescent) # True: AutoCAD is idle
        

 

ActiveX is COM automation, this is what pyautocad and win32com use to communicate with AutoCAD.

I used win32com’s makepy to generate the interface, then added converters to remove the need for variants.

 

PyRx is in process, the procedure is load in a python script with PyLoad, then run it, a quick example

import traceback
from pyrx_impx import Rx, Ge, Gi, Db, Ap, Ed, Ax

#creates a new command xdoit1
def PyRxCmd_xdoit1():
    try:
        theApp = Ax.getApp()
        doc = theApp.ActiveDocument
        blk = doc.Blocks.Add([0, 0, 0], "MYBLOCK")
        blk.AddAttribute(
            1,
            Ax.constants.acAttributeModeVerify,
            "New Prompt",
            [0, 0, 0],
            "NEW_TAG",
            "New Value",
        )
    except Exception as err:
        traceback.print_exception(err)

 

  • Like 1
Posted
24 minutes ago, pefi said:

Replacing:

self.acad.doc.SendCommand("_-INSERT" + " " + full_block_path + "\n" + "0,0,0" + "\n\n\n\n")

with

self.acad.doc.SendCommand("^C^C_-INSERT" + " " + full_block_path + "\n" + "0,0,0" + "\n\n\n\n")

produces this:

Command: ^C^C_-INSERT Unknown command "^C^C_-INSERT".  Press F1 for help.

 

 

 

Don’t use SendCommand, use the API

 

axApp = Ax.getApp()
path = "M:\\Dev\\Projects\\PyRxGit\\PySamples\\dwg\\18X36RP.dwg"
ref = axApp.ActiveDocument.ModelSpace.InsertBlock((0, 0, 0), path, 1, 1, 1, 0)

 

You may have to use APoint(0,0,0)

Posted

OK, but I also burst and purge, print to pdf using a custom command, so I need to use SendCommad anyway. I changed approach - try/except the whole drawing creation function and repeat after cleaning everything  on any failure. Seems to be working.

P.S. Digging into your bindings is something that I need to do - looks to good to stick with pyautocad or win32com. Do you mind adding an open source licence to your code in github?

Posted

Note, Explode, PurgeAll and plot are all part of the API, accessible through pyautocad or win32com

 

Quote

Do you mind adding an open source licence to your code in github?

I'll add it

  • Like 1

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...