Bom, já ouviram falar de reactor, certo? então vou apresentar um exemplo simples de um reactor que reaje aos eventos adicionar/apagar entidades do autocad. Funciona assim: temos um bloco qualquer que iremos monitorar no desenho, atualizando a quantidade dele num texto pré-selecionado, de forma automática, isto é, sem termos de editar este texto manualmente!!
Isto é possível com o reactor "vlr-acdb-reactor" monitorando os eventos ":vlr-objectAppended" e ":vlr-objectErased" apenas.
Claro, monitoramos apenas um tipo de bloco, mas nada impede que adaptemos o código para monitorar qualquer quantidade de blocos... clique para ver a rotina:
Para os que viram a rotina, seria interessante ainda tornar o reactor persistente, assim, ao fecharmos o desenho e abrirmos ele novamente, o reactor estará ativo sem que precisemos criar ele novamente, pois da forma que apresentei o exemplo, ao fechar o desenho, o reactor é destruído, e presisaríamos recriar ele a cada "open" que déssemos no desenho... para isso veja o help para "vlr-pers"
Particularmente eu não uso o "vlr-pers" pois se nao mantivermos a rotina no start up suite (ou no acad.lsp), se esta nao estiver carregada, com o reactor no modo persistente, a cada alteração no desenho veríamos uma mensagem na linha de comando dizendo que a função XXX não está definida... isso é irritante, ainda mais se mandarmos o desenho pro cliente!!! ele seguramente não terá a rotina carregada!!
Ao invés desta solução, prefiro criar uma rotina que ao ser carregada, inicialize um reactor novinho em folha no modo nao persistente, assim, ao fechar o desenho ele é destruído... e não me encomodará o cliente!!!
Isto é possível com o reactor "vlr-acdb-reactor" monitorando os eventos ":vlr-objectAppended" e ":vlr-objectErased" apenas.
Claro, monitoramos apenas um tipo de bloco, mas nada impede que adaptemos o código para monitorar qualquer quantidade de blocos... clique para ver a rotina:
mais...
(setq *lista_adicionados* nil) ;inicializa a lista de blocos
(defun c:teste (/ blc_name txt)
;pede o nome do bloco e pede para selecionar um texto a ser incrementado:
(if (setq blc_name (getstring "\nQual o nome do bloco que será monitorado?" t))
(if (setq txt (car (entsel "\nSelecione um texto que será incrementado")))
;tendo as duas informações, cria um reactor:
(vlr-acdb-reactor
;dados do reactor: nome do bloco e a HANDLE do texto
(list (strcase blc_name) (cdr (assoc 5 (entget txt))))
;eventos & ações deste reactor:
'((:vlr-objectAppended . objeto-adicionado)
(:vlr-objectErased . objeto-apagado)))))
;sai... fim do programa
(princ)
)
;-------------------------ações do nosso reactor:-------------------------
;ação para entidade adicionada no autocad:
(defun objeto-adicionado (rea ;o reactor em si
par ;parametros passados pelo reactor
/ ent name data blc_name txt qtd)
;ENAME da entidade que foi adicionada à base de entidades do cad:
(setq ent (cadr par)
;se for um bloco, terá o DXF 2, que é o nome do bloco:
name (cdr (assoc 2 (entget ent)))
;precisamos saber que tipo de entidade foi adicionada:
tipo (cdr (assoc 0 (entget ent)))
;dados do reactor, passamos estes valores no c:teste
;na linha (list (strcase blc_name) ...
data (vlr-data rea)
;nome do bloco que monitoramos
blc_name (car data)
;handle do texto que queremos incrementar:
txt (cadr data))
;teste se é um bloco e se é do nome que interessa:
(if (equal "INSERT" tipo)
(if (equal (strcase name) blc_name)
;o texto ainda existe?
(if (setq txt (handent txt))
;entao incrementa ele:
(progn
(setq txt (vlax-ename->vla-object txt) ;conversao
qtd (atoi (vla-get-textstring txt)) ;quantidade atual
qtd (1+ qtd);incrementa
;aqui, temos que gravar a ENAME do novo bloco numa lista, para podermos saber
;depois se ele for apagado:
*lista_adicionados* (cons ent *lista_adicionados*))
;altera o valor do texto e atualiza ele:
(vla-put-textstring txt (itoa qtd))
(vla-update txt)
;libera o VLA da memoria:
(vlax-release-object txt))))))
;ação para objeto APAGADO:
(defun objeto-apagado (rea par / ent data blc_name txt qtd)
;mesmas considerações do evento acima...
(setq ent (cadr par)
data (vlr-data rea)
txt (cadr data))
; a entidade apagada é um dos blocos que adicionamos??
(if (member ent *lista_adicionados*)
;entao, se o texto ainda existir:
(if (setq txt (handent txt))
(progn
;decrementa a quantidade e tira o ENAME da lista...
(setq txt (vlax-ename->vla-object txt)
*lista_adicionados* (vl-remove ent *lista_adicionados*)
qtd (atoi (vla-get-textstring txt))
qtd (1- qtd))
;atualiza o texto:
(vla-put-textstring txt (itoa qtd))
(vla-update txt)
;libera o VLA da memoria:
(vlax-release-object txt)
))))
(defun c:teste (/ blc_name txt)
;pede o nome do bloco e pede para selecionar um texto a ser incrementado:
(if (setq blc_name (getstring "\nQual o nome do bloco que será monitorado?" t))
(if (setq txt (car (entsel "\nSelecione um texto que será incrementado")))
;tendo as duas informações, cria um reactor:
(vlr-acdb-reactor
;dados do reactor: nome do bloco e a HANDLE do texto
(list (strcase blc_name) (cdr (assoc 5 (entget txt))))
;eventos & ações deste reactor:
'((:vlr-objectAppended . objeto-adicionado)
(:vlr-objectErased . objeto-apagado)))))
;sai... fim do programa
(princ)
)
;-------------------------ações do nosso reactor:-------------------------
;ação para entidade adicionada no autocad:
(defun objeto-adicionado (rea ;o reactor em si
par ;parametros passados pelo reactor
/ ent name data blc_name txt qtd)
;ENAME da entidade que foi adicionada à base de entidades do cad:
(setq ent (cadr par)
;se for um bloco, terá o DXF 2, que é o nome do bloco:
name (cdr (assoc 2 (entget ent)))
;precisamos saber que tipo de entidade foi adicionada:
tipo (cdr (assoc 0 (entget ent)))
;dados do reactor, passamos estes valores no c:teste
;na linha (list (strcase blc_name) ...
data (vlr-data rea)
;nome do bloco que monitoramos
blc_name (car data)
;handle do texto que queremos incrementar:
txt (cadr data))
;teste se é um bloco e se é do nome que interessa:
(if (equal "INSERT" tipo)
(if (equal (strcase name) blc_name)
;o texto ainda existe?
(if (setq txt (handent txt))
;entao incrementa ele:
(progn
(setq txt (vlax-ename->vla-object txt) ;conversao
qtd (atoi (vla-get-textstring txt)) ;quantidade atual
qtd (1+ qtd);incrementa
;aqui, temos que gravar a ENAME do novo bloco numa lista, para podermos saber
;depois se ele for apagado:
*lista_adicionados* (cons ent *lista_adicionados*))
;altera o valor do texto e atualiza ele:
(vla-put-textstring txt (itoa qtd))
(vla-update txt)
;libera o VLA da memoria:
(vlax-release-object txt))))))
;ação para objeto APAGADO:
(defun objeto-apagado (rea par / ent data blc_name txt qtd)
;mesmas considerações do evento acima...
(setq ent (cadr par)
data (vlr-data rea)
txt (cadr data))
; a entidade apagada é um dos blocos que adicionamos??
(if (member ent *lista_adicionados*)
;entao, se o texto ainda existir:
(if (setq txt (handent txt))
(progn
;decrementa a quantidade e tira o ENAME da lista...
(setq txt (vlax-ename->vla-object txt)
*lista_adicionados* (vl-remove ent *lista_adicionados*)
qtd (atoi (vla-get-textstring txt))
qtd (1- qtd))
;atualiza o texto:
(vla-put-textstring txt (itoa qtd))
(vla-update txt)
;libera o VLA da memoria:
(vlax-release-object txt)
))))
Para os que viram a rotina, seria interessante ainda tornar o reactor persistente, assim, ao fecharmos o desenho e abrirmos ele novamente, o reactor estará ativo sem que precisemos criar ele novamente, pois da forma que apresentei o exemplo, ao fechar o desenho, o reactor é destruído, e presisaríamos recriar ele a cada "open" que déssemos no desenho... para isso veja o help para "vlr-pers"
Particularmente eu não uso o "vlr-pers" pois se nao mantivermos a rotina no start up suite (ou no acad.lsp), se esta nao estiver carregada, com o reactor no modo persistente, a cada alteração no desenho veríamos uma mensagem na linha de comando dizendo que a função XXX não está definida... isso é irritante, ainda mais se mandarmos o desenho pro cliente!!! ele seguramente não terá a rotina carregada!!
Ao invés desta solução, prefiro criar uma rotina que ao ser carregada, inicialize um reactor novinho em folha no modo nao persistente, assim, ao fechar o desenho ele é destruído... e não me encomodará o cliente!!!
Olá Neyton,
ResponderExcluirNão consegui fazer a rotina que verifica se um dos blocos inseridos foi apagado funcionar. Sempre aparece o erro:
; error: bad argument type: VLA-OBJECT nil
Inserir 9 blocos e o texto foi incrementado para 9. Porém ao apagar 4 blocos a mensagem de erro sempre aparece e a quantidade, no texto, não é reduzida.
O que poderia ser?
---
Parabéns pelo ótimo Blog!!
[]s
fiz um teste aqui, o texto selecionado deve ser um TEXT e não um MTEXT, ok?
ResponderExcluirno mais funcionou...
Olá neyton
ResponderExcluirprocurava por esse lisp a tempos, porem frustrei-me com a tentativa pelo erro qpresentado a seguir:
Command: teste
Qual o nome do bloco que será monitorado?crt1_b1
Selecione um texto que será incrementado; error: no function definition:
VLR-ACDB-REACTOR
Command:
sei que este post é muito antigo e não quero pertubar-te ainda mais com isso, mais esse lisp facilitaria muito meu trabalho. uso o AutoCAD 2010 e esse lisp pelo que é descrito é sensacional e nunca encontrei algo parecido.
desde já lhe agradeço