Por estes dias me perguntaram como usar reactors.
Bem, não é complicado, mas o help não ajuda muito... enfim...
Considere o exemplo abaixo:
;nome da xdata
(setq xdata:nome "TESTEXDATAREACTOR")
;carrega funções vl*
(vl-load-com)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;subrotina para adicionar xdata na entidade
;ent -> ename, por exemplo: <Entity name: 7ffff4104e0>
;xdappname -> string, nome da xdada
;xdata elista da xdata, formato:
;((ExtendDataDxfCode . Valor) ... (ExtendDataDxfCode . Valor))
(defun xdata->put (ent xdappname xdata / elist)
;garanta que o nome da xdata esta no banco de dados do cad
(regapp xdappname)
;adiciona a xdata no elist da entidade
(setq elist (entget ent)
elist (cons (list -3 (cons xdappname xdata)) elist))
;atualiza a entidade
(entmod elist)
(entupd ent)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;reactor para ação da linha sendo modificada
;note que este reactor não causa modificações na LINHA, apenas no texto
;se fazemos um reactor causar modificações em algo que dispara reactors,
;temos de desabilitar eles antes de modificar
;parametros:
;linha, é o objeto que notificou o reactor, no caso a linha
;rea, é o ponteiro para o objeto do reactor
;par, são parâmetros adicionais que podem ser passados ao reactor
;na hora que o criamos, no caso, não passamos nenhum dado extra
;então não usamos o seu valor, que será nil
(defun reactor->modified (linha rea par / params texto)
;obter os dados do reactor. note que não seria necessario
;pois poderiamos encontrar o texto pelo xdata.
;no caso é só para mostrar o uso da função vlr-data
;para obter o texto pela xdata, veja a subrotina reactors->aciona
(setq params (vlr-data rea)
texto (car params))
;atualizar o conteudo do texto:
(vla-put-textstring
texto
(strcat "l=" (rtos (vla-get-length linha) 2 2)))
(vla-put-insertionpoint texto (vla-get-startpoint linha))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;subrotina para "ligar" os reators para as linhas já desenhadas
;em um desenho com o nosso novo comando "teste"
(defun reactors->aciona (/ ss ent linha xdata texto)
;seleção das linhas que tem a nossa xdata
(setq ss (ssget "X" (list
'(0 . "LINE")
(list -3 (list xdata:nome)))))
;se ela existir, processa as linhas
(if ss
(repeat (sslength ss)
;pega a primeira linha
(setq ent (ssname ss 0) ;ename
linha (vlax-ename->vla-object ent) ;ename para vla
xdata (assoc -3 (entget ent (list xdata:nome))) ;xdata da linha
;agora, pega o handle, que é string, acha o ename e obtem o vla
texto (vlax-ename->vla-object (handent (cdr (cadadr xdata))))
)
;cria o reactor para a linha
(vlr-object-reactor
(list linha) ;objeto modificado que notifica o reactor
(list texto) ;parametros a serem passados
'((:vlr-modified . reactor->modified)))
;tira a linha da seleção e reinicia o looping
(ssdel ent ss)
)
)
;perfumaria:
(princ "\nReactors criados")
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;função principal
(defun c:teste (/ linha texto pa pb thisdrawing model xdata)
;desenha uma lina e um texto no modelspace:
(setq pa (getpoint "\nPa")
pb (getpoint pa "\nPb")
;obtem o ponteiro para o modelspace
thisdrawing (vla-get-activedocument(vlax-get-acad-object))
model (vla-get-modelspace thisdrawing)
;cria uma linha no model
linha (vla-addline model
(vlax-3d-point pa)
(vlax-3d-point pb))
;cria um texto no model
texto (vla-addtext model
(strcat "l=" (rtos (vla-get-length linha) 2 2))
(vlax-3d-point pa)
4)
)
;vincula a linha ao texto usando um xdata
;1005 é o dxfcode de xdata para "handle" da entidade
(xdata->put
(vlax-vla-object->ename linha) ;ename da linha
xdata:nome ;nome da xdata
(list (cons 1005 (vla-get-handle texto))) ;a xdata propriamente dita
)
;cria um reactor para linha, associando ao evento de modificar a linha
(vlr-object-reactor
(list linha) ;objeto modificado que notifica o reactor
(list texto) ;parametros a serem passados
'((:vlr-modified . reactor->modified) ;evento a ser chamado ao disparar o reactor
))
;perfumaria
(princ "\nFeito")
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;sempre que a lisp for carregada com APPLOAD,
;será acionada a função 'reactors->aciona' para "ligar" os reactors nas linhas criadas
;com o comando que criamos
(reactors->aciona)
O exemplo pede dois pontos, por ele faz passar uma linha e cria um texto no inicio da linha.
Na linha, cria um vinculo com o texto atravez de xdata.
Por fim, cria um reactor, que é um evento. Este evento modifica o conteúdo e a posição do texto conforme modificamos a linha. Simples, não?
O evento que você informa no reactor é monitorado pelo cad e quando acontece o evento, o reactor dispara uma função que informamos.
Igual aos eventos do VBA ou VB. Claro que o exemplo é bem simples, ainda falta monitorar o que acontece se apagamos o texto por exemplo.
O reactor não teria o que atualizar e um erro seria mostrado.
Outro exemplo: Se copiássemos a linha, o texto também poderia ser copiado.....
Outro exemplo: Se editássemos o texto, o reactor não faria nada até modificar a linha.
Neste caso, poderíamos monitorar edições no texto.
Se o fizermos, temos de ter em mente que se precisar modificar o texto, o reactor que o monitora precisa ser desligado antes de editar ele....
Para esta situação, procure por reactor no meu blog. Tem algumas rotinas bem legais!!!
;nome da xdata
(setq xdata:nome "TESTEXDATAREACTOR")
;carrega funções vl*
(vl-load-com)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;subrotina para adicionar xdata na entidade
;ent -> ename, por exemplo: <Entity name: 7ffff4104e0>
;xdappname -> string, nome da xdada
;xdata elista da xdata, formato:
;((ExtendDataDxfCode . Valor) ... (ExtendDataDxfCode . Valor))
(defun xdata->put (ent xdappname xdata / elist)
;garanta que o nome da xdata esta no banco de dados do cad
(regapp xdappname)
;adiciona a xdata no elist da entidade
(setq elist (entget ent)
elist (cons (list -3 (cons xdappname xdata)) elist))
;atualiza a entidade
(entmod elist)
(entupd ent)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;reactor para ação da linha sendo modificada
;note que este reactor não causa modificações na LINHA, apenas no texto
;se fazemos um reactor causar modificações em algo que dispara reactors,
;temos de desabilitar eles antes de modificar
;parametros:
;linha, é o objeto que notificou o reactor, no caso a linha
;rea, é o ponteiro para o objeto do reactor
;par, são parâmetros adicionais que podem ser passados ao reactor
;na hora que o criamos, no caso, não passamos nenhum dado extra
;então não usamos o seu valor, que será nil
(defun reactor->modified (linha rea par / params texto)
;obter os dados do reactor. note que não seria necessario
;pois poderiamos encontrar o texto pelo xdata.
;no caso é só para mostrar o uso da função vlr-data
;para obter o texto pela xdata, veja a subrotina reactors->aciona
(setq params (vlr-data rea)
texto (car params))
;atualizar o conteudo do texto:
(vla-put-textstring
texto
(strcat "l=" (rtos (vla-get-length linha) 2 2)))
(vla-put-insertionpoint texto (vla-get-startpoint linha))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;subrotina para "ligar" os reators para as linhas já desenhadas
;em um desenho com o nosso novo comando "teste"
(defun reactors->aciona (/ ss ent linha xdata texto)
;seleção das linhas que tem a nossa xdata
(setq ss (ssget "X" (list
'(0 . "LINE")
(list -3 (list xdata:nome)))))
;se ela existir, processa as linhas
(if ss
(repeat (sslength ss)
;pega a primeira linha
(setq ent (ssname ss 0) ;ename
linha (vlax-ename->vla-object ent) ;ename para vla
xdata (assoc -3 (entget ent (list xdata:nome))) ;xdata da linha
;agora, pega o handle, que é string, acha o ename e obtem o vla
texto (vlax-ename->vla-object (handent (cdr (cadadr xdata))))
)
;cria o reactor para a linha
(vlr-object-reactor
(list linha) ;objeto modificado que notifica o reactor
(list texto) ;parametros a serem passados
'((:vlr-modified . reactor->modified)))
;tira a linha da seleção e reinicia o looping
(ssdel ent ss)
)
)
;perfumaria:
(princ "\nReactors criados")
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;função principal
(defun c:teste (/ linha texto pa pb thisdrawing model xdata)
;desenha uma lina e um texto no modelspace:
(setq pa (getpoint "\nPa")
pb (getpoint pa "\nPb")
;obtem o ponteiro para o modelspace
thisdrawing (vla-get-activedocument(vlax-get-acad-object))
model (vla-get-modelspace thisdrawing)
;cria uma linha no model
linha (vla-addline model
(vlax-3d-point pa)
(vlax-3d-point pb))
;cria um texto no model
texto (vla-addtext model
(strcat "l=" (rtos (vla-get-length linha) 2 2))
(vlax-3d-point pa)
4)
)
;vincula a linha ao texto usando um xdata
;1005 é o dxfcode de xdata para "handle" da entidade
(xdata->put
(vlax-vla-object->ename linha) ;ename da linha
xdata:nome ;nome da xdata
(list (cons 1005 (vla-get-handle texto))) ;a xdata propriamente dita
)
;cria um reactor para linha, associando ao evento de modificar a linha
(vlr-object-reactor
(list linha) ;objeto modificado que notifica o reactor
(list texto) ;parametros a serem passados
'((:vlr-modified . reactor->modified) ;evento a ser chamado ao disparar o reactor
))
;perfumaria
(princ "\nFeito")
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;sempre que a lisp for carregada com APPLOAD,
;será acionada a função 'reactors->aciona' para "ligar" os reactors nas linhas criadas
;com o comando que criamos
(reactors->aciona)
O exemplo pede dois pontos, por ele faz passar uma linha e cria um texto no inicio da linha.
Na linha, cria um vinculo com o texto atravez de xdata.
Por fim, cria um reactor, que é um evento. Este evento modifica o conteúdo e a posição do texto conforme modificamos a linha. Simples, não?
O evento que você informa no reactor é monitorado pelo cad e quando acontece o evento, o reactor dispara uma função que informamos.
Igual aos eventos do VBA ou VB. Claro que o exemplo é bem simples, ainda falta monitorar o que acontece se apagamos o texto por exemplo.
O reactor não teria o que atualizar e um erro seria mostrado.
Outro exemplo: Se copiássemos a linha, o texto também poderia ser copiado.....
Outro exemplo: Se editássemos o texto, o reactor não faria nada até modificar a linha.
Neste caso, poderíamos monitorar edições no texto.
Se o fizermos, temos de ter em mente que se precisar modificar o texto, o reactor que o monitora precisa ser desligado antes de editar ele....
Para esta situação, procure por reactor no meu blog. Tem algumas rotinas bem legais!!!
Nenhum comentário:
Postar um comentário